Smooth Animations & Wait4Retraces

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Smooth Animations & Wait4Retraces

Post by Pype.Clicker »

Tim Robinson wrote: I saw your post on mouse pointers. Currently I erase the old one then draw the new one; and there's no transparency, so you can only have square pointers. I think what I should do is:

If the old pointer rectangle and the new one intersect:
  • Create an in-memory bitmap big enough to span the two rectangles
  • Copy from the screen into the bitmap
  • Copy the saved "underneath the pointer" bitmap to the bitmap, to erase the pointer image
  • Copy the bitmap to the "underneath the pointer" bitmap
  • Draw the new pointer to the bitmap
  • Draw the bitmap to the screen
If they don't intersect then I don't think there will be any flicker problem.
BI lazy wrote:
I use the trick with the area spanned by two "displacement rectangles" to move window boxes around the screen with a small amount of flicker - this you just can't avoid.

for the mouse: to get it transparent, I use the same mechanism like for drawing font: where a pixel is set in a valid colour in the bitmap, there I draw a pixel. If naught is to draw, then the area remains unchanged.

I too erase the pointer before redrawing it - animation requires it, no help from that. either you redraw the area underneath from a double buffer or from some kind of "what's beneath" bitmap owned by the mouse pointer. But which ever method I use, I have to do a "wait-for-vertical-retrace()" call to avoid flickering whilst moving the pointer.

that's how I do a normal mouse-movement without dragging some window-box around:

1. wait for vertical retrace
2. restore what's beneath the mouse pointer - old location
3. paint the mousepointer to the new location and meanwhile save what's beneath.

Code: Select all

buffer[bmp_offs]=vid_mem[offset+x];
            if(bmp[bmp_offs]){
              vid_mem[offset+x]=bmp[bmp_offs];
            }
  
that's roughly my mouse painting thing. this way is described on some website I remember as www.brackeen.com.
Tim Robinson wrote: I see what you're saying. I seem to have overlooked that. I wonder how I could integrate waiting for vertical refresh (into the kernel-mode driver) without using too much CPU time.

It would be useful to provide a generic rubber banding mechanism to apps, not just for dragging windows. The window manager could keep a list of them; when one was to be moved, it could wait for the vertical blank interval. It could also prevent them from being drawn over by other programs. Windows seems to do this for window rectangles, but not in a general case: if you drag a dockable toolbar in an MFC app, it locks the display until you release the mouse button.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Smooth Animations & Wait4Retraces

Post by Pype.Clicker »

A technique i would use to get a 'wait4verticalRetrace' feature in a multitasked environment would be to estimate on which clock tick the retrace is going to occur...

Of course, you're unlikely to get an IRQ0 (if we select this one) at the very moment when a VRT occurs, but if your clock ticks fast often, you could calibrate a counter so that it will warn your device that 'the retrace occurs somewhere around now' and do a polling at that moment (yes, there'll still be polling, but only during one timeslice rather than for a long period).

Also, most of the super-Vga cards have a dedicated IRQ (11?) for vertical retraces ... the problem then is to know how the card must be configured to emit those IRQs (this is likely to be card-dependent).

That's all for now ... Got to fetch my bus ;)

<damn> no school 4 kids today. bus missed </damn>
User avatar
df
Member
Member
Posts: 1076
Joined: Fri Oct 22, 2004 11:00 pm
Contact:

Re:Smooth Animations & Wait4Retraces

Post by df »

hmm a thread that does notthing but draw to the screen, between retraces, if there is something to write to the screen.

thank the goddess unchainged vga modes have gone away ;) unchainged VGA sucks!! hahahah the same goes for unchained ega modes.

but i spose with a multi taksing environment you cant just loop ... as its a very tight timing....

Code: Select all

      mov dx 0x3da
.l1:
      in al, dx
      and al, 8
      jz .l1
.l2:
      in al, dx
      and al, 8
      jnz .l2
-- Stu --
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Smooth Animations & Wait4Retraces

Post by distantvoices »

I use the looping to wait for vertical retrace. the thing is, meanwhile nothing else can happen, because the video-driver which does the painting, also does the waiting. thats not a very nice thing.

Now, after having read Pypes cmment about vga IRQ requests upon vertical refresh, I've done some research. I have not yet finished, but when I've achieved some knowledge, I gonna post it. Maybe it is worth some lines ;).
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
Tim

Re:Smooth Animations & Wait4Retraces

Post by Tim »

Well, you'd only need to wait for the vertical retrace if there was something to be animated.

So:

Code: Select all

void move_mouse_pointer(void)
{
    post_queue(&flicker_free_queue, mouse_pointer);
}

void flicker_free_thread(void)
{
    while (true)
    {
        sprite = grab_queue(&flicker_free_queue);
        wait_for_vertical_retrace();
        draw_sprite(sprite);
    }
}
...or maybe draw multiple sprites in one frame (i.e. grab everything from the queue, wait, draw).

This way you'd waste a maximum of 1/75th of a second each time you moved the mouse.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Smooth Animations & Wait4Retraces

