From c93239d36d937e2b9923ce590afefe6029d92636 Mon Sep 17 00:00:00 2001 From: Ivan Gyurdiev Date: Mon, 8 May 2006 17:09:21 -0400 Subject: [PATCH] wined3d: Clean up per version shader limits code. --- dlls/wined3d/pixelshader.c | 162 +++++++++++++++++++++++------------------ dlls/wined3d/vertexshader.c | 143 +++++++++++++++++++----------------- dlls/wined3d/wined3d_private.h | 11 +++ 3 files changed, 178 insertions(+), 138 deletions(-) diff --git a/dlls/wined3d/pixelshader.c b/dlls/wined3d/pixelshader.c index 5a16a2883cc..f52c98c52ca 100644 --- a/dlls/wined3d/pixelshader.c +++ b/dlls/wined3d/pixelshader.c @@ -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 */ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelShader *iface, CONST DWORD *pFunction) { IWineD3DPixelShaderImpl *This = (IWineD3DPixelShaderImpl *)iface; @@ -991,7 +1046,7 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelSha BOOL saturate; /* clamp to 0.0 -> 1.0*/ int row = 0; /* not sure, something to do with macros? */ DWORD tcw[2]; - int version = 0; /* The version of the shader */ + int version = This->baseShader.version; /* Keep bitmaps of used temporary and texture registers */ DWORD tempsUsed, texUsed; @@ -1011,6 +1066,9 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelSha buffer.bsize = 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. */ for(i = 0; i < WINED3D_PSHADER_MAX_CONSTANTS; i++) 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 */ + /* 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 */ if (NULL != pToken) { while (D3DPS_END() != *pToken) { @@ -1029,79 +1114,15 @@ inline static VOID IWineD3DPixelShaderImpl_GenerateProgramArbHW(IWineD3DPixelSha instructionSize = pToken & SIZEBITS >> 27; } #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; 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; ++pToken; TRACE("#%s\n", (char*)pToken); @@ -1742,8 +1763,7 @@ HRESULT WINAPI IWineD3DPixelShaderImpl_SetFunction(IWineD3DPixelShader *iface, C if (NULL != pToken) { while (D3DPS_END() != *pToken) { if (pshader_is_version_token(*pToken)) { /** version */ - This->baseShader.version = (((*pToken >> 8) & 0x0F) * 10) + (*pToken & 0x0F); - TRACE("ps_%lu_%lu\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F)); + pshader_set_version(This, *pToken); ++pToken; ++len; continue; diff --git a/dlls/wined3d/vertexshader.c b/dlls/wined3d/vertexshader.c index 6b448ca8ea9..382700b35ac 100644 --- a/dlls/wined3d/vertexshader.c +++ b/dlls/wined3d/vertexshader.c @@ -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 ... */ @@ -1179,6 +1224,29 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS 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 */ pToken = pFunction; @@ -1191,73 +1259,14 @@ inline static VOID IWineD3DVertexShaderImpl_GenerateProgramArbHW(IWineD3DVertexS if (D3DVS_END() == *pToken) break; - if (vshader_is_version_token(*pToken)) { /** version */ - /* Extract version *10 into integer value (ie. 1.0 == 10, 1.1==11 etc */ - int version = (((*pToken >> 8) & 0x0F) * 10) + (*pToken & 0x0F); - int numTemps; - int numConstants; - - TRACE("found version token vs.%lu.%lu;\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F)); - - /* 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); + /* Skip version */ + if (vshader_is_version_token(*pToken)) { + ++pToken; + continue; + } - ++pToken; - continue; - } - if (vshader_is_comment_token(*pToken)) { /** comment */ + /* Skip comments */ + if (vshader_is_comment_token(*pToken)) { DWORD comment_len = (*pToken & D3DSI_COMMENTSIZE_MASK) >> D3DSI_COMMENTSIZE_SHIFT; ++pToken; TRACE("#%s\n", (char*)pToken); @@ -1885,7 +1894,7 @@ HRESULT WINAPI IWineD3DVertexShaderImpl_SetFunction(IWineD3DVertexShader *iface, if (NULL != pToken) { while (D3DVS_END() != *pToken) { if (vshader_is_version_token(*pToken)) { /** version */ - TRACE("vs_%lu_%lu\n", (*pToken >> 8) & 0x0F, (*pToken & 0x0F)); + vshader_set_version(This, *pToken); ++pToken; ++len; continue; diff --git a/dlls/wined3d/wined3d_private.h b/dlls/wined3d/wined3d_private.h index eae0293ce1b..de303c5de91 100644 --- a/dlls/wined3d/wined3d_private.h +++ b/dlls/wined3d/wined3d_private.h @@ -1205,6 +1205,15 @@ typedef struct SHADER_BUFFER { unsigned int lineNo; } 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. * (may move callers into the same file in the future) */ extern int shader_addline( @@ -1217,6 +1226,8 @@ extern int shader_addline( typedef struct IWineD3DBaseShaderClass { DWORD version; + DWORD hex_version; + SHADER_LIMITS limits; CONST SHADER_OPCODE *shader_ins; CONST DWORD *function; UINT functionLength; -- 2.11.4.GIT