From d47ec212807e2e7a4e9ba47b5fc4a0082dc0f966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20D=C3=B6singer?= Date: Sat, 6 Jan 2007 18:31:43 +0100 Subject: [PATCH] wined3d: Vertex buffers can use the declaration from the device. --- dlls/wined3d/drawprim.c | 39 ++++++++++++++++++++++++++-- dlls/wined3d/vertexbuffer.c | 51 ++++++++++++++----------------------- 2 files changed, 56 insertions(+), 34 deletions(-) diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c index 3b14c4ac62d..129c42e9240 100644 --- a/dlls/wined3d/drawprim.c +++ b/dlls/wined3d/drawprim.c @@ -219,6 +219,10 @@ void primitiveDeclarationConvertToStridedData( WINED3DVERTEXELEMENT *element; DWORD stride; int reg; + char isPreLoaded[MAX_STREAMS]; + DWORD preLoadStreams[MAX_STREAMS], numPreloadStreams = 0; + + memset(isPreLoaded, 0, sizeof(isPreLoaded)); /* Locate the vertex declaration */ if (This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->vertexDeclaration) { @@ -249,7 +253,11 @@ void primitiveDeclarationConvertToStridedData( if(fixup && *fixup) FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n"); } else { TRACE("Stream isn't up %d, %p\n", element->Stream, This->stateBlock->streamSource[element->Stream]); - IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[element->Stream]); + if(!isPreLoaded[element->Stream]) { + preLoadStreams[numPreloadStreams] = element->Stream; + numPreloadStreams++; + isPreLoaded[element->Stream] = 1; + } data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO); if(fixup) { if( streamVBO != 0) *fixup = TRUE; @@ -287,6 +295,17 @@ void primitiveDeclarationConvertToStridedData( } } }; + /* Now call PreLoad on all the vertex buffers. In the very rare case + * that the buffers stopps converting PreLoad will dirtify the VDECL again. + * The vertex buffer can now use the strided structure in the device instead of finding its + * own again. + * + * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only + * once in there. + */ + for(i=0; i < numPreloadStreams; i++) { + IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[preLoadStreams[i]]); + } } void primitiveConvertFVFtoOffset(DWORD thisFVF, DWORD stride, BYTE *data, WineDirect3DVertexStridedData *strided, GLint streamVBO) { @@ -413,6 +432,7 @@ void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStri short LoopThroughTo = 0; short nStream; GLint streamVBO = 0; + DWORD preLoadStreams[MAX_STREAMS], numPreloadStreams = 0; IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface; @@ -443,7 +463,11 @@ void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStri streamVBO = 0; data = (BYTE *)This->stateBlock->streamSource[nStream]; } else { - IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[nStream]); + /* The for loop should iterate through here only once per stream, so we don't need magic to prevent double loading + * buffers + */ + preLoadStreams[numPreloadStreams] = nStream; + numPreloadStreams++; /* GetMemory binds the VBO */ data = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[nStream], 0, &streamVBO); if(fixup) { @@ -462,6 +486,17 @@ void primitiveConvertToStridedData(IWineD3DDevice *iface, WineDirect3DVertexStri /* Now convert the stream into pointers */ primitiveConvertFVFtoOffset(thisFVF, stride, data, strided, streamVBO); } + /* Now call PreLoad on all the vertex buffers. In the very rare case + * that the buffers stopps converting PreLoad will dirtify the VDECL again. + * The vertex buffer can now use the strided structure in the device instead of finding its + * own again. + * + * NULL streams won't be recorded in the array, UP streams won't be either. A stream is only + * once in there. + */ + for(nStream=0; nStream < numPreloadStreams; nStream++) { + IWineD3DVertexBuffer_PreLoad(This->stateBlock->streamSource[preLoadStreams[nStream]]); + } } #if 0 /* TODO: Software Shaders */ diff --git a/dlls/wined3d/vertexbuffer.c b/dlls/wined3d/vertexbuffer.c index 2f8a4f79da3..b89d92267ba 100644 --- a/dlls/wined3d/vertexbuffer.c +++ b/dlls/wined3d/vertexbuffer.c @@ -164,7 +164,6 @@ inline BOOL WINAPI IWineD3DVertexBufferImpl_FindDecl(IWineD3DVertexBufferImpl *T { WineDirect3DVertexStridedData strided; IWineD3DDeviceImpl *device = This->resource.wineD3DDevice; - BOOL ret; memset(&strided, 0, sizeof(strided)); /* There are certain vertex data types that need to be fixed up. The Vertex Buffers FVF doesn't @@ -191,38 +190,18 @@ inline BOOL WINAPI IWineD3DVertexBufferImpl_FindDecl(IWineD3DVertexBufferImpl *T * FALSE: otherwise */ - if(device->stateBlock->vertexShader != NULL && wined3d_settings.vs_mode != VS_NONE - &&((IWineD3DVertexShaderImpl *)device->stateBlock->vertexShader)->baseShader.function != NULL - && GL_SUPPORT(ARB_VERTEX_PROGRAM)) { - /* Case 1: Vertex Shader: No conversion */ - TRACE("Vertex Shader, no conversion needed\n"); - } else if(device->stateBlock->vertexDecl || device->stateBlock->vertexShader) { - /* Case 2: Vertex Declaration */ - TRACE("Using vertex declaration\n"); - - This->Flags |= VBFLAG_LOAD; - primitiveDeclarationConvertToStridedData((IWineD3DDevice *) device, - FALSE, - &strided, - &ret /* buffer contains fixed data, ignored here */); - This->Flags &= ~VBFLAG_LOAD; - + if(device->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *) device->stateBlock->vertexShader)->baseShader.function) { + /* Assume no conversion */ + memset(&strided, 0, sizeof(strided)); } else { - /* Case 3: FVF */ - if(!(This->Flags & VBFLAG_STREAM) ) { - TRACE("No vertex decl used and buffer is not bound to a stream\n"); - /* No reload needed */ - return FALSE; - } else { - This->Flags |= VBFLAG_LOAD; - primitiveConvertFVFtoOffset(device->stateBlock->fvf, - device->stateBlock->streamStride[This->stream], - NULL, - &strided, - This->vbo); - This->Flags &= ~VBFLAG_LOAD; - /* Data can only come from this buffer */ - } + /* we need a copy because we modify some params */ + memcpy(&strided, &device->strided_streams, sizeof(strided)); + + /* Filter out data that does not come from this VBO */ + if(strided.u.s.position.VBO != This->vbo) memset(&strided.u.s.position, 0, sizeof(strided.u.s.position)); + if(strided.u.s.diffuse.VBO != This->vbo) memset(&strided.u.s.diffuse, 0, sizeof(strided.u.s.diffuse)); + if(strided.u.s.specular.VBO != This->vbo) memset(&strided.u.s.specular, 0, sizeof(strided.u.s.specular)); + if(strided.u.s.position2.VBO != This->vbo) memset(&strided.u.s.position2, 0, sizeof(strided.u.s.position2)); } /* Filter out data that does not come from this VBO */ @@ -297,6 +276,14 @@ static void WINAPI IWineD3DVertexBufferImpl_PreLoad(IWineD3DVertexBuffer *if 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,