[1/2] WINED3D: Delay vertex shader compilation until the shader is first used.

H. Verbeet hverbeet at gmail.com
Sat Aug 5 11:15:35 CDT 2006


This patch delays vertex shader compilation until the shader is first
used. The is required for the next patch, to properly determine what
shader attributes need swizzling.
-------------- next part --------------
diff --git a/dlls/wined3d/drawprim.c b/dlls/wined3d/drawprim.c
index e337789..434fab9 100644
--- a/dlls/wined3d/drawprim.c
+++ b/dlls/wined3d/drawprim.c
@@ -1780,6 +1780,10 @@ #undef BUFFER_OR_DATA
         loadNumberedArrays(iface, This->stateBlock->vertexShader, dataLocations);
         useDrawStridedSlow = FALSE;
 
+        /* We compile the shader here because we need the vertex declaration
+         * in order to determine if we need to do any swizzling for D3DCOLOR
+         * registers. If the shader is already compiled this call will do nothing. */
+        IWineD3DVertexShader_CompileShader(This->stateBlock->vertexShader);
     /* Draw vertex by vertex */
     } else { 
         TRACE("Not loading vertex data\n");
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c
index 9e7b852..9a8227f 100644
--- a/dlls/wined3d/pixelshader.c
+++ b/dlls/wined3d/pixelshader.c
@@ -913,7 +913,7 @@ static HRESULT WINAPI IWineD3DPixelShade
 
     IWineD3DPixelShaderImpl *This =(IWineD3DPixelShaderImpl *)iface;
     HRESULT hr;
-    shader_reg_maps reg_maps;
+    shader_reg_maps *reg_maps = &This->baseShader.reg_maps;
 
     TRACE("(%p) : pFunction %p\n", iface, pFunction);
 
@@ -927,18 +927,13 @@ static HRESULT WINAPI IWineD3DPixelShade
     list_init(&This->baseShader.constantsI);
 
     /* Second pass: figure out which registers are used, what the semantics are, etc.. */
-    memset(&reg_maps, 0, sizeof(shader_reg_maps));
-    hr = shader_get_registers_used((IWineD3DBaseShader*) This, &reg_maps,
+    memset(reg_maps, 0, sizeof(shader_reg_maps));
+    hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps,
         This->semantics_in, NULL, pFunction);
     if (hr != WINED3D_OK) return hr;
     /* FIXME: validate reg_maps against OpenGL */
 
-    /* Generate HW shader in needed */
     This->baseShader.shader_mode = wined3d_settings.ps_selected_mode;
-    if (NULL != pFunction && This->baseShader.shader_mode != SHADER_SW) {
-        TRACE("(%p) : Generating hardware program\n", This);
-        IWineD3DPixelShaderImpl_GenerateShader(iface, &reg_maps, pFunction);
-    }
 
     TRACE("(%p) : Copying the function\n", This);
     if (NULL != pFunction) {
@@ -949,6 +944,33 @@ static HRESULT WINAPI IWineD3DPixelShade
         This->baseShader.function = NULL;
     }
 
+    /* Compile the shader. */
+    IWineD3DPixelShader_CompileShader(iface);
+
+    return WINED3D_OK;
+}
+
+static HRESULT WINAPI IWineD3DPixelShaderImpl_CompileShader(IWineD3DPixelShader *iface) {
+    IWineD3DPixelShaderImpl *This =(IWineD3DPixelShaderImpl *)iface;
+    CONST DWORD *function = This->baseShader.function;
+
+    TRACE("(%p) : function %p\n", iface, function);
+
+    /* We're already compiled. */
+    if (This->baseShader.is_compiled) return WINED3D_OK;
+
+    /* We don't need to compile */
+    if (!function || This->baseShader.shader_mode == SHADER_SW) {
+        This->baseShader.is_compiled = TRUE;
+        return WINED3D_OK;
+    }
+
+    /* Generate the HW shader */
+    TRACE("(%p) : Generating hardware program\n", This);
+    IWineD3DPixelShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function);
+
+    This->baseShader.is_compiled = TRUE;
+
     return WINED3D_OK;
 }
 
@@ -962,6 +984,7 @@ const IWineD3DPixelShaderVtbl IWineD3DPi
     IWineD3DPixelShaderImpl_GetParent,
     /*** IWineD3DBaseShader methods ***/
     IWineD3DPixelShaderImpl_SetFunction,
