wined3d: Relative addressing offsets are limited to [-64; 63] in arb.
diff --git a/dlls/wined3d/arb_program_shader.c b/dlls/wined3d/arb_program_shader.c
index 20d338e..d6ca4a8 100644
--- a/dlls/wined3d/arb_program_shader.c
+++ b/dlls/wined3d/arb_program_shader.c
@@ -467,7 +467,15 @@
strcat(hwLine, tmpReg);
break;
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);
break;
case WINED3DSPR_ADDR: /*case D3DSPR_TEXTURE:*/
@@ -1571,6 +1579,7 @@
/* Map the opcode 1-to-1 to the GL code */
void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
+ IWineD3DVertexShaderImpl *shader = (IWineD3DVertexShaderImpl*) arg->shader;
CONST SHADER_OPCODE* curOpcode = arg->opcode;
SHADER_BUFFER* buffer = arg->buffer;
DWORD dst = arg->dst;
@@ -1580,9 +1589,17 @@
char tmpLine[256];
unsigned int i;
- if ((curOpcode->opcode == WINED3DSIO_MOV && dst_regtype == WINED3DSPR_ADDR) || curOpcode->opcode == WINED3DSIO_MOVA)
- strcpy(tmpLine, "ARL");
- else
+ if ((curOpcode->opcode == WINED3DSIO_MOV && dst_regtype == WINED3DSPR_ADDR) || curOpcode->opcode == WINED3DSIO_MOVA) {
+ if(shader->rel_offset) {
+ 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);
if (curOpcode->num_params > 0) {
diff --git a/dlls/wined3d/baseshader.c b/dlls/wined3d/baseshader.c
index df0ac0c..520554f 100644
--- a/dlls/wined3d/baseshader.c
+++ b/dlls/wined3d/baseshader.c
@@ -446,6 +446,15 @@
else if (WINED3DSPR_MISCTYPE == regtype && reg == 0 && pshader)
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;
+ }
+ }
}
}
}
diff --git a/dlls/wined3d/directx.c b/dlls/wined3d/directx.c
index a77ea96..ada76e2 100644
--- a/dlls/wined3d/directx.c
+++ b/dlls/wined3d/directx.c
@@ -407,6 +407,38 @@
**********************************************************/
#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) {
const char *GL_Extensions = NULL;
const char *WGL_Extensions = NULL;
@@ -691,7 +723,7 @@
if (gl_info->supported[ARB_FRAGMENT_PROGRAM]) {
GLint 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 {
gl_info->max_fragment_samplers = max(gl_info->max_fragment_samplers, gl_max);
}
@@ -747,6 +779,8 @@
GL_EXTCALL(glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, &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);
+
+ gl_info->arb_vs_offset_limit = test_arb_vs_offset_limit(gl_info);
}
if (gl_info->supported[ARB_VERTEX_SHADER]) {
glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, &gl_max);
diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c
index 5c9da19..e49e34a 100644
--- a/dlls/wined3d/vertexshader.c
+++ b/dlls/wined3d/vertexshader.c
@@ -353,7 +353,9 @@
* 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.
*/
- 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");
@@ -369,7 +371,7 @@
/* Create the hw ARB shader */
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 */
if (GL_VEND(MESA) || GL_VEND(WINE))
@@ -377,7 +379,7 @@
min(95, This->baseShader.limits.constant_float);
/* 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");
}
@@ -409,7 +411,7 @@
/* Z coord [0;1]->[-1;1] mapping, see comment in transform_projection in state.c
* 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");
@@ -566,6 +568,8 @@
list_init(&This->baseShader.constantsI);
/* 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));
hr = shader_get_registers_used((IWineD3DBaseShader*) This, reg_maps,
This->semantics_in, This->semantics_out, pFunction, NULL);
@@ -573,6 +577,23 @@
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 */
if (NULL != pFunction) {
void *function;
diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h
index 56ba569..baa9152 100644
--- a/dlls/wined3d/wined3d_private.h
+++ b/dlls/wined3d/wined3d_private.h
@@ -2051,6 +2051,9 @@
/* run time datas... */
VSHADERDATA *data;
+ UINT min_rel_offset, max_rel_offset;
+ UINT rel_offset;
+
#if 0 /* needs reworking */
/* run time datas */
VSHADERINPUTDATA input;
diff --git a/include/wine/wined3d_gl.h b/include/wine/wined3d_gl.h
index 8694f37..7fbe25c 100644
--- a/include/wine/wined3d_gl.h
+++ b/include/wine/wined3d_gl.h
@@ -3744,6 +3744,8 @@
GL_VSVersion vs_nv_version;
GL_VSVersion vs_ati_version;
+ BOOL arb_vs_offset_limit;
+
BOOL supported[OPENGL_SUPPORTED_EXT_END + 1];
/** OpenGL EXT and ARB functions ptr */