[PATCH] DRI2: fixup handling of last_swap_target

Mario Kleiner mario.kleiner at tuebingen.mpg.de
Thu Mar 4 14:42:06 PST 2010

On Mar 4, 2010, at 7:45 PM, Jesse Barnes wrote:
> I just pushed everything into my personal xserver tree, can you check
> them out and make sure I got your patches right?
> git://people.freedesktop.org/~jbarnes/xserver
> --  
> Jesse Barnes, Intel Open Source Technology Center

Ok Jesse, i checked them. Our patches are happy with each other as  
far as i can see :-) -- thanks for cleaning this up.

I went over the whole hw/xfree86/dri2/dri2.c file again and found a  
couple of new bugs and problems. Don't have the time for preparing  
patches myself now, so i'll just list them, from severe to harmless:

* In DRI2CreateDrawable(), in the new last_swap_target init code, you  

  ret = (*ds->GetMSC)(pDraw, &ust, &pPriv->last_swap_target);

... without checking for if (!ds->GetMSC) ...

If this happens on an old DDX / non-Intel DDX, GetMSC == NULL -->  
Crash! This wasn't a problem in the old implementation, but now needs  
this check.

* In DRI2CreateDrawable(), there is pPriv->swap_interval = 1;

Default swap interval is set to 1 at init, ie., sync to retrace is  
on. I'd suggest considering a 0 swap interval as default. The  
glXSwapIntervalSGI() call only allows to set swap_interval to > 0 due  
to this bit from the SGI_swap_control spec: "glXSwapIntervalSGI  
returns GLX_BAD_VALUE if parameter <interval> is less than or equal  
to zero."

That means once you have a non-zero swap_interval, applications can't  
opt-out of vsyn'ed bufferswaps, they can only opt-in. Iow there ain't  
no way for an app to start without vsync.

Related, in DRI2SwapInterval(), a check for...

     if (pPriv == NULL)
         return BadDrawable;

... seems to be missing. All other routines check for this, so this  
one should probably do so as well.

* There seems to be some inconsistency or missing pieces in the way a  
drawable is destroyed, but i may miss something.

In DRI2DestroyDrawable(), once the pPriv->refcount drops to zero, the  
drawable is destroyed if there aren't any swaps pending. If swaps are  
pending, according to the comments there, destruction is postponed  
until DRI2SwapComplete() gets called. Makes sense.

But in DRI2SwapComplete() there isn't any logic that would check if  
(pPriv->swapsPending == 0 && pPriv->refcount == 0) and then free the  
drawable. Instead it checks for pPriv->refcount == 0 and if so,  
throws an error and free's the drawable. It shouldn't throw an error  
and it should only free it at the very end of the routine after  
DRI2WakeClient() was called, if (pPriv->swapsPending == 0). Current  
implementation has a swap limit of 1, so this is always true, but if  
the allowable number of outstanding swaps would be increased at some  
time, this would cause problems.

Another issue is DRI2WaitMsc() and DRI2WaitSbc(). They should  
probably complete immediately or throw an error if called while the  
drawable is already awaiting destruction with a pPriv->refcount == 0?

If a wait for a certain target_msc or target_sbc is already  
scheduled, one should probably also defer the destruction of the  
drawable until they complete?


DRI2WaitSBC and DRI2WaitMSC, maybe others as well (e.g.,  
DRI2WaitSwap?) should probably check for pPriv->refcount == 0 and  
return either an error or return immediately on such an "undead"  
drawable. Error return is probably better, given that the  
OML_sync_control spec requires an error return if no context/drawable  
is bound at time of call, and the drawable has been kind'a destroyed  
already if refcount == 0.

DRI2DestroyDrawable() should probably postpone destruction if (pPriv- 
 >swapsPending > 0 || pPriv->blockedClient != NULL), ie., if any  
waitsbc/waitmsc is already scheduled.

DRI2SwapComplete at its end, and DRI2WaitMSCComplete should probably  
check if it is time to destroy the drawable before returning and do  
so  if neccessary to avoid leaks.

Finally at a quick glance, there are more places in the code were  
there are potential problems with CARD64 values vs. 32 bit integers.  
The OML_sync_control spec wants CARD64 as return values for msc and  
and as target_msc for glXWaitForMscOML and glXSwapbuffersMscOML(),  
but the DRM in the kernel only operates with 32 bit vbl.request/ 
reply.sequence numbers and some of the DRI2 functions pass values as  
32 bit signed integers. Assuming a video refresh rate of 200 Hz for  
the fastest crt monitors i'm aware of, this could cause some overflow  
problems after 2^31 / 200 / 3600 / 24 = 124 days of uptime - not that  
unrealistic for a desktop machine. This will probably need fixes to  
the DRM or some wraparound handling or range checking in the xserver  
to make it really robust for unlucky applications that happen to get  
launched at the 124th day of uptime.


Mario Kleiner
Max Planck Institute for Biological Cybernetics
Spemannstr. 38
72076 Tuebingen

e-mail: mario.kleiner at tuebingen.mpg.de
office: +49 (0)7071/601-1623
fax:    +49 (0)7071/601-616
www:    http://www.kyb.tuebingen.mpg.de/~kleinerm
"For a successful technology, reality must take precedence
over public relations, for Nature cannot be fooled."
(Richard Feynman)

More information about the xorg-devel mailing list