I was trying to run Starcraft under wine in using the X11 DGA2 mode to get a decent frame rate. I tried running it under various versions of wine and got the same result every time. The problem is that when wine runs the game using DGA2 it ignores all input from the keyboard and mouse and so appears to hang. When running the game with DGA2 support disabled (i.e. not running as root) everything works fine but I get a much lower frame rate. I'm new to wine but I had a stab at fixing the problem which as far as I can see is the following:
-> wine creates one X11 display connection for each thread and one 'global' display connection to use for various things like DGA2 which it puts in the 'gdi_display' global variable. The thread specific connections get put in x11drv_thread_data structure pointed to by the driver_data pointer in each thread's thread specific structure.
-> wine then switches to DGA2 mode if it can and does an 'XSelectInput' to turn on DGA2 input events. It switches to DGA2 mode using the gdi_display connection so all input events will now come through this connection.
-> at some point something asks for new X11 events. It goes into the 'X11DRV_MsgWaitForMultipleObjectsEx' function to poll the X11 display connections for each thread. This ends up calling the 'process_events' function in dlls/x11drv/event.c with the 'x11drv_thread_data' structure for each thread. This is the only function that calls 'process_events', which is the only place that calls any X11 event fetching function outside of 'wineclipserv.c' and 'clipping.c' (which seem do something irrelevant to the dga2 problem).
-> but process_events can only look at the thread specific X11 display connections since this is the data it gets passed. I cannot find any code which sets up an 'x11drv_thread_data' structure for gdi_display and XNextEvent is only ever called from inside process_events on data->display. Therefore we never poll gdi_display for X11 events at all so I never get any input. I tested this with some debug output code and wine deffinitely never polls gdi_display for events at any time while running the game. X11DRV_MsgWaitForMultipleObjectsEx explicitly does an XFlush on gdi_display as though it is expecting to have to poll it separately, but it never does ...
I tried changing 'process_events' in dlls/x11drv/events.c to the following:
static int process_events( struct x11drv_thread_data *data ) { XEvent event; int count = 0;
wine_tsx11_lock(); while ( XPending( data->display ) ) { XNextEvent( data->display, &event ); wine_tsx11_unlock(); EVENT_ProcessEvent( &event ); count++; wine_tsx11_lock(); }
#ifdef FIX_DGA2_INPUT while ( DGAUsed && gdi_display != NULL && data->display != gdi_display && XPending( gdi_display ) ) { XNextEvent( gdi_display, &event ); wine_tsx11_unlock(); EVENT_ProcessEvent( &event ); count++; wine_tsx11_lock(); } #endif
wine_tsx11_unlock(); return count; }
And this fixed the problem. What's bugging me though is that if this is the correct answer then how do any programs work at all in DGA2 mode? Wouldn't any program hang in the same way as soon as wine switched to DGA2 mode?
It would be handy if this were fixed in the wine code so I don't have to keep downloading source and patching so can someone who knows more about the code please let me know if they think this is worth submitting as a patch or point me in the right direction if this is on the wrong track?
Thanks in advance,
A.