[5/10] WineD3D: Do not release the local vertex buffer copy

Stefan Dösinger stefan at codeweavers.com
Wed Feb 14 10:51:21 CST 2007


If the stride of a stream is 0, loadStreams will need the local copy. 
Instancing emulation will need it too, simmilar for other (future) features 
like software vertex shaders and vertex blending emulation. This also allows 
setting up opengl vertex buffers as write only.
-------------- next part --------------
From 97e5eb3eca21141d708789837782f3d0aa5959ea Mon Sep 17 00:00:00 2001
From: Stefan Doesinger <stefan at codeweavers.com>
Date: Fri, 2 Feb 2007 13:04:35 +0100
Subject: [PATCH] WineD3D: Do not release the local vertex buffer copy

---
 dlls/wined3d/device.c       |   28 +++--------
 dlls/wined3d/vertexbuffer.c |  104 +++++++++----------------------------------
 2 files changed, 29 insertions(+), 103 deletions(-)

diff --git a/dlls/wined3d/device.c b/dlls/wined3d/device.c
index 8396f63..a28714d 100644
--- a/dlls/wined3d/device.c
+++ b/dlls/wined3d/device.c
@@ -355,31 +355,26 @@ static void CreateVBO(IWineD3DVertexBufferImpl *object) {
     }
 
     /* Don't use static, because dx apps tend to update the buffer
-      * quite often even if they specify 0 usage
-      */
+     * quite often even if they specify 0 usage. Because we always keep the local copy
+     * we never read from the vbo and can create a write only opengl buffer.
+     */
     switch(vboUsage & (D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC) ) {
         case D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC:
+        case D3DUSAGE_DYNAMIC:
             TRACE("Gl usage = GL_STREAM_DRAW\n");
             glUsage = GL_STREAM_DRAW_ARB;
             break;
         case D3DUSAGE_WRITEONLY:
+        default:
             TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
             glUsage = GL_DYNAMIC_DRAW_ARB;
             break;
-        case D3DUSAGE_DYNAMIC:
-            TRACE("Gl usage = GL_STREAM_COPY\n");
-            glUsage = GL_STREAM_COPY_ARB;
-            break;
-        default:
-            TRACE("Gl usage = GL_DYNAMIC_COPY\n");
-            glUsage = GL_DYNAMIC_COPY_ARB;
-            break;
     }
 
     /* Reserve memory for the buffer. The amount of data won't change
-      * so we are safe with calling glBufferData once with a NULL ptr and
-      * calling glBufferSubData on updates
-      */
+     * so we are safe with calling glBufferData once with a NULL ptr and
+     * calling glBufferSubData on updates
+     */
     GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
     error = glGetError();
     if(error != GL_NO_ERROR) {
@@ -444,13 +439,6 @@ static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *ifac
     if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && 
         (dxVersion > 7 || !conv) ) {
         CreateVBO(object);
-
-        /* DX7 buffers can be locked directly into the VBO (no conversion, see above */
-        if(dxVersion == 7 && object->vbo) {
-            HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
-            object->resource.allocatedMemory = NULL;
-        }
-
     }
     return WINED3D_OK;
 }
diff --git a/dlls/wined3d/vertexbuffer.c b/dlls/wined3d/vertexbuffer.c
index 6ef7533..84d0ca3 100644
--- a/dlls/wined3d/vertexbuffer.c
+++ b/dlls/wined3d/vertexbuffer.c
@@ -289,27 +289,21 @@ static void     WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *if
         This->draws = 0;
 
         if(This->declChanges > VB_MAXDECLCHANGES) {
-            if(This->resource.allocatedMemory) {
-                FIXME("Too much declaration changes, stopping converting\n");
-                ENTER_GL();
-                GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
-                checkGLcall("glDeleteBuffersARB");
-                LEAVE_GL();
-                This->vbo = 0;
-
-                /* The stream source state handler might have read the memory of the vertex buffer already
-                 * and got the memory in the vbo which is not valid any longer. Dirtify the stream source
-                 * to force a reload. This happens only once per changed vertexbuffer and should occur rather
-                 * rarely
-                 */
-                IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_STREAMSRC);
-
-                return;
-            }
-            /* Otherwise do not bother to release the VBO. If we're doing direct locking now,
-             * and the declarations changed the code below will fetch the VBO's contents, convert
-             * and on the next decl change the data will be in sysmem too and we can just release the VBO
+            FIXME("Too much declaration changes, stopping converting\n");
+            ENTER_GL();
+            GL_EXTCALL(glDeleteBuffersARB(1, &This->vbo));
+            checkGLcall("glDeleteBuffersARB");
+            LEAVE_GL();
+            This->vbo = 0;
+
+            /* The stream source state handler might have read the memory of the vertex buffer already
+             * and got the memory in the vbo which is not valid any longer. Dirtify the stream source
+             * to force a reload. This happens only once per changed vertexbuffer and should occur rather
+             * rarely
              */
