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

wined3d: Relative addressing offsets are limited to [-64; 63] in arb.

parent aafcae47
...@@ -467,7 +467,15 @@ static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param, ...@@ -467,7 +467,15 @@ static void vshader_program_add_param(SHADER_OPCODE_ARG *arg, const DWORD param,
strcat(hwLine, tmpReg); strcat(hwLine, tmpReg);
break; break;
case WINED3DSPR_CONST: case WINED3DSPR_CONST:
sprintf(tmpReg, "C[%s%u]", (param & WINED3DSHADER_ADDRMODE_RELATIVE) ? "A0.x + " : "", reg); if(param & WINED3DSHADER_ADDRMODE_RELATIVE) {
if(reg - This->rel_offset >= 0) {
sprintf(tmpReg, "C[A0.x + %u]", reg - This->rel_offset);
} else {
sprintf(tmpReg, "C[A0.x - %u]", -reg + This->rel_offset);
}
} else {
sprintf(tmpReg, "C[%u]", reg);
}
strcat(hwLine, tmpReg); strcat(hwLine, tmpReg);
break; break;
case WINED3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/ case WINED3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
...@@ -1571,6 +1579,7 @@ void shader_hw_sincos(SHADER_OPCODE_ARG* arg) { ...@@ -1571,6 +1579,7 @@ void shader_hw_sincos(SHADER_OPCODE_ARG* arg) {
/* Map the opcode 1-to-1 to the GL code */ /* Map the opcode 1-to-1 to the GL code */
void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) { void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl*) arg->shader;
CONST SHADER_OPCODE* curOpcode = arg->opcode; CONST SHADER_OPCODE* curOpcode = arg->opcode;
SHADER_BUFFER* buffer = arg->buffer; SHADER_BUFFER* buffer = arg->buffer;
DWORD dst = arg->dst; DWORD dst = arg->dst;
...@@ -1580,9 +1589,17 @@ void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) { ...@@ -1580,9 +1589,17 @@ void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
char tmpLine[256]; char tmpLine[256];
unsigned int i; unsigned int i;
if ((curOpcode->opcode == WINED3DSIO_MOV && dst_regtype == WINED3DSPR_ADDR) || curOpcode->opcode == WINED3DSIO_MOVA) if ((curOpcode->opcode == WINED3DSIO_MOV && dst_regtype == WINED3DSPR_ADDR) || curOpcode->opcode == WINED3DSIO_MOVA) {
strcpy(tmpLine, "ARL"); if(shader->rel_offset) {
else memset(tmpLine, 0, sizeof(tmpLine));
vshader_program_add_param(arg, src[0], TRUE, tmpLine);
shader_addline(buffer, "ADD TMP.x, %s, helper_const.z;\n", tmpLine);
shader_addline(buffer, "ARL A0.x, TMP.x;\n");
return;
} else {
strcpy(tmpLine, "ARL");
}
} else
strcpy(tmpLine, curOpcode->glname); strcpy(tmpLine, curOpcode->glname);
if (curOpcode->num_params > 0) { if (curOpcode->num_params > 0) {
......
...@@ -446,6 +446,15 @@ HRESULT shader_get_registers_used( ...@@ -446,6 +446,15 @@ HRESULT shader_get_registers_used(
else if (WINED3DSPR_MISCTYPE == regtype && reg == 0 && pshader) else if (WINED3DSPR_MISCTYPE == regtype && reg == 0 && pshader)
reg_maps->vpos = 1; reg_maps->vpos = 1;
else if(WINED3DSPR_CONST == regtype && !pshader &&
param & WINED3DSHADER_ADDRMODE_RELATIVE) {
if(reg <= ((IWineD3DVertexShaderImpl *) This)->min_rel_offset) {
((IWineD3DVertexShaderImpl *) This)->min_rel_offset = reg;
} else if(reg >= ((IWineD3DVertexShaderImpl *) This)->max_rel_offset) {
((IWineD3DVertexShaderImpl *) This)->max_rel_offset = reg;
}
}
} }
} }
} }
......
...@@ -407,6 +407,38 @@ static void select_shader_max_constants( ...@@ -407,6 +407,38 @@ static void select_shader_max_constants(
**********************************************************/ **********************************************************/
#define GLINFO_LOCATION (*gl_info) #define GLINFO_LOCATION (*gl_info)
static inline BOOL test_arb_vs_offset_limit(WineD3D_GL_Info *gl_info) {
GLuint prog;
BOOL ret = FALSE;
const char *testcode =
"!!ARBvp1.0\n"
"PARAM C[66] = { program.env[0..65] };\n"
"ADDRESS A0;"
"ARL A0.x, 0.0;\n"
"MOV result.position, C[A0.x + 65];\n"
"END\n";
while(glGetError());
GL_EXTCALL(glGenProgramsARB(1, &prog));
if(!prog) {
ERR("Failed to create an ARB offset limit test program\n");
}
GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, prog));
GL_EXTCALL(glProgramStringARB(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB,
strlen(testcode), testcode));
if(glGetError() != 0) {
TRACE("OpenGL implementation does not allow indirect addressing offsets > 63\n");
TRACE("error: %s\n", debugstr_a((const char *)glGetString(GL_PROGRAM_ERROR_STRING_ARB)));
ret = TRUE;
} else TRACE("OpenGL implementation allows offsets > 63\n");
GL_EXTCALL(glBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0));
GL_EXTCALL(glDeleteProgramsARB(1, &prog));
checkGLcall("ARB vp offset limit test cleanup\n");
return ret;
}
BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) {
const char *GL_Extensions = NULL; const char *GL_Extensions = NULL;
const char *WGL_Extensions = NULL; const char *WGL_Extensions = NULL;
...@@ -691,7 +723,7 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { ...@@ -691,7 +723,7 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) {
if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) { if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) {
GLint tmp; GLint tmp;
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &tmp); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &tmp);
gl_info->max_fragment_samplers = min(MAX_FRAGMENT_SAMPLERS, tmp); gl_info->max_fragment_samplers = min(8, tmp);
} else { } else {
gl_info->max_fragment_samplers = max(gl_info->max_fragment_samplers, gl_max); gl_info->max_fragment_samplers = max(gl_info->max_fragment_samplers, gl_max);
} }
...@@ -747,6 +779,8 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) { ...@@ -747,6 +779,8 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) {
GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &gl_max)); GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &gl_max));
gl_info->vs_arb_max_instructions = gl_max; gl_info->vs_arb_max_instructions = gl_max;
TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM native instructions: %d\n", gl_info->vs_arb_max_instructions); TRACE_(d3d_caps)("Max ARB_VERTEX_PROGRAM native instructions: %d\n", gl_info->vs_arb_max_instructions);
gl_info->arb_vs_offset_limit = test_arb_vs_offset_limit(gl_info);
} }
if (gl_info->supported[ARB_VERTEX_SHADER]) { if (gl_info->supported[ARB_VERTEX_SHADER]) {
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &gl_max); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &gl_max);
......
...@@ -353,7 +353,9 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader( ...@@ -353,7 +353,9 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader(
* before the homogenous divide, so we have to take the w into account: z = ((z / w) * 2 - 1) * w, * before the homogenous divide, so we have to take the w into account: z = ((z / w) * 2 - 1) * w,
* which is the same as z = z / 2 - w. * which is the same as z = z / 2 - w.
*/ */
shader_addline(&buffer, "gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n"); shader_addline(&buffer, "tmp0 = gl_Position;\n");
shader_addline(&buffer, "gl_Position.z = tmp0.z * 2.0;\n");
shader_addline(&buffer, "gl_Position.z = gl_Position.z - gl_Position.w;\n");
shader_addline(&buffer, "}\n"); shader_addline(&buffer, "}\n");
...@@ -369,7 +371,7 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader( ...@@ -369,7 +371,7 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader(
/* Create the hw ARB shader */ /* Create the hw ARB shader */
shader_addline(&buffer, "!!ARBvp1.0\n"); shader_addline(&buffer, "!!ARBvp1.0\n");
shader_addline(&buffer, "PARAM zfixup = { 2.0, -1.0, 0.0, 0.0 };\n"); shader_addline(&buffer, "PARAM helper_const = { 2.0, -1.0, %d.0, 0.0 };\n", This->rel_offset);
/* Mesa supports only 95 constants */ /* Mesa supports only 95 constants */
if (GL_VEND(MESA) || GL_VEND(WINE)) if (GL_VEND(MESA) || GL_VEND(WINE))
...@@ -377,7 +379,7 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader( ...@@ -377,7 +379,7 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader(
min(95, This->baseShader.limits.constant_float); min(95, This->baseShader.limits.constant_float);
/* Some instructions need a temporary register. Add it if needed, but only if it is really needed */ /* Some instructions need a temporary register. Add it if needed, but only if it is really needed */
if(reg_maps->usesnrm) { if(reg_maps->usesnrm || This->rel_offset) {
shader_addline(&buffer, "TEMP TMP;\n"); shader_addline(&buffer, "TEMP TMP;\n");
} }
...@@ -409,7 +411,7 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader( ...@@ -409,7 +411,7 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader(
/* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c /* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
* and the glsl equivalent * and the glsl equivalent
*/ */
shader_addline(&buffer, "MAD TMP_OUT.z, TMP_OUT.z, zfixup.x, -TMP_OUT.w;\n"); shader_addline(&buffer, "MAD TMP_OUT.z, TMP_OUT.z, helper_const.x, -TMP_OUT.w;\n");
shader_addline(&buffer, "MOV result.position, TMP_OUT;\n"); shader_addline(&buffer, "MOV result.position, TMP_OUT;\n");
...@@ -566,6 +568,8 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader ...@@ -566,6 +568,8 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader
list_init(&This->baseShader.constantsI); list_init(&This->baseShader.constantsI);
/* Second pass: figure out registers used, semantics, etc.. */ /* Second pass: figure out registers used, semantics, etc.. */
This->min_rel_offset = GL_LIMITS(vshader_constantsF);
This->max_rel_offset = 0;
memset(reg_maps, 0, sizeof(shader_reg_maps)); memset(reg_maps, 0, sizeof(shader_reg_maps));
hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps, hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps,
This->semantics_in, This->semantics_out, pFunction, NULL); This->semantics_in, This->semantics_out, pFunction, NULL);
...@@ -573,6 +577,23 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader ...@@ -573,6 +577,23 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader
This->baseShader.shader_mode = deviceImpl->vs_selected_mode; This->baseShader.shader_mode = deviceImpl->vs_selected_mode;
if(deviceImpl->vs_selected_mode == SHADER_ARB &&
(GLINFO_LOCATION).arb_vs_offset_limit &&
This->min_rel_offset <= This->max_rel_offset) {
if(This->max_rel_offset - This->min_rel_offset > 127) {
FIXME("The difference between the minimum and maximum relative offset is > 127\n");
FIXME("Which this OpenGL implementation does not support. Try using GLSL\n");
FIXME("Min: %d, Max: %d\n", This->min_rel_offset, This->max_rel_offset);
} else if(This->max_rel_offset - This->min_rel_offset > 63) {
This->rel_offset = This->min_rel_offset + 63;
} else if(This->max_rel_offset > 63) {
This->rel_offset = This->min_rel_offset;
} else {
This->rel_offset = 0;
}
}
/* copy the function ... because it will certainly be released by application */ /* copy the function ... because it will certainly be released by application */
if (NULL != pFunction) { if (NULL != pFunction) {
void *function; void *function;
......
...@@ -2051,6 +2051,9 @@ typedef struct IWineD3DVertexShaderImpl { ...@@ -2051,6 +2051,9 @@ typedef struct IWineD3DVertexShaderImpl {
/* run time datas... */ /* run time datas... */
VSHADERDATA *data; VSHADERDATA *data;
UINT min_rel_offset, max_rel_offset;
UINT rel_offset;
#if 0 /* needs reworking */ #if 0 /* needs reworking */
/* run time datas */ /* run time datas */
VSHADERINPUTDATA input; VSHADERINPUTDATA input;
......
...@@ -3744,6 +3744,8 @@ typedef struct _WineD3D_GL_Info { ...@@ -3744,6 +3744,8 @@ typedef struct _WineD3D_GL_Info {
GL_VSVersion vs_nv_version; GL_VSVersion vs_nv_version;
GL_VSVersion vs_ati_version; GL_VSVersion vs_ati_version;
BOOL arb_vs_offset_limit;
BOOL supported[OPENGL_SUPPORTED_EXT_END + 1]; BOOL supported[OPENGL_SUPPORTED_EXT_END + 1];
/** OpenGL EXT and ARB functions ptr */ /** OpenGL EXT and ARB functions ptr */
......
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