[PATCH] WineD3D: Put vertex shader duplication infrastructure =

Stefan Doesinger stefan at codeweavers.com
Sat Jan 10 23:53:52 CST 2009


in place=0A=
=0A=
It works the same way as the code we already have for pixel shaders=0A=
---=0A=
 dlls/d3d9/tests/visual.c          |    2 +-=0A=
 dlls/wined3d/arb_program_shader.c |   53 ++++++++++++---------=0A=
 dlls/wined3d/baseshader.c         |    3 +-=0A=
 dlls/wined3d/glsl_shader.c        |   69 +++++++++++++++++----------=0A=
 dlls/wined3d/pixelshader.c        |    2 -=0A=
 dlls/wined3d/vertexshader.c       |   93 =
+++++++++++++++++++-----------------=0A=
 dlls/wined3d/wined3d_private.h    |   36 +++++++++++---=0A=
 7 files changed, 154 insertions(+), 104 deletions(-)=0A=
=0A=
diff --git a/dlls/d3d9/tests/visual.c b/dlls/d3d9/tests/visual.c=0A=
index 22035b8..1521a2e 100644=0A=
--- a/dlls/d3d9/tests/visual.c=0A=
+++ b/dlls/d3d9/tests/visual.c=0A=
@@ -1536,7 +1536,7 @@ static void fog_with_shader_test(IDirect3DDevice9 =
*device)=0A=
 =0A=
             /* As the red and green component are the result of =
blending use 5% tolerance on the expected value */=0A=
             color =3D getPixelColor(device, 128, 240);=0A=
-            if(test_data[i].vshader =3D=3D 1 && test_data[i].tfog =
=3D=3D 0) {=0A=
+            if(test_data[i].vshader =3D=3D 1 && test_data[i].tfog =
=3D=3D 0 && color !=3D test_data[i].color[j]) {=0A=
                 todo_wine ok(color_match(color, test_data[i].color[j], =
13),=0A=
                              "fog vs%i ps%i fvm%i ftm%i %d: got color =
%08x, expected %08x +-5%%(todo)\n",=0A=
                              test_data[i].vshader, =
test_data[i].pshader, test_data[i].vfog, test_data[i].tfog, j, color, =
test_data[i].color[j]);=0A=
diff --git a/dlls/wined3d/arb_program_shader.c =
b/dlls/wined3d/arb_program_shader.c=0A=
index 4ffa45f..898f2cb 100644=0A=
--- a/dlls/wined3d/arb_program_shader.c=0A=
+++ b/dlls/wined3d/arb_program_shader.c=0A=
@@ -510,7 +510,7 @@ static void vshader_program_add_param(const =
SHADER_OPCODE_ARG *arg, const DWORD=0A=
     break;=0A=
   case WINED3DSPR_INPUT:=0A=
 =0A=
-    if (This->swizzle_map & (1 << reg)) is_color =3D TRUE;=0A=
+    if (This->cur_args->swizzle_map & (1 << reg)) is_color =3D TRUE;=0A=
 =0A=
     sprintf(tmpReg, "vertex.attrib[%u]", reg);=0A=
     strcat(hwLine, tmpReg);=0A=
@@ -1745,14 +1745,15 @@ static void shader_arb_select(IWineD3DDevice =
*iface, BOOL usePS, BOOL useVS) {=0A=
     const WineD3D_GL_Info *gl_info =3D &This->adapter->gl_info;=0A=
 =0A=
     if (useVS) {=0A=
-        TRACE("Using vertex shader\n");=0A=
-        =
IWineD3DVertexShaderImpl_CompileShader(This->stateBlock->vertexShader);=0A=
+        struct vs_compile_args compile_args;=0A=
 =0A=
-        priv->current_vprogram_id =3D ((IWineD3DVertexShaderImpl =
*)This->stateBlock->vertexShader)->prgId;=0A=
+        TRACE("Using vertex shader\n");=0A=
+        find_vs_compile_args((IWineD3DVertexShaderImpl *) =
This->stateBlock->vertexShader, This->stateBlock, &compile_args);=0A=
+        priv->current_vprogram_id =3D =
find_gl_vshader((IWineD3DVertexShaderImpl *) =
This->stateBlock->vertexShader, &compile_args);=0A=
 =0A=
         /* Bind the vertex program */=0A=
         GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, =
priv->current_vprogram_id));=0A=
-        checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, =
vertexShader->prgId);");=0A=
+        checkGLcall("glBindProgramARB(GL_VERTEX_PROGRAM_ARB, =
priv->current_vprogram_id);");=0A=
 =0A=
         /* Enable OpenGL vertex programs */=0A=
         glEnable(GL_VERTEX_PROGRAM_ARB);=0A=
@@ -1773,7 +1774,7 @@ static void shader_arb_select(IWineD3DDevice =
*iface, BOOL usePS, BOOL useVS) {=0A=
 =0A=
         /* Bind the fragment program */=0A=
         GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, =
priv->current_fprogram_id));=0A=
-        checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, =
pixelShader->prgId);");=0A=
+        checkGLcall("glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, =
priv->current_fprogram_id);");=0A=
 =0A=
         if(!priv->use_arbfp_fixed_func) {=0A=
             /* Enable OpenGL fragment programs */=0A=
@@ -1859,14 +1860,18 @@ static void =
shader_arb_destroy(IWineD3DBaseShader *iface) {=0A=
         This->num_gl_shaders =3D 0;=0A=
     } else {=0A=
         IWineD3DVertexShaderImpl *This =3D (IWineD3DVertexShaderImpl *) =
iface;=0A=
+        UINT i;=0A=
 =0A=
         ENTER_GL();=0A=
-        GL_EXTCALL(glDeleteProgramsARB(1, &This->prgId));=0A=
-        checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, &This->prgId))");=0A=
-        ((IWineD3DVertexShaderImpl *) This)->prgId =3D 0;=0A=
+        for(i =3D 0; i < This->num_gl_shaders; i++) {=0A=
+            GL_EXTCALL(glDeleteProgramsARB(1, =
&This->gl_shaders[i].prgId));=0A=
+            checkGLcall("GL_EXTCALL(glDeleteProgramsARB(1, =
&This->gl_shaders[i].prgId))");=0A=
+        }=0A=
         LEAVE_GL();=0A=
