[9/12] WineD3D: When multithreading, call glFinish after drawing

Stefan Dösinger stefan at codeweavers.com
Mon Feb 26 06:51:01 CST 2007


-------------- next part --------------
From 591b870d169c2c9dc917d39fb98126fbb84ab178 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Sun, 25 Feb 2007 14:36:52 +0100
Subject: [PATCH] WineD3D: When multithreading, call glFinish after drawing

glXSwapBuffers requires, that if more than one context is used to draw
to a drawable, all threads using the contexts call glFinish before
swaping. Also seperate gl contexts aren't synchronised with each other,
so wined3d has to use the brute force method and call glFinish after
each draw if the multithreading flag is set.
---
 dlls/wined3d/device.c   |    7 +++++++
 dlls/wined3d/drawprim.c |   18 ++++++++++++++++++
 dlls/wined3d/surface.c  |   20 ++++++++++++++++++++
 3 files changed, 45 insertions(+), 0 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 7f08fcc..0d765c0 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -4320,6 +4320,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
                     mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
     }
 
+    if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
+        /* Required by glXSwapBuffers if more than one context draws to a drawable - see comment in
+         * drawprim.c
+         */
+        glFinish();
+    }
+
     LEAVE_GL();
 
     /* Dirtify the target surface for now. If the surface is locked regularily, and an up to date sysmem copy exists,
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index c115f2e..f809236 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -1051,6 +1051,24 @@ void drawPrimitive(IWineD3DDevice *iface,
         }
     }
 
+    if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
+        /* glXSwapBuffers that all contexts and threads drawing to a drawable have finished drawing
+         * before the swap if there is more than one context in one thread drawing to a window.
+         * The man page says finish drawing, not finish sending commands, and it recommends calling
+         * glFinish() in all threads.
+         *
+         * Because wine does not know when the app will be done with all drawing commands, and wined3d
+         * can't cause another thread to call glFinish() from IWineD3DSwapChain::Present, glFinish()
+         * has to be called after drawing if the device is requested to be thread safe.
+         *
+         * Furthermore, Windows seems to assure that drawing commands are executed in the order they are
+         * called, but seperate opengl contexts aren't synchronised. Drawables do not provide synchronisation
+         * either, so wined3d has to make sure that drawing is finished the brute force way.
+         */
+        glFinish();
+        checkGLcall("glFinish()");
+    }
+
     /* Finshed updating the screen, restore lock */
     LEAVE_GL();
     TRACE("Done all gl drawing\n");
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 7255172..b779704 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -2240,6 +2240,12 @@ static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3D
     }
 
     vcheckGLcall("glCopyTexSubImage2D");
+    if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
+        /* This is not required for glXSwapBuffers, but the readback has to be finished before
+         * new things are drawn to the drawable
+         */
+        glFinish();
+    }
     LEAVE_GL();
 }
 
@@ -2385,6 +2391,13 @@ static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWine
         glVertex2i(fbwidth, 0);
     glEnd();
 
+    if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
+        /* Required by glXSwapBuffers if more than one context draws to a drawable - see comment in
+         * drawprim.c
+         */
+        glFinish();
+    }
+
     /* Cleanup */
     if(src != backup) {
         glDeleteTextures(1, &src);
@@ -2717,6 +2730,13 @@ static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *
         Src->CKeyFlags = oldCKeyFlags;
         This->SrcBltCKey = oldBltCKey;
 
+        if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
+            /* Required by glXSwapBuffers if more than one context draws to a drawable - see comment in
+             * drawprim.c
+             */
+            glFinish();
+        }
+
         LEAVE_GL();
 
         /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
-- 
1.4.4.3



More information about the wine-patches mailing list