[PATCH 4/5] wined3d: Simplify shader selection.

Henri Verbeet hverbeet at codeweavers.com
Sun Nov 4 12:51:32 CST 2012


---
 dlls/wined3d/arb_program_shader.c  |   45 +++++-------------------
 dlls/wined3d/ati_fragment_shader.c |   12 +-----
 dlls/wined3d/context.c             |   17 +++++++--
 dlls/wined3d/state.c               |   67 +++++++-----------------------------
 dlls/wined3d/wined3d_private.h     |   32 +++++++++--------
 5 files changed, 56 insertions(+), 117 deletions(-)

diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index 3db3b54..e2faaac 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -5821,14 +5821,10 @@ static void set_bumpmat_arbfp(struct wined3d_context *context, const struct wine
 
     if (use_ps(state))
     {
+        /* The pixel shader has to know the bump env matrix. Do a constants
+         * update. */
         if (stage && (state->pixel_shader->reg_maps.bumpmat & (1 << stage)))
-        {
-            /* The pixel shader has to know the bump env matrix. Do a constants update if it isn't scheduled
-             * anyway
-             */
-            if (!isStateDirty(context, STATE_PIXELSHADERCONSTANT))
-                context_apply_state(context, state, STATE_PIXELSHADERCONSTANT);
-        }
+            context->load_constants = 1;
 
         if(device->shader_backend == &arb_program_shader_backend) {
             /* Exit now, don't set the bumpmat below, otherwise we may overwrite pixel shader constants */
@@ -5861,14 +5857,10 @@ static void tex_bumpenvlum_arbfp(struct wined3d_context *context,
 
     if (use_ps(state))
     {
+        /* The pixel shader has to know the luminance offset. Do a constants
+         * update. */
         if (stage && (state->pixel_shader->reg_maps.luminanceparams & (1 << stage)))
-        {
-            /* The pixel shader has to know the luminance offset. Do a constants update if it
-             * isn't scheduled anyway
-             */
-            if (!isStateDirty(context, STATE_PIXELSHADERCONSTANT))
-                context_apply_state(context, state, STATE_PIXELSHADERCONSTANT);
-        }
+            context->load_constants = 1;
 
         if(device->shader_backend == &arb_program_shader_backend) {
             /* Exit now, don't set the bumpmat below, otherwise we may overwrite pixel shader constants */
@@ -6391,7 +6383,6 @@ static void fragment_prog_arbfp(struct wined3d_context *context, const struct wi
     const struct wined3d_device *device = context->swapchain->device;
     const struct wined3d_gl_info *gl_info = context->gl_info;
     struct shader_arb_priv *priv = device->fragment_priv;
-    BOOL use_vshader = use_vs(state);
     BOOL use_pshader = use_ps(state);
     struct ffp_frag_settings settings;
     const struct arbfp_ffp_desc *desc;
@@ -6412,9 +6403,9 @@ static void fragment_prog_arbfp(struct wined3d_context *context, const struct wi
             state_texfactor_arbfp(context, state, STATE_RENDER(WINED3D_RS_TEXTUREFACTOR));
             state_arb_specularenable(context, state, STATE_RENDER(WINED3D_RS_SPECULARENABLE));
         }
-        else if (use_pshader && !isStateDirty(context, context->state_table[STATE_VSHADER].representative))
+        else if (use_pshader)
         {
-            device->shader_backend->shader_select(context, use_pshader, use_vshader);
+            context->select_shader = 1;
         }
         return;
     }
@@ -6464,24 +6455,8 @@ static void fragment_prog_arbfp(struct wined3d_context *context, const struct wi
         context->last_was_pshader = TRUE;
     }
 
-    /* Finally, select the shader. If a pixel shader is used, it will be set and enabled by the shader backend.
-     * If this shader backend is arbfp(most likely), then it will simply overwrite the last fixed function
-     * replacement shader. If the shader backend is not ARB, it currently is important that the opengl implementation
-     * type overwrites GL_ARB_fragment_program. This is currently the case with GLSL. If we really want to use
-     * atifs or nvrc pixel shaders with arb fragment programs we'd have to disable GL_FRAGMENT_PROGRAM_ARB here
-     *
-     * Don't call shader_select if the vertex shader is dirty, because it will be called later on by the vertex
-     * shader handler.
-     */
-    if (!isStateDirty(context, context->state_table[STATE_VSHADER].representative))
-    {
-        device->shader_backend->shader_select(context, use_pshader, use_vshader);
-
-        if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && (use_vshader || use_pshader))
-            context_apply_state(context, state, STATE_VERTEXSHADERCONSTANT);
-    }
-    if (use_pshader)
-        context_apply_state(context, state, STATE_PIXELSHADERCONSTANT);
+    context->select_shader = 1;
+    context->load_constants = 1;
 }
 
 /* We can't link the fog states to the fragment state directly since the
diff --git a/dlls/wined3d/ati_fragment_shader.c b/dlls/wined3d/ati_fragment_shader.c
index 5e04878..fba55ea 100644
--- a/dlls/wined3d/ati_fragment_shader.c
+++ b/dlls/wined3d/ati_fragment_shader.c
@@ -926,9 +926,6 @@ static void textransform(struct wined3d_context *context, const struct wined3d_s
 
 static void atifs_apply_pixelshader(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
-    const struct wined3d_device *device = context->swapchain->device;
-    BOOL use_vshader = use_vs(state);
-
     context->last_was_pshader = use_ps(state);
     /* The ATIFS code does not support pixel shaders currently, but we have to
      * provide a state handler to call shader_select to select a vertex shader
@@ -943,13 +940,8 @@ static void atifs_apply_pixelshader(struct wined3d_context *context, const struc
      * startup, and blitting disables all shaders and dirtifies all shader
      * states. If atifs can deal with this it keeps the rest of the code
      * simpler. */
-    if (!isStateDirty(context, context->state_table[STATE_VSHADER].representative))
-    {
-        device->shader_backend->shader_select(context, FALSE, use_vshader);
-
-        if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && use_vshader)
-            context_apply_state(context, state, STATE_VERTEXSHADERCONSTANT);
-    }
+    context->select_shader = 1;
+    context->load_constants = 1;
 }
 
 static void atifs_srgbwriteenable(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
diff --git a/dlls/wined3d/context.c b/dlls/wined3d/context.c
index 9ef0dff..999adee 100644
--- a/dlls/wined3d/context.c
+++ b/dlls/wined3d/context.c
@@ -1711,11 +1711,10 @@ static void SetupForBlit(const struct wined3d_device *device, struct wined3d_con
     /* Disable shaders */
     ENTER_GL();
     device->shader_backend->shader_select(context, FALSE, FALSE);
+    context->select_shader = 1;
+    context->load_constants = 1;
     LEAVE_GL();
 
-    context_invalidate_state(context, STATE_VSHADER);
-    context_invalidate_state(context, STATE_PIXELSHADER);
-
     /* Call ENTER_GL() once for all gl calls below. In theory we should not call
      * helper functions in between gl calls. This function is full of context_invalidate_state
      * which can safely be called from here, we only lock once instead locking/unlocking
@@ -2365,6 +2364,18 @@ BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_de
         state_table[rep].apply(context, state, rep);
     }
 
+    if (context->select_shader)
+    {
+        device->shader_backend->shader_select(context, use_ps(state), use_vs(state));
+        context->select_shader = 0;
+    }
+
+    if (context->load_constants)
+    {
+        device->shader_backend->shader_load_constants(context, use_ps(state), use_vs(state));
+        context->load_constants = 0;
+    }
+
     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
     {
         context_check_fbo_status(context, GL_FRAMEBUFFER);
diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c
index 32e6d73..7538721 100644
--- a/dlls/wined3d/state.c
+++ b/dlls/wined3d/state.c
@@ -599,15 +599,7 @@ static void state_alpha(struct wined3d_context *context, const struct wined3d_st
 
 static void shaderconstant(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
-    const struct wined3d_device *device = context->swapchain->device;
-
-    /* Vertex and pixel shader states will call a shader upload, don't do
-     * anything as long one of them has an update pending. */
-    if (isStateDirty(context, STATE_VDECL)
-            || isStateDirty(context, STATE_PIXELSHADER))
-       return;
-
-    device->shader_backend->shader_load_constants(context, use_ps(state), use_vs(state));
+    context->load_constants = 1;
 }
 
 static void state_clipping(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
@@ -640,12 +632,8 @@ static void state_clipping(struct wined3d_context *context, const struct wined3d
 
         /* glEnable(GL_CLIP_PLANEx) doesn't apply to vertex shaders. The enabled / disabled planes are
          * hardcoded into the shader. Update the shader to update the enabled clipplanes */
-        if (!isStateDirty(context, context->state_table[STATE_VSHADER].representative))
-        {
-            device->shader_backend->shader_select(context, use_ps(state), TRUE);
-            if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT))
-                shaderconstant(context, state, STATE_VERTEXSHADERCONSTANT);
-        }
+        context->select_shader = 1;
+        context->load_constants = 1;
     }
 
     /* TODO: Keep track of previously enabled clipplanes to avoid unnecessary resetting
@@ -3618,14 +3606,9 @@ static void tex_bumpenvlscale(struct wined3d_context *context, const struct wine
     DWORD stage = (state_id - STATE_TEXTURESTAGE(0, 0)) / (WINED3D_HIGHEST_TEXTURE_STATE + 1);
     const struct wined3d_shader *ps = state->pixel_shader;
 
+    /* The pixel shader has to know the luminance scale. Do a constants update. */
     if (ps && stage && (ps->reg_maps.luminanceparams & (1 << stage)))
-    {
-        /* The pixel shader has to know the luminance scale. Do a constants
-         * update if it isn't scheduled anyway. */
-        if (!isStateDirty(context, STATE_PIXELSHADERCONSTANT)
-                && !isStateDirty(context, STATE_PIXELSHADER))
-            shaderconstant(context, state, STATE_PIXELSHADERCONSTANT);
-    }
+        context->load_constants = 1;
 }
 
 static void sampler_texmatrix(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
@@ -3738,12 +3721,9 @@ static void sampler(struct wined3d_context *context, const struct wined3d_state
 
 void apply_pixelshader(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
 {
-    const struct wined3d_device *device = context->swapchain->device;
-    BOOL use_vshader = use_vs(state);
-    BOOL use_pshader = use_ps(state);
     unsigned int i;
 
-    if (use_pshader)
+    if (use_ps(state))
     {
         if (!context->last_was_pshader)
         {
@@ -3776,13 +3756,8 @@ void apply_pixelshader(struct wined3d_context *context, const struct wined3d_sta
         context->last_was_pshader = FALSE;
     }
 
-    if (!isStateDirty(context, context->state_table[STATE_VSHADER].representative))
-    {
-        device->shader_backend->shader_select(context, use_pshader, use_vshader);
-
-        if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT) && (use_vshader || use_pshader))
-            shaderconstant(context, state, STATE_VERTEXSHADERCONSTANT);
-    }
+    context->select_shader = 1;
+    context->load_constants = 1;
 }
 
 static void shader_bumpenvmat(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
@@ -3790,14 +3765,9 @@ static void shader_bumpenvmat(struct wined3d_context *context, const struct wine
     DWORD stage = (state_id - STATE_TEXTURESTAGE(0, 0)) / (WINED3D_HIGHEST_TEXTURE_STATE + 1);
     const struct wined3d_shader *ps = state->pixel_shader;
 
+    /* The pixel shader has to know the bump env matrix. Do a constants update. */
     if (ps && stage && (ps->reg_maps.bumpmat & (1 << stage)))
-    {
-        /* The pixel shader has to know the bump env matrix. Do a constants
-         * update if it isn't scheduled anyway. */
-        if (!isStateDirty(context, STATE_PIXELSHADERCONSTANT)
-                && !isStateDirty(context, STATE_PIXELSHADER))
-            shaderconstant(context, state, STATE_PIXELSHADERCONSTANT);
-    }
+        context->load_constants = 1;
 }
 
 static void transform_world(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
@@ -4580,7 +4550,6 @@ static void vertexdeclaration(struct wined3d_context *context, const struct wine
     const struct wined3d_device *device = context->swapchain->device;
     const struct wined3d_gl_info *gl_info = context->gl_info;
     BOOL useVertexShaderFunction = use_vs(state);
-    BOOL usePixelShaderFunction = use_ps(state);
     BOOL updateFog = FALSE;
     BOOL transformed;
     BOOL wasrhw = context->last_was_rhw;
@@ -4684,18 +4653,9 @@ static void vertexdeclaration(struct wined3d_context *context, const struct wine
         }
     }
 
-    /* Vertex and pixel shaders are applied together, so let the last dirty
-     * state do the application. */
-    if (!isStateDirty(context, STATE_PIXELSHADER))
-    {
-        device->shader_backend->shader_select(context, usePixelShaderFunction, useVertexShaderFunction);
-
-        if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT)
-                && (useVertexShaderFunction || usePixelShaderFunction))
-            shaderconstant(context, state, STATE_VERTEXSHADERCONSTANT);
-    }
-
     context->last_was_vshader = useVertexShaderFunction;
+    context->select_shader = 1;
+    context->load_constants = 1;
 
     if (updateFog)
         context_apply_state(context, state, STATE_RENDER(WINED3D_RS_FOGVERTEXMODE));
@@ -4753,8 +4713,7 @@ static void viewport_vertexpart(struct wined3d_context *context, const struct wi
     if (!isStateDirty(context, STATE_RENDER(WINED3D_RS_POINTSCALEENABLE)))
         state_pscale(context, state, STATE_RENDER(WINED3D_RS_POINTSCALEENABLE));
     /* Update the position fixup. */
-    if (!isStateDirty(context, STATE_VERTEXSHADERCONSTANT))
-        shaderconstant(context, state, STATE_VERTEXSHADERCONSTANT);
+    context->load_constants = 1;
 }
 
 static void light(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index c189963..e9fd80f 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -1084,21 +1084,23 @@ struct wined3d_context
     DWORD                   tid;    /* Thread ID which owns this context at the moment */
 
     /* Stores some information about the context state for optimization */
-    WORD render_offscreen : 1;
-    WORD last_was_rhw : 1;              /* true iff last draw_primitive was in xyzrhw mode */
-    WORD last_was_pshader : 1;
-    WORD last_was_vshader : 1;
-    WORD namedArraysLoaded : 1;
-    WORD numberedArraysLoaded : 1;
-    WORD last_was_blit : 1;
-    WORD last_was_ckey : 1;
-    WORD fog_coord : 1;
-    WORD fog_enabled : 1;
-    WORD num_untracked_materials : 2;   /* Max value 2 */
-    WORD current : 1;
-    WORD destroyed : 1;
-    WORD valid : 1;
-    WORD padding : 1;
+    DWORD render_offscreen : 1;
+    DWORD last_was_rhw : 1;             /* true iff last draw_primitive was in xyzrhw mode */
+    DWORD last_was_pshader : 1;
+    DWORD last_was_vshader : 1;
+    DWORD namedArraysLoaded : 1;
+    DWORD numberedArraysLoaded : 1;
+    DWORD last_was_blit : 1;
+    DWORD last_was_ckey : 1;
+    DWORD fog_coord : 1;
+    DWORD fog_enabled : 1;
+    DWORD num_untracked_materials : 2;  /* Max value 2 */
+    DWORD current : 1;
+    DWORD destroyed : 1;
+    DWORD valid : 1;
+    DWORD select_shader : 1;
+    DWORD load_constants : 1;
+    DWORD padding : 15;
     BYTE texShaderBumpMap;              /* MAX_TEXTURES, 8 */
     BYTE lastWasPow2Texture;            /* MAX_TEXTURES, 8 */
     DWORD                   numbered_array_mask;
-- 
1.7.8.6




More information about the wine-patches mailing list