WineD3D: Read the screen when locking the front buffer

Stefan Dösinger stefandoesinger at gmx.at
Sat Sep 9 06:43:07 CDT 2006


Windowed(DDSCL_NORMAL) DDraw apps can mix DDraw and GDI rendering on the same 
window. Our GDI surface implementation BitBlts the contents of the front 
buffer onto the window when the front buffer is modified. Simmilarly, the gdi 
contents have to read when the front buffer is locked.

This used to be the QuickTime hack in CrossOver. My concerns regarding double 
buffering vanished when I noticed that double buffering is not allowed in 
DDSCL_NORMAL mode(see the previous patch). We only have to read the content 
when we are not in fullscreen mode, and we do not have to care about double 
buffer flipping.

One issue is that reading from gdi takes some time, no matter how big the read 
area is. This is due to the lack of a gdi engine. So it is assumed that when 
the application specifies a rectangle to lock that it knows pretty well which 
parts it wants locked, so no readback is done with the assumption that the 
app doesn't lock areas with gdi-drawn contents.

This patch depends on the "pass the fullscreen flag to wined3d" patch, but not 
necessarily on the double buffering test. The test is mainly to show that we 
do not have to care for double buffering when reading into the front buffer.
-------------- next part --------------
From a7e8373eda0d70a93feec74e8c23544e335eef35 Mon Sep 17 00:00:00 2001
From: =?utf-8?q?Stefan_D=F6singer?= <stefan at codeweavers.com>
Date: Sat, 9 Sep 2006 11:36:51 +0200
Subject: [PATCH] WineD3D: Read the gdi content when locking the front buffer in windowed mode
---
 dlls/wined3d/surface_gdi.c |   50 ++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 50 insertions(+), 0 deletions(-)

diff --git a/dlls/wined3d/surface_gdi.c b/dlls/wined3d/surface_gdi.c
index 9609ebd..548a29c 100644
--- a/dlls/wined3d/surface_gdi.c
+++ b/dlls/wined3d/surface_gdi.c
@@ -122,6 +122,39 @@ #endif
 }
 
 /*****************************************************************************
+ * x11_copy_from_screen
+ *
+ * Reads the contents of a window into the front buffer
+ *
+ *****************************************************************************/
+static void x11_copy_from_screen(IWineD3DSurfaceImpl* This,
+                                 const RECT *rc)
+{
+    if (This->resource.usage & WINED3DUSAGE_RENDERTARGET)
+    {
+        HWND hDisplayWnd = This->resource.wineD3DDevice->ddraw_window;
+        HDC hDisplayDC = GetDC(hDisplayWnd);
+        RECT drawrect;
+
+        drawrect.left	= 0;
+        drawrect.right	= This->currentDesc.Width;
+        drawrect.top	= 0;
+        drawrect.bottom	= This->currentDesc.Height;
+        if (rc)
+            IntersectRect(&drawrect,&drawrect,rc);
+
+        BitBlt(This->hDC,
+               drawrect.left, drawrect.top,
+               drawrect.right-drawrect.left, drawrect.bottom-drawrect.top,
+               hDisplayDC,
+               drawrect.left, drawrect.top,
+               SRCCOPY
+              );
+        ReleaseDC(hDisplayWnd, hDisplayDC);
+    }
+}
+
+/*****************************************************************************
  * IWineD3DSurface::PreLoad, GDI version
  *
  * This call is unsupported on GDI surfaces, if it's called something went
@@ -239,6 +272,23 @@ IWineGDISurfaceImpl_LockRect(IWineD3DSur
         This->lockedRect.bottom = pRect->bottom;
     }
 
+    /* DDraw apps can share ddraw operation with GDI if not in exclusive mode. This surface
+     * implementation BitBlts the front buffer's content onto the GDI device context. In the
+     * same way as we write to GDI we have to read from there when we lock the primary surface.
+     *
+     * Reading from GDI is slow, so do it only when the app locks the whole surface. If the app
+     * specifies a rectangle to lock it is assumed that the app knows what part it wants to lock.
+     *
+     * There is no need to take care for gdi readback for back buffers, or in the Flip method,
+     * because double buffered surfaces can only be created in DDSCL_EXCLUSIVE mode, and in
+     * this mode gdi stuff can't be done anyway.
+     */
+    if(!pRect && iface == This->resource.wineD3DDevice->ddraw_primary &&
+       !This->resource.wineD3DDevice->ddraw_fullscreen)
+    {
+        x11_copy_from_screen(This, NULL);
+    }
+
     /* No dirtifying is needed for this surface implementation */
     TRACE("returning memory@%p, pitch(%d)\n", pLockedRect->pBits, pLockedRect->Pitch);
 
-- 
1.4.1.1



More information about the wine-patches mailing list