From: Matteo Bruni Subject: [PATCH 7/7] wined3d: Avoid reading uninitialized texcoord varyings in pixel shaders. Message-Id: <1443790490-26613-7-git-send-email-mbruni@codeweavers.com> Date: Fri, 2 Oct 2015 14:54:50 +0200 In-Reply-To: <1443790490-26613-1-git-send-email-mbruni@codeweavers.com> References: <1443790490-26613-1-git-send-email-mbruni@codeweavers.com> Signed-off-by: Matteo Bruni --- dlls/wined3d/arb_program_shader.c | 2 +- dlls/wined3d/glsl_shader.c | 79 +++++++++++++++++++++------------------ dlls/wined3d/shader.c | 32 +++++++++++++++- dlls/wined3d/wined3d_private.h | 5 ++- 4 files changed, 77 insertions(+), 41 deletions(-) diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c index b1d9869..3dff527 100644 --- a/dlls/wined3d/arb_program_shader.c +++ b/dlls/wined3d/arb_program_shader.c @@ -4538,7 +4538,7 @@ static void find_arb_ps_compile_args(const struct wined3d_state *state, int i; WORD int_skip; - find_ps_compile_args(state, shader, context->stream_info.position_transformed, &args->super, gl_info); + find_ps_compile_args(state, shader, context->stream_info.position_transformed, &args->super, context); /* This forces all local boolean constants to 1 to make them stateblock independent */ args->bools = shader->reg_maps.local_bool_consts; diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index ef6b567..633c489 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -1806,12 +1806,6 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont if (map & 1) shader_addline(buffer, "ivec4 A%u;\n", i); } - /* Declare texture coordinate temporaries and initialize them */ - for (i = 0, map = reg_maps->texcoord; map; map >>= 1, ++i) - { - if (map & 1) shader_addline(buffer, "vec4 T%u = gl_TexCoord[%u];\n", i, i); - } - if (version->type == WINED3D_SHADER_TYPE_VERTEX) { for (i = 0; i < shader->input_signature.element_count; ++i) @@ -1858,10 +1852,12 @@ static void shader_generate_glsl_declarations(const struct wined3d_context *cont if (gl_info->supported[WINED3D_GL_LEGACY_CONTEXT]) { + shader_addline(buffer, "vec4 ffp_texcoord[%u];\n", MAX_TEXTURES); shader_addline(buffer, "float ffp_varying_fogcoord;\n"); } else { + shader_addline(buffer, "vec4 ffp_texcoord[%u];\n", MAX_TEXTURES); declare_in_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n"); } } @@ -4209,7 +4205,7 @@ static void shader_glsl_texcoord(const struct wined3d_shader_instruction *ins) char dst_mask[6]; shader_glsl_get_write_mask(&ins->dst[0], dst_mask); - shader_addline(buffer, "clamp(gl_TexCoord[%u], 0.0, 1.0)%s);\n", + shader_addline(buffer, "clamp(ffp_texcoord[%u], 0.0, 1.0)%s);\n", ins->dst[0].reg.idx[0].offset, dst_mask); } else @@ -4220,33 +4216,22 @@ static void shader_glsl_texcoord(const struct wined3d_shader_instruction *ins) shader_glsl_get_swizzle(&ins->src[0], FALSE, write_mask, dst_swizzle); - if (src_mod == WINED3DSPSM_DZ) + if (src_mod == WINED3DSPSM_DZ || src_mod == WINED3DSPSM_DW) { unsigned int mask_size = shader_glsl_get_write_mask_size(write_mask); struct glsl_src_param div_param; + DWORD src_writemask = src_mod == WINED3DSPSM_DZ ? WINED3DSP_WRITEMASK_2 : WINED3DSP_WRITEMASK_3; - shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_2, &div_param); + shader_glsl_add_src_param(ins, &ins->src[0], src_writemask, &div_param); - if (mask_size > 1) { - shader_addline(buffer, "gl_TexCoord[%u]%s / vec%d(%s));\n", reg, dst_swizzle, mask_size, div_param.param_str); - } else { - shader_addline(buffer, "gl_TexCoord[%u]%s / %s);\n", reg, dst_swizzle, div_param.param_str); - } + if (mask_size > 1) + shader_addline(buffer, "ffp_texcoord[%u]%s / vec%d(%s));\n", reg, dst_swizzle, mask_size, div_param.param_str); + else + shader_addline(buffer, "ffp_texcoord[%u]%s / %s);\n", reg, dst_swizzle, div_param.param_str); } - else if (src_mod == WINED3DSPSM_DW) + else { - unsigned int mask_size = shader_glsl_get_write_mask_size(write_mask); - struct glsl_src_param div_param; - - shader_glsl_add_src_param(ins, &ins->src[0], WINED3DSP_WRITEMASK_3, &div_param); - - if (mask_size > 1) { - shader_addline(buffer, "gl_TexCoord[%u]%s / vec%d(%s));\n", reg, dst_swizzle, mask_size, div_param.param_str); - } else { - shader_addline(buffer, "gl_TexCoord[%u]%s / %s);\n", reg, dst_swizzle, div_param.param_str); - } - } else { - shader_addline(buffer, "gl_TexCoord[%u]%s);\n", reg, dst_swizzle); + shader_addline(buffer, "ffp_texcoord[%u]%s);\n", reg, dst_swizzle); } } } @@ -4276,17 +4261,17 @@ static void shader_glsl_texdp3tex(const struct wined3d_shader_instruction *ins) { case 1: shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL, - "dot(gl_TexCoord[%u].xyz, %s)", sampler_idx, src0_param.param_str); + "dot(ffp_texcoord[%u].xyz, %s)", sampler_idx, src0_param.param_str); break; case 2: shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL, - "vec2(dot(gl_TexCoord[%u].xyz, %s), 0.0)", sampler_idx, src0_param.param_str); + "vec2(dot(ffp_texcoord[%u].xyz, %s), 0.0)", sampler_idx, src0_param.param_str); break; case 3: shader_glsl_gen_sample_code(ins, sampler_idx, &sample_function, WINED3DSP_NOSWIZZLE, NULL, NULL, NULL, - "vec3(dot(gl_TexCoord[%u].xyz, %s), 0.0, 0.0)", sampler_idx, src0_param.param_str); + "vec3(dot(ffp_texcoord[%u].xyz, %s), 0.0, 0.0)", sampler_idx, src0_param.param_str); break; default: @@ -4491,7 +4476,7 @@ static void shader_glsl_texm3x3vspec(const struct wined3d_shader_instruction *in shader_addline(buffer, "tmp0.z = dot(vec3(T%u), vec3(%s));\n", reg, src0_param.param_str); /* Construct the eye-ray vector from w coordinates */ - shader_addline(buffer, "tmp1.xyz = normalize(vec3(gl_TexCoord[%u].w, gl_TexCoord[%u].w, gl_TexCoord[%u].w));\n", + shader_addline(buffer, "tmp1.xyz = normalize(vec3(ffp_texcoord[%u].w, ffp_texcoord[%u].w, ffp_texcoord[%u].w));\n", tex_mx->texcoord_w[0], tex_mx->texcoord_w[1], reg); shader_addline(buffer, "tmp0.xyz = -reflect(tmp1.xyz, normalize(tmp0.xyz));\n"); @@ -4732,7 +4717,10 @@ static void shader_glsl_input_pack(const struct wined3d_shader *shader, struct w } else if (shader_match_semantic(semantic_name, WINED3D_DECL_USAGE_TEXCOORD)) { - if (semantic_idx < 8 && args->vp_mode == pretransformed) + if (args->pointsprite) + shader_addline(buffer, "ps_in[%u] = vec4(gl_PointCoord.xy, 0.0, 0.0);\n", + shader->u.ps.input_reg_map[input->register_idx]); + else if (args->vp_mode == pretransformed && args->inited_texcoords & (1u << semantic_idx)) shader_addline(buffer, "ps_in[%u]%s = gl_TexCoord[%u]%s;\n", shader->u.ps.input_reg_map[input->register_idx], reg_mask, semantic_idx, reg_mask); else @@ -5137,6 +5125,23 @@ static GLuint shader_glsl_generate_pshader(const struct wined3d_context *context if (reg_maps->shader_version.major < 3 || args->vp_mode != vertexshader) { + unsigned int i; + WORD map = reg_maps->texcoord; + + for (i = 0; map; map >>= 1, ++i) + { + if (map & 1) + { + if (args->pointsprite) + shader_addline(buffer, "ffp_texcoord[%u] = vec4(gl_PointCoord.xy, 0.0, 0.0);\n", i); + else if (args->inited_texcoords & (1u << i)) + shader_addline(buffer, "ffp_texcoord[%u] = gl_TexCoord[%u];\n", i, i); + else + shader_addline(buffer, "ffp_texcoord[%u] = vec4(0.0f);\n", i); + shader_addline(buffer, "vec4 T%u = ffp_texcoord[%u];\n", i, i); + } + } + if (legacy_context) shader_addline(buffer, "ffp_varying_fogcoord = gl_FogFragCoord;\n"); } @@ -6816,7 +6821,7 @@ static void set_glsl_shader_program(const struct wined3d_context *context, const { struct ps_compile_args ps_compile_args; pshader = state->shader[WINED3D_SHADER_TYPE_PIXEL]; - find_ps_compile_args(state, pshader, context->stream_info.position_transformed, &ps_compile_args, gl_info); + find_ps_compile_args(state, pshader, context->stream_info.position_transformed, &ps_compile_args, context); ps_id = find_glsl_pshader(context, &priv->shader_buffer, &priv->string_buffers, pshader, &ps_compile_args, &np2fixup_info); ps_list = &pshader->linked_programs; @@ -8406,8 +8411,8 @@ static void glsl_fragment_pipe_fog(struct wined3d_context *context, static void glsl_fragment_pipe_vdecl(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { - /* Because of settings->inited_texcoords. */ - if (!use_ps(state) && context->gl_info->limits.glsl_varyings < wined3d_max_compat_varyings(context->gl_info)) + /* Because of settings->inited_texcoords and args->inited_texcoords. */ + if (context->gl_info->limits.glsl_varyings < wined3d_max_compat_varyings(context->gl_info)) context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL; if (!isStateDirty(context, STATE_RENDER(WINED3D_RS_FOGENABLE))) @@ -8417,8 +8422,8 @@ static void glsl_fragment_pipe_vdecl(struct wined3d_context *context, static void glsl_fragment_pipe_vs(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { - /* Because of settings->inited_texcoords. */ - if (!use_ps(state) && context->gl_info->limits.glsl_varyings < wined3d_max_compat_varyings(context->gl_info)) + /* Because of settings->inited_texcoords and args->inited_texcoords. */ + if (context->gl_info->limits.glsl_varyings < wined3d_max_compat_varyings(context->gl_info)) context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL; } diff --git a/dlls/wined3d/shader.c b/dlls/wined3d/shader.c index 8574881..8158c2d 100644 --- a/dlls/wined3d/shader.c +++ b/dlls/wined3d/shader.c @@ -2397,8 +2397,9 @@ static HRESULT geometryshader_init(struct wined3d_shader *shader, struct wined3d } void find_ps_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader, - BOOL position_transformed, struct ps_compile_args *args, const struct wined3d_gl_info *gl_info) + BOOL position_transformed, struct ps_compile_args *args, const struct wined3d_context *context) { + const struct wined3d_gl_info *gl_info = context->gl_info; const struct wined3d_texture *texture; UINT i; @@ -2571,6 +2572,35 @@ void find_ps_compile_args(const struct wined3d_state *state, const struct wined3 } } + if (context->d3d_info->limits.varying_count < wined3d_max_compat_varyings(context->gl_info)) + { + const struct wined3d_shader *vs = state->shader[WINED3D_SHADER_TYPE_VERTEX]; + + args->inited_texcoords = 0; + for (i = 0; i < MAX_TEXTURES; ++i) + { + if (vs) + { + if (state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.output_registers & (1u << i)) + args->inited_texcoords |= 1u << i; + } + else + { + const struct wined3d_stream_info *si = &context->stream_info; + unsigned int coord_idx = state->texture_states[i][WINED3D_TSS_TEXCOORD_INDEX]; + + if ((state->texture_states[i][WINED3D_TSS_TEXCOORD_INDEX] >> WINED3D_FFP_TCI_SHIFT) + & WINED3D_FFP_TCI_MASK + || (coord_idx < MAX_TEXTURES && (si->use_map & (1u << (WINED3D_FFP_TEXCOORD0 + coord_idx))))) + args->inited_texcoords |= 1u << i; + } + } + } + else + { + args->inited_texcoords = (1u << MAX_TEXTURES) - 1; + } + args->pointsprite = state->render_states[WINED3D_RS_POINTSPRITEENABLE] && state->gl_primitive_type == GL_POINTS; } diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 9a5b9c4..d33fb1b 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -833,11 +833,12 @@ struct ps_compile_args { WORD tex_transform; /* ps 1.0-1.3, 4 textures */ WORD tex_types; /* ps 1.0 - 1.4, 6 textures */ WORD srgb_correction; - WORD np2_fixup; /* Bitmap for NP2 texcoord fixups (16 samplers max currently). D3D9 has a limit of 16 samplers and the fixup is superfluous in D3D10 (unconditional NP2 support mandatory). */ + WORD np2_fixup; WORD shadow; /* MAX_FRAGMENT_SAMPLERS, 16 */ + WORD inited_texcoords; /* MAX_TEXTURES, 8 */ BOOL pointsprite; }; @@ -3003,7 +3004,7 @@ struct wined3d_shader void pixelshader_update_resource_types(struct wined3d_shader *shader, WORD tex_types) DECLSPEC_HIDDEN; void find_ps_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader, BOOL position_transformed, struct ps_compile_args *args, - const struct wined3d_gl_info *gl_info) DECLSPEC_HIDDEN; + const struct wined3d_context *context) DECLSPEC_HIDDEN; void find_vs_compile_args(const struct wined3d_state *state, const struct wined3d_shader *shader, WORD swizzle_map, struct vs_compile_args *args) DECLSPEC_HIDDEN; -- 2.4.6