From nobody Mon Sep 17 00:00:00 2001 From: Stefan Dösinger Date: Mon Jul 10 18:00:21 2006 +0200 Subject: [PATCH] WineD3D: async surface updates --- dlls/wined3d/surface.c | 16 ++++++- dlls/wined3d/surface_gdi.c | 98 ++++++++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 4 ++ 3 files changed, 117 insertions(+), 1 deletions(-) 09fdf66b6b3367c2f71ad979b282612373b229d4 diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c index 8a4d747..308c1ba 100644 --- a/dlls/wined3d/surface.c +++ b/dlls/wined3d/surface.c @@ -75,6 +75,21 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release LEAVE_GL(); } + if(This->update_thread) + { + HANDLE event = This->update_event; + This->update_event = 0; + SetEvent(event); + + TRACE("waiting for update thread to terminate...\n"); + WaitForSingleObject(This->update_thread, INFINITE); + + CloseHandle(event); + CloseHandle(This->update_thread); + CloseHandle(This->refresh_event); + DeleteCriticalSection(&This->crit); + } + if(This->Flags & SFLAG_DIBSECTION) { /* Release the DC */ SelectObject(This->hDC, This->dib.holdbitmap); @@ -91,7 +106,6 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release TRACE("(%p) Released\n", This); HeapFree(GetProcessHeap(), 0, This); - } return ref; } diff --git a/dlls/wined3d/surface_gdi.c b/dlls/wined3d/surface_gdi.c index bb07afa..b090ae0 100644 --- a/dlls/wined3d/surface_gdi.c +++ b/dlls/wined3d/surface_gdi.c @@ -36,6 +36,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface); WINE_DECLARE_DEBUG_CHANNEL(fps); +#ifndef SYNC_UPDATE +static DWORD CALLBACK User_update_thread(void *); +static void IWineGDISurface_wait_update(IWineD3DSurfaceImpl* This); +#endif + /***************************************************************************** * x11_copy_to_screen * @@ -178,6 +183,10 @@ IWineGDISurfaceImpl_LockRect(IWineD3DSur TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory); +#ifndef SYNC_UPDATE + if (iface == This->resource.wineD3DDevice->ddraw_primary && Flags & DDLOCK_WAIT) IWineGDISurface_wait_update(This); +#endif + pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface); if (NULL == pRect) @@ -231,6 +240,7 @@ IWineGDISurfaceImpl_LockRect(IWineD3DSur TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch); This->Flags |= SFLAG_LOCKED; + This->dirtyRect = This->lockedRect; return D3D_OK; } @@ -281,7 +291,11 @@ IWineGDISurfaceImpl_UnlockRect(IWineD3DS /* Update the screen */ if(This == (IWineD3DSurfaceImpl *) dev->ddraw_primary) { +#ifdef SYNC_UPDATE x11_copy_to_screen(This, &This->lockedRect); +#else + SetEvent(This->update_event); +#endif } This->Flags &= ~SFLAG_LOCKED; @@ -378,7 +392,16 @@ IWineGDISurfaceImpl_Flip(IWineD3DSurface #endif /* Update the screen */ +#ifdef SYNC_UPDATE x11_copy_to_screen(This, NULL); +#else + if (Flags & DDFLIP_WAIT) IWineGDISurface_wait_update(This); + This->dirtyRect.left = 0; + This->dirtyRect.top = 0; + This->dirtyRect.right = This->currentDesc.Width; + This->dirtyRect.bottom = This->currentDesc.Height; + SetEvent(This->update_event); +#endif /* FPS support */ if (TRACE_ON(fps)) @@ -1531,9 +1554,84 @@ IWineGDISurfaceImpl_PrivateSetup(IWineD3 return hr; } +#ifndef SYNC_UPDATE + if(iface == This->resource.wineD3DDevice->ddraw_primary) + { + InitializeCriticalSection(&This->crit); + This->refresh_event = CreateEventW(NULL, TRUE, FALSE, NULL); + This->update_event = CreateEventW(NULL, FALSE, FALSE, NULL); + This->update_thread = CreateThread(NULL, 0, User_update_thread, This, 0, NULL); + } +#endif return WINED3D_OK; } +#ifndef SYNC_UPDATE +static DWORD CALLBACK User_update_thread(LPVOID arg) +{ + IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)arg; + volatile HANDLE *pActive = (volatile HANDLE *)&This->update_event; + HANDLE event = *pActive; + + /* the point of this is that many games lock the primary surface + * multiple times per frame; this thread will then simply copy as + * often as it can without keeping the main thread waiting for + * each unlock, thus keeping the frame rate high */ + do + { + DWORD ret = WaitForSingleObject(event, INFINITE); + + if (ret == WAIT_OBJECT_0) + { + if (*pActive) + { + This->in_refresh = TRUE; + x11_copy_to_screen(This, &This->dirtyRect); + EnterCriticalSection(&This->crit); + This->in_refresh = FALSE; + if (This->wait_count) + SetEvent(This->refresh_event); + LeaveCriticalSection(&This->crit); + } + else break; + } + else if (ret != WAIT_OBJECT_0+1) break; + } while (TRUE); + + SetEvent(This->refresh_event); + + return 0; +} + +static int IWineGDISurface_init_wait(IWineD3DSurfaceImpl* This) +{ + int need_wait; + EnterCriticalSection(&This->crit); + This->wait_count++; + need_wait = This->in_refresh; + LeaveCriticalSection(&This->crit); + return need_wait; +} + +static void IWineGDISurface_end_wait(IWineD3DSurfaceImpl* This) +{ + EnterCriticalSection(&This->crit); + if (!--This->wait_count) + ResetEvent(This->refresh_event); + LeaveCriticalSection(&This->crit); +} + +static void IWineGDISurface_wait_update(IWineD3DSurfaceImpl* This) +{ + if (This->in_refresh) { + if (IWineGDISurface_init_wait(This)) + WaitForSingleObject(This->refresh_event, 2); + IWineGDISurface_end_wait(This); + } +} + +#endif + const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl = { /* IUnknown */ diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 0f6d85e..b237019 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -876,6 +876,10 @@ struct IWineD3DSurfaceImpl DDCOLORKEY SrcBltCKey; DWORD CKeyFlags; + /* Async surface updates */ + HANDLE update_thread, update_event, refresh_event; + CRITICAL_SECTION crit; + volatile int wait_count, in_refresh; }; extern const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl; -- 1.2.4