wined3d: Handle projected textures properly in arbfp and atifs.

GL_ARB_fragment_program and GL_ATI_fragment_shader can disable
projected textures properly, and they can also handle
D3DTTFF_PROJECTED | D3DTTFF_COUNT3 properly.
This commit is contained in:
Stefan Dösinger 2008-08-23 15:41:51 -05:00 committed by Alexandre Julliard
parent ec4955630e
commit af8d268a39
7 changed files with 86 additions and 50 deletions

View File

@ -2066,7 +2066,8 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF
IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface; IWineD3DVertexShaderImpl *This = (IWineD3DVertexShaderImpl *)iface;
shader_reg_maps* reg_maps = &This->baseShader.reg_maps; shader_reg_maps* reg_maps = &This->baseShader.reg_maps;
CONST DWORD *function = This->baseShader.function; CONST DWORD *function = This->baseShader.function;
WineD3D_GL_Info *gl_info = &((IWineD3DDeviceImpl *)This->baseShader.device)->adapter->gl_info; IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *)This->baseShader.device;
WineD3D_GL_Info *gl_info = &device->adapter->gl_info;
local_constant* lconst; local_constant* lconst;
/* Create the hw ARB shader */ /* Create the hw ARB shader */
@ -2100,7 +2101,7 @@ static void shader_arb_generate_vshader(IWineD3DVertexShader *iface, SHADER_BUFF
if(!GL_SUPPORT(NV_VERTEX_PROGRAM)) { if(!GL_SUPPORT(NV_VERTEX_PROGRAM)) {
shader_addline(buffer, "MOV result.color.secondary, -helper_const.wwwy;\n"); shader_addline(buffer, "MOV result.color.secondary, -helper_const.wwwy;\n");
if((GLINFO_LOCATION).set_texcoord_w) { if((GLINFO_LOCATION).set_texcoord_w && !device->frag_pipe->ffp_proj_control) {
int i; int i;
for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) { for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) {
if(This->baseShader.reg_maps.texcoord_mask[i] != 0 && if(This->baseShader.reg_maps.texcoord_mask[i] != 0 &&
@ -2746,11 +2747,12 @@ static GLuint gen_arbfp_ffp_shader(struct ffp_settings *settings, IWineD3DStateB
if(settings->op[stage].projected == proj_none) { if(settings->op[stage].projected == proj_none) {
instr = "TEX"; instr = "TEX";
} else if(settings->op[stage].projected == proj_count4) { } else if(settings->op[stage].projected == proj_count4 ||
settings->op[stage].projected == proj_count3) {
instr = "TXP"; instr = "TXP";
} else { } else {
FIXME("Unexpected projection mode %d\n", settings->op[stage].projected);
instr = "TXP"; instr = "TXP";
ERR("Implement proj_count3\n");
} }
if(stage > 0 && if(stage > 0 &&
@ -2768,7 +2770,11 @@ static GLuint gen_arbfp_ffp_shader(struct ffp_settings *settings, IWineD3DStateB
/* Note: Currently always divide by .a because the vertex pipeline moves the correct value /* Note: Currently always divide by .a because the vertex pipeline moves the correct value
* into the 4th component * into the 4th component
*/ */
shader_addline(&buffer, "RCP arg1.a, fragment.texcoord[%u].a;\n", stage); if(settings->op[stage].projected == proj_count4) {
shader_addline(&buffer, "RCP arg1.a, fragment.texcoord[%u].a;\n", stage);
} else {
shader_addline(&buffer, "RCP arg1.a, fragment.texcoord[%u].b;\n", stage);
}
shader_addline(&buffer, "MUL arg1.rg, fragment.texcoord[%u], arg1.a;\n", stage); shader_addline(&buffer, "MUL arg1.rg, fragment.texcoord[%u], arg1.a;\n", stage);
shader_addline(&buffer, "ADD ret, ret, arg1;\n"); shader_addline(&buffer, "ADD ret, ret, arg1;\n");
} else { } else {
@ -2782,6 +2788,11 @@ static GLuint gen_arbfp_ffp_shader(struct ffp_settings *settings, IWineD3DStateB
stage - 1, stage - 1, stage - 1); stage - 1, stage - 1, stage - 1);
shader_addline(&buffer, "MUL tex%u, tex%u, ret.r;\n", stage, stage); shader_addline(&buffer, "MUL tex%u, tex%u, ret.r;\n", stage, stage);
} }
} else if(settings->op[stage].projected == proj_count3) {
shader_addline(&buffer, "MOV ret, fragment.texcoord[%u];\n", stage);
shader_addline(&buffer, "MOV ret.a, ret.b;\n");
shader_addline(&buffer, "%s%s tex%u, ret, texture[%u], %s;\n",
instr, sat, stage, stage, textype);
} else { } else {
shader_addline(&buffer, "%s%s tex%u, fragment.texcoord[%u], texture[%u], %s;\n", shader_addline(&buffer, "%s%s tex%u, fragment.texcoord[%u], texture[%u], %s;\n",
instr, sat, stage, stage, stage, textype); instr, sat, stage, stage, stage, textype);
@ -3122,7 +3133,8 @@ const struct fragment_pipeline arbfp_fragment_pipeline = {
arbfp_alloc, arbfp_alloc,
arbfp_free, arbfp_free,
shader_arb_conv_supported, shader_arb_conv_supported,
arbfp_fragmentstate_template arbfp_fragmentstate_template,
TRUE /* We can disable projected textures */
}; };
#define GLINFO_LOCATION device->adapter->gl_info #define GLINFO_LOCATION device->adapter->gl_info

View File

@ -314,8 +314,10 @@ static GLuint gen_ati_shader(struct texture_stage_op op[MAX_TEXTURES], WineD3D_G
GL_SWIZZLE_STR_ATI)); GL_SWIZZLE_STR_ATI));
if(op[stage + 1].projected == proj_none) { if(op[stage + 1].projected == proj_none) {
swizzle = GL_SWIZZLE_STR_ATI; swizzle = GL_SWIZZLE_STR_ATI;
} else { } else if(op[stage + 1].projected == proj_count4) {
swizzle = GL_SWIZZLE_STQ_DQ_ATI; swizzle = GL_SWIZZLE_STQ_DQ_ATI;
} else {
swizzle = GL_SWIZZLE_STR_DR_ATI;
} }
TRACE("glPassTexCoordATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, %s)\n", TRACE("glPassTexCoordATI(GL_REG_%d_ATI, GL_TEXTURE_%d_ARB, %s)\n",
stage + 1, stage + 1, debug_swizzle(swizzle)); stage + 1, stage + 1, debug_swizzle(swizzle));
@ -382,15 +384,7 @@ static GLuint gen_ati_shader(struct texture_stage_op op[MAX_TEXTURES], WineD3D_G
if(op[stage].projected == proj_none) { if(op[stage].projected == proj_none) {
swizzle = GL_SWIZZLE_STR_ATI; swizzle = GL_SWIZZLE_STR_ATI;
} else if(op[stage].projected == proj_count3) { } else if(op[stage].projected == proj_count3) {
/* TODO: D3DTTFF_COUNT3 | D3DTTFF_PROJECTED would be GL_SWIZZLE_STR_DR_ATI. swizzle = GL_SWIZZLE_STR_DR_ATI;
* However, the FFP vertex processing texture transform matrix handler does
* some transformations in the texture matrix which makes the 3rd coordinate
* arrive in Q, not R in that case. This is needed for opengl fixed function
* fragment processing which always divides by Q. In this backend we can
* handle that properly and be compatible with vertex shader output and avoid
* side effects of the texture matrix games
*/
swizzle = GL_SWIZZLE_STQ_DQ_ATI;
} else { } else {
swizzle = GL_SWIZZLE_STQ_DQ_ATI; swizzle = GL_SWIZZLE_STQ_DQ_ATI;
} }
@ -875,6 +869,13 @@ static void set_bumpmat(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3D
GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), (float *) mat)); GL_EXTCALL(glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), (float *) mat));
checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), mat)"); checkGLcall("glSetFragmentShaderConstantATI(ATI_FFP_CONST_BUMPMAT(stage), mat)");
} }
static void textransform(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context) {
if(!isStateDirty(context, STATE_PIXELSHADER)) {
set_tex_op_atifs(state, stateblock, context);
}
}
#undef GLINFO_LOCATION #undef GLINFO_LOCATION
static const struct StateEntryTemplate atifs_fragmentstate_template[] = { static const struct StateEntryTemplate atifs_fragmentstate_template[] = {
@ -991,6 +992,14 @@ static const struct StateEntryTemplate atifs_fragmentstate_template[] = {
{ STATE_SAMPLER(5), { STATE_SAMPLER(5), sampler_texdim }, 0 }, { STATE_SAMPLER(5), { STATE_SAMPLER(5), sampler_texdim }, 0 },
{ STATE_SAMPLER(6), { STATE_SAMPLER(6), sampler_texdim }, 0 }, { STATE_SAMPLER(6), { STATE_SAMPLER(6), sampler_texdim }, 0 },
{ STATE_SAMPLER(7), { STATE_SAMPLER(7), sampler_texdim }, 0 }, { STATE_SAMPLER(7), { STATE_SAMPLER(7), sampler_texdim }, 0 },
{STATE_TEXTURESTAGE(0,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(0, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 },
{STATE_TEXTURESTAGE(1,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(1, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 },
{STATE_TEXTURESTAGE(2,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(2, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 },
{STATE_TEXTURESTAGE(3,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(3, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 },
{STATE_TEXTURESTAGE(4,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(4, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 },
{STATE_TEXTURESTAGE(5,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(5, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 },
{STATE_TEXTURESTAGE(6,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(6, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 },
{STATE_TEXTURESTAGE(7,WINED3DTSS_TEXTURETRANSFORMFLAGS),{STATE_TEXTURESTAGE(7, WINED3DTSS_TEXTURETRANSFORMFLAGS), textransform }, 0 },
{0 /* Terminate */, { 0, 0 }, 0 }, {0 /* Terminate */, { 0, 0 }, 0 },
}; };
@ -1107,5 +1116,6 @@ const struct fragment_pipeline atifs_fragment_pipeline = {
atifs_alloc, atifs_alloc,
atifs_free, atifs_free,
atifs_conv_supported, atifs_conv_supported,
atifs_fragmentstate_template atifs_fragmentstate_template,
TRUE /* We can disable projected textures */
}; };

View File

@ -3008,6 +3008,7 @@ static GLhandleARB generate_param_reorder_function(IWineD3DVertexShader *vertexs
GLhandleARB ret = 0; GLhandleARB ret = 0;
IWineD3DVertexShaderImpl *vs = (IWineD3DVertexShaderImpl *) vertexshader; IWineD3DVertexShaderImpl *vs = (IWineD3DVertexShaderImpl *) vertexshader;
IWineD3DPixelShaderImpl *ps = (IWineD3DPixelShaderImpl *) pixelshader; IWineD3DPixelShaderImpl *ps = (IWineD3DPixelShaderImpl *) pixelshader;
IWineD3DDeviceImpl *device;
DWORD vs_major = vs ? WINED3DSHADER_VERSION_MAJOR(vs->baseShader.hex_version) : 0; DWORD vs_major = vs ? WINED3DSHADER_VERSION_MAJOR(vs->baseShader.hex_version) : 0;
DWORD ps_major = ps ? WINED3DSHADER_VERSION_MAJOR(ps->baseShader.hex_version) : 0; DWORD ps_major = ps ? WINED3DSHADER_VERSION_MAJOR(ps->baseShader.hex_version) : 0;
unsigned int i; unsigned int i;
@ -3029,7 +3030,9 @@ static GLhandleARB generate_param_reorder_function(IWineD3DVertexShader *vertexs
/* That one is easy: The vertex shader writes to the builtin varyings, the pixel shader reads from them. /* That one is easy: The vertex shader writes to the builtin varyings, the pixel shader reads from them.
* Take care about the texcoord .w fixup though if we're using the fixed function fragment pipeline * Take care about the texcoord .w fixup though if we're using the fixed function fragment pipeline
*/ */
if((GLINFO_LOCATION).set_texcoord_w && ps_major == 0 && vs_major > 0) { device = (IWineD3DDeviceImpl *) vs->baseShader.device;
if((GLINFO_LOCATION).set_texcoord_w && ps_major == 0 && vs_major > 0 &&
!device->frag_pipe->ffp_proj_control) {
shader_addline(&buffer, "void order_ps_input() {\n"); shader_addline(&buffer, "void order_ps_input() {\n");
for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) { for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) {
if(vs->baseShader.reg_maps.texcoord_mask[i] != 0 && if(vs->baseShader.reg_maps.texcoord_mask[i] != 0 &&

View File

@ -810,7 +810,8 @@ const struct fragment_pipeline nvts_fragment_pipeline = {
nvrc_fragment_alloc, nvrc_fragment_alloc,
nvrc_fragment_free, nvrc_fragment_free,
nvts_conv_supported, nvts_conv_supported,
nvrc_fragmentstate_template nvrc_fragmentstate_template,
FALSE /* we cannot disable projected textures. The vertex pipe has to do it */
}; };
const struct fragment_pipeline nvrc_fragment_pipeline = { const struct fragment_pipeline nvrc_fragment_pipeline = {
@ -819,5 +820,6 @@ const struct fragment_pipeline nvrc_fragment_pipeline = {
nvrc_fragment_alloc, nvrc_fragment_alloc,
nvrc_fragment_free, nvrc_fragment_free,
nvts_conv_supported, nvts_conv_supported,
nvrc_fragmentstate_template nvrc_fragmentstate_template,
FALSE /* we cannot disable projected textures. The vertex pipe has to do it */
}; };

View File

@ -1,3 +1,4 @@
/* /*
* Direct3D state management * Direct3D state management
* *
@ -3139,7 +3140,8 @@ static void transform_texture(DWORD state, IWineD3DStateBlockImpl *stateblock, W
context->last_was_rhw, context->last_was_rhw,
stateblock->wineD3DDevice->strided_streams.u.s.texCoords[coordIdx].dwStride ? stateblock->wineD3DDevice->strided_streams.u.s.texCoords[coordIdx].dwStride ?
stateblock->wineD3DDevice->strided_streams.u.s.texCoords[coordIdx].dwType: stateblock->wineD3DDevice->strided_streams.u.s.texCoords[coordIdx].dwType:
WINED3DDECLTYPE_UNUSED); WINED3DDECLTYPE_UNUSED,
stateblock->wineD3DDevice->frag_pipe->ffp_proj_control);
/* The sampler applying function calls us if this changes */ /* The sampler applying function calls us if this changes */
if(context->lastWasPow2Texture[texUnit] && stateblock->textures[texUnit]) { if(context->lastWasPow2Texture[texUnit] && stateblock->textures[texUnit]) {
@ -5565,7 +5567,8 @@ const struct fragment_pipeline ffp_fragment_pipeline = {
ffp_fragment_alloc, ffp_fragment_alloc,
ffp_fragment_free, ffp_fragment_free,
ffp_conv_supported, ffp_conv_supported,
ffp_fragmentstate_template ffp_fragmentstate_template,
FALSE /* we cannot disable projected textures. The vertex pipe has to do it */
}; };
static int num_handlers(APPLYSTATEFUNC *funcs) { static int num_handlers(APPLYSTATEFUNC *funcs) {

View File

@ -1166,7 +1166,8 @@ BOOL is_invalid_op(IWineD3DDeviceImpl *This, int stage, WINED3DTEXTUREOP op, DWO
} }
/* Setup this textures matrix according to the texture flags*/ /* Setup this textures matrix according to the texture flags*/
void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype) void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype,
BOOL ffp_proj_control)
{ {
float mat[16]; float mat[16];
@ -1187,15 +1188,17 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, B
memcpy(mat, smat, 16 * sizeof(float)); memcpy(mat, smat, 16 * sizeof(float));
if (flags & WINED3DTTFF_PROJECTED) { if (flags & WINED3DTTFF_PROJECTED) {
switch (flags & ~WINED3DTTFF_PROJECTED) { if(!ffp_proj_control) {
case WINED3DTTFF_COUNT2: switch (flags & ~WINED3DTTFF_PROJECTED) {
mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13]; case WINED3DTTFF_COUNT2:
mat[1] = mat[5] = mat[9] = mat[13] = 0; mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13];
break; mat[1] = mat[5] = mat[9] = mat[13] = 0;
case WINED3DTTFF_COUNT3: break;
mat[3] = mat[2], mat[7] = mat[6], mat[11] = mat[10], mat[15] = mat[14]; case WINED3DTTFF_COUNT3:
mat[2] = mat[6] = mat[10] = mat[14] = 0; mat[3] = mat[2], mat[7] = mat[6], mat[11] = mat[10], mat[15] = mat[14];
break; mat[2] = mat[6] = mat[10] = mat[14] = 0;
break;
}
} }
} else { /* under directx the R/Z coord can be used for translation, under opengl we use the Q coord instead */ } else { /* under directx the R/Z coord can be used for translation, under opengl we use the Q coord instead */
if(!calculatedCoords) { if(!calculatedCoords) {
@ -1231,23 +1234,25 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, B
FIXME("Unexpected fixed function texture coord input\n"); FIXME("Unexpected fixed function texture coord input\n");
} }
} }
switch (flags & ~WINED3DTTFF_PROJECTED) { if(!ffp_proj_control) {
/* case WINED3DTTFF_COUNT1: Won't ever get here */ switch (flags & ~WINED3DTTFF_PROJECTED) {
case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0; /* case WINED3DTTFF_COUNT1: Won't ever get here */
/* OpenGL divides the first 3 vertex coord by the 4th by default, case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0;
* which is essentially the same as D3DTTFF_PROJECTED. Make sure that /* OpenGL divides the first 3 vertex coord by the 4th by default,
* the 4th coord evaluates to 1.0 to eliminate that. * which is essentially the same as D3DTTFF_PROJECTED. Make sure that
* * the 4th coord evaluates to 1.0 to eliminate that.
* If the fixed function pipeline is used, the 4th value remains unused, *
* so there is no danger in doing this. With vertex shaders we have a * If the fixed function pipeline is used, the 4th value remains unused,
* problem. Should an app hit that problem, the code here would have to * so there is no danger in doing this. With vertex shaders we have a
* check for pixel shaders, and the shader has to undo the default gl divide. * problem. Should an app hit that problem, the code here would have to
* * check for pixel shaders, and the shader has to undo the default gl divide.
* A more serious problem occurs if the app passes 4 coordinates in, and the *
* 4th is != 1.0(opengl default). This would have to be fixed in drawStridedSlow * A more serious problem occurs if the app passes 4 coordinates in, and the
* or a replacement shader * 4th is != 1.0(opengl default). This would have to be fixed in drawStridedSlow
*/ * or a replacement shader
default: mat[3] = mat[7] = mat[11] = 0; mat[15] = 1; */
default: mat[3] = mat[7] = mat[11] = 0; mat[15] = 1;
}
} }
} }

View File

@ -559,6 +559,7 @@ struct fragment_pipeline {
void (*free_private)(IWineD3DDevice *iface); void (*free_private)(IWineD3DDevice *iface);
BOOL (*conv_supported)(WINED3DFORMAT conv); BOOL (*conv_supported)(WINED3DFORMAT conv);
const struct StateEntryTemplate *states; const struct StateEntryTemplate *states;
BOOL ffp_proj_control;
}; };
extern const struct StateEntryTemplate misc_state_template[]; extern const struct StateEntryTemplate misc_state_template[];
@ -1816,7 +1817,7 @@ GLenum StencilOp(DWORD op);
GLenum CompareFunc(DWORD func); GLenum CompareFunc(DWORD func);
BOOL is_invalid_op(IWineD3DDeviceImpl *This, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3); BOOL is_invalid_op(IWineD3DDeviceImpl *This, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3);
void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx, DWORD dst); void set_tex_op_nvrc(IWineD3DDevice *iface, BOOL is_alpha, int stage, WINED3DTEXTUREOP op, DWORD arg1, DWORD arg2, DWORD arg3, INT texture_idx, DWORD dst);
void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype); void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, BOOL transformed, DWORD coordtype, BOOL ffp_can_disable_proj);
void texture_activate_dimensions(DWORD stage, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context); void texture_activate_dimensions(DWORD stage, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context);
void sampler_texdim(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context); void sampler_texdim(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context);
void tex_alphaop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context); void tex_alphaop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context);