From 62859daf0bcfedcb198642d21a106edbc4b8d49b Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Wed, 21 Aug 2013 08:29:27 +0200 Subject: [PATCH] wined3d: Avoid looking up shaders for shader stages that didn't change. --- dlls/wined3d/arb_program_shader.c | 4 +- dlls/wined3d/ati_fragment_shader.c | 2 +- dlls/wined3d/context.c | 12 ++- dlls/wined3d/glsl_shader.c | 130 +++++++++++++++++------------ dlls/wined3d/state.c | 12 ++- dlls/wined3d/wined3d_private.h | 3 +- 6 files changed, 98 insertions(+), 65 deletions(-) diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index 032ff143bb3..1ba41b0ac16 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -6493,7 +6493,7 @@ static void fragment_prog_arbfp(struct wined3d_context *context, const struct wi } else if (use_pshader) { - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; } return; } @@ -6543,7 +6543,7 @@ static void fragment_prog_arbfp(struct wined3d_context *context, const struct wi context->last_was_pshader = TRUE; } - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; } /* 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 d3c01f2264c..cf35f64e83b 100644 --- a/dlls/wined3d/ati_fragment_shader.c +++ b/dlls/wined3d/ati_fragment_shader.c @@ -942,7 +942,7 @@ 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. */ - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; } 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 123e9b17ec6..dd0c1a907e2 100644 --- a/dlls/wined3d/context.c +++ b/dlls/wined3d/context.c @@ -1624,7 +1624,9 @@ struct wined3d_context *context_create(struct wined3d_swapchain *swapchain, { GL_EXTCALL(glProvokingVertexEXT(GL_FIRST_VERTEX_CONVENTION_EXT)); } - ret->select_shader = 1; + ret->shader_update_mask = (1 << WINED3D_SHADER_TYPE_PIXEL) + | (1 << WINED3D_SHADER_TYPE_VERTEX) + | (1 << WINED3D_SHADER_TYPE_GEOMETRY); /* If this happens to be the first context for the device, dummy textures * are not created yet. In that case, they will be created (and bound) by @@ -1901,7 +1903,9 @@ static void SetupForBlit(const struct wined3d_device *device, struct wined3d_con /* Disable shaders */ device->shader_backend->shader_disable(device->shader_priv, context); - context->select_shader = 1; + context->shader_update_mask = (1 << WINED3D_SHADER_TYPE_PIXEL) + | (1 << WINED3D_SHADER_TYPE_VERTEX) + | (1 << WINED3D_SHADER_TYPE_GEOMETRY); context->blit_w = rt_size.cx; context->blit_h = rt_size.cy; @@ -2379,10 +2383,10 @@ BOOL context_apply_draw_state(struct wined3d_context *context, struct wined3d_de state_table[rep].apply(context, state, rep); } - if (context->select_shader) + if (context->shader_update_mask) { device->shader_backend->shader_select(device->shader_priv, context, state); - context->select_shader = 0; + context->shader_update_mask = 0; } if (context->constant_update_mask) diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index a5b8c3b0515..4faf8598308 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -5843,23 +5843,40 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const GLhandleARB programId = 0; GLhandleARB reorder_shader_id = 0; unsigned int i; - struct ps_compile_args ps_compile_args; - struct vs_compile_args vs_compile_args; - GLhandleARB vs_id, gs_id, ps_id; + GLhandleARB vs_id = 0; + GLhandleARB gs_id = 0; + GLhandleARB ps_id = 0; struct list *ps_list, *vs_list; struct wined3d_device *device = context->swapchain->device; - if (use_vs(state)) + if (!(context->shader_update_mask & (1 << WINED3D_SHADER_TYPE_VERTEX))) { + vs_id = priv->glsl_program->vs.id; + vs_list = &priv->glsl_program->vs.shader_entry; + + if (use_vs(state)) + { + vshader = state->vertex_shader; + gshader = state->geometry_shader; + + if (!(context->shader_update_mask & (1 << WINED3D_SHADER_TYPE_GEOMETRY)) + && priv->glsl_program->gs.id) + gs_id = priv->glsl_program->gs.id; + else if (gshader) + gs_id = find_glsl_geometry_shader(context, &priv->shader_buffer, gshader); + } + } + else if (use_vs(state)) + { + struct vs_compile_args vs_compile_args; vshader = state->vertex_shader; + find_vs_compile_args(state, vshader, &vs_compile_args); vs_id = find_glsl_vshader(context, &priv->shader_buffer, vshader, &vs_compile_args); vs_list = &vshader->linked_programs; if ((gshader = state->geometry_shader)) gs_id = find_glsl_geometry_shader(context, &priv->shader_buffer, gshader); - else - gs_id = 0; } else if (priv->vertex_pipe == &glsl_vertex_pipe) { @@ -5870,17 +5887,19 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const ffp_shader = shader_glsl_find_ffp_vertex_shader(priv, gl_info, &settings); vs_id = ffp_shader->id; vs_list = &ffp_shader->linked_programs; - - gs_id = 0; - } - else - { - vs_id = 0; - gs_id = 0; } - if (use_ps(state)) + if (!(context->shader_update_mask & (1 << WINED3D_SHADER_TYPE_PIXEL))) { + ps_id = priv->glsl_program->ps.id; + ps_list = &priv->glsl_program->ps.shader_entry; + + if (use_ps(state)) + pshader = state->pixel_shader; + } + else if (use_ps(state)) + { + struct ps_compile_args ps_compile_args; pshader = state->pixel_shader; find_ps_compile_args(state, pshader, &ps_compile_args); ps_id = find_glsl_pshader(context, &priv->shader_buffer, @@ -5897,10 +5916,6 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const ps_id = ffp_shader->id; ps_list = &ffp_shader->linked_programs; } - else - { - ps_id = 0; - } if ((!vs_id && !gs_id && !ps_id) || (entry = get_glsl_program_entry(priv, vs_id, gs_id, ps_id))) { @@ -6320,6 +6335,7 @@ static void shader_glsl_destroy(struct wined3d_shader *shader) struct glsl_shader_private *shader_data = shader->backend_data; struct wined3d_device *device = shader->device; struct shader_glsl_priv *priv = device->shader_priv; + BOOL invalidate_current_program = FALSE; const struct wined3d_gl_info *gl_info; const struct list *linked_programs; struct wined3d_context *context; @@ -6347,22 +6363,22 @@ static void shader_glsl_destroy(struct wined3d_shader *shader) { struct glsl_ps_compiled_shader *gl_shaders = shader_data->gl_shaders.ps; + for (i = 0; i < shader_data->num_gl_shaders; ++i) + { + TRACE("Deleting pixel shader %u.\n", gl_shaders[i].prgId); + if (priv->glsl_program && priv->glsl_program->ps.id == gl_shaders[i].prgId) + invalidate_current_program = TRUE; + GL_EXTCALL(glDeleteObjectARB(gl_shaders[i].prgId)); + checkGLcall("glDeleteObjectARB"); + } + HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.ps); + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, struct glsl_shader_prog_link, ps.shader_entry) { delete_glsl_program_entry(priv, gl_info, entry); } - for (i = 0; i < shader_data->num_gl_shaders; ++i) - { - TRACE("Deleting pixel shader %u.\n", gl_shaders[i].prgId); - if (priv->glsl_program && priv->glsl_program->ps.id == gl_shaders[i].prgId) - shader_glsl_disable(priv, context); - GL_EXTCALL(glDeleteObjectARB(gl_shaders[i].prgId)); - checkGLcall("glDeleteObjectARB"); - } - HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.ps); - break; } @@ -6370,22 +6386,22 @@ static void shader_glsl_destroy(struct wined3d_shader *shader) { struct glsl_vs_compiled_shader *gl_shaders = shader_data->gl_shaders.vs; + for (i = 0; i < shader_data->num_gl_shaders; ++i) + { + TRACE("Deleting vertex shader %u.\n", gl_shaders[i].prgId); + if (priv->glsl_program && priv->glsl_program->vs.id == gl_shaders[i].prgId) + invalidate_current_program = TRUE; + GL_EXTCALL(glDeleteObjectARB(gl_shaders[i].prgId)); + checkGLcall("glDeleteObjectARB"); + } + HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.vs); + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, struct glsl_shader_prog_link, vs.shader_entry) { delete_glsl_program_entry(priv, gl_info, entry); } - for (i = 0; i < shader_data->num_gl_shaders; ++i) - { - TRACE("Deleting vertex shader %u.\n", gl_shaders[i].prgId); - if (priv->glsl_program && priv->glsl_program->vs.id == gl_shaders[i].prgId) - shader_glsl_disable(priv, context); - GL_EXTCALL(glDeleteObjectARB(gl_shaders[i].prgId)); - checkGLcall("glDeleteObjectARB"); - } - HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.vs); - break; } @@ -6393,22 +6409,22 @@ static void shader_glsl_destroy(struct wined3d_shader *shader) { struct glsl_gs_compiled_shader *gl_shaders = shader_data->gl_shaders.gs; + for (i = 0; i < shader_data->num_gl_shaders; ++i) + { + TRACE("Deleting geometry shader %u.\n", gl_shaders[i].id); + if (priv->glsl_program && priv->glsl_program->gs.id == gl_shaders[i].id) + invalidate_current_program = TRUE; + GL_EXTCALL(glDeleteObjectARB(gl_shaders[i].id)); + checkGLcall("glDeleteObjectARB"); + } + HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.gs); + LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, linked_programs, struct glsl_shader_prog_link, gs.shader_entry) { delete_glsl_program_entry(priv, gl_info, entry); } - for (i = 0; i < shader_data->num_gl_shaders; ++i) - { - TRACE("Deleting geometry shader %u.\n", gl_shaders[i].id); - if (priv->glsl_program && priv->glsl_program->gs.id == gl_shaders[i].id) - shader_glsl_disable(priv, context); - GL_EXTCALL(glDeleteObjectARB(gl_shaders[i].id)); - checkGLcall("glDeleteObjectARB"); - } - HeapFree(GetProcessHeap(), 0, shader_data->gl_shaders.gs); - break; } @@ -6418,6 +6434,14 @@ static void shader_glsl_destroy(struct wined3d_shader *shader) } } + if (invalidate_current_program) + { + shader_glsl_disable(priv, context); + context->shader_update_mask = (1 << WINED3D_SHADER_TYPE_PIXEL) + | (1 << WINED3D_SHADER_TYPE_VERTEX) + | (1 << WINED3D_SHADER_TYPE_GEOMETRY); + } + HeapFree(GetProcessHeap(), 0, shader->backend_data); shader->backend_data = NULL; @@ -6887,7 +6911,7 @@ static void glsl_vertex_pipe_vp_free(struct wined3d_device *device) static void glsl_vertex_pipe_shader(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_VERTEX; } static void glsl_vertex_pipe_projection(struct wined3d_context *context, @@ -6896,7 +6920,7 @@ static void glsl_vertex_pipe_projection(struct wined3d_context *context, /* Table fog behavior depends on the projection matrix. */ if (state->render_states[WINED3D_RS_FOGENABLE] && state->render_states[WINED3D_RS_FOGTABLEMODE] != WINED3D_FOG_NONE) - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_VERTEX; transform_projection(context, state, state_id); } @@ -7160,7 +7184,7 @@ static void glsl_fragment_pipe_shader(struct wined3d_context *context, { context->last_was_pshader = use_ps(state); - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; } static void glsl_fragment_pipe_fog(struct wined3d_context *context, @@ -7171,7 +7195,7 @@ static void glsl_fragment_pipe_fog(struct wined3d_context *context, DWORD fogstart = state->render_states[WINED3D_RS_FOGSTART]; DWORD fogend = state->render_states[WINED3D_RS_FOGEND]; - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; if (!state->render_states[WINED3D_RS_FOGENABLE]) return; @@ -7200,7 +7224,7 @@ static void glsl_fragment_pipe_fog(struct wined3d_context *context, static void glsl_fragment_pipe_tex_transform(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; } static void glsl_fragment_pipe_invalidate_constants(struct wined3d_context *context, diff --git a/dlls/wined3d/state.c b/dlls/wined3d/state.c index ffc3101bba2..b43fda8f2cd 100644 --- a/dlls/wined3d/state.c +++ b/dlls/wined3d/state.c @@ -607,7 +607,7 @@ void state_clipping(struct wined3d_context *context, const struct wined3d_state * The enabled / disabled planes are hardcoded into the shader. Update the * shader to update the enabled clipplanes. In case of fixed function, we * need to update the clipping field from ffp_vertex_settings. */ - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_VERTEX; /* TODO: Keep track of previously enabled clipplanes to avoid unnecessary resetting * of already set values @@ -3731,12 +3731,12 @@ void apply_pixelshader(struct wined3d_context *context, const struct wined3d_sta context->last_was_pshader = FALSE; } - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; } static void state_geometry_shader(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_GEOMETRY; } static void shader_bumpenv(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) @@ -4630,7 +4630,7 @@ void vertexdeclaration(struct wined3d_context *context, const struct wined3d_sta } context->last_was_vshader = useVertexShaderFunction; - context->select_shader = 1; + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_VERTEX; if (updateFog) context_apply_state(context, state, STATE_RENDER(WINED3D_RS_FOGVERTEXMODE)); @@ -4644,6 +4644,10 @@ void vertexdeclaration(struct wined3d_context *context, const struct wined3d_sta if (!isStateDirty(context, STATE_TRANSFORM(WINED3D_TS_TEXTURE0 + i))) transform_texture(context, state, STATE_TEXTURESTAGE(i, WINED3D_TSS_TEXTURE_TRANSFORM_FLAGS)); } + + if (use_ps(state) && state->pixel_shader->reg_maps.shader_version.major == 1 + && state->pixel_shader->reg_maps.shader_version.minor <= 3) + context->shader_update_mask |= 1 << WINED3D_SHADER_TYPE_PIXEL; } if (transformed != wasrhw && !isStateDirty(context, STATE_RENDER(WINED3D_RS_ZENABLE))) diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 49aacc1f37b..12dd2c64294 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1092,9 +1092,10 @@ struct wined3d_context DWORD current : 1; DWORD destroyed : 1; DWORD valid : 1; - DWORD select_shader : 1; + DWORD padding : 1; DWORD texShaderBumpMap : 8; /* MAX_TEXTURES, 8 */ DWORD lastWasPow2Texture : 8; /* MAX_TEXTURES, 8 */ + DWORD shader_update_mask; DWORD constant_update_mask; DWORD numbered_array_mask; GLenum tracking_parm; /* Which source is tracking current colour */