Commit 3c2d0b98 authored by Stefan Dösinger's avatar Stefan Dösinger Committed by Alexandre Julliard

wined3d: Avoid constant collision in atifs.

parent 239e8cad
...@@ -44,12 +44,20 @@ WINE_DECLARE_DEBUG_CHANNEL(d3d); ...@@ -44,12 +44,20 @@ WINE_DECLARE_DEBUG_CHANNEL(d3d);
#define ATI_FFP_CONST_CONSTANT5 GL_CON_5_ATI #define ATI_FFP_CONST_CONSTANT5 GL_CON_5_ATI
#define ATI_FFP_CONST_TFACTOR GL_CON_6_ATI #define ATI_FFP_CONST_TFACTOR GL_CON_6_ATI
enum atifs_constant_value
{
ATIFS_CONSTANT_UNUSED = 0,
ATIFS_CONSTANT_BUMP,
ATIFS_CONSTANT_TFACTOR
};
/* GL_ATI_fragment_shader specific fixed function pipeline description. "Inherits" from the common one */ /* GL_ATI_fragment_shader specific fixed function pipeline description. "Inherits" from the common one */
struct atifs_ffp_desc struct atifs_ffp_desc
{ {
struct ffp_frag_desc parent; struct ffp_frag_desc parent;
GLuint shader; GLuint shader;
unsigned int num_textures_used; unsigned int num_textures_used;
enum atifs_constant_value constants[8];
}; };
struct atifs_private_data struct atifs_private_data
...@@ -57,6 +65,11 @@ struct atifs_private_data ...@@ -57,6 +65,11 @@ struct atifs_private_data
struct wine_rb_tree fragment_shaders; /* A rb-tree to track fragment pipeline replacement shaders */ struct wine_rb_tree fragment_shaders; /* A rb-tree to track fragment pipeline replacement shaders */
}; };
struct atifs_context_private_data
{
const struct atifs_ffp_desc *last_shader;
};
static const char *debug_dstmod(GLuint mod) { static const char *debug_dstmod(GLuint mod) {
switch(mod) { switch(mod) {
case GL_NONE: return "GL_NONE"; case GL_NONE: return "GL_NONE";
...@@ -439,7 +452,20 @@ static void atifs_color_fixup(const struct wined3d_gl_info *gl_info, struct colo ...@@ -439,7 +452,20 @@ static void atifs_color_fixup(const struct wined3d_gl_info *gl_info, struct colo
} }
} }
static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], const struct wined3d_gl_info *gl_info) static BOOL op_reads_tfactor(const struct texture_stage_op *op)
{
return (op->carg0 & WINED3DTA_SELECTMASK) == WINED3DTA_TFACTOR
|| (op->carg1 & WINED3DTA_SELECTMASK) == WINED3DTA_TFACTOR
|| (op->carg2 & WINED3DTA_SELECTMASK) == WINED3DTA_TFACTOR
|| (op->aarg0 & WINED3DTA_SELECTMASK) == WINED3DTA_TFACTOR
|| (op->aarg1 & WINED3DTA_SELECTMASK) == WINED3DTA_TFACTOR
|| (op->aarg2 & WINED3DTA_SELECTMASK) == WINED3DTA_TFACTOR
|| op->cop == WINED3D_TOP_BLEND_FACTOR_ALPHA
|| op->aop == WINED3D_TOP_BLEND_FACTOR_ALPHA;
}
static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES],
const struct wined3d_gl_info *gl_info, enum atifs_constant_value *constants)
{ {
GLuint ret = GL_EXTCALL(glGenFragmentShadersATI(1)); GLuint ret = GL_EXTCALL(glGenFragmentShadersATI(1));
unsigned int stage; unsigned int stage;
...@@ -449,6 +475,7 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con ...@@ -449,6 +475,7 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con
GLuint swizzle; GLuint swizzle;
GLuint tmparg = find_tmpreg(op); GLuint tmparg = find_tmpreg(op);
GLuint dstreg; GLuint dstreg;
BOOL tfactor_used = FALSE;
if(!ret) { if(!ret) {
ERR("Failed to generate a GL_ATI_fragment_shader shader id\n"); ERR("Failed to generate a GL_ATI_fragment_shader shader id\n");
...@@ -470,6 +497,8 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con ...@@ -470,6 +497,8 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con
&& op[stage].cop != WINED3D_TOP_BUMPENVMAP_LUMINANCE) && op[stage].cop != WINED3D_TOP_BUMPENVMAP_LUMINANCE)
continue; continue;
constants[stage] = ATIFS_CONSTANT_BUMP;
TRACE("glSampleMapATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, GL_SWIZZLE_STR_ATI)\n", TRACE("glSampleMapATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, GL_SWIZZLE_STR_ATI)\n",
stage, stage); stage, stage);
GL_EXTCALL(glSampleMapATI(GL_REG_0_ATI + stage, GL_EXTCALL(glSampleMapATI(GL_REG_0_ATI + stage,
...@@ -615,6 +644,9 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con ...@@ -615,6 +644,9 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con
argmodextra = GL_NONE; argmodextra = GL_NONE;
extrarg = GL_NONE; extrarg = GL_NONE;
if (op_reads_tfactor(&op[stage]))
tfactor_used = TRUE;
if (op_reads_texture(&op[stage]) && !is_identity_fixup(op[stage].color_fixup)) if (op_reads_texture(&op[stage]) && !is_identity_fixup(op[stage].color_fixup))
atifs_color_fixup(gl_info, op[stage].color_fixup, GL_REG_0_ATI + stage); atifs_color_fixup(gl_info, op[stage].color_fixup, GL_REG_0_ATI + stage);
...@@ -889,18 +921,74 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con ...@@ -889,18 +921,74 @@ static GLuint gen_ati_shader(const struct texture_stage_op op[MAX_TEXTURES], con
} }
} }
if (tfactor_used && constants[ATI_FFP_CONST_TFACTOR - GL_CON_0_ATI] != ATIFS_CONSTANT_UNUSED)
FIXME("Texture factor constant already used.\n");
constants[ATI_FFP_CONST_TFACTOR - GL_CON_0_ATI] = ATIFS_CONSTANT_TFACTOR;
/* Assign unused constants to avoid reloading due to unused <-> bump matrix switches. */
for (stage = 0; stage < 8; ++stage)
{
if (constants[stage] == ATIFS_CONSTANT_UNUSED)
constants[stage] = ATIFS_CONSTANT_BUMP;
}
TRACE("glEndFragmentShaderATI()\n"); TRACE("glEndFragmentShaderATI()\n");
GL_EXTCALL(glEndFragmentShaderATI()); GL_EXTCALL(glEndFragmentShaderATI());
checkGLcall("GL_EXTCALL(glEndFragmentShaderATI())"); checkGLcall("GL_EXTCALL(glEndFragmentShaderATI())");
return ret; return ret;
} }
static void atifs_tfactor(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
{
const struct wined3d_gl_info *gl_info = context->gl_info;
float col[4];
struct atifs_context_private_data *ctx_priv = context->fragment_pipe_data;
if (!ctx_priv->last_shader
|| ctx_priv->last_shader->constants[ATI_FFP_CONST_TFACTOR - GL_CON_0_ATI] != ATIFS_CONSTANT_TFACTOR)
return;
D3DCOLORTOGLFLOAT4(state->render_states[WINED3D_RS_TEXTUREFACTOR], col);
GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col));
checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col)");
}
static void set_bumpmat(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
{
DWORD stage = (state_id - STATE_TEXTURESTAGE(0, 0)) / (WINED3D_HIGHEST_TEXTURE_STATE + 1);
const struct wined3d_gl_info *gl_info = context->gl_info;
float mat[2][2];
struct atifs_context_private_data *ctx_priv = context->fragment_pipe_data;
if (!ctx_priv->last_shader
|| ctx_priv->last_shader->constants[stage] != ATIFS_CONSTANT_BUMP)
return;
mat[0][0] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT00]);
mat[1][0] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT01]);
mat[0][1] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT10]);
mat[1][1] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT11]);
/* GL_ATI_fragment_shader allows only constants from 0.0 to 1.0, but the bumpmat
* constants can be in any range. While they should stay between [-1.0 and 1.0] because
* Shader Model 1.x pixel shaders are clamped to that range negative values are used occasionally,
* for example by our d3d9 test. So to get negative values scale -1;1 to 0;1 and undo that in the
* shader(it is free). This might potentially reduce precision. However, if the hardware does
* support proper floats it shouldn't, and if it doesn't we can't get anything better anyway. */
mat[0][0] = (mat[0][0] + 1.0f) * 0.5f;
mat[1][0] = (mat[1][0] + 1.0f) * 0.5f;
mat[0][1] = (mat[0][1] + 1.0f) * 0.5f;
mat[1][1] = (mat[1][1] + 1.0f) * 0.5f;
GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), (float *) mat));
checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), mat)");
}
static void set_tex_op_atifs(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) static void set_tex_op_atifs(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
{ {
const struct wined3d_device *device = context->swapchain->device; const struct wined3d_device *device = context->swapchain->device;
const struct wined3d_gl_info *gl_info = context->gl_info; const struct wined3d_gl_info *gl_info = context->gl_info;
const struct wined3d_d3d_info *d3d_info = context->d3d_info; const struct wined3d_d3d_info *d3d_info = context->d3d_info;
const struct atifs_ffp_desc *desc; struct atifs_context_private_data *ctx_priv = context->fragment_pipe_data;
const struct atifs_ffp_desc *desc, *last_shader = ctx_priv->last_shader;
struct ffp_frag_settings settings; struct ffp_frag_settings settings;
struct atifs_private_data *priv = device->fragment_priv; struct atifs_private_data *priv = device->fragment_priv;
DWORD mapped_stage; DWORD mapped_stage;
...@@ -909,7 +997,7 @@ static void set_tex_op_atifs(struct wined3d_context *context, const struct wined ...@@ -909,7 +997,7 @@ static void set_tex_op_atifs(struct wined3d_context *context, const struct wined
gen_ffp_frag_op(context, state, &settings, TRUE); gen_ffp_frag_op(context, state, &settings, TRUE);
desc = (const struct atifs_ffp_desc *)find_ffp_frag_shader(&priv->fragment_shaders, &settings); desc = (const struct atifs_ffp_desc *)find_ffp_frag_shader(&priv->fragment_shaders, &settings);
if(!desc) { if(!desc) {
struct atifs_ffp_desc *new_desc = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_desc)); struct atifs_ffp_desc *new_desc = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*new_desc));
if (!new_desc) if (!new_desc)
{ {
ERR("Out of memory\n"); ERR("Out of memory\n");
...@@ -924,7 +1012,7 @@ static void set_tex_op_atifs(struct wined3d_context *context, const struct wined ...@@ -924,7 +1012,7 @@ static void set_tex_op_atifs(struct wined3d_context *context, const struct wined
} }
new_desc->parent.settings = settings; new_desc->parent.settings = settings;
new_desc->shader = gen_ati_shader(settings.op, gl_info); new_desc->shader = gen_ati_shader(settings.op, gl_info, new_desc->constants);
add_ffp_frag_shader(&priv->fragment_shaders, &new_desc->parent); add_ffp_frag_shader(&priv->fragment_shaders, &new_desc->parent);
TRACE("Allocated fixed function replacement shader descriptor %p\n", new_desc); TRACE("Allocated fixed function replacement shader descriptor %p\n", new_desc);
desc = new_desc; desc = new_desc;
...@@ -944,41 +1032,27 @@ static void set_tex_op_atifs(struct wined3d_context *context, const struct wined ...@@ -944,41 +1032,27 @@ static void set_tex_op_atifs(struct wined3d_context *context, const struct wined
} }
GL_EXTCALL(glBindFragmentShaderATI(desc->shader)); GL_EXTCALL(glBindFragmentShaderATI(desc->shader));
} ctx_priv->last_shader = desc;
static void state_texfactor_atifs(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) for (i = 0; i < 8; i++)
{ {
const struct wined3d_gl_info *gl_info = context->gl_info; if (last_shader && last_shader->constants[i] == desc->constants[i])
float col[4]; continue;
D3DCOLORTOGLFLOAT4(state->render_states[WINED3D_RS_TEXTUREFACTOR], col); switch (desc->constants[i])
GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col)); {
checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_TFACTOR, col)"); case ATIFS_CONSTANT_BUMP:
} set_bumpmat(context, state, STATE_TEXTURESTAGE(i, WINED3D_TSS_BUMPENV_MAT00));
break;
static void set_bumpmat(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) case ATIFS_CONSTANT_TFACTOR:
{ atifs_tfactor(context, state, STATE_RENDER(WINED3D_RS_TEXTUREFACTOR));
DWORD stage = (state_id - STATE_TEXTURESTAGE(0, 0)) / (WINED3D_HIGHEST_TEXTURE_STATE + 1); break;
const struct wined3d_gl_info *gl_info = context->gl_info;
float mat[2][2];
mat[0][0] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT00]); default:
mat[1][0] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT01]); ERR("Unexpected constant type %u.\n", desc->constants[i]);
mat[0][1] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT10]); }
mat[1][1] = *((float *)&state->texture_states[stage][WINED3D_TSS_BUMPENV_MAT11]); }
/* GL_ATI_fragment_shader allows only constants from 0.0 to 1.0, but the bumpmat
* constants can be in any range. While they should stay between [-1.0 and 1.0] because
* Shader Model 1.x pixel shaders are clamped to that range negative values are used occasionally,
* for example by our d3d9 test. So to get negative values scale -1;1 to 0;1 and undo that in the
* shader(it is free). This might potentially reduce precision. However, if the hardware does
* support proper floats it shouldn't, and if it doesn't we can't get anything better anyway
*/
mat[0][0] = (mat[0][0] + 1.0f) * 0.5f;
mat[1][0] = (mat[1][0] + 1.0f) * 0.5f;
mat[0][1] = (mat[0][1] + 1.0f) * 0.5f;
mat[1][1] = (mat[1][1] + 1.0f) * 0.5f;
GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), (float *) mat));
checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), mat)");
} }
static void textransform(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id) static void textransform(struct wined3d_context *context, const struct wined3d_state *state, DWORD state_id)
...@@ -994,7 +1068,7 @@ static void atifs_srgbwriteenable(struct wined3d_context *context, const struct ...@@ -994,7 +1068,7 @@ static void atifs_srgbwriteenable(struct wined3d_context *context, const struct
} }
static const struct StateEntryTemplate atifs_fragmentstate_template[] = { static const struct StateEntryTemplate atifs_fragmentstate_template[] = {
{STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), { STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), state_texfactor_atifs }, WINED3D_GL_EXT_NONE }, {STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), { STATE_RENDER(WINED3D_RS_TEXTUREFACTOR), atifs_tfactor }, WINED3D_GL_EXT_NONE },
{STATE_RENDER(WINED3D_RS_FOGCOLOR), { STATE_RENDER(WINED3D_RS_FOGCOLOR), state_fogcolor }, WINED3D_GL_EXT_NONE }, {STATE_RENDER(WINED3D_RS_FOGCOLOR), { STATE_RENDER(WINED3D_RS_FOGCOLOR), state_fogcolor }, WINED3D_GL_EXT_NONE },
{STATE_RENDER(WINED3D_RS_FOGDENSITY), { STATE_RENDER(WINED3D_RS_FOGDENSITY), state_fogdensity }, WINED3D_GL_EXT_NONE }, {STATE_RENDER(WINED3D_RS_FOGDENSITY), { STATE_RENDER(WINED3D_RS_FOGDENSITY), state_fogdensity }, WINED3D_GL_EXT_NONE },
{STATE_RENDER(WINED3D_RS_FOGENABLE), { STATE_RENDER(WINED3D_RS_FOGENABLE), state_fog_fragpart }, WINED3D_GL_EXT_NONE }, {STATE_RENDER(WINED3D_RS_FOGENABLE), { STATE_RENDER(WINED3D_RS_FOGENABLE), state_fog_fragpart }, WINED3D_GL_EXT_NONE },
...@@ -1251,11 +1325,16 @@ static BOOL atifs_color_fixup_supported(struct color_fixup_desc fixup) ...@@ -1251,11 +1325,16 @@ static BOOL atifs_color_fixup_supported(struct color_fixup_desc fixup)
static BOOL atifs_alloc_context_data(struct wined3d_context *context) static BOOL atifs_alloc_context_data(struct wined3d_context *context)
{ {
struct atifs_context_private_data *priv = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*priv));
if (!priv)
return FALSE;
context->fragment_pipe_data = priv;
return TRUE; return TRUE;
} }
static void atifs_free_context_data(struct wined3d_context *context) static void atifs_free_context_data(struct wined3d_context *context)
{ {
HeapFree(GetProcessHeap(), 0, context->fragment_pipe_data);
} }
const struct fragment_pipeline atifs_fragment_pipeline = { const struct fragment_pipeline atifs_fragment_pipeline = {
......
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