+        HeapFree(GetProcessHeap(), 0, This->gl_shaders);=0A=
+        This->gl_shaders =3D NULL;=0A=
+        This->num_gl_shaders =3D 0;=0A=
     }=0A=
-    baseShader->baseShader.is_compiled =3D FALSE;=0A=
 }=0A=
 =0A=
 static HRESULT shader_arb_alloc(IWineD3DDevice *iface) {=0A=
@@ -2007,13 +2012,14 @@ static GLuint =
shader_arb_generate_pshader(IWineD3DPixelShader *iface, SHADER_BUF=0A=
     return retval;=0A=
 }=0A=
 =0A=
-static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, =
SHADER_BUFFER *buffer) {=0A=
+static GLuint shader_arb_generate_vshader(IWineD3DVertexShader *iface, =
SHADER_BUFFER *buffer, const struct vs_compile_args *args) {=0A=
     IWineD3DVertexShaderImpl *This =3D (IWineD3DVertexShaderImpl =
*)iface;=0A=
     const shader_reg_maps *reg_maps =3D &This->baseShader.reg_maps;=0A=
     CONST DWORD *function =3D This->baseShader.function;=0A=
     IWineD3DDeviceImpl *device =3D (IWineD3DDeviceImpl =
*)This->baseShader.device;=0A=
     const WineD3D_GL_Info *gl_info =3D &device->adapter->gl_info;=0A=
     const local_constant *lconst;=0A=
+    GLuint ret;=0A=
 =0A=
     /*  Create the hw ARB shader */=0A=
     shader_addline(buffer, "!!ARBvp1.0\n");=0A=
@@ -2085,12 +2091,12 @@ static void =
shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF=0A=
     shader_addline(buffer, "END\n");=0A=
 =0A=
     /* TODO: change to resource.glObjectHandle or something like that */=0A=
-    GL_EXTCALL(glGenProgramsARB(1, &This->prgId));=0A=
+    GL_EXTCALL(glGenProgramsARB(1, &ret));=0A=
 =0A=
-    TRACE("Creating a hw vertex shader, prg=3D%d\n", This->prgId);=0A=
-    GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, This->prgId));=0A=
+    TRACE("Creating a hw vertex shader, prg=3D%d\n", ret);=0A=
+    GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, ret));=0A=
 =0A=
-    TRACE("Created hw vertex shader, prg=3D%d\n", This->prgId);=0A=
+    TRACE("Created hw vertex shader, prg=3D%d\n", ret);=0A=
     /* Create the program and check for errors */=0A=
     GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, =
GL_PROGRAM_FORMAT_ASCII_ARB,=0A=
                buffer->bsize, buffer->buffer));=0A=
@@ -2100,16 +2106,17 @@ static void =
shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF=0A=
         glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos);=0A=
         FIXME("HW VertexShader Error at position %d: %s\n",=0A=
               errPos, debugstr_a((const char =
*)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));=0A=
-        This->prgId =3D -1;=0A=
-    }=0A=
-=0A=
-    /* Load immediate constants */=0A=
-    if(!This->baseShader.load_local_constsF) {=0A=
-        LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, =
local_constant, entry) {=0A=
-            const float *value =3D (const float *)lconst->value;=0A=
-            =
GL_EXTCALL(glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, =
lconst->idx, value));=0A=
+        ret =3D -1;=0A=
+    } else {=0A=
+        /* Load immediate constants */=0A=
+        if(!This->baseShader.load_local_constsF) {=0A=
+            LIST_FOR_EACH_ENTRY(lconst, &This->baseShader.constantsF, =
local_constant, entry) {=0A=
+                const float *value =3D (const float *)lconst->value;=0A=
+                =
GL_EXTCALL(glProgramLocalParameter4fvARB(GL_VERTEX_PROGRAM_ARB, =
lconst->idx, value));=0A=
+            }=0A=
         }=0A=
     }=0A=
+    return ret;=0A=
 }=0A=
 =0A=
 static void shader_arb_get_caps(WINED3DDEVTYPE devtype, const =
WineD3D_GL_Info *gl_info, struct shader_caps *pCaps)=0A=
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c=0A=
index a270b0c..ecbf23e 100644=0A=
--- a/dlls/wined3d/baseshader.c=0A=
+++ b/dlls/wined3d/baseshader.c=0A=
@@ -1135,8 +1135,9 @@ static GLuint =
shader_none_generate_pshader(IWineD3DPixelShader *iface, SHADER_BU=0A=
     FIXME("NONE shader backend asked to generate a pixel shader\n");=0A=
     return 0;=0A=
 }=0A=
-static void shader_none_generate_vshader(IWineD3DVertexShader *iface, =
SHADER_BUFFER *buffer) {=0A=
+static GLuint shader_none_generate_vshader(IWineD3DVertexShader *iface, =
SHADER_BUFFER *buffer, const struct vs_compile_args *args) {=0A=
     FIXME("NONE shader backend asked to generate a vertex shader\n");=0A=
+    return 0;=0A=
 }=0A=
 =0A=
 #define GLINFO_LOCATION      (*gl_info)=0A=
diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c=0A=
index 8dfb416..5b5827d 100644=0A=
--- a/dlls/wined3d/glsl_shader.c=0A=
+++ b/dlls/wined3d/glsl_shader.c=0A=
@@ -101,16 +101,18 @@ struct glsl_shader_prog_link {=0A=
     GLhandleARB                 luminanceoffset_location[MAX_TEXTURES];=0A=
     GLhandleARB                 ycorrection_location;=0A=
     GLenum                      vertex_color_clamp;=0A=
-    GLhandleARB                 vshader;=0A=
+    IWineD3DVertexShader        *vshader;=0A=
     IWineD3DPixelShader         *pshader;=0A=
+    struct vs_compile_args      vs_args;=0A=
     struct ps_compile_args      ps_args;=0A=
     UINT                        constant_version;=0A=
 };=0A=
 =0A=
 typedef struct {=0A=
-    GLhandleARB                 vshader;=0A=
+    IWineD3DVertexShader        *vshader;=0A=
     IWineD3DPixelShader         *pshader;=0A=
     struct ps_compile_args      ps_args;=0A=
+    struct vs_compile_args      vs_args;=0A=
 } glsl_program_key_t;=0A=
 =0A=
 =0A=
@@ -1030,7 +1032,7 @@ static void shader_glsl_get_register_name(const =
DWORD param, const DWORD addr_to=0A=
                     strcpy(tmpStr, "gl_SecondaryColor");=0A=
             }=0A=
         } else {=0A=
-            if (((IWineD3DVertexShaderImpl *)This)->swizzle_map & (1 << =
reg)) *is_color =3D TRUE;=0A=
+            if (((IWineD3DVertexShaderImpl =
*)This)->cur_args->swizzle_map & (1 << reg)) *is_color =3D TRUE;=0A=
             sprintf(tmpStr, "attrib%u", reg);=0A=
         } =0A=
         break;=0A=
@@ -2918,17 +2920,20 @@ static void add_glsl_program_entry(struct =
shader_glsl_priv *priv, struct glsl_sh=0A=
     key =3D HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t));=0A=
     key->vshader =3D entry->vshader;=0A=
     key->pshader =3D entry->pshader;=0A=
+    key->vs_args =3D entry->vs_args;=0A=
     key->ps_args =3D entry->ps_args;=0A=
 =0A=
     hash_table_put(priv->glsl_program_lookup, key, entry);=0A=
 }=0A=
 =0A=
 static struct glsl_shader_prog_link *get_glsl_program_entry(struct =
shader_glsl_priv *priv,=0A=
-        GLhandleARB vshader, IWineD3DPixelShader *pshader, struct =
ps_compile_args *ps_args) {=0A=
+        IWineD3DVertexShader *vshader, IWineD3DPixelShader *pshader, =
struct vs_compile_args *vs_args,=0A=
+        struct ps_compile_args *ps_args) {=0A=
     glsl_program_key_t key;=0A=
 =0A=
     key.vshader =3D vshader;=0A=
     key.pshader =3D pshader;=0A=
+    key.vs_args =3D *vs_args;=0A=
     key.ps_args =3D *ps_args;=0A=
 =0A=
     return (struct glsl_shader_prog_link =
*)hash_table_get(priv->glsl_program_lookup, &key);=0A=
@@ -2942,6 +2947,7 @@ static void delete_glsl_program_entry(struct =
shader_glsl_priv *priv, const WineD=0A=
     key =3D HeapAlloc(GetProcessHeap(), 0, sizeof(glsl_program_key_t));=0A=
     key->vshader =3D entry->vshader;=0A=
     key->pshader =3D entry->pshader;=0A=
+    key->vs_args =3D entry->vs_args;=0A=
     key->ps_args =3D entry->ps_args;=0A=
     hash_table_remove(priv->glsl_program_lookup, key);=0A=
 =0A=
@@ -3293,21 +3299,22 @@ static void =
set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use=0A=
     int i;=0A=
     char glsl_name[8];=0A=
     GLhandleARB vshader_id, pshader_id;=0A=
-    struct ps_compile_args compile_args;=0A=
+    struct ps_compile_args ps_compile_args;=0A=
+    struct vs_compile_args vs_compile_args;=0A=
 =0A=
     if(use_vs) {=0A=
-        IWineD3DVertexShaderImpl_CompileShader(vshader);=0A=
-        vshader_id =3D ((IWineD3DVertexShaderImpl*)vshader)->prgId;=0A=
+        =
find_vs_compile_args((IWineD3DVertexShaderImpl*)This->stateBlock->vertexS=
hader, This->stateBlock, &vs_compile_args);=0A=
     } else {=0A=
-        vshader_id =3D 0;=0A=
+        /* FIXME: Do we really have to spend CPU cycles to generate a =
few zeroed bytes? */=0A=
+        memset(&vs_compile_args, 0, sizeof(vs_compile_args));=0A=
     }=0A=
     if(use_ps) {=0A=
-        =
find_ps_compile_args((IWineD3DPixelShaderImpl*)This->stateBlock->pixelSha=
der, This->stateBlock, &compile_args);=0A=
+        =
find_ps_compile_args((IWineD3DPixelShaderImpl*)This->stateBlock->pixelSha=
der, This->stateBlock, &ps_compile_args);=0A=
     } else {=0A=
         /* FIXME: Do we really have to spend CPU cycles to generate a =
few zeroed bytes? */=0A=
-        memset(&compile_args, 0, sizeof(compile_args));=0A=
+        memset(&ps_compile_args, 0, sizeof(ps_compile_args));=0A=
     }=0A=
-    entry =3D get_glsl_program_entry(priv, vshader_id, pshader, =
&compile_args);=0A=
+    entry =3D get_glsl_program_entry(priv, vshader, pshader, =
&vs_compile_args, &ps_compile_args);=0A=
     if (entry) {=0A=
         priv->glsl_program =3D entry;=0A=
         return;=0A=
@@ -3320,9 +3327,10 @@ static void =
set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use=0A=
     /* Create the entry */=0A=
     entry =3D HeapAlloc(GetProcessHeap(), 0, sizeof(struct =
glsl_shader_prog_link));=0A=
     entry->programId =3D programId;=0A=
-    entry->vshader =3D vshader_id;=0A=
+    entry->vshader =3D vshader;=0A=
     entry->pshader =3D pshader;=0A=
-    entry->ps_args =3D compile_args;=0A=
+    entry->vs_args =3D vs_compile_args;=0A=
+    entry->ps_args =3D ps_compile_args;=0A=
     entry->constant_version =3D 0;=0A=
     /* Add the hash table entry */=0A=
     add_glsl_program_entry(priv, entry);=0A=
@@ -3330,6 +3338,12 @@ static void =
set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use=0A=
     /* Set the current program */=0A=
     priv->glsl_program =3D entry;=0A=
 =0A=
+    if(use_vs) {=0A=
+        vshader_id =3D find_gl_vshader((IWineD3DVertexShaderImpl *) =
vshader, &vs_compile_args);=0A=
+    } else {=0A=
+        vshader_id =3D 0;=0A=
+    }=0A=
+=0A=
     /* Attach GLSL vshader */=0A=
     if (vshader_id) {=0A=
         int max_attribs =3D 16;   /* TODO: Will this always be the =
case? It is at the moment... */=0A=
@@ -3369,7 +3383,7 @@ static void set_glsl_shader_program(IWineD3DDevice =
*iface, BOOL use_ps, BOOL use=0A=
     }=0A=
 =0A=
     if(use_ps) {=0A=
-        pshader_id =3D find_gl_pshader((IWineD3DPixelShaderImpl *) =
pshader, &compile_args);=0A=
+        pshader_id =3D find_gl_pshader((IWineD3DPixelShaderImpl *) =
pshader, &ps_compile_args);=0A=
     } else {=0A=
         pshader_id =3D 0;=0A=
     }=0A=
@@ -3619,7 +3633,7 @@ static void shader_glsl_destroy(IWineD3DBaseShader =
*iface) {=0A=
         if(ps->num_gl_shaders =3D=3D 0) return;=0A=
     } else {=0A=
         vs =3D (IWineD3DVertexShaderImpl *) This;=0A=
-        if(vs->prgId =3D=3D 0) return;=0A=
+        if(vs->num_gl_shaders =3D=3D 0) return;=0A=
     }=0A=
 =0A=
     linked_programs =3D &This->baseShader.linked_programs;=0A=
@@ -3653,13 +3667,18 @@ static void =
shader_glsl_destroy(IWineD3DBaseShader *iface) {=0A=
         ps->gl_shaders =3D NULL;=0A=
         ps->num_gl_shaders =3D 0;=0A=
     } else {=0A=
-        TRACE("Deleting shader object %u\n", vs->prgId);=0A=
+        UINT i;=0A=
+=0A=
         ENTER_GL();=0A=
-        GL_EXTCALL(glDeleteObjectARB(vs->prgId));=0A=
-        checkGLcall("glDeleteObjectARB");=0A=
+        for(i =3D 0; i < vs->num_gl_shaders; i++) {=0A=
+            TRACE("deleting vshader %u\n", vs->gl_shaders[i].prgId);=0A=
+            GL_EXTCALL(glDeleteObjectARB(vs->gl_shaders[i].prgId));=0A=
+            checkGLcall("glDeleteObjectARB");=0A=
+        }=0A=
         LEAVE_GL();=0A=
-        vs->prgId =3D 0;=0A=
-        vs->baseShader.is_compiled =3D FALSE;=0A=
+        HeapFree(GetProcessHeap(), 0, vs->gl_shaders);=0A=
+        vs->gl_shaders =3D NULL;=0A=
+        vs->num_gl_shaders =3D 0;=0A=
     }=0A=
 }=0A=
 =0A=
@@ -3667,7 +3686,7 @@ static unsigned int glsl_program_key_hash(const =
void *key)=0A=
 {=0A=
     const glsl_program_key_t *k =3D (const glsl_program_key_t *)key;=0A=
 =0A=
-    unsigned int hash =3D k->vshader | ((DWORD_PTR) k->pshader) << 16;=0A=
+    unsigned int hash =3D ((DWORD_PTR) k->vshader) | ((DWORD_PTR) =
k->pshader) << 16;=0A=
     hash +=3D ~(hash << 15);=0A=
     hash ^=3D  (hash >> 10);=0A=
     hash +=3D  (hash << 3);=0A=
@@ -3684,7 +3703,8 @@ static BOOL glsl_program_key_compare(const void =
*keya, const void *keyb)=0A=
     const glsl_program_key_t *kb =3D (const glsl_program_key_t *)keyb;=0A=
 =0A=
     return ka->vshader =3D=3D kb->vshader && ka->pshader =3D=3D =
kb->pshader &&=0A=
-           (memcmp(&ka->ps_args, &kb->ps_args, sizeof(kb->ps_args)) =
=3D=3D 0);=0A=
+           (memcmp(&ka->ps_args, &kb->ps_args, sizeof(kb->ps_args)) =
=3D=3D 0) &&=0A=
+           (memcmp(&ka->vs_args, &kb->vs_args, sizeof(kb->vs_args)) =
=3D=3D 0);=0A=
 }=0A=
 =0A=
 static BOOL constant_heap_init(struct constant_heap *heap, unsigned int =
constant_count)=0A=
@@ -3869,7 +3889,7 @@ static GLuint =
shader_glsl_generate_pshader(IWineD3DPixelShader *iface, SHADER_BU=0A=
     return shader_obj;=0A=
 }=0A=
 =0A=
-static void shader_glsl_generate_vshader(IWineD3DVertexShader *iface, =
SHADER_BUFFER *buffer) {=0A=
+static GLuint shader_glsl_generate_vshader(IWineD3DVertexShader *iface, =
SHADER_BUFFER *buffer, const struct vs_compile_args *args) {=0A=
     IWineD3DVertexShaderImpl *This =3D (IWineD3DVertexShaderImpl =
*)iface;=0A=
     const struct shader_reg_maps *reg_maps =3D =
&This->baseShader.reg_maps;=0A=
     CONST DWORD *function =3D This->baseShader.function;=0A=
@@ -3919,8 +3939,7 @@ static void =
shader_glsl_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUF=0A=
     GL_EXTCALL(glCompileShaderARB(shader_obj));=0A=
     print_glsl_info_log(&GLINFO_LOCATION, shader_obj);=0A=
 =0A=
-    /* Store the shader object */=0A=
-    This->prgId =3D shader_obj;=0A=
+    return shader_obj;=0A=
 }=0A=
 =0A=
 static void shader_glsl_get_caps(WINED3DDEVTYPE devtype, const =
WineD3D_GL_Info *gl_info, struct shader_caps *pCaps)=0A=
diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c=0A=
index 9f96c59..022ced3 100644=0A=
--- a/dlls/wined3d/pixelshader.c=0A=
+++ b/dlls/wined3d/pixelshader.c=0A=
@@ -439,8 +439,6 @@ static GLuint =
pixelshader_compile(IWineD3DPixelShaderImpl *This, const struct ps=0A=
     retval =3D =
device->shader_backend->shader_generate_pshader((IWineD3DPixelShader =
*)This, &buffer, args);=0A=
     shader_buffer_free(&buffer);=0A=
 =0A=
-    This->baseShader.is_compiled =3D TRUE;=0A=
-=0A=
     return retval;=0A=
 }=0A=
 =0A=
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c=0A=
index 339d955..84e415b 100644=0A=
--- a/dlls/wined3d/vertexshader.c=0A=
+++ b/dlls/wined3d/vertexshader.c=0A=
@@ -218,21 +218,6 @@ BOOL vshader_get_input(=0A=
     return FALSE;=0A=
 }=0A=
 =0A=
-/** Generate a vertex shader string using either GL_VERTEX_PROGRAM_ARB=0A=
-    or GLSL and send it to the card */=0A=
-static void =
IWineD3DVertexShaderImpl_GenerateShader(IWineD3DVertexShader *iface,=0A=
-        const struct shader_reg_maps* reg_maps, const DWORD *pFunction)=0A=
-{=0A=
-    IWineD3DVertexShaderImpl *This =3D (IWineD3DVertexShaderImpl =
*)iface;=0A=
-    SHADER_BUFFER buffer;=0A=
-=0A=
-    This->swizzle_map =3D ((IWineD3DDeviceImpl =
*)This->baseShader.device)->strided_streams.swizzle_map;=0A=
-=0A=
-    shader_buffer_init(&buffer);=0A=
-    ((IWineD3DDeviceImpl =
*)This->baseShader.device)->shader_backend->shader_generate_vshader(iface=
, &buffer);=0A=
-    shader_buffer_free(&buffer);=0A=
-}=0A=
-=0A=
 /* *******************************************=0A=
    IWineD3DVertexShader IUnknown parts follow=0A=
    ******************************************* */=0A=
@@ -418,40 +403,20 @@ static HRESULT WINAPI =
IWIneD3DVertexShaderImpl_SetLocalConstantsF(IWineD3DVertex=0A=
     return WINED3D_OK;=0A=
 }=0A=
 =0A=
-HRESULT IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader =
*iface) {=0A=
-    IWineD3DVertexShaderImpl *This =3D (IWineD3DVertexShaderImpl =
*)iface;=0A=
-    CONST DWORD *function =3D This->baseShader.function;=0A=
+static GLuint vertexshader_compile(IWineD3DVertexShaderImpl *This, =
const struct vs_compile_args *args) {=0A=
     IWineD3DDeviceImpl *deviceImpl =3D (IWineD3DDeviceImpl *) =
This->baseShader.device;=0A=
-=0A=
-    TRACE("(%p) : function %p\n", iface, function);=0A=
-=0A=
-    /* We're already compiled. */=0A=
-    if (This->baseShader.is_compiled) {=0A=
-        if ((This->swizzle_map & deviceImpl->strided_streams.use_map) =
!=3D deviceImpl->strided_streams.swizzle_map)=0A=
-        {=0A=
-            WARN("Recompiling vertex shader %p due to D3DCOLOR input =
changes\n", This);=0A=
-            goto recompile;=0A=
-        }=0A=
-=0A=
-        return WINED3D_OK;=0A=
-=0A=
-        recompile:=0A=
-        if(This->recompile_count < 50) {=0A=
-            This->recompile_count++;=0A=
-        } else {=0A=
-            FIXME("Vertexshader %p recompiled more than 50 times\n", =
This);=0A=
-        }=0A=
-=0A=
-        deviceImpl->shader_backend->shader_destroy((IWineD3DBaseShader =
*) iface);=0A=
-    }=0A=
+    SHADER_BUFFER buffer;=0A=
+    GLuint ret;=0A=
 =0A=
     /* Generate the HW shader */=0A=
     TRACE("(%p) : Generating hardware program\n", This);=0A=
-    IWineD3DVertexShaderImpl_GenerateShader(iface, =
&This->baseShader.reg_maps, function);=0A=
-=0A=
-    This->baseShader.is_compiled =3D TRUE;=0A=
+    shader_buffer_init(&buffer);=0A=
+    This->cur_args =3D args;=0A=
+    ret =3D =
deviceImpl->shader_backend->shader_generate_vshader((IWineD3DVertexShader=
 *)This, &buffer, args);=0A=
+    This->cur_args =3D NULL;=0A=
+    shader_buffer_free(&buffer);=0A=
 =0A=
-    return WINED3D_OK;=0A=
+    return ret;=0A=
 }=0A=
 =0A=
 const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl =3D=0A=
@@ -470,3 +435,43 @@ const IWineD3DVertexShaderVtbl =
IWineD3DVertexShader_Vtbl =3D=0A=
     IWineD3DVertexShaderImpl_FakeSemantics,=0A=
     IWIneD3DVertexShaderImpl_SetLocalConstantsF=0A=
 };=0A=
+=0A=
+void find_vs_compile_args(IWineD3DVertexShaderImpl *shader, =
IWineD3DStateBlockImpl *stateblock, struct vs_compile_args *args) {=0A=
+    args->fog_src =3D stateblock->renderState[WINED3DRS_FOGTABLEMODE] =
=3D=3D WINED3DFOG_NONE ? VS_FOG_COORD : VS_FOG_Z;=0A=
+    args->swizzle_map =3D ((IWineD3DDeviceImpl =
*)shader->baseShader.device)->strided_streams.swizzle_map;=0A=
+}=0A=
+=0A=
+GLuint find_gl_vshader(IWineD3DVertexShaderImpl *shader, const struct =
vs_compile_args *args)=0A=
+{=0A=
+    UINT i;=0A=
+    struct vs_compiled_shader *old_array;=0A=
+=0A=
+    /* Usually we have very few GL shaders for each d3d shader(just 1 =
or maybe 2),=0A=
+     * so a linear search is more performant than a hashmap=0A=
+     */=0A=
+    for(i =3D 0; i < shader->num_gl_shaders; i++) {=0A=
+        if(memcmp(&shader->gl_shaders[i].args, args, sizeof(*args)) =
=3D=3D 0) {=0A=
+            return shader->gl_shaders[i].prgId;=0A=
+        }=0A=
+    }=0A=
+=0A=
+    TRACE("No matching GL shader found, compiling a new shader\n");=0A=
+    old_array =3D shader->gl_shaders;=0A=
+=0A=
+    if(old_array) {=0A=
+        shader->gl_shaders =3D HeapReAlloc(GetProcessHeap(), 0, =
old_array,=0A=
+                                         (shader->num_gl_shaders + 1) * =
sizeof(*shader->gl_shaders));=0A=
+    } else {=0A=
+        shader->gl_shaders =3D HeapAlloc(GetProcessHeap(), 0, =
sizeof(*shader->gl_shaders));=0A=
+    }=0A=
+=0A=
+    if(!shader->gl_shaders) {=0A=
+        ERR("Out of memory\n");=0A=
+        shader->gl_shaders =3D old_array;=0A=
+        return 0;=0A=
+    }=0A=
+=0A=
+    shader->gl_shaders[shader->num_gl_shaders].args =3D *args;=0A=
+    shader->gl_shaders[shader->num_gl_shaders].prgId =3D =
vertexshader_compile(shader, args);=0A=
+    return shader->gl_shaders[shader->num_gl_shaders++].prgId;=0A=
+}=0A=
diff --git a/dlls/wined3d/wined3d_private.h =
b/dlls/wined3d/wined3d_private.h=0A=
index ded6d48..ae7aca2 100644=0A=
--- a/dlls/wined3d/wined3d_private.h=0A=
+++ b/dlls/wined3d/wined3d_private.h=0A=
@@ -10,7 +10,7 @@=0A=
  * modify it under the terms of the GNU Lesser General Public=0A=
  * License as published by the Free Software Foundation; either=0A=
  * version 2.1 of the License, or (at your option) any later version.=0A=
- *=0A=
+ * =0A=
  * This library is distributed in the hope that it will be useful,=0A=
  * but WITHOUT ANY WARRANTY; without even the implied warranty of=0A=
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU=0A=
@@ -459,6 +459,18 @@ struct ps_compile_args {=0A=
     /* Texture types(2D, Cube, 3D) in ps 1.x */=0A=
 };=0A=
 =0A=
+#define MAX_ATTRIBS 16=0A=
+=0A=
+enum fog_src_type {=0A=
+    VS_FOG_Z        =3D 0,=0A=
+    VS_FOG_COORD    =3D 1=0A=
+};=0A=
+=0A=
+struct vs_compile_args {=0A=
+    WORD                        fog_src;=0A=
+    WORD                        swizzle_map;   /* MAX_ATTRIBS, 16 */=0A=
+};=0A=
+=0A=
 typedef struct {=0A=
     const SHADER_HANDLER *shader_instruction_handler_table;=0A=
     void (*shader_select)(IWineD3DDevice *iface, BOOL usePS, BOOL =
useVS);=0A=
@@ -473,7 +485,7 @@ typedef struct {=0A=
     void (*shader_free_private)(IWineD3DDevice *iface);=0A=
     BOOL (*shader_dirtifyable_constants)(IWineD3DDevice *iface);=0A=
     GLuint (*shader_generate_pshader)(IWineD3DPixelShader *iface, =
SHADER_BUFFER *buffer, const struct ps_compile_args *args);=0A=
-    void (*shader_generate_vshader)(IWineD3DVertexShader *iface, =
SHADER_BUFFER *buffer);=0A=
+    GLuint (*shader_generate_vshader)(IWineD3DVertexShader *iface, =
SHADER_BUFFER *buffer, const struct vs_compile_args *args);=0A=
     void (*shader_get_caps)(WINED3DDEVTYPE devtype, const =
WineD3D_GL_Info *gl_info, struct shader_caps *caps);=0A=
     BOOL (*shader_color_fixup_supported)(struct color_fixup_desc fixup);=0A=
 } shader_backend_t;=0A=
@@ -2201,7 +2213,6 @@ typedef struct IWineD3DBaseShaderClass=0A=
     CONST SHADER_OPCODE             *shader_ins;=0A=
     DWORD                          *function;=0A=
     UINT                            functionLength;=0A=
-    BOOL                            is_compiled;=0A=
     UINT                            cur_loop_depth, cur_loop_regno;=0A=
     BOOL                            load_local_constsF;=0A=
     BOOL                            uses_bool_consts, uses_int_consts;=0A=
@@ -2317,8 +2328,14 @@ static inline BOOL =
shader_constant_is_local(IWineD3DBaseShaderImpl* This, DWORD=0A=
 }=0A=
 =0A=
 =
/************************************************************************=
*****=0A=
- * IDirect3DVertexShader implementation structure=0A=
+ * IDirect3DVertexShader implementation structures=0A=
  */=0A=
+=0A=
+struct vs_compiled_shader {=0A=
+    struct vs_compile_args      args;=0A=
+    GLuint                      prgId;=0A=
+};=0A=
+=0A=
 typedef struct IWineD3DVertexShaderImpl {=0A=
     /* IUnknown parts*/   =0A=
     const IWineD3DVertexShaderVtbl *lpVtbl;=0A=
@@ -2332,22 +2349,25 @@ typedef struct IWineD3DVertexShaderImpl {=0A=
     DWORD                       usage;=0A=
 =0A=
     /* The GL shader */=0A=
-    GLuint                          prgId;=0A=
+    struct vs_compiled_shader   *gl_shaders;=0A=
+    UINT                        num_gl_shaders;=0A=
 =0A=
     /* Vertex shader input and output semantics */=0A=
     semantic semantics_in [MAX_ATTRIBS];=0A=
     semantic semantics_out [MAX_REG_OUTPUT];=0A=
 =0A=
-    WORD swizzle_map;   /* MAX_ATTRIBS, 16 */=0A=
-=0A=
     UINT                       min_rel_offset, max_rel_offset;=0A=
     UINT                       rel_offset;=0A=
 =0A=
     UINT                       recompile_count;=0A=
+=0A=
+    const struct vs_compile_args    *cur_args;=0A=
 } IWineD3DVertexShaderImpl;=0A=
 extern const SHADER_OPCODE IWineD3DVertexShaderImpl_shader_ins[];=0A=
 extern const IWineD3DVertexShaderVtbl IWineD3DVertexShader_Vtbl;=0A=
-HRESULT IWineD3DVertexShaderImpl_CompileShader(IWineD3DVertexShader =
*iface);=0A=
+=0A=
+void find_vs_compile_args(IWineD3DVertexShaderImpl *shader, =
IWineD3DStateBlockImpl *stateblock, struct vs_compile_args *args);=0A=
+GLuint find_gl_vshader(IWineD3DVertexShaderImpl *shader, const struct =
vs_compile_args *args);=0A=
 =0A=
 =
/************************************************************************=
*****=0A=
  * IDirect3DPixelShader implementation structure=0A=
-- =0A=
1.6.0.6=0A=
=0A=

------=_NextPart_000_000C_01C97515.C4C38240--




More information about the wine-patches mailing list