Commit f5117874 authored by Matteo Bruni's avatar Matteo Bruni Committed by Alexandre Julliard

wined3d: Avoid reading uninitialized texcoord varyings in FFP replacement fragment shaders.

parent 93db8e97
...@@ -6295,20 +6295,35 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv * ...@@ -6295,20 +6295,35 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *
if (legacy_context) if (legacy_context)
{ {
shader_addline(buffer, "vec4 ffp_texcoord[%u];\n", MAX_TEXTURES);
shader_addline(buffer, "float ffp_varying_fogcoord;\n"); shader_addline(buffer, "float ffp_varying_fogcoord;\n");
} }
else else
{ {
shader_addline(buffer, "vec4 ffp_texcoord[%u];\n", MAX_TEXTURES);
declare_in_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n"); declare_in_varying(gl_info, buffer, FALSE, "float ffp_varying_fogcoord;\n");
} }
shader_addline(buffer, "void main()\n{\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, 0.0);\n", stage);
else if (settings->texcoords_initialized & (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) if (legacy_context && settings->fog != WINED3D_FFP_PS_FOG_OFF)
shader_addline(buffer, "ffp_varying_fogcoord = gl_FogFragCoord;\n"); shader_addline(buffer, "ffp_varying_fogcoord = gl_FogFragCoord;\n");
if (lowest_disabled_stage < 7 && settings->emul_clipplanes) 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) */ /* Generate texture sampling instructions) */
for (stage = 0; stage < MAX_TEXTURES && settings->op[stage].cop != WINED3D_TOP_DISABLE; ++stage) 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 * ...@@ -6409,20 +6424,20 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *
{ {
if (settings->op[stage].projected == proj_count4) 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); 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 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); 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 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", 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 * ...@@ -6434,12 +6449,12 @@ static GLuint shader_glsl_generate_ffp_fragment_shader(struct shader_glsl_priv *
} }
else if (settings->op[stage].projected == proj_count3) 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); stage, texture_function, stage, stage);
} }
else 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); stage, texture_function, stage, stage, coord_mask);
} }
...@@ -8391,10 +8406,22 @@ static void glsl_fragment_pipe_fog(struct wined3d_context *context, ...@@ -8391,10 +8406,22 @@ static void glsl_fragment_pipe_fog(struct wined3d_context *context,
static void glsl_fragment_pipe_vdecl(struct wined3d_context *context, static void glsl_fragment_pipe_vdecl(struct wined3d_context *context,
const struct wined3d_state *state, DWORD state_id) const struct wined3d_state *state, DWORD state_id)
{ {
/* Because of settings->texcoords_initialized. */
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))) if (!isStateDirty(context, STATE_RENDER(WINED3D_RS_FOGENABLE)))
glsl_fragment_pipe_fog(context, state, state_id); 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->texcoords_initialized. */
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, static void glsl_fragment_pipe_tex_transform(struct wined3d_context *context,
const struct wined3d_state *state, DWORD state_id) const struct wined3d_state *state, DWORD state_id)
{ {
...@@ -8447,6 +8474,7 @@ static void glsl_fragment_pipe_color_key(struct wined3d_context *context, ...@@ -8447,6 +8474,7 @@ static void glsl_fragment_pipe_color_key(struct wined3d_context *context,
static const struct StateEntryTemplate glsl_fragment_pipe_state_template[] = static const struct StateEntryTemplate glsl_fragment_pipe_state_template[] =
{ {
{STATE_VDECL, {STATE_VDECL, glsl_fragment_pipe_vdecl }, WINED3D_GL_EXT_NONE }, {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_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_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 }, {STATE_TEXTURESTAGE(0, WINED3D_TSS_COLOR_ARG1), {STATE_SHADER(WINED3D_SHADER_TYPE_PIXEL), NULL }, WINED3D_GL_EXT_NONE },
......
...@@ -4629,6 +4629,43 @@ void gen_ffp_frag_op(const struct wined3d_context *context, const struct wined3d ...@@ -4629,6 +4629,43 @@ void gen_ffp_frag_op(const struct wined3d_context *context, const struct wined3d
settings->color_key_enabled = 1; settings->color_key_enabled = 1;
else else
settings->color_key_enabled = 0; settings->color_key_enabled = 0;
/* texcoords_initialized 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->texcoords_initialized = 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->texcoords_initialized |= 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->texcoords_initialized |= 1u << i;
}
}
}
else
{
settings->texcoords_initialized = (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, const struct ffp_frag_desc *find_ffp_frag_shader(const struct wine_rb_tree *fragment_shaders,
......
...@@ -1865,8 +1865,10 @@ struct ffp_frag_settings ...@@ -1865,8 +1865,10 @@ struct ffp_frag_settings
enum wined3d_ffp_ps_fog_mode fog; enum wined3d_ffp_ps_fog_mode fog;
unsigned char sRGB_write; unsigned char sRGB_write;
unsigned char emul_clipplanes; unsigned char emul_clipplanes;
unsigned char color_key_enabled; unsigned char texcoords_initialized;
unsigned char padding; unsigned char color_key_enabled : 1;
unsigned char pointsprite : 1;
unsigned char padding : 6;
}; };
struct ffp_frag_desc struct ffp_frag_desc
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment