DirectX-XShm now waits for the X server to finish the previous frame
before sending another frame down its pipe, avoiding the X server overload and resulting slowness that used to be.
This commit is contained in:
parent
56403478c7
commit
7da242dbd5
|
@ -708,7 +708,11 @@ static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) {
|
||||||
This->s.palette);
|
This->s.palette);
|
||||||
|
|
||||||
#ifdef HAVE_LIBXXSHM
|
#ifdef HAVE_LIBXXSHM
|
||||||
if (This->s.ddraw->e.xlib.xshm_active)
|
if (This->s.ddraw->e.xlib.xshm_active) {
|
||||||
|
int compl = This->s.ddraw->e.xlib.xshm_compl;
|
||||||
|
if (compl)
|
||||||
|
X11DRV_EVENT_WaitShmCompletion( compl );
|
||||||
|
This->s.ddraw->e.xlib.xshm_compl = X11DRV_EVENT_PrepareShmCompletion( This->s.ddraw->d.drawable );
|
||||||
TSXShmPutImage(display,
|
TSXShmPutImage(display,
|
||||||
This->s.ddraw->d.drawable,
|
This->s.ddraw->d.drawable,
|
||||||
DefaultGCOfScreen(X11DRV_GetXScreen()),
|
DefaultGCOfScreen(X11DRV_GetXScreen()),
|
||||||
|
@ -716,7 +720,8 @@ static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) {
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
This->t.xlib.image->width,
|
This->t.xlib.image->width,
|
||||||
This->t.xlib.image->height,
|
This->t.xlib.image->height,
|
||||||
False);
|
True);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
TSXPutImage( display,
|
TSXPutImage( display,
|
||||||
|
@ -5027,8 +5032,10 @@ static HRESULT WINAPI Xlib_DirectDrawCreate( LPDIRECTDRAW *lplpDD, LPUNKNOWN pUn
|
||||||
|
|
||||||
#ifdef HAVE_LIBXXSHM
|
#ifdef HAVE_LIBXXSHM
|
||||||
/* Test if XShm is available. */
|
/* Test if XShm is available. */
|
||||||
if (((*ilplpDD)->e.xlib.xshm_active = DDRAW_XSHM_Available()))
|
if (((*ilplpDD)->e.xlib.xshm_active = DDRAW_XSHM_Available())) {
|
||||||
|
(*ilplpDD)->e.xlib.xshm_compl = 0;
|
||||||
TRACE("Using XShm extension.\n");
|
TRACE("Using XShm extension.\n");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
|
|
|
@ -81,7 +81,7 @@ struct _dga_directdrawdata
|
||||||
struct _xlib_directdrawdata
|
struct _xlib_directdrawdata
|
||||||
{
|
{
|
||||||
#ifdef HAVE_LIBXXSHM
|
#ifdef HAVE_LIBXXSHM
|
||||||
int xshm_active;
|
int xshm_active, xshm_compl;
|
||||||
#endif /* defined(HAVE_LIBXXSHM) */
|
#endif /* defined(HAVE_LIBXXSHM) */
|
||||||
|
|
||||||
/* are these needed for anything? (draw_surf is the active surface)
|
/* are these needed for anything? (draw_surf is the active surface)
|
||||||
|
|
|
@ -53,6 +53,7 @@ extern int TSXChangeGC(Display*, GC, unsigned long, XGCValues*);
|
||||||
extern int TSXChangeKeyboardControl(Display*, unsigned long, XKeyboardControl*);
|
extern int TSXChangeKeyboardControl(Display*, unsigned long, XKeyboardControl*);
|
||||||
extern int TSXChangeProperty(Display*, Window, Atom, Atom, int, int, const unsigned char*, int);
|
extern int TSXChangeProperty(Display*, Window, Atom, Atom, int, int, const unsigned char*, int);
|
||||||
extern int TSXChangeWindowAttributes(Display*, Window, unsigned long, XSetWindowAttributes*);
|
extern int TSXChangeWindowAttributes(Display*, Window, unsigned long, XSetWindowAttributes*);
|
||||||
|
extern int TSXCheckTypedEvent(Display*, int, XEvent*);
|
||||||
extern int TSXCheckTypedWindowEvent(Display*, Window, int, XEvent*);
|
extern int TSXCheckTypedWindowEvent(Display*, Window, int, XEvent*);
|
||||||
extern int TSXCheckWindowEvent(Display*, Window, long, XEvent*);
|
extern int TSXCheckWindowEvent(Display*, Window, long, XEvent*);
|
||||||
extern int TSXConvertSelection(Display*, Atom, Atom, Atom, Window, Time);
|
extern int TSXConvertSelection(Display*, Atom, Atom, Atom, Window, Time);
|
||||||
|
|
|
@ -469,4 +469,7 @@ extern void X11DRV_WND_SetDrawable(struct tagWND *wndPtr, struct tagDC *dc, WORD
|
||||||
extern BOOL X11DRV_WND_SetHostAttr(struct tagWND *wndPtr, INT haKey, INT value);
|
extern BOOL X11DRV_WND_SetHostAttr(struct tagWND *wndPtr, INT haKey, INT value);
|
||||||
extern BOOL X11DRV_WND_IsSelfClipping(struct tagWND *wndPtr);
|
extern BOOL X11DRV_WND_IsSelfClipping(struct tagWND *wndPtr);
|
||||||
|
|
||||||
|
extern int X11DRV_EVENT_PrepareShmCompletion( Drawable dw );
|
||||||
|
extern void X11DRV_EVENT_WaitShmCompletion( int compl );
|
||||||
|
|
||||||
#endif /* __WINE_X11DRV_H */
|
#endif /* __WINE_X11DRV_H */
|
||||||
|
|
|
@ -16,6 +16,7 @@ XChangeGC
|
||||||
XChangeKeyboardControl
|
XChangeKeyboardControl
|
||||||
XChangeProperty
|
XChangeProperty
|
||||||
XChangeWindowAttributes
|
XChangeWindowAttributes
|
||||||
|
XCheckTypedEvent
|
||||||
XCheckTypedWindowEvent
|
XCheckTypedWindowEvent
|
||||||
XCheckWindowEvent
|
XCheckWindowEvent
|
||||||
XClipBox
|
XClipBox
|
||||||
|
|
|
@ -422,6 +422,17 @@ int TSXChangeWindowAttributes(Display* a0, Window a1, unsigned long a2, XSetWin
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TSXCheckTypedEvent(Display* a0, int a1, XEvent* a2)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
TRACE("Call XCheckTypedEvent\n");
|
||||||
|
EnterCriticalSection( &X11DRV_CritSection );
|
||||||
|
r = XCheckTypedEvent(a0, a1, a2);
|
||||||
|
LeaveCriticalSection( &X11DRV_CritSection );
|
||||||
|
TRACE("Ret XCheckTypedEvent\n");
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
int TSXCheckTypedWindowEvent(Display* a0, Window a1, int a2, XEvent* a3)
|
int TSXCheckTypedWindowEvent(Display* a0, Window a1, int a2, XEvent* a3)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
#include "ts_xlib.h"
|
#include "ts_xlib.h"
|
||||||
#include "ts_xresource.h"
|
#include "ts_xresource.h"
|
||||||
#include "ts_xutil.h"
|
#include "ts_xutil.h"
|
||||||
|
#ifdef HAVE_LIBXXSHM
|
||||||
|
#include "ts_xshm.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -102,6 +105,11 @@ static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event );
|
||||||
static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
|
static void EVENT_MapNotify( HWND pWnd, XMapEvent *event );
|
||||||
static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
|
static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBXXSHM
|
||||||
|
static void EVENT_ShmCompletion( XShmCompletionEvent *event );
|
||||||
|
static int ShmCompletionType;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Usable only with OLVWM - compile option perhaps?
|
/* Usable only with OLVWM - compile option perhaps?
|
||||||
static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
|
static void EVENT_EnterNotify( HWND hWnd, XCrossingEvent *event );
|
||||||
*/
|
*/
|
||||||
|
@ -121,6 +129,10 @@ static BOOL in_transition = FALSE; /* This is not used as for today */
|
||||||
*/
|
*/
|
||||||
BOOL X11DRV_EVENT_Init(void)
|
BOOL X11DRV_EVENT_Init(void)
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBXXSHM
|
||||||
|
ShmCompletionType = XShmGetEventBase( display ) + ShmCompletion;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Install the X event processing callback */
|
/* Install the X event processing callback */
|
||||||
SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display),
|
SERVICE_AddObject( FILE_DupUnixHandle( ConnectionNumber(display),
|
||||||
GENERIC_READ | SYNCHRONIZE ),
|
GENERIC_READ | SYNCHRONIZE ),
|
||||||
|
@ -150,7 +162,7 @@ static void CALLBACK EVENT_ProcessAllEvents( ULONG_PTR arg )
|
||||||
{
|
{
|
||||||
XEvent event;
|
XEvent event;
|
||||||
|
|
||||||
TRACE_(event)( "called.\n" );
|
TRACE_(event)( "called (thread %lx).\n", GetCurrentThreadId() );
|
||||||
|
|
||||||
EnterCriticalSection( &X11DRV_CritSection );
|
EnterCriticalSection( &X11DRV_CritSection );
|
||||||
while ( XPending( display ) )
|
while ( XPending( display ) )
|
||||||
|
@ -211,6 +223,13 @@ static void EVENT_ProcessEvent( XEvent *event )
|
||||||
case ReparentNotify:
|
case ReparentNotify:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBXXSHM
|
||||||
|
if (event->type == ShmCompletionType) {
|
||||||
|
EVENT_ShmCompletion( (XShmCompletionEvent*)event );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( TSXFindContext( display, event->xany.window, winContext,
|
if ( TSXFindContext( display, event->xany.window, winContext,
|
||||||
(char **)&hWnd ) != 0) {
|
(char **)&hWnd ) != 0) {
|
||||||
|
@ -373,6 +392,7 @@ static void EVENT_ProcessEvent( XEvent *event )
|
||||||
event_names[event->type], hWnd );
|
event_names[event->type], hWnd );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
TRACE_(event)( "returns.\n" );
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
@ -1780,4 +1800,96 @@ INPUT_TYPE X11DRV_EVENT_SetInputMehod(INPUT_TYPE type)
|
||||||
return prev;
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBXXSHM
|
||||||
|
|
||||||
|
/*
|
||||||
|
Normal XShm operation:
|
||||||
|
|
||||||
|
X11 service thread app thread
|
||||||
|
------------- ----------------- ------------------------
|
||||||
|
(idle) ddraw calls XShmPutImage
|
||||||
|
(copies data) (waiting for shm_event)
|
||||||
|
ShmCompletion -> (waiting for shm_event)
|
||||||
|
(idle) signal shm_event ->
|
||||||
|
(idle) returns to app
|
||||||
|
|
||||||
|
However, this situation can occur for some reason:
|
||||||
|
|
||||||
|
X11 service thread app thread
|
||||||
|
------------- ----------------- ------------------------
|
||||||
|
Expose ->
|
||||||
|
WM_ERASEBKGND? ->
|
||||||
|
(waiting for app) ddraw calls XShmPutImage
|
||||||
|
(copies data) (waiting for app) (waiting for shm_event)
|
||||||
|
ShmCompletion (waiting for app) (waiting for shm_event)
|
||||||
|
(idle) DEADLOCK DEADLOCK
|
||||||
|
|
||||||
|
which is why I also wait for shm_read and do XCheckTypedEvent()
|
||||||
|
calls in the wait loop. This results in:
|
||||||
|
|
||||||
|
X11 service thread app thread
|
||||||
|
------------- ----------------- ------------------------
|
||||||
|
ShmCompletion (waiting for app) waking up on shm_read
|
||||||
|
(idle) (waiting for app) XCheckTypedEvent() -> signal shm_event
|
||||||
|
(waiting for app) returns
|
||||||
|
(idle)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* FIXME: this is not pretty */
|
||||||
|
static Drawable shm_draw = 0;
|
||||||
|
static HANDLE shm_event = 0, shm_read = 0;
|
||||||
|
|
||||||
|
static void EVENT_ShmCompletion( XShmCompletionEvent *event )
|
||||||
|
{
|
||||||
|
TRACE_(event)("Got ShmCompletion for drawable %ld (time %ld)\n", event->drawable, GetTickCount() );
|
||||||
|
if (event->drawable == shm_draw) {
|
||||||
|
HANDLE event = shm_event;
|
||||||
|
shm_draw = 0;
|
||||||
|
shm_event = 0;
|
||||||
|
SetEvent(event);
|
||||||
|
TRACE_(event)("Event object triggered\n" );
|
||||||
|
} else ERR_(event)("Got ShmCompletion for unknown drawable %ld\n", event->drawable );
|
||||||
|
}
|
||||||
|
|
||||||
|
int X11DRV_EVENT_PrepareShmCompletion( Drawable dw )
|
||||||
|
{
|
||||||
|
if (shm_draw) {
|
||||||
|
ERR_(event)("Multiple ShmCompletion requests not implemented\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
TRACE_(event)("Preparing ShmCompletion (%d) wait for drawable %ld (time %ld)\n", ShmCompletionType, dw, GetTickCount() );
|
||||||
|
shm_draw = dw;
|
||||||
|
if (!shm_event)
|
||||||
|
/* use manual reset just in case */
|
||||||
|
shm_event = ConvertToGlobalHandle( CreateEventA( NULL, TRUE, FALSE, NULL ) );
|
||||||
|
if (!shm_read)
|
||||||
|
shm_read = ConvertToGlobalHandle( FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE ) );
|
||||||
|
return shm_event;
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11DRV_EVENT_WaitShmCompletion( int compl )
|
||||||
|
{
|
||||||
|
if (!compl) return;
|
||||||
|
TRACE_(event)("Waiting for ShmCompletion (%d) (thread %lx) (time %ld)\n", ShmCompletionType, GetCurrentThreadId(), GetTickCount() );
|
||||||
|
/* already triggered? */
|
||||||
|
if ( WaitForSingleObject( compl, 0 ) != WAIT_OBJECT_0 ) {
|
||||||
|
/* nope, may need to poll X event queue, in case the service thread is blocked */
|
||||||
|
XEvent event;
|
||||||
|
HANDLE hnd[2];
|
||||||
|
|
||||||
|
hnd[0] = compl;
|
||||||
|
hnd[1] = shm_read;
|
||||||
|
do {
|
||||||
|
/* check X event queue */
|
||||||
|
if (TSXCheckTypedEvent( display, ShmCompletionType, &event)) {
|
||||||
|
EVENT_ProcessEvent( &event );
|
||||||
|
}
|
||||||
|
} while ( WaitForMultipleObjects(2, hnd, FALSE, INFINITE) > WAIT_OBJECT_0 );
|
||||||
|
}
|
||||||
|
ResetEvent(compl); /* manual reset */
|
||||||
|
TRACE_(event)("Wait complete (time %ld)\n", GetTickCount() );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* !defined(X_DISPLAY_MISSING) */
|
#endif /* !defined(X_DISPLAY_MISSING) */
|
||||||
|
|
Loading…
Reference in New Issue