+    IWineD3DPixelShaderImpl_CompileShader,
     /*** IWineD3DPixelShader methods ***/
     IWineD3DPixelShaderImpl_GetDevice,
     IWineD3DPixelShaderImpl_GetFunction
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index 0d4bac6..e837772 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -1131,11 +1131,15 @@ static HRESULT WINAPI IWineD3DVertexShad
     return WINED3D_OK;
 }
 
+/* Note that for vertex shaders CompileShader isn't called until the
+ * shader is first used. The reason for this is that we need the vertex
+ * declaration the shader will be used with in order to determine if
+ * the data in a register is of type D3DCOLOR, and needs swizzling. */
 static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader *iface, CONST DWORD *pFunction) {
 
     IWineD3DVertexShaderImpl *This =(IWineD3DVertexShaderImpl *)iface;
     HRESULT hr;
-    shader_reg_maps reg_maps;
+    shader_reg_maps *reg_maps = &This->baseShader.reg_maps;
 
     TRACE("(%p) : pFunction %p\n", iface, pFunction);
 
@@ -1159,15 +1163,12 @@ static HRESULT WINAPI IWineD3DVertexShad
     }
 
     /* Second pass: figure out registers used, semantics, etc.. */
-    memset(&reg_maps, 0, sizeof(shader_reg_maps));
-    hr = shader_get_registers_used((IWineD3DBaseShader*) This, &reg_maps,
+    memset(reg_maps, 0, sizeof(shader_reg_maps));
+    hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps,
        This->semantics_in, This->semantics_out, pFunction);
     if (hr != WINED3D_OK) return hr;
 
-    /* Generate HW shader in needed */
     This->baseShader.shader_mode = wined3d_settings.vs_selected_mode;
-    if (NULL != pFunction && This->baseShader.shader_mode != SHADER_SW) 
-        IWineD3DVertexShaderImpl_GenerateShader(iface, &reg_maps, pFunction);
 
     /* copy the function ... because it will certainly be released by application */
     if (NULL != pFunction) {
@@ -1181,6 +1182,30 @@ static HRESULT WINAPI IWineD3DVertexShad
     return WINED3D_OK;
 }
 
+static HRESULT WINAPI IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader *iface) {
+    IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
+    CONST DWORD *function = This->baseShader.function;
+
+    TRACE("(%p) : function %p\n", iface, function);
+
+    /* We're already compiled. */
+    if (This->baseShader.is_compiled) return WINED3D_OK;
+
+    /* We don't need to compile */
+    if (!function || This->baseShader.shader_mode == SHADER_SW) {
+        This->baseShader.is_compiled = TRUE;
+        return WINED3D_OK;
+    }
+
+    /* Generate the HW shader */
+    TRACE("(%p) : Generating hardware program\n", This);
+    IWineD3DVertexShaderImpl_GenerateShader(iface, &This->baseShader.reg_maps, function);
+
+    This->baseShader.is_compiled = TRUE;
+
+    return WINED3D_OK;
+}
+
 const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =
 {
     /*** IUnknown methods ***/
@@ -1191,6 +1216,7 @@ const IWineD3DVertexShaderVtbl IWineD3DV
     IWineD3DVertexShaderImpl_GetParent,
     /*** IWineD3DBaseShader methods ***/
     IWineD3DVertexShaderImpl_SetFunction,
+    IWineD3DVertexShaderImpl_CompileShader,
     /*** IWineD3DVertexShader methods ***/
     IWineD3DVertexShaderImpl_GetDevice,
     IWineD3DVertexShaderImpl_GetFunction
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index b3dc283..7ef8877 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1552,6 +1552,7 @@ typedef struct IWineD3DBaseShaderClass
     CONST DWORD                     *function;
     UINT                            functionLength;
     GLuint                          prgId;
+    BOOL                            is_compiled;
 
     /* Type of shader backend */
     int shader_mode;
@@ -1560,6 +1561,7 @@ typedef struct IWineD3DBaseShaderClass
     struct list constantsB;
     struct list constantsF;
     struct list constantsI;
+    shader_reg_maps reg_maps;
 
 } IWineD3DBaseShaderClass;
 
