[5/12] WineD3D: Activate a context before doing opengl calls

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


-------------- next part --------------
From 1d22412cbdd0b3a980d4d5c40fd75b99969500c5 Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Sat, 24 Feb 2007 22:52:31 +0100
Subject: [PATCH] WineD3D: Activate a context before doing opengl calls

When opengl calls are made a context has to be active, otherwise gl goes insane.
This patch adds ActivateContext calls to code doing opengl calls which can be
called directly by the application. In general the last active render target is
reactivated with the RESOURCELOAD usage, this will result in a NOP check render
target - check context - return sequence in ActivateContext, except if the thread
changed, and thus be cheap.

In performance critical path the isInDraw flag is checked first to avoid needless
calling of ActivateContext in PreLoad(which is called mostly from drawPrimitive),
or in other places, the multithreading flag is checked.

IWineD3DDevice::Clear is an exception regarding the render target. Clear needs the
primary render target activated.
---
 dlls/wined3d/basetexture.c   |    4 ++-
 dlls/wined3d/context.c       |   10 ++++++++
 dlls/wined3d/cubetexture.c   |   12 ++++++++++
 dlls/wined3d/device.c        |   39 ++++++++++++++++++++++++++++++++
 dlls/wined3d/indexbuffer.c   |   11 ++++++++-
 dlls/wined3d/stateblock.c    |    2 +
 dlls/wined3d/surface.c       |   51 ++++++++++++++++++++---------------------
 dlls/wined3d/swapchain.c     |    2 +
 dlls/wined3d/texture.c       |   10 ++++++++
 dlls/wined3d/utils.c         |   11 ++------
 dlls/wined3d/vertexbuffer.c  |   15 ++++++++++-
 dlls/wined3d/volumetexture.c |    4 +++
 12 files changed, 133 insertions(+), 38 deletions(-)

