[4/7] wined3d: Disable vertex shaders when transformed vertices are used

H. Verbeet hverbeet at gmail.com
Mon Mar 12 17:22:00 CDT 2007


When transformed vertices are used, all vertex processing should be
bypassed, including any vertex shaders that are set. A sane
application wouldn't set a vertex shader in the first place in that
case, so it's relatively uncommon for this condition to occur, but
some do. This should also fix bug 6056.

Changelog:
  - Disable vertex shaders when transformed vertices are used
-------------- next part --------------
---

 dlls/wined3d/drawprim.c        |   23 +++++++++++++----------
 dlls/wined3d/glsl_shader.c     |    8 ++++----
 dlls/wined3d/state.c           |   30 +++++++++++++++++-------------
 dlls/wined3d/vertexbuffer.c    |    2 +-
 dlls/wined3d/wined3d_private.h |   14 ++++++++++++++
 5 files changed, 49 insertions(+), 28 deletions(-)

diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index 14fb3e0..ecaaf0d 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -161,6 +161,17 @@ void primitiveDeclarationConvertToStridedData(
 
     memset(isPreLoaded, 0, sizeof(isPreLoaded));
 
+    /* Check for transformed vertices, disable vertex shader if present */
+    strided->u.s.position_transformed = FALSE;
+    for (i = 0; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
+        element = vertexDeclaration->pDeclarationWine + i;
+
+        if (element->Usage == WINED3DDECLUSAGE_POSITIONT) {
+            strided->u.s.position_transformed = TRUE;
+            useVertexShaderFunction = FALSE;
+        }
+    }
+
     /* Translate the declaration into strided data */
     for (i = 0 ; i < vertexDeclaration->declarationWNumElements - 1; ++i) {
         GLint streamVBO = 0;
@@ -188,7 +199,7 @@ void primitiveDeclarationConvertToStridedData(
             data    = IWineD3DVertexBufferImpl_GetMemory(This->stateBlock->streamSource[element->Stream], 0, &streamVBO);
             if(fixup) {
                 if( streamVBO != 0) *fixup = TRUE;
-                else if(*fixup && This->stateBlock->vertexShader == NULL) {
+                else if(*fixup && !useVertexShaderFunction) {
                     /* This may be bad with the fixed function pipeline */
                     FIXME("Missing fixed and unfixed vertices, expect graphics glitches\n");
                 }
@@ -218,12 +229,6 @@ void primitiveDeclarationConvertToStridedData(
             strided->u.input[idx].dwStride = stride;
             strided->u.input[idx].VBO = streamVBO;
             strided->u.input[idx].streamNo = element->Stream;
-            if (!useVertexShaderFunction) {
-                if (element->Usage == WINED3DDECLUSAGE_POSITION)
-                    strided->u.s.position_transformed = FALSE;
-                else if (element->Usage == WINED3DDECLUSAGE_POSITIONT)
-                    strided->u.s.position_transformed = TRUE;
-            }
         }
     }
     /* Now call PreLoad on all the vertex buffers. In the very rare case
@@ -796,9 +801,7 @@ static void depth_blt(IWineD3DDevice *iface, GLuint texture) {
      * and this seems easier and more efficient than providing the shader backend with a private
      * storage to read and restore the old shader settings
      */
-    This->shader_backend->shader_select(iface,
-        This->stateBlock->pixelShader && ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.function,
-        This->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.function);
+    This->shader_backend->shader_select(iface, use_ps(This), use_vs(This));
 }
 
 static void depth_copy(IWineD3DDevice *iface) {
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c
index af038b5..a9d01e0 100644
--- a/dlls/wined3d/glsl_shader.c
+++ b/dlls/wined3d/glsl_shader.c
@@ -2049,7 +2049,7 @@ void delete_glsl_program_entry(IWineD3DDevice *iface, struct glsl_shader_prog_li
  * the program in the hash table.  If it creates a program, it will link the
  * given objects, too.
  */
-static void set_glsl_shader_program(IWineD3DDevice *iface) {
+static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use_vs) {
     IWineD3DDeviceImpl *This               = (IWineD3DDeviceImpl *)iface;
     WineD3D_GL_Info *gl_info               = &((IWineD3DImpl *)(This->wineD3D))->gl_info;
     IWineD3DPixelShader  *pshader          = This->stateBlock->pixelShader;
@@ -2059,8 +2059,8 @@ static void set_glsl_shader_program(IWineD3DDevice *iface) {
     int i;
     char glsl_name[8];
 
-    GLhandleARB vshader_id = (vshader && This->vs_selected_mode == SHADER_GLSL) ? ((IWineD3DBaseShaderImpl*)vshader)->baseShader.prgId : 0;
-    GLhandleARB pshader_id = (pshader && This->ps_selected_mode == SHADER_GLSL) ? ((IWineD3DBaseShaderImpl*)pshader)->baseShader.prgId : 0;
+    GLhandleARB vshader_id = use_vs ? ((IWineD3DBaseShaderImpl*)vshader)->baseShader.prgId : 0;
+    GLhandleARB pshader_id = use_ps ? ((IWineD3DBaseShaderImpl*)pshader)->baseShader.prgId : 0;
     entry = get_glsl_program_entry(This, vshader_id, pshader_id);
     if (entry) {
         This->stateBlock->glsl_program = entry;
@@ -2179,7 +2179,7 @@ static void shader_glsl_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {
     WineD3D_GL_Info *gl_info = &((IWineD3DImpl *)(This->wineD3D))->gl_info;
     GLhandleARB program_id = 0;
 
-    if (useVS || usePS) set_glsl_shader_program(iface);
+    if (useVS || usePS) set_glsl_shader_program(iface, usePS, useVS);
     else This->stateBlock->glsl_program = NULL;
 
     program_id = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->programId : 0;
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 0e12a23..5b4a304 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -395,7 +395,7 @@ static void state_clipping(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
     DWORD enable  = 0xFFFFFFFF;
     DWORD disable = 0x00000000;
 
-    if(stateblock->vertexShader) {
+    if (use_vs(stateblock->wineD3DDevice)) {
         /* The spec says that opengl clipping planes are disabled when using shaders. Direct3D planes aren't,
          * so that is an issue. The MacOS ATI driver keeps clipping planes activated with shaders in some
          * contitions I got sick of tracking down. The shader state handler disables all clip planes because
@@ -709,8 +709,8 @@ static void state_fog(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DCo
     fogend = tmpvalue.f;
 
     /* Activate when vertex shaders are in the state table */
-    if(stateblock->vertexShader && ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->baseShader.function &&
-       ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->usesFog) {
+    if (use_vs(stateblock->wineD3DDevice)
+            && ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->usesFog) {
         glFogi(GL_FOG_MODE, GL_LINEAR);
         checkGLcall("glFogi(GL_FOG_MODE, GL_LINEAR)");
         if (stateblock->renderState[WINED3DRS_FOGTABLEMODE] == WINED3DFOG_NONE) {
@@ -1977,17 +1977,16 @@ static void shaderconstant(DWORD state, IWineD3DStateBlockImpl *stateblock, Wine
        return;
     }
     
-    device->shader_backend->shader_load_constants((IWineD3DDevice *) device,
-        stateblock->pixelShader && ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.function,
-        stateblock->vertexShader && ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->baseShader.function);
+    device->shader_backend->shader_load_constants((IWineD3DDevice *) device, use_ps(device), use_vs(device));
 }
 
 static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
-    BOOL use_ps = stateblock->pixelShader && ((IWineD3DPixelShaderImpl *)stateblock->pixelShader)->baseShader.function != NULL;
-    BOOL use_vs = stateblock->vertexShader && ((IWineD3DVertexShaderImpl *)stateblock->vertexShader)->baseShader.function != NULL;
+    IWineD3DDeviceImpl *device = stateblock->wineD3DDevice;
+    BOOL use_pshader = use_ps(device);
+    BOOL use_vshader = use_vs(device);
     int i;
 
-    if (use_ps) {
+    if (use_pshader) {
         if(!context->last_was_pshader) {
             /* Former draw without a pixel shader, some samplers
              * may be disabled because of WINED3DTSS_COLOROP = WINED3DTOP_DISABLE
@@ -2018,14 +2017,14 @@ static void pixelshader(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
     }
 
     if(!isStateDirty(context, StateTable[STATE_VSHADER].representative)) {
-        stateblock->wineD3DDevice->shader_backend->shader_select((IWineD3DDevice *)stateblock->wineD3DDevice, use_ps, use_vs);
+        device->shader_backend->shader_select((IWineD3DDevice *)stateblock->wineD3DDevice, use_pshader, use_vshader);
 
-        if(!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && (use_vs || use_ps)) {
+        if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && (use_vshader || use_pshader)) {
             shaderconstant(STATE_VERTEXSHADERCONSTANT, stateblock, context);
         }
     }
 
-    context->last_was_pshader = use_ps;
+    context->last_was_pshader = use_pshader;
 }
 
 static void tex_bumpenvmat(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
@@ -2827,6 +2826,10 @@ static inline void handleStreams(IWineD3DStateBlockImpl *stateblock, BOOL useVer
         }
      }
 
+    if (dataLocations->u.s.position_transformed) {
+        useVertexShaderFunction = FALSE;
+    }
+
     /* Unload the old arrays before loading the new ones to get old junk out */
     if(context->numberedArraysLoaded) {
         unloadNumberedArrays(stateblock);
@@ -2906,6 +2909,7 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W
     transformed = ((device->strided_streams.u.s.position.lpData != NULL ||
                     device->strided_streams.u.s.position.VBO != 0) &&
                     device->strided_streams.u.s.position_transformed) ? TRUE : FALSE;
+    if (transformed) useVertexShaderFunction = FALSE;
 
     if(transformed != context->last_was_rhw && !useVertexShaderFunction) {
         updateFog = TRUE;
@@ -2916,7 +2920,7 @@ static void vertexdeclaration(DWORD state, IWineD3DStateBlockImpl *stateblock, W
         state_lighting(STATE_RENDER(WINED3DRS_LIGHTING), stateblock, context);
     }
 
-    if (!useVertexShaderFunction && transformed) {
+    if (transformed) {
         context->last_was_rhw = TRUE;
     } else {
 
diff --git a/dlls/wined3d/vertexbuffer.c b/dlls/wined3d/vertexbuffer.c
index 2e97c20..63b381a 100644
--- a/dlls/wined3d/vertexbuffer.c
+++ b/dlls/wined3d/vertexbuffer.c
@@ -197,7 +197,7 @@ inline BOOL WINAPI IWineD3DVertexBufferImpl_FindDecl(IWineD3DVertexBufferImpl *T
      *  FALSE: otherwise
      */
 
-    if(device->stateBlock->vertexShader && ((IWineD3DVertexShaderImpl *) device->stateBlock->vertexShader)->baseShader.function) {
+    if (use_vs(device)) {
         /* Assume no conversion */
         memset(&strided, 0, sizeof(strided));
     } else {
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index dab9f35..f7b9dbd 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1936,4 +1936,18 @@ typedef struct {
 } PixelFormatDesc;
 
 const PixelFormatDesc *getFormatDescEntry(WINED3DFORMAT fmt);
+
+inline static BOOL use_vs(IWineD3DDeviceImpl *device) {
+    return (device->vs_selected_mode != SHADER_NONE
+            && device->stateBlock->vertexShader
+            && ((IWineD3DVertexShaderImpl *)device->stateBlock->vertexShader)->baseShader.function
+            && !device->strided_streams.u.s.position_transformed);
+}
+
+inline static BOOL use_ps(IWineD3DDeviceImpl *device) {
+    return (device->ps_selected_mode != SHADER_NONE
+            && device->stateBlock->pixelShader
+            && ((IWineD3DPixelShaderImpl *)device->stateBlock->pixelShader)->baseShader.function);
+}
+
 #endif


More information about the wine-patches mailing list