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.
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:
You can see that this topic was already debated in the following threads :
http://www.winehq.com/hypermail/wine-devel/2002/06/0396.html
And even earlier here :
http://www.winehq.com/hypermail/wine-devel/2002/01/0392.html
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?
DGA2 do not work at all for any application, it's as easy as that :-)
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?
Well, the problem is that a fix like the one you did will be hard to have committed to the Wine source tree as it's too much of a kludge (I already proposed a fix like that in the thread I started on it in January of this year).
Now one just need to find somebody committed enough to investigate the problem and to fix it properly :-)
Lionel
Lionel Ulmer wrote:
You can see that this topic was already debated in the following threads :
http://www.winehq.com/hypermail/wine-devel/2002/06/0396.html
And even earlier here :
http://www.winehq.com/hypermail/wine-devel/2002/01/0392.html
Thanks, I probably should have searched the archive first before jumping in and posting. Had a read of the previous threads and I'm still trying to understand exactly what's wrong with the fix, here are some questions:
-> if gdi_display gets replaced with the thread specific display, won't this cause more problems than it fixes? Would a windows program not expect to be able to switch on directX in one thread then operate on the raw display from any thread? Using the thread specific display would require the thread which switched DGA2 on to perform all operations because most DGA2 calls throw errors if a display is not in DGA2 mode and only one display can be in this mode at any one time.
-> In a multi-threaded program, does it matter which WaitForMultipleObjects is used to collect the events? The event gets dispatched to the wineserver with the DGA window's hWnd attached in the same way as it would if 'emulated' direct access were used (i.e. drawing with normal X11 calls). This then sends the event on to the windows program. If this is a problem then wouldn't it also affect non-DGA2 modes and therefore be a separate problem? It's been ages since I did any windows programming (win 3.1), what would a multi-threaded windows app expect to happen if it starts multiple threads and runs more than one event loop?
Perhaps a better fix might be to have a thread 'own' the gdi_display if it switches DGA2 mode on. The X11drv_thread_data structure for each thread could get a new 'gdi_display' field which would default to NULL. This could get set to the global gdi_display field for the thread which switches on DGA2 and process_events could be changed to poll data->gdi_display in addition to data->display if this was non-null. I think this would produce input event behaviour identical to the 'emulated' DGA2 mode since DGA2 events would only be handled when the thread which entered DGA2 mode was polled for events.
A.