wined3d: Use gl_Color and gl_SecondaryColor to support more varyings in SM3.0 shaders.

SM3.0 requires 10 4 component float varyings for passing stuff between
vertex and pixel shaders. GF7 and earlier report 8 generic varyings +
gl_Color and gl_SecondaryColor in GLSL. This patch allows us to use
gl_Color and gl_SecondaryColor to get 2 extra varyings, which some
games, like C&C3 with highest gfx settings, require.
This commit is contained in:
H. Verbeet 2008-06-19 00:36:35 +02:00 committed by Alexandre Julliard
parent 4a4ab5f2ae
commit a6fa6a4a31
3 changed files with 109 additions and 42 deletions

View File

@ -39,12 +39,12 @@ WINE_DECLARE_DEBUG_CHANNEL(d3d_caps);
#define GLINFO_LOCATION (*gl_info)
typedef struct {
char reg_name[50];
char reg_name[150];
char mask_str[6];
} glsl_dst_param_t;
typedef struct {
char reg_name[50];
char reg_name[150];
char param_str[100];
} glsl_src_param_t;
@ -836,7 +836,7 @@ static void shader_glsl_get_register_name(
WineD3D_GL_Info* gl_info = &deviceImpl->adapter->gl_info;
char pshader = shader_is_pshader_version(This->baseShader.hex_version);
char tmpStr[50];
char tmpStr[150];
*is_color = FALSE;
@ -848,6 +848,8 @@ static void shader_glsl_get_register_name(
if (pshader) {
/* Pixel shaders >= 3.0 */
if (WINED3DSHADER_VERSION_MAJOR(This->baseShader.hex_version) >= 3) {
DWORD in_count = GL_LIMITS(glsl_varyings) / 4;
if (param & WINED3DSHADER_ADDRMODE_RELATIVE) {
glsl_src_param_t rel_param;
shader_glsl_add_src_param(arg, addr_token, 0, WINED3DSP_WRITEMASK_0, &rel_param);
@ -856,14 +858,33 @@ static void shader_glsl_get_register_name(
* operation there
*/
if(((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg]) {
sprintf(tmpStr, "IN[%s + %u]", rel_param.param_str,
((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg]);
if (((IWineD3DPixelShaderImpl *)This)->declared_in_count > in_count) {
sprintf(tmpStr, "((%s + %u) > %d ? (%s + %u) > %d ? gl_SecondaryColor : gl_Color : IN[%s + %u])",
rel_param.param_str, ((IWineD3DPixelShaderImpl *)This)->input_reg_map[reg], in_count - 1,
rel_param.param_str, ((IWineD3DPixelShaderImpl *)This)->input_reg_map[reg], in_count,
rel_param.param_str, ((IWineD3DPixelShaderImpl *)This)->input_reg_map[reg]);
} else {
sprintf(tmpStr, "IN[%s + %u]", rel_param.param_str, ((IWineD3DPixelShaderImpl *)This)->input_reg_map[reg]);
}
} else {
sprintf(tmpStr, "IN[%s]", rel_param.param_str);
if (((IWineD3DPixelShaderImpl *)This)->declared_in_count > in_count) {
sprintf(tmpStr, "((%s) > %d ? (%s) > %d ? gl_SecondaryColor : gl_Color : IN[%s])",
rel_param.param_str, in_count - 1,
rel_param.param_str, in_count,
rel_param.param_str);
} else {
sprintf(tmpStr, "IN[%s]", rel_param.param_str);
}
}
} else {
sprintf(tmpStr, "IN[%u]",
((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg]);
DWORD idx = ((IWineD3DPixelShaderImpl *) This)->input_reg_map[reg];
if (idx == in_count) {
sprintf(tmpStr, "gl_Color");
} else if (idx == in_count + 1) {
sprintf(tmpStr, "gl_SecondaryColor");
} else {
sprintf(tmpStr, "IN[%u]", idx);
}
}
} else {
if (reg==0)
@ -2804,20 +2825,40 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
DWORD register_token, register_token_out;
DWORD usage, usage_idx, usage_out, usage_idx_out;
DWORD *set;
DWORD in_idx;
DWORD in_count = GL_LIMITS(glsl_varyings) / 4;
char reg_mask[6], reg_mask_out[6];
char destination[50];
set = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*set) * (GL_LIMITS(glsl_varyings) / 4));
set = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*set) * (in_count + 2));
if (!semantics_out) {
/* Save gl_FrontColor & gl_FrontSecondaryColor before overwriting them. */
shader_addline(buffer, "vec4 front_color = gl_FrontColor;");
shader_addline(buffer, "vec4 front_secondary_color = gl_FrontSecondaryColor;");
}
for(i = 0; i < MAX_REG_INPUT; i++) {
usage_token = semantics_in[i].usage;
if (!usage_token) continue;
if(map[i] >= (GL_LIMITS(glsl_varyings) / 4)) {
in_idx = map[i];
if (in_idx >= (in_count + 2)) {
FIXME("More input varyings declared than supported, expect issues\n");
continue;
} else if(map[i] == -1) {
/* Declared, but not read register */
continue;
}
if (in_idx == in_count) {
sprintf(destination, "gl_FrontColor");
} else if (in_idx == in_count + 1) {
sprintf(destination, "gl_FrontSecondaryColor");
} else {
sprintf(destination, "IN[%u]", in_idx);
}
register_token = semantics_in[i].reg;
usage = (usage_token & WINED3DSP_DCL_USAGE_MASK) >> WINED3DSP_DCL_USAGE_SHIFT;
@ -2828,34 +2869,34 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
switch(usage) {
case WINED3DDECLUSAGE_COLOR:
if (usage_idx == 0)
shader_addline(buffer, "IN[%u]%s = gl_FrontColor%s;\n",
map[i], reg_mask, reg_mask);
shader_addline(buffer, "%s%s = front_color%s;\n",
destination, reg_mask, reg_mask);
else if (usage_idx == 1)
shader_addline(buffer, "IN[%u]%s = gl_FrontSecondaryColor%s;\n",
map[i], reg_mask, reg_mask);
shader_addline(buffer, "%s%s = front_secondary_color%s;\n",
destination, reg_mask, reg_mask);
else
shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
map[i], reg_mask, reg_mask);
shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
destination, reg_mask, reg_mask);
break;
case WINED3DDECLUSAGE_TEXCOORD:
if (usage_idx < 8) {
shader_addline(buffer, "IN[%u]%s = gl_TexCoord[%u]%s;\n",
map[i], reg_mask, usage_idx, reg_mask);
shader_addline(buffer, "%s%s = gl_TexCoord[%u]%s;\n",
destination, reg_mask, usage_idx, reg_mask);
} else {
shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
map[i], reg_mask, reg_mask);
shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
destination, reg_mask, reg_mask);
}
break;
case WINED3DDECLUSAGE_FOG:
shader_addline(buffer, "IN[%u]%s = vec4(gl_FogFragCoord, 0.0, 0.0, 0.0)%s;\n",
map[i], reg_mask, reg_mask);
shader_addline(buffer, "%s%s = vec4(gl_FogFragCoord, 0.0, 0.0, 0.0)%s;\n",
destination, reg_mask, reg_mask);
break;
default:
shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
map[i], reg_mask, reg_mask);
shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
destination, reg_mask, reg_mask);
}
} else {
BOOL found = FALSE;
@ -2870,14 +2911,14 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
if(usage == usage_out &&
usage_idx == usage_idx_out) {
shader_addline(buffer, "IN[%u]%s = OUT[%u]%s;\n",
map[i], reg_mask, j, reg_mask);
shader_addline(buffer, "%s%s = OUT[%u]%s;\n",
destination, reg_mask, j, reg_mask);
found = TRUE;
}
}
if(!found) {
shader_addline(buffer, "IN[%u]%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
map[i], reg_mask, reg_mask);
shader_addline(buffer, "%s%s = vec4(0.0, 0.0, 0.0, 0.0)%s;\n",
destination, reg_mask, reg_mask);
}
}
}
@ -2886,7 +2927,7 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
* varyings. It shouldn't result in any real code executed on the GPU, since all read
* input varyings are assigned above, if the optimizer works properly.
*/
for(i = 0; i < GL_LIMITS(glsl_varyings) / 4; i++) {
for(i = 0; i < in_count + 2; i++) {
if(set[i] != WINED3DSP_WRITEMASK_ALL) {
unsigned int size = 0;
memset(reg_mask, 0, sizeof(reg_mask));
@ -2906,19 +2947,19 @@ static void handle_ps3_input(SHADER_BUFFER *buffer, semantic *semantics_in, sema
reg_mask[size] = 'w';
size++;
}
switch(size) {
case 1:
shader_addline(buffer, "IN[%u].%s = 0.0;\n", i, reg_mask);
break;
case 2:
shader_addline(buffer, "IN[%u].%s = vec2(0.0, 0.0);\n", i, reg_mask);
break;
case 3:
shader_addline(buffer, "IN[%u].%s = vec3(0.0, 0.0, 0.0);\n", i, reg_mask);
break;
case 4:
shader_addline(buffer, "IN[%u].%s = vec4(0.0, 0.0, 0.0, 0.0);\n", i, reg_mask);
break;
if (i == in_count) {
sprintf(destination, "gl_FrontColor");
} else if (i == in_count + 1) {
sprintf(destination, "gl_FrontSecondaryColor");
} else {
sprintf(destination, "IN[%u]", i);
}
if (size == 1) {
shader_addline(buffer, "%s.%s = 0.0;\n", destination, reg_mask);
} else {
shader_addline(buffer, "%s.%s = vec%u(0.0);\n", destination, reg_mask, size);
}
}
}
@ -3224,6 +3265,14 @@ static void set_glsl_shader_program(IWineD3DDevice *iface, BOOL use_ps, BOOL use
entry->ycorrection_location = GL_EXTCALL(glGetUniformLocationARB(programId, "ycorrection"));
checkGLcall("Find glsl program uniform locations");
if (pshader && WINED3DSHADER_VERSION_MAJOR(((IWineD3DPixelShaderImpl *)pshader)->baseShader.hex_version) >= 3
&& ((IWineD3DPixelShaderImpl *)pshader)->declared_in_count > GL_LIMITS(glsl_varyings) / 4) {
TRACE("Shader %d needs vertex color clamping disabled\n", programId);
entry->vertex_color_clamp = GL_FALSE;
} else {
entry->vertex_color_clamp = GL_FIXED_ONLY_ARB;
}
/* Set the shader to allow uniform loading on it */
GL_EXTCALL(glUseProgramObjectARB(programId));
checkGLcall("glUseProgramObjectARB(programId)");
@ -3305,10 +3354,24 @@ static void shader_glsl_select(IWineD3DDevice *iface, BOOL usePS, BOOL useVS) {
IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
WineD3D_GL_Info *gl_info = &This->adapter->gl_info;
GLhandleARB program_id = 0;
GLenum old_vertex_color_clamp, current_vertex_color_clamp;
old_vertex_color_clamp = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->vertex_color_clamp : GL_FIXED_ONLY_ARB;
if (useVS || usePS) set_glsl_shader_program(iface, usePS, useVS);
else This->stateBlock->glsl_program = NULL;
current_vertex_color_clamp = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->vertex_color_clamp : GL_FIXED_ONLY_ARB;
if (old_vertex_color_clamp != current_vertex_color_clamp) {
if (GL_SUPPORT(ARB_COLOR_BUFFER_FLOAT)) {
GL_EXTCALL(glClampColorARB(GL_CLAMP_VERTEX_COLOR_ARB, current_vertex_color_clamp));
checkGLcall("glClampColorARB");
} else {
FIXME("vertex color clamp needs to be changed, but extension not supported.\n");
}
}
program_id = This->stateBlock->glsl_program ? This->stateBlock->glsl_program->programId : 0;
if (program_id) TRACE("Using GLSL program %u\n", program_id);
GL_EXTCALL(glUseProgramObjectARB(program_id));

View File

@ -359,6 +359,7 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i
for(i = 0; i < MAX_REG_INPUT; i++) {
This->input_reg_map[i] = i;
}
This->declared_in_count = highest_reg_used + 1;
} else {
j = 0;
for(i = 0; i < MAX_REG_INPUT; i++) {
@ -369,6 +370,7 @@ static HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *i
This->input_reg_map[i] = -1;
}
}
This->declared_in_count = j;
}
}
This->baseShader.load_local_constsF = FALSE;

View File

@ -1830,6 +1830,7 @@ struct glsl_shader_prog_link {
GLhandleARB srgb_comparison_location;
GLhandleARB srgb_mul_low_location;
GLhandleARB ycorrection_location;
GLenum vertex_color_clamp;
GLhandleARB vshader;
GLhandleARB pshader;
};
@ -2343,6 +2344,7 @@ typedef struct IWineD3DPixelShaderImpl {
semantic semantics_in [MAX_REG_INPUT];
DWORD input_reg_map[MAX_REG_INPUT];
BOOL input_reg_used[MAX_REG_INPUT];
int declared_in_count;
/* run time data */
PSHADERDATA *data;