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;
shader_reg_maps* reg_maps = &This->baseShader.reg_maps;
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;
/* 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)) {
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;
for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) {
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) {
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";
} else {
FIXME("Unexpected projection mode %d\n", settings->op[stage].projected);
instr = "TXP";
ERR("Implement proj_count3\n");
}
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
* 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, "ADD ret, ret, arg1;\n");
} else {
@ -2782,6 +2788,11 @@ static GLuint gen_arbfp_ffp_shader(struct ffp_settings *settings, IWineD3DStateB
stage - 1, stage - 1, stage - 1);
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 {
shader_addline(&buffer, "%s%s tex%u, fragment.texcoord[%u], texture[%u], %s;\n",
instr, sat, stage, stage, stage, textype);
@ -3122,7 +3133,8 @@ const struct fragment_pipeline arbfp_fragment_pipeline = {
arbfp_alloc,
arbfp_free,
shader_arb_conv_supported,
arbfp_fragmentstate_template
arbfp_fragmentstate_template,
TRUE /* We can disable projected textures */
};
#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));
if(op[stage + 1].projected == proj_none) {
swizzle = GL_SWIZZLE_STR_ATI;
} else {
} else if(op[stage + 1].projected == proj_count4) {
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",
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) {
swizzle = GL_SWIZZLE_STR_ATI;
} else if(op[stage].projected == proj_count3) {
/* TODO: D3DTTFF_COUNT3 | D3DTTFF_PROJECTED would be 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;
swizzle = GL_SWIZZLE_STR_DR_ATI;
} else {
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));
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
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(6), { STATE_SAMPLER(6), 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 },
};
@ -1107,5 +1116,6 @@ const struct fragment_pipeline atifs_fragment_pipeline = {
atifs_alloc,
atifs_free,
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;
IWineD3DVertexShaderImpl *vs = (IWineD3DVertexShaderImpl *) vertexshader;
IWineD3DPixelShaderImpl *ps = (IWineD3DPixelShaderImpl *) pixelshader;
IWineD3DDeviceImpl *device;
DWORD vs_major = vs ? WINED3DSHADER_VERSION_MAJOR(vs->baseShader.hex_version) : 0;
DWORD ps_major = ps ? WINED3DSHADER_VERSION_MAJOR(ps->baseShader.hex_version) : 0;
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.
* 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");
for(i = 0; i < min(8, MAX_REG_TEXCRD); i++) {
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_free,
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 = {
@ -819,5 +820,6 @@ const struct fragment_pipeline nvrc_fragment_pipeline = {
nvrc_fragment_alloc,
nvrc_fragment_free,
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
*
@ -3139,7 +3140,8 @@ static void transform_texture(DWORD state, IWineD3DStateBlockImpl *stateblock, W
context->last_was_rhw,
stateblock->wineD3DDevice->strided_streams.u.s.texCoords[coordIdx].dwStride ?
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 */
if(context->lastWasPow2Texture[texUnit] && stateblock->textures[texUnit]) {
@ -5565,7 +5567,8 @@ const struct fragment_pipeline ffp_fragment_pipeline = {
ffp_fragment_alloc,
ffp_fragment_free,
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) {

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*/
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];
@ -1187,15 +1188,17 @@ void set_texture_matrix(const float *smat, DWORD flags, BOOL calculatedCoords, B
memcpy(mat, smat, 16 * sizeof(float));
if (flags & WINED3DTTFF_PROJECTED) {
switch (flags & ~WINED3DTTFF_PROJECTED) {
case WINED3DTTFF_COUNT2:
mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13];
mat[1] = mat[5] = mat[9] = mat[13] = 0;
break;
case WINED3DTTFF_COUNT3:
mat[3] = mat[2], mat[7] = mat[6], mat[11] = mat[10], mat[15] = mat[14];
mat[2] = mat[6] = mat[10] = mat[14] = 0;
break;
if(!ffp_proj_control) {
switch (flags & ~WINED3DTTFF_PROJECTED) {
case WINED3DTTFF_COUNT2:
mat[3] = mat[1], mat[7] = mat[5], mat[11] = mat[9], mat[15] = mat[13];
mat[1] = mat[5] = mat[9] = mat[13] = 0;
break;
case WINED3DTTFF_COUNT3:
mat[3] = mat[2], mat[7] = mat[6], mat[11] = mat[10], mat[15] = mat[14];
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 */
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");
}
}
switch (flags & ~WINED3DTTFF_PROJECTED) {
/* case WINED3DTTFF_COUNT1: Won't ever get here */
case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0;
/* OpenGL divides the first 3 vertex coord by the 4th by default,
* 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
* 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
* or a replacement shader
*/
default: mat[3] = mat[7] = mat[11] = 0; mat[15] = 1;
if(!ffp_proj_control) {
switch (flags & ~WINED3DTTFF_PROJECTED) {
/* case WINED3DTTFF_COUNT1: Won't ever get here */
case WINED3DTTFF_COUNT2: mat[2] = mat[6] = mat[10] = mat[14] = 0;
/* OpenGL divides the first 3 vertex coord by the 4th by default,
* 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
* 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
* or a replacement shader
*/
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);
BOOL (*conv_supported)(WINED3DFORMAT conv);
const struct StateEntryTemplate *states;
BOOL ffp_proj_control;
};
extern const struct StateEntryTemplate misc_state_template[];
@ -1816,7 +1817,7 @@ GLenum StencilOp(DWORD op);
GLenum CompareFunc(DWORD func);
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_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 sampler_texdim(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context);
void tex_alphaop(DWORD state, IWineD3DStateBlockImpl *stateblock, WineD3DContext *context);