From: Matteo Bruni Subject: [PATCH 6/7] wined3d: Avoid reading uninitialized texcoord varyings in FFP replacement fragment shaders. Message-Id: <1443790490-26613-6-git-send-email-mbruni@codeweavers.com> Date: Fri, 2 Oct 2015 14:54:49 +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 --- Probably this code can only be triggered by a D3D9-class GPU with core contexts, which is a combination that just doesn't happen in practice AFAIK. Another case is OpenGL ES 2.0, which allows a minimum of 8 4-component varyings. --- dlls/wined3d/glsl_shader.c | 44 ++++++++++++++++++++++++++++++++++-------- dlls/wined3d/utils.c | 37 +++++++++++++++++++++++++++++++++++ dlls/wined3d/wined3d_private.h | 4 +++- 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/dlls/wined3d/glsl_shader.c b/dlls/wined3d/glsl_shader.c index 54f004f..ef6b567 100644 --- a/dlls/wined3d/glsl_shader.c +++ b/dlls/wined3d/glsl_shader.c @@ -6295,20 +6295,35 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv * if (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"); } shader_addline(buffer, "void main()\n{\n"); + for (stage = 0; stage < MAX_TEXTURES; ++stage) + { + if (tex_map & (1u << stage)) + { + if (settings->pointsprite) + shader_addline(buffer, "ffp_texcoord[%u] = vec4(gl_PointCoord.xy, 0.0, 1.0);\n", stage); + else if (settings->inited_texcoords & (1u << stage)) + shader_addline(buffer, "ffp_texcoord[%u] = gl_TexCoord[%u];\n", stage, stage); + else + shader_addline(buffer, "ffp_texcoord[%u] = vec4(0.0);\n", stage); + } + } + if (legacy_context && settings->fog != WINED3D_FFP_PS_FOG_OFF) shader_addline(buffer, "ffp_varying_fogcoord = gl_FogFragCoord;\n"); if (lowest_disabled_stage < 7 && settings->emul_clipplanes) - shader_addline(buffer, "if (any(lessThan(gl_TexCoord[7], vec4(0.0)))) discard;\n"); + shader_addline(buffer, "if (any(lessThan(ffp_texcoord[7], vec4(0.0)))) discard;\n"); /* Generate texture sampling instructions) */ for (stage = 0; stage < MAX_TEXTURES && settings->op[stage].cop != WINED3D_TOP_DISABLE; ++stage) @@ -6409,20 +6424,20 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv * { if (settings->op[stage].projected == proj_count4) { - shader_addline(buffer, "ret.xy = (ret.xy * gl_TexCoord[%u].w) + gl_TexCoord[%u].xy;\n", + shader_addline(buffer, "ret.xy = (ret.xy * ffp_texcoord[%u].w) + ffp_texcoord[%u].xy;\n", stage, stage); - shader_addline(buffer, "ret.zw = gl_TexCoord[%u].ww;\n", stage); + shader_addline(buffer, "ret.zw = ffp_texcoord[%u].ww;\n", stage); } else { - shader_addline(buffer, "ret.xy = (ret.xy * gl_TexCoord[%u].z) + gl_TexCoord[%u].xy;\n", + shader_addline(buffer, "ret.xy = (ret.xy * ffp_texcoord[%u].z) + ffp_texcoord[%u].xy;\n", stage, stage); - shader_addline(buffer, "ret.zw = gl_TexCoord[%u].zz;\n", stage); + shader_addline(buffer, "ret.zw = ffp_texcoord[%u].zz;\n", stage); } } else { - shader_addline(buffer, "ret = gl_TexCoord[%u] + ret.xyxy;\n", stage); + shader_addline(buffer, "ret = ffp_texcoord[%u] + ret.xyxy;\n", stage); } shader_addline(buffer, "tex%u = %s(ps_sampler%u, ret.%s);\n", @@ -6434,12 +6449,12 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv * } else if (settings->op[stage].projected == proj_count3) { - shader_addline(buffer, "tex%u = %s(ps_sampler%u, gl_TexCoord[%u].xyz);\n", + shader_addline(buffer, "tex%u = %s(ps_sampler%u, ffp_texcoord[%u].xyz);\n", stage, texture_function, stage, stage); } else { - shader_addline(buffer, "tex%u = %s(ps_sampler%u, gl_TexCoord[%u].%s);\n", + shader_addline(buffer, "tex%u = %s(ps_sampler%u, ffp_texcoord[%u].%s);\n", stage, texture_function, stage, stage, coord_mask); } @@ -8391,10 +8406,22 @@ 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)) + context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL; + if (!isStateDirty(context, STATE_RENDER(WINED3D_RS_FOGENABLE))) glsl_fragment_pipe_fog(context, state, state_id); } +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)) + context->shader_update_mask |= 1u << WINED3D_SHADER_TYPE_PIXEL; +} + static void glsl_fragment_pipe_tex_transform(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) { @@ -8447,6 +8474,7 @@ static void glsl_fragment_pipe_color_key(struct wined3d_context *context, static const struct StateEntryTemplate glsl_fragment_pipe_state_template[] = { {STATE_VDECL, {STATE_VDECL, glsl_fragment_pipe_vdecl }, WINED3D_GL_EXT_NONE }, + {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), {STATE_SHADER(WINED3D_SHADER_TYPE_VERTEX), glsl_fragment_pipe_vs }, WINED3D_GL_EXT_NONE }, {STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), {STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), glsl_fragment_pipe_invalidate_constants}, WINED3D_GL_EXT_NONE }, {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_OP), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE }, diff --git a/dlls/wined3d/utils.c b/dlls/wined3d/utils.c index 1a2cbdd..07178f0 100644 --- a/dlls/wined3d/utils.c +++ b/dlls/wined3d/utils.c @@ -4629,6 +4629,43 @@ void gen_ffp_frag_op(const struct wined3d_context *context, const struct wined3d settings->color_key_enabled = 1; else settings->color_key_enabled = 0; + + /* inited_texcoords is set to meaningful values only when GL doesn't support + * enough varyings to always pass around all the possible texture + * coordinates. + * This is used to avoid reading a varying not written by the vertex shader. + * Reading uninitialized varyings on core profile contexts results in an + * error while with builtin varyings on legacy contexts you get undefined + * behavior. */ + if (d3d_info->limits.varying_count + && d3d_info->limits.varying_count < wined3d_max_compat_varyings(gl_info)) + { + settings->inited_texcoords = 0; + for (i = 0; i < MAX_TEXTURES; ++i) + { + if (use_vs(state)) + { + if (state->shader[WINED3D_SHADER_TYPE_VERTEX]->reg_maps.output_registers & (1u << i)) + settings->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))))) + settings->inited_texcoords |= 1u << i; + } + } + } + else + { + settings->inited_texcoords = (1u << MAX_TEXTURES) - 1; + } + + settings->pointsprite = state->render_states[WINED3D_RS_POINTSPRITEENABLE] + && state->gl_primitive_type == GL_POINTS; } const struct ffp_frag_desc *find_ffp_frag_shader(const struct wine_rb_tree *fragment_shaders, diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index 87c07db..9a5b9c4 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1866,7 +1866,9 @@ struct ffp_frag_settings unsigned char sRGB_write; unsigned char emul_clipplanes; unsigned char color_key_enabled; - unsigned char padding; + unsigned char pointsprite : 1; + unsigned char padding : 7; + unsigned int inited_texcoords; }; struct ffp_frag_desc -- 2.4.6