Supercharged XShm implementation for DirectDraw.
This commit is contained in:
parent
52faa5658c
commit
b030d20fc4
|
@ -737,6 +737,18 @@ static HRESULT WINAPI IDirectDrawSurface4Impl_Lock(
|
||||||
} else {
|
} else {
|
||||||
assert(This->s.surface_desc.u1.lpSurface);
|
assert(This->s.surface_desc.u1.lpSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* wait for any previous operations to complete */
|
||||||
|
#ifdef HAVE_LIBXXSHM
|
||||||
|
if (This->t.xlib.image && (SDDSCAPS(This) & DDSCAPS_VISIBLE) &&
|
||||||
|
This->s.ddraw->e.xlib.xshm_active) {
|
||||||
|
/*
|
||||||
|
int compl = InterlockedExchange( &This->s.ddraw->e.xlib.xshm_compl, 0 );
|
||||||
|
if (compl) X11DRV_EVENT_WaitShmCompletion( compl );
|
||||||
|
*/
|
||||||
|
X11DRV_EVENT_WaitShmCompletions( This->s.ddraw->d.drawable );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,10 +773,13 @@ static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) {
|
||||||
|
|
||||||
#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_WaitReplaceShmCompletion( &This->s.ddraw->e.xlib.xshm_compl, This->s.ddraw->d.drawable );
|
||||||
X11DRV_EVENT_WaitShmCompletion( compl );
|
*/
|
||||||
This->s.ddraw->e.xlib.xshm_compl = X11DRV_EVENT_PrepareShmCompletion( This->s.ddraw->d.drawable );
|
/* let WaitShmCompletions track 'em for now */
|
||||||
|
/* (you may want to track it again whenever you implement DX7's partial surface locking,
|
||||||
|
where threads have concurrent access) */
|
||||||
|
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()),
|
||||||
|
@ -773,6 +788,8 @@ static void Xlib_copy_surface_on_screen(IDirectDrawSurface4Impl* This) {
|
||||||
This->t.xlib.image->width,
|
This->t.xlib.image->width,
|
||||||
This->t.xlib.image->height,
|
This->t.xlib.image->height,
|
||||||
True);
|
True);
|
||||||
|
/* make sure the image is transferred ASAP */
|
||||||
|
TSXFlush(display);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -479,5 +479,7 @@ extern void X11DRV_WND_DockWindow(struct tagWND *wndPtr);
|
||||||
|
|
||||||
extern int X11DRV_EVENT_PrepareShmCompletion( Drawable dw );
|
extern int X11DRV_EVENT_PrepareShmCompletion( Drawable dw );
|
||||||
extern void X11DRV_EVENT_WaitShmCompletion( int compl );
|
extern void X11DRV_EVENT_WaitShmCompletion( int compl );
|
||||||
|
extern void X11DRV_EVENT_WaitShmCompletions( Drawable dw );
|
||||||
|
extern void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw );
|
||||||
|
|
||||||
#endif /* __WINE_X11DRV_H */
|
#endif /* __WINE_X11DRV_H */
|
||||||
|
|
|
@ -112,7 +112,7 @@ static void EVENT_UnmapNotify( HWND pWnd, XUnmapEvent *event );
|
||||||
|
|
||||||
#ifdef HAVE_LIBXXSHM
|
#ifdef HAVE_LIBXXSHM
|
||||||
static void EVENT_ShmCompletion( XShmCompletionEvent *event );
|
static void EVENT_ShmCompletion( XShmCompletionEvent *event );
|
||||||
static int ShmCompletionType;
|
static int ShmAvailable, ShmCompletionType;
|
||||||
extern int XShmGetEventBase( Display * );/* Missing prototype for function in libXext. */
|
extern int XShmGetEventBase( Display * );/* Missing prototype for function in libXext. */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -151,7 +151,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
|
#ifdef HAVE_LIBXXSHM
|
||||||
ShmCompletionType = XShmGetEventBase( display ) + ShmCompletion;
|
ShmAvailable = XShmQueryExtension( display );
|
||||||
|
if (ShmAvailable) {
|
||||||
|
ShmCompletionType = XShmGetEventBase( display ) + ShmCompletion;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Install the X event processing callback */
|
/* Install the X event processing callback */
|
||||||
|
@ -246,7 +249,7 @@ static void EVENT_ProcessEvent( XEvent *event )
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBXXSHM
|
#ifdef HAVE_LIBXXSHM
|
||||||
if (event->type == ShmCompletionType) {
|
if (ShmAvailable && (event->type == ShmCompletionType)) {
|
||||||
EVENT_ShmCompletion( (XShmCompletionEvent*)event );
|
EVENT_ShmCompletion( (XShmCompletionEvent*)event );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2003,58 +2006,154 @@ ShmCompletion (waiting for app) waking up on shm_read
|
||||||
(idle)
|
(idle)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Drawable draw;
|
||||||
|
LONG state, waiter;
|
||||||
|
HANDLE sema;
|
||||||
|
} shm_qs;
|
||||||
|
|
||||||
/* FIXME: this is not pretty */
|
/* FIXME: this is not pretty */
|
||||||
static Drawable shm_draw = 0;
|
static HANDLE shm_read = 0;
|
||||||
static HANDLE shm_event = 0, shm_read = 0;
|
|
||||||
|
#define SHM_MAX_Q 4
|
||||||
|
static volatile shm_qs shm_q[SHM_MAX_Q];
|
||||||
|
|
||||||
static void EVENT_ShmCompletion( XShmCompletionEvent *event )
|
static void EVENT_ShmCompletion( XShmCompletionEvent *event )
|
||||||
{
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event->drawable, GetTickCount() );
|
TRACE("Got ShmCompletion for drawable %ld (time %ld)\n", event->drawable, GetTickCount() );
|
||||||
if (event->drawable == shm_draw) {
|
|
||||||
HANDLE event = shm_event;
|
for (n=0; n<SHM_MAX_Q; n++)
|
||||||
shm_draw = 0;
|
if ((shm_q[n].draw == event->drawable) && (shm_q[n].state == 0)) {
|
||||||
SetEvent(event);
|
HANDLE sema = shm_q[n].sema;
|
||||||
TRACE("Event object triggered\n" );
|
if (!InterlockedCompareExchange((PVOID*)&shm_q[n].state, (PVOID)1, (PVOID)0)) {
|
||||||
} else ERR("Got ShmCompletion for unknown drawable %ld\n", event->drawable );
|
ReleaseSemaphore(sema, 1, NULL);
|
||||||
|
TRACE("Signaling ShmCompletion (#%d) (semaphore %x)\n", n, sema);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ERR("Got ShmCompletion for unknown drawable %ld\n", event->drawable );
|
||||||
}
|
}
|
||||||
|
|
||||||
int X11DRV_EVENT_PrepareShmCompletion( Drawable dw )
|
int X11DRV_EVENT_PrepareShmCompletion( Drawable dw )
|
||||||
{
|
{
|
||||||
if (shm_draw) {
|
int n;
|
||||||
ERR("Multiple ShmCompletion requests not implemented\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
TRACE("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)
|
if (!shm_read)
|
||||||
shm_read = ConvertToGlobalHandle( FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE ) );
|
shm_read = ConvertToGlobalHandle( FILE_DupUnixHandle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE ) );
|
||||||
return shm_event;
|
|
||||||
|
for (n=0; n<SHM_MAX_Q; n++)
|
||||||
|
if (!shm_q[n].draw)
|
||||||
|
if (!InterlockedCompareExchange((PVOID*)&shm_q[n].draw, (PVOID)dw, (PVOID)0))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (n>=SHM_MAX_Q) {
|
||||||
|
ERR("Maximum number of outstanding ShmCompletions exceeded!\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
shm_q[n].state = 0;
|
||||||
|
if (!shm_q[n].sema) {
|
||||||
|
shm_q[n].sema = ConvertToGlobalHandle( CreateSemaphoreA( NULL, 0, 256, NULL ) );
|
||||||
|
TRACE("Allocated ShmCompletion slots have been increased to %d, new semaphore is %x\n", n+1, shm_q[n].sema);
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("Prepared ShmCompletion (#%d) wait for drawable %ld (thread %lx) (time %ld)\n", n, dw, GetCurrentThreadId(), GetTickCount() );
|
||||||
|
return n+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void X11DRV_EVENT_WaitReplaceShmCompletionInternal( int *compl, Drawable dw, int creat )
|
||||||
|
{
|
||||||
|
int n = *compl;
|
||||||
|
LONG nn, st;
|
||||||
|
HANDLE sema;
|
||||||
|
|
||||||
|
if ((!n) || (creat && (!shm_q[n-1].draw))) {
|
||||||
|
nn = X11DRV_EVENT_PrepareShmCompletion(dw);
|
||||||
|
if (!(n=(LONG)InterlockedCompareExchange((PVOID*)compl, (PVOID)nn, (PVOID)n)))
|
||||||
|
return;
|
||||||
|
/* race for compl lost, clear slot */
|
||||||
|
shm_q[nn-1].draw = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dw && (shm_q[n-1].draw != dw)) {
|
||||||
|
/* this shouldn't happen with the current ddraw implementation */
|
||||||
|
FIXME("ShmCompletion replace with different drawable!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sema = shm_q[n-1].sema;
|
||||||
|
if (!sema) {
|
||||||
|
/* nothing to wait on (PrepareShmCompletion not done yet?), so probably nothing to wait for */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nn = InterlockedExchangeAdd((PLONG)&shm_q[n-1].waiter, 1);
|
||||||
|
if ((!shm_q[n-1].draw) || (shm_q[n-1].state == 2)) {
|
||||||
|
/* too late, the wait was just cleared (wait complete) */
|
||||||
|
TRACE("Wait skip for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
|
||||||
|
} else {
|
||||||
|
TRACE("Waiting for ShmCompletion (#%d) (thread %lx) (time %ld) (semaphore %x)\n", n-1, GetCurrentThreadId(), GetTickCount(), sema);
|
||||||
|
if (nn) {
|
||||||
|
/* another thread is already waiting, let the primary waiter do the dirty work
|
||||||
|
* (to avoid TSX critical section contention - that could get really slow) */
|
||||||
|
WaitForSingleObject( sema, INFINITE );
|
||||||
|
} else
|
||||||
|
/* we're primary waiter - first check if it's already triggered */
|
||||||
|
if ( WaitForSingleObject( sema, 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] = sema;
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
TRACE("Wait complete (thread %lx) (time %ld)\n", GetCurrentThreadId(), GetTickCount() );
|
||||||
|
|
||||||
|
/* clear wait */
|
||||||
|
st = InterlockedExchange(&shm_q[n-1].state, 2);
|
||||||
|
if (st != 2) {
|
||||||
|
/* first waiter to return, release all other waiters */
|
||||||
|
nn = shm_q[n-1].waiter;
|
||||||
|
TRACE("Signaling %ld additional ShmCompletion (#%d) waiter(s), semaphore %x\n", nn-1, n-1, sema);
|
||||||
|
ReleaseSemaphore(sema, nn-1, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nn = InterlockedDecrement((LPLONG)&shm_q[n-1].waiter);
|
||||||
|
if (!nn) {
|
||||||
|
/* last waiter to return, replace drawable and prepare new wait */
|
||||||
|
shm_q[n-1].draw = dw;
|
||||||
|
shm_q[n-1].state = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void X11DRV_EVENT_WaitReplaceShmCompletion( int *compl, Drawable dw )
|
||||||
|
{
|
||||||
|
X11DRV_EVENT_WaitReplaceShmCompletionInternal( compl, dw, 1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
void X11DRV_EVENT_WaitShmCompletion( int compl )
|
void X11DRV_EVENT_WaitShmCompletion( int compl )
|
||||||
{
|
{
|
||||||
if (!compl) return;
|
if (!compl) return;
|
||||||
TRACE("Waiting for ShmCompletion (%d) (thread %lx) (time %ld)\n", ShmCompletionType, GetCurrentThreadId(), GetTickCount() );
|
X11DRV_EVENT_WaitReplaceShmCompletionInternal( &compl, 0, 0 );
|
||||||
/* 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;
|
void X11DRV_EVENT_WaitShmCompletions( Drawable dw )
|
||||||
hnd[1] = shm_read;
|
{
|
||||||
do {
|
int n;
|
||||||
/* check X event queue */
|
|
||||||
if (TSXCheckTypedEvent( display, ShmCompletionType, &event)) {
|
for (n=0; n<SHM_MAX_Q; n++)
|
||||||
EVENT_ProcessEvent( &event );
|
if (shm_q[n].draw == dw)
|
||||||
}
|
X11DRV_EVENT_WaitShmCompletion( n+1 );
|
||||||
} while ( WaitForMultipleObjects(2, hnd, FALSE, INFINITE) > WAIT_OBJECT_0 );
|
|
||||||
}
|
|
||||||
ResetEvent(compl); /* manual reset */
|
|
||||||
TRACE("Wait complete (time %ld)\n", GetTickCount() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* defined(HAVE_LIBXXSHM) */
|
#endif /* defined(HAVE_LIBXXSHM) */
|
||||||
|
|
Loading…
Reference in New Issue