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,
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 @@ void shader_hw_sincos(SHADER_OPCODE_ARG* arg) {
/* 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 @@ void vshader_hw_map2gl(SHADER_OPCODE_ARG* arg) {
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) {
......
......@@ -446,6 +446,15 @@ HRESULT shader_get_registers_used(
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;
}
}
}
}
}
......
......@@ -407,6 +407,38 @@ static void select_shader_max_constants(
**********************************************************/
#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 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) {
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 @@ BOOL IWineD3DImpl_FillGLCaps(WineD3D_GL_Info *gl_info) {
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);
......
......@@ -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,
* 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 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader(
/* 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 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader(
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 @@ static VOID IWineD3DVertexShaderImpl_GenerateShader(
/* 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 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader
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 @@ static HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader
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;
......
......@@ -2051,6 +2051,9 @@ typedef struct IWineD3DVertexShaderImpl {
/* run time datas... */
VSHADERDATA *data;
UINT min_rel_offset, max_rel_offset;
UINT rel_offset;
#if 0 /* needs reworking */
/* run time datas */
VSHADERINPUTDATA input;
......
......@@ -3744,6 +3744,8 @@ typedef struct _WineD3D_GL_Info {
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 */
......
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