diff --git a/include/wine/wined3d_interface.h b/include/wine/wined3d_interface.h
index 2104aaa..01cc8ef 100644
--- a/include/wine/wined3d_interface.h
+++ b/include/wine/wined3d_interface.h
@@ -1424,6 +1424,7 @@ DECLARE_INTERFACE_(IWineD3DBaseShader,IW
     STDMETHOD(GetParent)(THIS_ IUnknown **pParent) PURE;
     /*** IWineD3DBaseShader methods ***/
     STDMETHOD(SetFunction)(THIS_ CONST DWORD *pFunction) PURE;
+    STDMETHOD(CompileShader)(THIS) PURE;
 };
 #undef INTERFACE
 
@@ -1436,6 +1437,7 @@ #define IWineD3DBaseShader_Release(p)   
 #define IWineD3DBaseShader_GetParent(p,a)            (p)->lpVtbl->GetParent(p,a)
 /*** IWineD3DBaseShader methods ***/
 #define IWineD3DBaseShader_SetFunction(p,a)          (p)->lpVtbl->SetFunction(p,a)
+#define IWineD3DBaseShader_CompileShader(p)          (p)->lpVtbl->CompileShader(p)
 #endif
 
 /*****************************************************************************
@@ -1452,6 +1454,7 @@ DECLARE_INTERFACE_(IWineD3DVertexShader,
     STDMETHOD(GetParent)(THIS_ IUnknown **pParent) PURE;
     /*** IWineD3DBaseShader methods ***/
     STDMETHOD(SetFunction)(THIS_ CONST DWORD *pFunction) PURE;
+    STDMETHOD(CompileShader)(THIS) PURE;
     /*** IWineD3DVertexShader methods ***/
     STDMETHOD(GetDevice)(THIS_ IWineD3DDevice** ppDevice) PURE;
     STDMETHOD(GetFunction)(THIS_ VOID *pData, UINT *pSizeOfData) PURE;
@@ -1475,6 +1478,7 @@ #define IWineD3DVertexShader_Release(p) 
 #define IWineD3DVertexShader_GetParent(p,a)            (p)->lpVtbl->GetParent(p,a)
 /*** IWineD3DBaseShader methods ***/
 #define IWineD3DVertexShader_SetFunction(p,a)          (p)->lpVtbl->SetFunction(p,a)
+#define IWineD3DVertexShader_CompileShader(p)          (p)->lpVtbl->CompileShader(p)
 /*** IWineD3DVertexShader methods ***/
 #define IWineD3DVertexShader_GetDevice(p,a)            (p)->lpVtbl->GetDevice(p,a)
 #define IWineD3DVertexShader_GetFunction(p,a,b)        (p)->lpVtbl->GetFunction(p,a,b)
@@ -1501,6 +1505,7 @@ DECLARE_INTERFACE_(IWineD3DPixelShader,I
     STDMETHOD(GetParent)(THIS_ IUnknown **pParent) PURE;
     /*** IWineD3DBaseShader methods ***/
     STDMETHOD(SetFunction)(THIS_ CONST DWORD *pFunction) PURE;
+    STDMETHOD(CompileShader)(THIS) PURE;
     /*** IWineD3DPixelShader methods ***/
     STDMETHOD(GetDevice)(THIS_ IWineD3DDevice** ppDevice) PURE;
     STDMETHOD(GetFunction)(THIS_ VOID* pData, UINT* pSizeOfData) PURE;
@@ -1516,6 +1521,7 @@ #define IWineD3DPixelShader_Release(p)  
 #define IWineD3DPixelShader_GetParent(p,a)             (p)->lpVtbl->GetParent(p,a)
 /*** IWineD3DBaseShader methods ***/
 #define IWineD3DPixelShader_SetFunction(p,a)           (p)->lpVtbl->SetFunction(p,a)
+#define IWineD3DPixelShader_CompileShader(p)           (p)->lpVtbl->CompileShader(p)
 /*** IWineD3DPixelShader methods ***/
 #define IWineD3DPixelShader_GetDevice(p,a)             (p)->lpVtbl->GetDevice(p,a)
 #define IWineD3DPixelShader_GetFunction(p,a,b)         (p)->lpVtbl->GetFunction(p,a,b)


More information about the wine-patches mailing list