+            IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_STREAMSRC);
+
+            return;
         }
     } else {
         /* However, it is perfectly fine to change the declaration every now and then. We don't want a game that
@@ -339,46 +333,20 @@ static void     WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *if
     This->dirtystart = 0;
     This->dirtyend = 0;
 
-    /* If there was no conversion done before, then resource.allocatedMemory does not exist
-     * because locking was done directly into the VBO. In this case get the data out
-     */
-    if(declChanged && !This->resource.allocatedMemory) {
-
-        This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, This->resource.size);
-        if(!This->resource.allocatedMemory) {
-            ERR("Out of memory when allocating memory for a vertex buffer\n");
-            return;
-        }
-        ERR("Was locking directly into the VBO, reading data back because conv is needed\n");
-
-        ENTER_GL();
-        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
-        checkGLcall("glBindBufferARB");
-        data = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_WRITE_ARB));
-        if(!data) {
-            ERR("glMapBuffer failed!\n");
-            LEAVE_GL();
-            return;
-        }
-        memcpy(This->resource.allocatedMemory, data, This->resource.size);
-        GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
-        checkGLcall("glUnmapBufferARB");
-        LEAVE_GL();
-    }
-
     if     (This->strided.u.s.position.dwStride) stride = This->strided.u.s.position.dwStride;
     else if(This->strided.u.s.specular.dwStride) stride = This->strided.u.s.specular.dwStride;
     else if(This->strided.u.s.diffuse.dwStride)  stride = This->strided.u.s.diffuse.dwStride;
     else {
-        /* That means that there is nothing to fixup. Upload everything into the VBO and
-         * free This->resource.allocatedMemory
+        /* That means that there is nothing to fixup. Just upload from This->resource.allocatedMemory
+         * directly into the vbo. Do not free the system memory copy because drawPrimitive may need it if
+         * the stride is 0, for instancing emulation, vertex blending emulation or shader emulation.
          */
         TRACE("No conversion needed, locking directly into the VBO in future\n");
 
         ENTER_GL();
         GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
         checkGLcall("glBindBufferARB");
-        GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, This->resource.size, This->resource.allocatedMemory));
+        GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, start, end-start, This->resource.allocatedMemory + start));
         checkGLcall("glBufferSubDataARB");
         LEAVE_GL();
         return;
@@ -448,31 +416,8 @@ static HRESULT  WINAPI IWineD3DVertexBufferImpl_Lock(IWineD3DVertexBuffer *iface
             This->dirtyend = This->resource.size;
     }
 
-    if(This->resource.allocatedMemory) {
-          data = This->resource.allocatedMemory;
-          This->Flags |= VBFLAG_DIRTY;
-    } else {
-        GLenum mode = GL_READ_WRITE_ARB;
-        /* Return data to the VBO */
-
-        TRACE("Locking directly into the buffer\n");
-
-        if((This->resource.usage & WINED3DUSAGE_WRITEONLY) || ( Flags & WINED3DLOCK_DISCARD) ) {
-            mode = GL_WRITE_ONLY_ARB;
-        } else if( Flags & (WINED3DLOCK_READONLY | WINED3DLOCK_NO_DIRTY_UPDATE) ) {
-            mode = GL_READ_ONLY_ARB;
-        }
-
-        ENTER_GL();
-        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
-        checkGLcall("glBindBufferARB");
-        data = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, mode));
-        LEAVE_GL();
-        if(!data) {
-            ERR("glMapBuffer failed\n");
-            return WINED3DERR_INVALIDCALL;
-        }
-    }
+    data = This->resource.allocatedMemory;
+    This->Flags |= VBFLAG_DIRTY;
     *ppbData = data + OffsetToLock;
 
     TRACE("(%p) : returning memory of %p (base:%p,offset:%u)\n", This, data + OffsetToLock, data, OffsetToLock);
@@ -491,14 +436,7 @@ HRESULT  WINAPI IWineD3DVertexBufferImpl_Unlock(IWineD3DVertexBuffer *iface) {
         return D3D_OK;
     }
 
-    if(!This->resource.allocatedMemory) {
-        ENTER_GL();
-        GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, This->vbo));
-        checkGLcall("glBindBufferARB");
-        GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
-        checkGLcall("glUnmapBufferARB");
-        LEAVE_GL();
-    } else if(This->Flags & VBFLAG_HASDESC){
+    if(This->Flags & VBFLAG_HASDESC) {
         IWineD3DVertexBufferImpl_PreLoad(iface);
     }
     return WINED3D_OK;
-- 
1.4.4.3



More information about the wine-patches mailing list