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:
parent
ec4955630e
commit
af8d268a39
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue