wined3d: Clean up per version shader limits code.

This commit is contained in:
Ivan Gyurdiev 2006-05-08 17:09:21 -04:00 committed by Alexandre Julliard
parent 5f10560762
commit c93239d36d
3 changed files with 178 additions and 138 deletions

View File

@ -975,6 +975,61 @@ inline static void pshader_program_get_registers_used(
} }
} }
void pshader_set_version(
IWineD3DPixelShaderImpl *This,
DWORD version) {
DWORD major = (version >> 8) & 0x0F;
DWORD minor = version & 0x0F;
This->baseShader.hex_version = version;
This->baseShader.version = major * 10 + minor;
TRACE("ps_%lu_%lu\n", major, minor);
This->baseShader.limits.address = 0;
switch (This->baseShader.version) {
case 10:
case 11:
case 12:
case 13: This->baseShader.limits.temporary = 2;
This->baseShader.limits.constant_float = 8;
This->baseShader.limits.constant_int = 0;
This->baseShader.limits.constant_bool = 0;
This->baseShader.limits.texture = 4;
break;
case 14: This->baseShader.limits.temporary = 6;
This->baseShader.limits.constant_float = 8;
This->baseShader.limits.constant_int = 0;
This->baseShader.limits.constant_bool = 0;
This->baseShader.limits.texture = 6;
break;
/* FIXME: temporaries must match D3DPSHADERCAPS2_0.NumTemps */
case 20: This->baseShader.limits.temporary = 32;
This->baseShader.limits.constant_float = 32;
This->baseShader.limits.constant_int = 16;
This->baseShader.limits.constant_bool = 16;
This->baseShader.limits.texture = 8;
break;
case 30: This->baseShader.limits.temporary = 32;
This->baseShader.limits.constant_float = 224;
This->baseShader.limits.constant_int = 16;
This->baseShader.limits.constant_bool = 16;
This->baseShader.limits.texture = 0;
break;
default: This->baseShader.limits.temporary = 32;
This->baseShader.limits.constant_float = 8;
This->baseShader.limits.constant_int = 0;
This->baseShader.limits.constant_bool = 0;
This->baseShader.limits.texture = 8;
FIXME("Unrecognized pixel shader version %lu!\n", version);
}
}
/* NOTE: A description of how to parse tokens can be found at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/graphics/hh/graphics/usermodedisplaydriver_shader_cc8e4e05-f5c3-4ec0-8853-8ce07c1551b2.xml.asp */ /* NOTE: A description of how to parse tokens can be found at http://msdn.microsoft.com/library/default.asp?url=/library/en-us/graphics/hh/graphics/usermodedisplaydriver_shader_cc8e4e05-f5c3-4ec0-8853-8ce07c1551b2.xml.asp */
inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelShader *iface, CONST DWORD *pFunction) { inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelShader *iface, CONST DWORD *pFunction) {
IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface;
@ -991,7 +1046,7 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelSha
BOOL saturate; /* clamp to 0.0 -> 1.0*/ BOOL saturate; /* clamp to 0.0 -> 1.0*/
int row = 0; /* not sure, something to do with macros? */ int row = 0; /* not sure, something to do with macros? */
DWORD tcw[2]; DWORD tcw[2];
int version = 0; /* The version of the shader */ int version = This->baseShader.version;
/* Keep bitmaps of used temporary and texture registers */ /* Keep bitmaps of used temporary and texture registers */
DWORD tempsUsed, texUsed; DWORD tempsUsed, texUsed;
@ -1011,6 +1066,9 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelSha
buffer.bsize = 0; buffer.bsize = 0;
buffer.lineNo = 0; buffer.lineNo = 0;
/* FIXME: if jumps are used, use GLSL, else use ARB_fragment_program */
shader_addline(&buffer, "!!ARBfp1.0\n");
/* TODO: Think about using a first pass to work out what's required for the second pass. */ /* TODO: Think about using a first pass to work out what's required for the second pass. */
for(i = 0; i < WINED3D_PSHADER_MAX_CONSTANTS; i++) for(i = 0; i < WINED3D_PSHADER_MAX_CONSTANTS; i++)
This->constants[i] = 0; This->constants[i] = 0;
@ -1021,6 +1079,33 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelSha
/* TODO: check register usage against GL/Directx limits, and fail if they're exceeded */ /* TODO: check register usage against GL/Directx limits, and fail if they're exceeded */
/* Pre-declare registers */
for(i = 0; i < This->baseShader.limits.texture; i++) {
if (texUsed & (1 << i))
shader_addline(&buffer,"TEMP T%lu;\n", i);
}
for(i = 0; i < This->baseShader.limits.temporary; i++) {
if (tempsUsed & (1 << i))
shader_addline(&buffer, "TEMP R%lu;\n", i);
}
/* Necessary for internal operations */
shader_addline(&buffer, "TEMP TMP;\n");
shader_addline(&buffer, "TEMP TMP2;\n");
shader_addline(&buffer, "TEMP TA;\n");
shader_addline(&buffer, "TEMP TB;\n");
shader_addline(&buffer, "TEMP TC;\n");
shader_addline(&buffer, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n");
shader_addline(&buffer, "PARAM coefmul = { 2, 4, 8, 16 };\n");
shader_addline(&buffer, "PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n");
/* Texture coordinate registers must be pre-loaded */
for (i = 0; i < This->baseShader.limits.texture; i++) {
if (texUsed & (1 << i))
shader_addline(&buffer, "MOV T%lu, fragment.texcoord[%lu];\n", i, i);
}
/* Second pass, process opcodes */ /* Second pass, process opcodes */
if (NULL != pToken) { if (NULL != pToken) {
while (D3DPS_END() != *pToken) { while (D3DPS_END() != *pToken) {
@ -1029,79 +1114,15 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelSha
instructionSize = pToken & SIZEBITS >> 27; instructionSize = pToken & SIZEBITS >> 27;
} }
#endif #endif
if (pshader_is_version_token(*pToken)) { /** version */
int numTemps;
int numConstants;
int numTex;
/* Extract version *10 into integer value (ie. 1.0 == 10, 1.1==11 etc */
version = (((*pToken >> 8) & 0x0F) * 10) + (*pToken & 0x0F);
TRACE("found version token ps.%lu.%lu;\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F));
/* Each release of pixel shaders has had different numbers of temp registers */
switch (version) {
case 10:
case 11:
case 12:
case 13:numTemps=12;
numConstants=8;
numTex=4;
break;
case 14: numTemps=12;
numConstants=8;
numTex=6;
break;
case 20: numTemps=12;
numConstants=8;
numTex=8;
FIXME("No work done yet to support ps2.0 in hw\n");
break;
case 30: numTemps=32;
numConstants=8;
numTex=0;
FIXME("No work done yet to support ps3.0 in hw\n");
break;
default:
numTemps=12;
numConstants=8;
numTex=8;
FIXME("Unrecognized pixel shader version!\n");
}
/* FIXME: if jumps are used, use GLSL, else use ARB_fragment_program */
shader_addline(&buffer, "!!ARBfp1.0\n");
for(i = 0; i < numTex; i++) {
if (texUsed & (1 << i))
shader_addline(&buffer,"TEMP T%lu;\n", i);
}
for(i = 0; i < numTemps; i++) {
if (tempsUsed & (1 << i))
shader_addline(&buffer, "TEMP R%lu;\n", i);
}
shader_addline(&buffer, "TEMP TMP;\n");
shader_addline(&buffer, "TEMP TMP2;\n");
shader_addline(&buffer, "TEMP TA;\n");
shader_addline(&buffer, "TEMP TB;\n");
shader_addline(&buffer, "TEMP TC;\n");
shader_addline(&buffer, "PARAM coefdiv = { 0.5, 0.25, 0.125, 0.0625 };\n");
shader_addline(&buffer, "PARAM coefmul = { 2, 4, 8, 16 };\n");
shader_addline(&buffer, "PARAM one = { 1.0, 1.0, 1.0, 1.0 };\n");
for(i = 0; i < numTex; i++) {
if (texUsed & (1 << i))
shader_addline(&buffer, "MOV T%lu, fragment.texcoord[%lu];\n", i, i);
}
/* Skip version token */
if (pshader_is_version_token(*pToken)) {
++pToken; ++pToken;
continue; continue;
} }
if (pshader_is_comment_token(*pToken)) { /** comment */ /* Skip comment tokens */
if (pshader_is_comment_token(*pToken)) {
DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT; DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
++pToken; ++pToken;
TRACE("#%s\n", (char*)pToken); TRACE("#%s\n", (char*)pToken);
@ -1742,8 +1763,7 @@ HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *iface, C
if (NULL != pToken) { if (NULL != pToken) {
while (D3DPS_END() != *pToken) { while (D3DPS_END() != *pToken) {
if (pshader_is_version_token(*pToken)) { /** version */ if (pshader_is_version_token(*pToken)) { /** version */
This->baseShader.version = (((*pToken >> 8) & 0x0F) * 10) + (*pToken & 0x0F); pshader_set_version(This, *pToken);
TRACE("ps_%lu_%lu\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F));
++pToken; ++pToken;
++len; ++len;
continue; continue;

View File

@ -1036,6 +1036,51 @@ static void parse_decl_usage(IWineD3DVertexShaderImpl *This, INT usage, INT arra
} }
} }
void vshader_set_version(
IWineD3DVertexShaderImpl *This,
DWORD version) {
DWORD major = (version >> 8) & 0x0F;
DWORD minor = version & 0x0F;
This->baseShader.hex_version = version;
This->baseShader.version = major * 10 + minor;
TRACE("vs_%lu_%lu\n", major, minor);
This->baseShader.limits.texture = 0;
/* Must match D3DCAPS9.MaxVertexShaderConst: at least 256 for vs_2_0 */
This->baseShader.limits.constant_float = WINED3D_VSHADER_MAX_CONSTANTS;
switch (This->baseShader.version) {
case 10:
case 11: This->baseShader.limits.temporary = 12;
This->baseShader.limits.constant_bool = 0;
This->baseShader.limits.constant_int = 0;
This->baseShader.limits.address = 1;
break;
case 20:
case 21: This->baseShader.limits.temporary = 12;
This->baseShader.limits.constant_bool = 16;
This->baseShader.limits.constant_int = 16;
This->baseShader.limits.address = 1;
break;
case 30: This->baseShader.limits.temporary = 32;
This->baseShader.limits.constant_bool = 32;
This->baseShader.limits.constant_int = 32;
This->baseShader.limits.address = 1;
break;
default: This->baseShader.limits.temporary = 12;
This->baseShader.limits.constant_bool = 0;
This->baseShader.limits.constant_int = 0;
This->baseShader.limits.address = 1;
FIXME("Unrecognized vertex shader version %lu!\n", version);
}
}
/** /**
* Function parser ... * Function parser ...
*/ */
@ -1179,6 +1224,29 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS
nUseTempRegister <= GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB nUseTempRegister <= GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB
*/ */
/* Mesa supports only 95 constants */
if (GL_VEND(MESA) || GL_VEND(WINE))
This->baseShader.limits.constant_float =
min(95, This->baseShader.limits.constant_float);
/* FIXME: if jumps are used, use GLSL, else use ARB_vertex_program */
shader_addline(&buffer, "!!ARBvp1.0\n");
/* Declare necessary things.
* FIXME: replace with a bitmap
* FIXME: loop counts as an address register */
for (i = 0; i < nUseTempRegister /* we should check numTemps here */ ; i++) {
if (tmpsUsed[i])
shader_addline(&buffer, "TEMP T%ld;\n", i);
}
for (i = 0; i < nUseAddressRegister; i++)
shader_addline(&buffer, "ADDRESS A%ld;\n", i);
shader_addline(&buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
This->baseShader.limits.constant_float,
This->baseShader.limits.constant_float - 1);
/** second pass, now generate */ /** second pass, now generate */
pToken = pFunction; pToken = pFunction;
@ -1191,73 +1259,14 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS
if (D3DVS_END() == *pToken) if (D3DVS_END() == *pToken)
break; break;
if (vshader_is_version_token(*pToken)) { /** version */ /* Skip version */
/* Extract version *10 into integer value (ie. 1.0 == 10, 1.1==11 etc */ if (vshader_is_version_token(*pToken)) {
int version = (((*pToken >> 8) & 0x0F) * 10) + (*pToken & 0x0F); ++pToken;
int numTemps; continue;
int numConstants; }
TRACE("found version token vs.%lu.%lu;\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F)); /* Skip comments */
if (vshader_is_comment_token(*pToken)) {
/* Each release of vertex shaders has had different numbers of temp registers */
switch (version) {
case 10:
case 11: numTemps=12;
numConstants=96;/* min(GL_LIMITS(constants),96) */
break;
/* FIXME: if there are no calls or loops then use ARBvp1 otherwise use GLSL instead
TODO: see if there are any operations in vs2/3 that aren't supported by ARBvp
TODO: only map the maximum possible number of constants supported by openGL and not the maximum required by d3d (even better only map the used constants)*/
case 20: numTemps=12; /* min(GL_LIMITS(temps),12) */
numConstants=96; /* min(GL_LIMITS(constants),256) */
FIXME("No work done yet to support vs2.0 in hw\n");
break;
case 21: numTemps=12; /* min(GL_LIMITS(temps),12) */
numConstants=96; /* min(GL_LIMITS(constants),256) */
FIXME("No work done yet to support vs2.1 in hw\n");
break;
case 30: numTemps=32; /* min(GL_LIMITS(temps),32) */
numConstants=96;/* min(GL_LIMITS(constants),256) */
FIXME("No work done yet to support vs3.0 in hw\n");
break;
default:
numTemps=12;/* min(GL_LIMITS(temps),12) */
numConstants=96;/* min(GL_LIMITS(constants),96) */
FIXME("Unrecognized vertex shader version %d!\n", version);
}
/* FIXME: if jumps are used, use GLSL, else use ARB_vertex_program */
shader_addline(&buffer, "!!ARBvp1.0\n");
/* This should be a bitmap so that only temp registers that are used are declared. */
for (i = 0; i < nUseTempRegister /* we should check numTemps here */ ; i++) {
if (tmpsUsed[i])
shader_addline(&buffer, "TEMP T%ld;\n", i);
}
/* TODO: loop register counts as an address register */
for (i = 0; i < nUseAddressRegister; i++) {
shader_addline(&buffer, "ADDRESS A%ld;\n", i);
}
/* Due to the dynamic constants binding mechanism, we need to declare
* all the constants for relative addressing. */
/* Mesa supports only 95 constants for VS1.X although we should have at least 96. */
if (GL_VEND(MESA) || GL_VEND(WINE)) {
numConstants = 95;
}
/* FIXME: We should be counting the number of constants in the first pass
* and then validating that many are supported. Looking at some of the shaders in use
* by applications we'd need to create a list of all used env variables
*/
shader_addline(&buffer, "PARAM C[%d] = { program.env[0..%d] };\n",
numConstants, numConstants - 1);
++pToken;
continue;
}
if (vshader_is_comment_token(*pToken)) { /** comment */
DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT; DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT;
++pToken; ++pToken;
TRACE("#%s\n", (char*)pToken); TRACE("#%s\n", (char*)pToken);
@ -1885,7 +1894,7 @@ HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader *iface,
if (NULL != pToken) { if (NULL != pToken) {
while (D3DVS_END() != *pToken) { while (D3DVS_END() != *pToken) {
if (vshader_is_version_token(*pToken)) { /** version */ if (vshader_is_version_token(*pToken)) { /** version */
TRACE("vs_%lu_%lu\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F)); vshader_set_version(This, *pToken);
++pToken; ++pToken;
++len; ++len;
continue; continue;

View File

@ -1205,6 +1205,15 @@ typedef struct SHADER_BUFFER {
unsigned int lineNo; unsigned int lineNo;
} SHADER_BUFFER; } SHADER_BUFFER;
typedef struct SHADER_LIMITS {
unsigned int temporary;
unsigned int texture;
unsigned int constant_int;
unsigned int constant_float;
unsigned int constant_bool;
unsigned int address;
} SHADER_LIMITS;
/* Base Shader utility functions. /* Base Shader utility functions.
* (may move callers into the same file in the future) */ * (may move callers into the same file in the future) */
extern int shader_addline( extern int shader_addline(
@ -1217,6 +1226,8 @@ extern int shader_addline(
typedef struct IWineD3DBaseShaderClass typedef struct IWineD3DBaseShaderClass
{ {
DWORD version; DWORD version;
DWORD hex_version;
SHADER_LIMITS limits;
CONST SHADER_OPCODE *shader_ins; CONST SHADER_OPCODE *shader_ins;
CONST DWORD *function; CONST DWORD *function;
UINT functionLength; UINT functionLength;