Post by Pype.Clicker »

Tim Robinson wrote: This way you'd waste a maximum of 1/75th of a second each time you moved the mouse.
true, but this means that if you're moving the mouse often enough (i.e. at least one mouse IRQ per 1/75th of second), you'll be consuming up to 100% of the CPU time with the VRT wait thread :(


now, suppose you have IRQ0 working at a frequency higher than the time spent in vertical retrace (i.e. you're sure you'll always have at least *one* clock interrupt during the vertical retrace), you can estimate the amount of clock irq between 2 vertical retraces with

Code: Select all

clock_handler() {
   if (screen.retracing()) {
      new_vrt_speed=now() - screen.last_seen_vrt;
      screen.vrt_speed = alpha * screen.vrt_speed + (1-alpha) * new_vrt_speed;
      screen.retrace_counter=screen_vrt_speed;
   } 
   if (screen.retrace_counter<=1) {
       if (screen.need_refresh()) screen.refresher().wakeup();
   } else screen.retrace_counter--;
}
however, i must admit i don't really know the amount of time we have during the retrace, so i dunno if it's really practical or not.
It also require a scheduler that will be able to execute 'refresher' thread almost immediately (putting it at the end of the list would be useless as it would have an unpredictable delay before it gets executed :-/ )
BI lazy

Re:Smooth Animations & Wait4Retraces

Post by BI lazy »

Hmmm....

still haven't found anything USEABLE regarding vga interrupt handlers, but that is most probably coz I am searching for the wrong things.

I have found one thing: on former vga cards one has had the possibility to enable vga irq via a jumper. On nowadays mainboard bios there is a possibility to enable vga interrrupts. I am going to continue research in this direction. It woud be nice to have repaint start by an interrupt instead of busy waiting, albeit the whole messagepassing and wake up thread stuff might be more time consuming and inefficient. Just for the sak of trying it out....
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:Smooth Animations & Wait4Retraces

Post by Pype.Clicker »

i would say that either it's in the PCI configuration that you would find it or in some kind of card-specific informations ...
Tim

Re:Smooth Animations & Wait4Retraces

Post by Tim »

Update: I worked out a cool method of drawing a mouse pointer without flicker.

Here's the pseudocode:

At startup:
1. Allocate bitmap under and bitmap image, each big enough to hold the cursor image. Put the cursor image in image.
2. Allocate bitmap combined as twice the width and height of image.

To move the cursor:
Work out the rectangle covered by the cursor in its old position. Call it from.
Work out the rectangle covered by the cursor in its new position. Call it to.

If they overlap:
1. Work out a rectangle which covers both the old position and the new one. Call it both.
2. Translate from and to so that they're relative to the top-left corner of both.
3. Copy area both from the screen to combined.
4. Copy under to area from of combined.
5. Copy area to of combined to under.
6. Copy image to area to of combined.
7. Copy combined to area both of the screen.

If they don't overlap:
1. Erase the cursor from the old position
2. Draw the cursor at the new position

Here's my code:

Code: Select all

void GmgrMoveCursor(MGLreal from_x, MGLreal from_y, MGLreal to_x, MGLreal to_y)
{
   static const rect_t rect_cursor = { 0, 0, CURSOR_WIDTH, CURSOR_HEIGHT };
   rect_t from, to, both;

   set_cursor_rect(&from, from_x, from_y);
   set_cursor_rect(&to, to_x, to_y);

   if (RectTTestOverlap(&from, &to))
   {
      RectTUnion(&both, &from, &to);
      RectTOffset(&from, -both.left, -both.top);
      RectTOffset(&to, -both.left, -both.top);

      /* Capture what's on the screen now to cursor_combined */
      gmgr_screen->surf.vtbl->SurfBltScreenToMemory(&gmgr_screen->surf,
         cursor_combined.data, cursor_combined.pitch,
         &both);

      /* Erase the cursor image from cursor_combined */
      gmgr_screen->surf.vtbl->SurfBltMemoryToMemory(&gmgr_screen->surf,
         &cursor_combined, &from,
         &cursor_under, &rect_cursor);

      /* Capture what's at the new position to cursor_under */
      gmgr_screen->surf.vtbl->SurfBltMemoryToMemory(&gmgr_screen->surf,
         &cursor_under, &rect_cursor,
         &cursor_combined, &to);

      /* Draw the cursor image to cursor_combined */
      gmgr_screen->surf.vtbl->SurfBltMemoryToMemory(&gmgr_screen->surf,
         &cursor_combined, &to,
         &cursor_image, &rect_cursor);

      /* Draw the combined area to the screen */
      gmgr_screen->surf.vtbl->SurfBltMemoryToScreen(&gmgr_screen->surf,
         &both,
         cursor_combined.data, cursor_combined.pitch);
   }
   else
   {
      GmgrDrawCursor(from_x, from_y, false);
      GmgrDrawCursor(to_x, to_y, true);
   }
}
Post Reply