diff --git a/dlls/wined3d/basetexture.c b/dlls/wined3d/basetexture.c
index c55ceda..63c5d7c 100644
--- a/dlls/wined3d/basetexture.c
+++ b/dlls/wined3d/basetexture.c
@@ -96,9 +96,12 @@ ULONG WINAPI IWineD3DBaseTextureImpl_Release(IWineD3DBaseTexture *iface) {
 /* class static */
 void IWineD3DBaseTextureImpl_CleanUp(IWineD3DBaseTexture *iface) {
     IWineD3DBaseTextureImpl *This = (IWineD3DBaseTextureImpl *)iface;
+    IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
+
     TRACE("(%p) : textureName(%d)\n", This, This->baseTexture.textureName);
     if (This->baseTexture.textureName != 0) {
         ENTER_GL();
+        ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
         TRACE("(%p) : Deleting texture %d\n", This, This->baseTexture.textureName);
         glDeleteTextures(1, &This->baseTexture.textureName);
         LEAVE_GL();
@@ -236,7 +239,6 @@ HRESULT WINAPI IWineD3DBaseTextureImpl_BindTexture(IWineD3DBaseTexture *iface) {
 
     textureDimensions = IWineD3DBaseTexture_GetTextureDimensions(iface);
     ENTER_GL();
-
     /* Generate a texture name if we don't already have one */
     if (This->baseTexture.textureName == 0) {
         glGenTextures(1, &This->baseTexture.textureName);
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index ac2ca44..c4715d5 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -693,6 +693,14 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU
             }
         }
         if (readTexture) {
+            BOOL oldInDraw = This->isInDraw;
+
+            /* PreLoad requires a context to load the texture, thus it will call ActivateContext.
+             * Set the isInDraw to true to signal PreLoad that it has a context. Will be tricky
+             * when using offscreen rendering with multithreading
+             */
+            This->isInDraw = TRUE;
+
             /* Do that before switching the context:
              * Read the back buffer of the old drawable into the destination texture
              */
@@ -700,6 +708,8 @@ void ActivateContext(IWineD3DDeviceImpl *This, IWineD3DSurface *target, ContextU
             IWineD3DSurface_AddDirtyRect(This->lastActiveRenderTarget, NULL);
             IWineD3DSurface_PreLoad(This->lastActiveRenderTarget);
             IWineD3DSurface_SetPBufferState(This->lastActiveRenderTarget, FALSE /* inPBuffer */, FALSE /* inTexture */);
+
+            This->isInDraw = oldInDraw;
         }
         This->lastActiveRenderTarget = target;
         if(oldRenderOffscreen != This->render_offscreen && This->depth_copy_state != WINED3D_DCS_NO_COPY) {
diff --git a/dlls/wined3d/cubetexture.c b/dlls/wined3d/cubetexture.c
index f3df9f4..d9b0c47 100644
--- a/dlls/wined3d/cubetexture.c
+++ b/dlls/wined3d/cubetexture.c
@@ -104,11 +104,23 @@ static void WINAPI IWineD3DCubeTextureImpl_PreLoad(IWineD3DCubeTexture *iface) {
     unsigned int i,j;
     BOOL setGlTextureDesc = FALSE;
     IWineD3DCubeTextureImpl *This = (IWineD3DCubeTextureImpl *)iface;
+    IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
 
     TRACE("(%p) : About to load texture: dirtified(%d)\n", This, This->baseTexture.dirty);
 
     if (This->baseTexture.textureName == 0)  setGlTextureDesc = TRUE;
 
+    /* We only have to activate a context for gl when we're not drawing. In most cases PreLoad will be called during draw
+     * and a context was activated at the beginning of drawPrimitive
+     */
+    if(!device->isInDraw) {
+        /* No danger of recursive calls, ActivateContext sets isInDraw to true when loading
+         * offscreen render targets into their texture
+         */
+        ENTER_GL();
+        ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+        LEAVE_GL();
+    }
     IWineD3DCubeTexture_BindTexture(iface);
 
     ENTER_GL();
diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index dbd2071..02625ef 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -326,6 +326,9 @@ static void CreateVBO(IWineD3DVertexBufferImpl *object) {
     TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p  Usage(%s)\n", object, debug_d3dusage(vboUsage));
 
     ENTER_GL();
+    /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
+    ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+
     /* Make sure that the gl error is cleared. Do not use checkGLcall
       * here because checkGLcall just prints a fixme and continues. However,
       * if an error during VBO creation occurs we can fall back to non-vbo operation
@@ -453,6 +456,9 @@ static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferIm
     IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
 
     ENTER_GL();
+    /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
+    ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+
     while(glGetError());
 
     GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
@@ -1801,6 +1807,13 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_D
 
     if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
 
+    ENTER_GL();
+    /* I don't think that the interface guarants that the device is destroyed from the same thread
+     * it was created. Thus make sure a context is active for the glDelete* calls
+     */
+    ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+    LEAVE_GL();
+
     /* Delete the pbuffer context if there is any */
     if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
 
@@ -3722,6 +3735,16 @@ static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface,
         WARN("NULL source vertex buffer\n");
         return WINED3DERR_INVALIDCALL;
     }
+
+    /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
+     * and this call is quite performance critical, so don't call needlessly
+     */
+    if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
+        ENTER_GL();
+        ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+        LEAVE_GL();
+    }
+
     /* We don't need the source vbo because this buffer is only used as
      * a source for ProcessVertices. Avoid wasting resources by converting the
      * buffer and loading the VBO
@@ -4151,6 +4174,9 @@ static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
     }
 
     ENTER_GL();
+    if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
+        ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+    }
     /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
     glFlush();
     checkGLcall("glFlush");
@@ -4196,6 +4222,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Coun
           Count, pRects, Flags, Z, Stencil);
 
     ENTER_GL();
+    /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
+     * and not the last active one.
+     */
+    ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
 
     if(pRects) {
         glEnable(GL_SCISSOR_TEST);
@@ -4766,6 +4796,9 @@ static HRESULT  WINAPI  IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface,
     }
 
     ENTER_GL();
+
+    ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+
     if (GL_SUPPORT(ARB_MULTITEXTURE)) {
         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
         checkGLcall("glActiveTextureARB");
@@ -5005,6 +5038,10 @@ static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *ifa
 
     if(Swapchain->backBuffer[0] != Back) {
         TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
+
+        /* What to do about the context here in the case of multithreading? Not sure.
+         * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
+         */
         ENTER_GL();
         if(!Swapchain->backBuffer[0]) {
             /* GL was told to draw to the front buffer at creation,
@@ -5250,6 +5287,7 @@ static HRESULT  WINAPI  IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* i
     /* some basic validation checks */
     if(This->cursorTexture) {
         ENTER_GL();
+        ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
         glDeleteTextures(1, &This->cursorTexture);
         LEAVE_GL();
         This->cursorTexture = 0;
@@ -5375,6 +5413,7 @@ void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS*
     }
     if(surface->glDescription.textureName) {
         ENTER_GL();
+        ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
         glDeleteTextures(1, &surface->glDescription.textureName);
         LEAVE_GL();
         surface->glDescription.textureName = 0;
diff --git a/dlls/wined3d/indexbuffer.c b/dlls/wined3d/indexbuffer.c
index ae2294a..f64d6aa 100644
--- a/dlls/wined3d/indexbuffer.c
+++ b/dlls/wined3d/indexbuffer.c
@@ -59,7 +59,10 @@ static ULONG WINAPI IWineD3DIndexBufferImpl_Release(IWineD3DIndexBuffer *iface)
     TRACE("(%p) : Releasing from %d\n", This, ref + 1);
     if (ref == 0) {
         if(This->vbo) {
+            IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
+
             ENTER_GL();
+            ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
             /* No need to manually unset the buffer. glDeleteBuffers unsets it for the current context,
              * but not for other contexts. However, because the d3d buffer is destroyed the app has to
              * unset it before doing the next draw, thus dirtifying the index buffer state and forcing
@@ -153,7 +156,13 @@ static HRESULT WINAPI IWineD3DIndexBufferImpl_Unlock(IWineD3DIndexBuffer *iface)
 
     /* For now load in unlock */
     if(locks == 0 && This->vbo) {
+        IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
         ENTER_GL();
+
+        if(device->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
+            ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+        }
+
         GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, This->vbo));
         checkGLcall("glBindBufferARB");
         GL_EXTCALL(glBufferSubDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB,
@@ -163,7 +172,7 @@ static HRESULT WINAPI IWineD3DIndexBufferImpl_Unlock(IWineD3DIndexBuffer *iface)
         This->dirtystart = 0;
         This->dirtyend = 0;
         /* TODO: Move loading into preload when the buffer is used, that avoids dirtifying the state */
-        IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_INDEXBUFFER);
+        IWineD3DDeviceImpl_MarkStateDirty(device, STATE_INDEXBUFFER);
     }
     return WINED3D_OK;
 }
diff --git a/dlls/wined3d/stateblock.c b/dlls/wined3d/stateblock.c
index 7622d8e..dc872ce 100644
--- a/dlls/wined3d/stateblock.c
+++ b/dlls/wined3d/stateblock.c
@@ -1062,6 +1062,8 @@ static HRESULT  WINAPI IWineD3DStateBlockImpl_InitStartupStateBlock(IWineD3DStat
        then the default texture will kick in until replaced by a SetTexture call     */
     ENTER_GL();
 
+    /* This is initialization code - A context is supposed to be there, no need to activate one */
+
     for (i = 0; i < GL_LIMITS(texture_stages); i++) {
         GLubyte white = 255;
 
diff --git a/dlls/wined3d/surface.c b/dlls/wined3d/surface.c
index 00199c8..7255172 100644
--- a/dlls/wined3d/surface.c
+++ b/dlls/wined3d/surface.c
@@ -60,12 +60,8 @@ static void surface_download_data(IWineD3DSurfaceImpl *This) {
             TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
                 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
 
-            ENTER_GL();
-
             GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
             checkGLcall("glGetCompressedTexImageARB()");
-
-            LEAVE_GL();
         }
     } else {
         void *mem;
@@ -89,14 +85,10 @@ static void surface_download_data(IWineD3DSurfaceImpl *This) {
         TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
                 This->glDescription.glFormat, This->glDescription.glType, mem);
 
-        ENTER_GL();
-
         glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
                 This->glDescription.glType, mem);
         checkGLcall("glGetTexImage()");
 
-        LEAVE_GL();
-
         if (This->Flags & SFLAG_NONPOW2) {
             LPBYTE src_data, dst_data;
             int y;
@@ -258,6 +250,7 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
              * and the lastActiveRenderTarget member shouldn't matter
              */
             if(swapchain) {
+                ENTER_GL(); /* For ActivateContext */
                 if(swapchain->backBuffer && swapchain->backBuffer[0] != iface) {
                     TRACE("Activating primary back buffer\n");
                     ActivateContext(device, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
@@ -272,6 +265,7 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
                      */
                     device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
                 }
+                LEAVE_GL();
             } else {
                 /* May happen during ddraw uninitialization */
                 TRACE("Render target set, but swapchain does not exist!\n");
@@ -281,6 +275,15 @@ ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
 
         if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
             ENTER_GL();
+
+            /* Need a context to destroy the texture. Use the currently active render target, but only if
+             * the primary render target exists. Otherwise lastActiveRenderTarget is garbage, see above.
+             * When destroying the primary rt, Uninit3D will activate a context before doing anything
+             */
+            if(device->render_targets[0]) {
+                ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+            }
+
             TRACE("Deleting texture %d\n", This->glDescription.textureName);
             glDeleteTextures(1, &This->glDescription.textureName);
             LEAVE_GL();
@@ -338,13 +341,11 @@ DWORD   WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
 }
 
 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
-    /* TODO: re-write the way textures and managed,
-    *  use a 'opengl context manager' to manage RenderTarget surfaces
-    ** *********************************************************/
-
     /* TODO: check for locks */
     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
     IWineD3DBaseTexture *baseTexture = NULL;
+    IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
+
     TRACE("(%p)Checking to see if the container is a base texture\n", This);
     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
         TRACE("Passing to conatiner\n");
@@ -352,10 +353,12 @@ void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
         IWineD3DBaseTexture_Release(baseTexture);
     } else {
     TRACE("(%p) : About to load surface\n", This);
+
     ENTER_GL();
-#if 0 /* TODO: context manager support */
-     IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
-#endif
+    if(!device->isInDraw) {
+        ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+    }
+
     glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
     if (!This->glDescription.level) {
         if (!This->glDescription.textureName) {
@@ -377,11 +380,6 @@ void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
        tmp = 0.9f;
         glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
     }
-    /* TODO: disable texture support, if it wastn't enabled when we entered. */
-#if 0 /* TODO: context manager support */
-     IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
-              /* we don't care when the state is disabled(if atall) */);
-#endif
     LEAVE_GL();
     }
     return;
@@ -758,24 +756,25 @@ static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED
         /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
         TRACE("locking an ordinarary surface\n");
 
-        /* TODO: Make sure that *any* context is active for this thread. It is not important which context that is,
-         * nor that is has any special setup(CTXUSAGE_LOADRESOURCE is fine), but the code below needs a context.
-         * A context is guaranteed to be there in a single threaded environment, but not with multithreading
-         */
         if (0 != This->glDescription.textureName) {
             /* Now I have to copy thing bits back */
 
+            ENTER_GL();
+
+            if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
+                ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+            }
+
             /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
             if (GL_SUPPORT(ARB_MULTITEXTURE)) {
-                ENTER_GL();
                 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
                 checkGLcall("glActiveTextureARB");
-                LEAVE_GL();
             }
             IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
             IWineD3DSurface_PreLoad(iface);
 
             surface_download_data(This);
+            LEAVE_GL();
         }
 
         /* The local copy is now up to date to the opengl one because a full download was done */
diff --git a/dlls/wined3d/swapchain.c b/dlls/wined3d/swapchain.c
index 48253e9..08695a0 100644
--- a/dlls/wined3d/swapchain.c
+++ b/dlls/wined3d/swapchain.c
@@ -146,6 +146,8 @@ static HRESULT WINAPI IWineD3DSwapChainImpl_Present(IWineD3DSwapChain *iface, CO
 
     ENTER_GL();
 
+    /* Does glXSwapBuffers need a glx context? I don't think so. Blt will activate its own context if needed */
+
     /* Render the cursor onto the back buffer, using our nifty directdraw blitting code :-) */
     if(This->wineD3DDevice->bCursorVisible && This->wineD3DDevice->cursorTexture) {
         IWineD3DSurfaceImpl cursor;
diff --git a/dlls/wined3d/texture.c b/dlls/wined3d/texture.c
index e9a78cc..cc8a83a 100644
--- a/dlls/wined3d/texture.c
+++ b/dlls/wined3d/texture.c
@@ -97,11 +97,21 @@ static void WINAPI IWineD3DTextureImpl_PreLoad(IWineD3DTexture *iface) {
     unsigned int i;
     BOOL setGlTextureDesc = FALSE;
     IWineD3DTextureImpl *This = (IWineD3DTextureImpl *)iface;
+    IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
 
     TRACE("(%p) : About to load texture\n", This);
 
     if (This->baseTexture.textureName == 0)  setGlTextureDesc = TRUE;
 
+    if(!device->isInDraw) {
+        /* ActivateContext sets isInDraw to TRUE when loading a pbuffer into a texture, thus no danger of
+         * recursive calls
+         */
+        ENTER_GL();
+        ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+        LEAVE_GL();
+    }
+
     IWineD3DTexture_BindTexture(iface);
     ENTER_GL();
         /* If were dirty then reload the surfaces */
diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c
index 849f915..6a85ba0 100644
--- a/dlls/wined3d/utils.c
+++ b/dlls/wined3d/utils.c
@@ -810,7 +810,8 @@ void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEX
     get_src_and_opr_nvrc(stage, arg3, is_alpha, &tex_op_args.input[2],
             &tex_op_args.mapping[2], &tex_op_args.component_usage[2], texture_idx);
 
-    ENTER_GL();
+
+    /* This is called by a state handler which has the gl lock held and a context for the thread */
 
     switch(op)
     {
@@ -1082,7 +1083,6 @@ void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEX
 
     checkGLcall("set_tex_op_nvrc()\n");
 
-    LEAVE_GL();
 }
 
 static void get_src_and_opr(DWORD arg, BOOL is_alpha, GLenum* source, GLenum* operand) {
@@ -1160,7 +1160,7 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP
 
         TRACE("Alpha?(%d), Stage:%d Op(%s), a1(%d), a2(%d), a3(%d)\n", isAlpha, Stage, debug_d3dtop(op), arg1, arg2, arg3);
 
-        ENTER_GL();
+        /* This is called by a state handler which has the gl lock held and a context for the thread */
 
         /* Note: Operations usually involve two ars, src0 and src1 and are operations of
            the form (a1 <operation> a2). However, some of the more complex operations
@@ -1681,7 +1681,6 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP
             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV);
             checkGLcall("GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE4_NV");
 
-            LEAVE_GL();
             return;
           }
         } /* GL_NV_texture_env_combine4 */
@@ -2148,7 +2147,6 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP
                 break;
               default:
                 FIXME("Can't use COMBINE4 and COMBINE together, thisop=%s, otherop=%s, isAlpha(%d)\n", debug_d3dtop(op), debug_d3dtop(op2), isAlpha);
-                LEAVE_GL();
                 return;
               }
             }
@@ -2158,13 +2156,10 @@ void set_tex_op(IWineD3DDevice *iface, BOOL isAlpha, int Stage, WINED3DTEXTUREOP
             glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, useext(GL_COMBINE));
             checkGLcall("GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, useext(GL_COMBINE)");
 
-            LEAVE_GL();
             return;
           }
         }
 
-        LEAVE_GL();
-
         /* After all the extensions, if still unhandled, report fixme */
         FIXME("Unhandled texture operation %s\n", debug_d3dtop(op));
         #undef GLINFO_LOCATION
diff --git a/dlls/wined3d/vertexbuffer.c b/dlls/wined3d/vertexbuffer.c
index 2e97c20..0a3706e 100644
--- a/dlls/wined3d/vertexbuffer.c
+++ b/dlls/wined3d/vertexbuffer.c
@@ -62,7 +62,10 @@ static ULONG WINAPI IWineD3DVertexBufferImpl_Release(IWineD3DVertexBuffer *iface
     if (ref == 0) {
 
         if(This->vbo) {
+            IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
+
             ENTER_GL();
+            ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
             GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
             checkGLcall("glDeleteBuffersARB");
             LEAVE_GL();
@@ -251,6 +254,7 @@ inline BOOL WINAPI IWineD3DVertexBufferImpl_FindDecl(IWineD3DVertexBufferImpl *T
 
 static void     WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *iface) {
     IWineD3DVertexBufferImpl *This = (IWineD3DVertexBufferImpl *) iface;
+    IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
     BYTE *data;
     UINT start = 0, end = 0, stride = 0;
     BOOL declChanged = FALSE;
@@ -266,7 +270,7 @@ static void     WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *if
     }
 
     /* Reading the declaration makes only sense if the stateblock is finalized and the buffer bound to a stream */
-    if(This->resource.wineD3DDevice->isInDraw && This->bindCount > 0) {
+    if(device->isInDraw && This->bindCount > 0) {
         declChanged = IWineD3DVertexBufferImpl_FindDecl(This);
     } else if(This->Flags & VBFLAG_HASDESC) {
         /* Reuse the declaration stored in the buffer. It will most likely not change, and if it does
@@ -291,6 +295,7 @@ static void     WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *if
         if(This->declChanges > VB_MAXDECLCHANGES) {
             FIXME("Too much declaration changes, stopping converting\n");
             ENTER_GL();
+            ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
             GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
             checkGLcall("glDeleteBuffersARB");
             LEAVE_GL();
@@ -301,7 +306,7 @@ static void     WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *if
              * to force a reload. This happens only once per changed vertexbuffer and should occur rather
              * rarely
              */
-            IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_STREAMSRC);
+            IWineD3DDeviceImpl_MarkStateDirty(device, STATE_STREAMSRC);
 
             return;
         }
@@ -344,6 +349,9 @@ static void     WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *if
         TRACE("No conversion needed, locking directly into the VBO in future\n");
 
         ENTER_GL();
+        if(!device->isInDraw) {
+            ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+        }
         GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
         checkGLcall("glBindBufferARB");
         GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, start, end-start, This->resource.allocatedMemory + start));
@@ -374,6 +382,9 @@ static void     WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *if
                    This->strided.u.s.specular.dwType == WINED3DDECLTYPE_SHORT4 || This->strided.u.s.specular.dwType == WINED3DDECLTYPE_D3DCOLOR);
 
     ENTER_GL();
+    if(!device->isInDraw) {
+        ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+    }
     GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
     checkGLcall("glBindBufferARB");
     GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, start, end - start, data));
diff --git a/dlls/wined3d/volumetexture.c b/dlls/wined3d/volumetexture.c
index 46e0c4d..1d75bdc 100644
--- a/dlls/wined3d/volumetexture.c
+++ b/dlls/wined3d/volumetexture.c
@@ -94,12 +94,16 @@ static void WINAPI IWineD3DVolumeTextureImpl_PreLoad(IWineD3DVolumeTexture *ifac
     /* Overrider the IWineD3DResource Preload method */
     UINT i;
     IWineD3DVolumeTextureImpl *This = (IWineD3DVolumeTextureImpl *)iface;
+    IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
 
     TRACE("(%p) : About to load texture\n", This);
 
     IWineD3DVolumeTexture_BindTexture(iface);
 
     ENTER_GL();
+    if(!device->isInDraw) {
+        ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
+    }
     /* If were dirty then reload the volumes */
     if(This->baseTexture.dirty) {
         for (i = 0; i < This->baseTexture.levels; i++) {
-- 
1.4.4.3



More information about the wine-patches mailing list