diff --git a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp index 8a8af1349..70324d22b 100644 --- a/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp +++ b/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp @@ -489,6 +489,17 @@ const char *CxbxGetErrorDescription(HRESULT hResult) return nullptr; } +// TODO move to shader file. Needs to be called whenever a shader or declaration is set +void SetOverrideFlags(CxbxVertexShader* pCxbxVertexShader) { + if (pCxbxVertexShader != nullptr && pCxbxVertexShader->pHostVertexShader != nullptr) { + float overrideFlags[16]; + for (int i = 0; i < 16; i++) { + overrideFlags[i] = !pCxbxVertexShader->VertexShaderInfo.vRegisterInDeclaration[i]; + } + g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_CONSTREG_VERTEXDATA4F_FLAG_BASE, overrideFlags, 4); + } +} + const char *D3DErrorString(HRESULT hResult) { static char buffer[1024]; @@ -3452,6 +3463,8 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SelectVertexShader) pHostVertexDeclaration = pCxbxVertexShader->pHostVertexDeclaration; pHostVertexShader = pCxbxVertexShader->pHostVertexShader; HostFVF = pCxbxVertexShader->HostFVF; + + SetOverrideFlags(pCxbxVertexShader); } hRet = g_pD3DDevice->SetVertexDeclaration(pHostVertexDeclaration); @@ -3808,15 +3821,10 @@ void UpdateViewPortOffsetAndScaleConstants() { float vOffset[4], vScale[4]; GetViewPortOffsetAndScale(vOffset, vScale); - float vScaleReversed[4] = { 1.0f / (double)vScale[0], 1.0f / (double)vScale[1], 1.0f / (double)vScale[2], 0 }; - g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_VIEWPORT_SCALE_MIRROR_INVERTED, vScaleReversed, 1); + g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_VIEWPORT_SCALE_MIRROR, vScale, 1); g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_VIEWPORT_OFFSET_MIRROR, vOffset, 1); - // Set 0 and 1 constant, used to compare and transform W when required - float ZeroOne[] = { 0, 1, 0, 0 }; - g_pD3DDevice->SetVertexShaderConstantF(X_D3DVS_VIEWPORT_SCALE_ZERO_ONE, ZeroOne, 1); - // Store viewport offset and scale in constant registers 58 (c-38) and // 59 (c-37) used for screen space transformation. // We only do this if X_D3DSCM_NORESERVEDCONSTANTS is not set, since enabling this flag frees up these registers for shader used @@ -6674,18 +6682,12 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexShader) } else { + SetOverrideFlags(pCxbxVertexShader); + hRet = g_pD3DDevice->SetVertexShader(pCxbxVertexShader->pHostVertexShader); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader(VshHandleIsVertexShader)"); } - // Set default constant values for specular, diffuse, etc - static const float ColorBlack[4] = { 0,0,0,0 }; - static const float ColorWhite[4] = { 1,1,1,1 }; - - g_pD3DDevice->SetVertexShaderConstantF(CXBX_D3DVS_CONSTREG_VERTEXDATA4F_BASE + XTL::X_D3DVSDE_DIFFUSE, ColorWhite, 1); - g_pD3DDevice->SetVertexShaderConstantF(CXBX_D3DVS_CONSTREG_VERTEXDATA4F_BASE + XTL::X_D3DVSDE_BACKDIFFUSE, ColorWhite, 1); - g_pD3DDevice->SetVertexShaderConstantF(CXBX_D3DVS_CONSTREG_VERTEXDATA4F_BASE + XTL::X_D3DVSDE_SPECULAR, ColorBlack, 1); - g_pD3DDevice->SetVertexShaderConstantF(CXBX_D3DVS_CONSTREG_VERTEXDATA4F_BASE + XTL::X_D3DVSDE_BACKSPECULAR, ColorBlack, 1); } else { hRet = g_pD3DDevice->SetVertexShader(nullptr); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader"); diff --git a/src/core/hle/D3D8/Direct3D9/Xb.hlsl b/src/core/hle/D3D8/Direct3D9/Xb.hlsl index ee5f4aebf..563d7aeab 100644 --- a/src/core/hle/D3D8/Direct3D9/Xb.hlsl +++ b/src/core/hle/D3D8/Direct3D9/Xb.hlsl @@ -25,6 +25,13 @@ struct VS_OUTPUT // Xbox constant registers extern uniform float4 c[192] : register(c0); +// Vertex input overrides for SetVertexData4f support +extern float4 vOverrideValue[16] : register(c192); +extern float4 vOverridePacked[4] : register(c208); + +extern float4 xboxViewportScale : register(c212); +extern float4 xboxViewportOffset : register(c213); + // Overloaded casts, assuring all inputs are treated as float4 float4 _tof4(float src) { return float4(src, src, src, src); } float4 _tof4(float2 src) { return src.xyyy; } @@ -176,16 +183,16 @@ float _rcc(float input) float4 reverseScreenspaceTransform(float4 oPos) { // On Xbox, oPos should contain the vertex position in screenspace + // We need to reverse this transformation // Conventionally, each Xbox Vertex Shader includes instructions like this // mul oPos.xyz, r12, c-38 // +rcc r1.x, r12.w // mad oPos.xyz, r12, r1.x, c-37 // where c-37 and c-38 are reserved transform values - // Lets hope c-37 and c-38 contain the conventional values - oPos.xyz -= (float3)c[-37 + 96]; // reverse offset + oPos.xyz -= xboxViewportOffset.xyz; // reverse offset oPos.xyz *= oPos.w; // reverse perspective divide - oPos.xyz /= (float3)c[-38 + 96]; // reverse scale + oPos.xyz /= xboxViewportScale.xyz; // reverse scale return oPos; } @@ -208,25 +215,33 @@ VS_OUTPUT main(const VS_INPUT xIn) r0 = r1 = r2 = r3 = r4 = r5 = r6 = r7 = r8 = r9 = r10 = r11 = float4(0, 0, 0, 0); #define r12 oPos // oPos and r12 are two ways of accessing the same register on Xbox - // Input registers - float4 v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15; - // Initialize input variables - v0 = xIn.v[0]; - v1 = xIn.v[1]; - v2 = xIn.v[2]; - v3 = xIn.v[3]; - v4 = xIn.v[4]; - v5 = xIn.v[5]; - v6 = xIn.v[6]; - v7 = xIn.v[7]; - v8 = xIn.v[8]; - v9 = xIn.v[9]; - v10 = xIn.v[10]; - v11 = xIn.v[11]; - v12 = xIn.v[12]; - v13 = xIn.v[13]; - v14 = xIn.v[14]; - v15 = xIn.v[15]; + // Input registerss + float4 v[16]; + # define v0 v[0] + # define v1 v[1] + # define v2 v[2] + # define v3 v[3] + # define v4 v[4] + # define v5 v[5] + # define v6 v[6] + # define v7 v[7] + # define v8 v[8] + # define v9 v[9] + # define v10 v[10] + # define v11 v[11] + # define v12 v[12] + # define v13 v[13] + # define v14 v[14] + # define v15 v[15] + + // View 4 packed overrides as an array of 16 floats + float vOverride[16] = (float[16])vOverridePacked; + + // Initialize input registers from the vertex buffer + // Or use an override value set with SetVertexData4f + for(uint i = 0; i < 16; i++){ + v[i] = vOverride[i] ? vOverrideValue[i] : xIn.v[i]; + } // Xbox shader program // diff --git a/src/core/hle/D3D8/XbD3D8Types.h b/src/core/hle/D3D8/XbD3D8Types.h index a217d11f2..51b662dda 100644 --- a/src/core/hle/D3D8/XbD3D8Types.h +++ b/src/core/hle/D3D8/XbD3D8Types.h @@ -988,17 +988,13 @@ typedef DWORD X_VERTEXSHADERCONSTANTMODE; #define X_D3DSCM_CORRECTION 96 // Add 96 to arrive at the range 0..191 (instead of 96..95) #define X_D3DVS_CONSTREG_COUNT 192 -#define X_D3DVS_RESERVED_CONSTANT1 -38 // Becomes 58 after correction, contains Scale v -#define X_D3DVS_RESERVED_CONSTANT2 -37 // Becomes 59 after correction, contains Offset -#define X_D3DVS_RESERVED_CONSTANT1_CORRECTED (X_D3DVS_RESERVED_CONSTANT1 + X_D3DVS_CONSTREG_BIAS) -#define X_D3DVS_RESERVED_CONSTANT2_CORRECTED (X_D3DVS_RESERVED_CONSTANT2 + X_D3DVS_CONSTREG_BIAS) // Special Registers, used to pass additional information to the shaders -#define X_D3DVS_CONSTREG_VERTEXDATA4F_BASE (X_D3DVS_CONSTREG_COUNT + 1) -#define X_D3DVS_CONSTREG_VERTEXDATA4F_END (X_D3DVS_CONSTREG_VERTEXDATA4F_BASE + 14) -#define X_D3DVS_VIEWPORT_SCALE_MIRROR_INVERTED (X_D3DVS_CONSTREG_VERTEXDATA4F_END + 1) -#define X_D3DVS_VIEWPORT_OFFSET_MIRROR (X_D3DVS_VIEWPORT_SCALE_MIRROR_INVERTED + 1) -#define X_D3DVS_VIEWPORT_SCALE_ZERO_ONE (X_D3DVS_VIEWPORT_OFFSET_MIRROR + 1) +// TODO co-locate shader workaround constants with shader code +#define X_D3DVS_CONSTREG_VERTEXDATA4F_BASE (X_D3DVS_CONSTREG_COUNT) +#define X_D3DVS_CONSTREG_VERTEXDATA4F_FLAG_BASE (X_D3DVS_CONSTREG_VERTEXDATA4F_BASE + 16) +#define X_D3DVS_VIEWPORT_SCALE_MIRROR (X_D3DVS_CONSTREG_VERTEXDATA4F_FLAG_BASE + 4) +#define X_D3DVS_VIEWPORT_OFFSET_MIRROR (X_D3DVS_VIEWPORT_SCALE_MIRROR + 1) #define X_D3DSCM_RESERVED_CONSTANT_SCALE_CORRECTED (X_D3DSCM_RESERVED_CONSTANT_SCALE + X_D3DSCM_CORRECTION) #define X_D3DSCM_RESERVED_CONSTANT_OFFSET_CORRECTED (X_D3DSCM_RESERVED_CONSTANT_OFFSET + X_D3DSCM_CORRECTION) diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index 164c6f211..9bbf82fda 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -302,7 +302,7 @@ typedef struct _VSH_XBOX_SHADER } VSH_XBOX_SHADER; -// TODO : Reinstate and use : std::array RegVIsPresentInDeclaration; +std::array RegVIsPresentInDeclaration; /* TODO : map non-FVF Xbox vertex shader handle to CxbxVertexShader (a struct containing a host Xbox vertex shader handle and the original members) std::unordered_map g_CxbxVertexShaders; @@ -1290,7 +1290,7 @@ private: } // Add this register to the list of declared registers - // TODO : Reinstate and use : RegVIsPresentInDeclaration[VertexRegister] = true; + RegVIsPresentInDeclaration[VertexRegister] = true; DWORD XboxVertexElementDataType = (*pXboxToken & X_D3DVSD_DATATYPEMASK) >> X_D3DVSD_DATATYPESHIFT; WORD XboxVertexElementByteSize = 0; @@ -1617,7 +1617,7 @@ public: IsFixedFunction = bIsFixedFunction; - // TODO : Reinstate and use : RegVIsPresentInDeclaration.fill(false); + RegVIsPresentInDeclaration.fill(false); // First of all some info: // We have to figure out which flags are set and then @@ -1661,6 +1661,11 @@ public: // Free the preprocessed declaration copy free(pXboxVertexDeclarationCopy); + for (int i = 0; i < RegVIsPresentInDeclaration.size(); i++) { + pCxbxVertexShaderInfo->vRegisterInDeclaration[i] = RegVIsPresentInDeclaration[i]; + EmuLog(LOG_LEVEL::DEBUG, "Vertex regs used: v%d %d", i, pCxbxVertexShaderInfo->vRegisterInDeclaration[i]); + } + return Result; } }; diff --git a/src/core/hle/D3D8/XbVertexShader.h b/src/core/hle/D3D8/XbVertexShader.h index 36b963a49..43e9b1b06 100644 --- a/src/core/hle/D3D8/XbVertexShader.h +++ b/src/core/hle/D3D8/XbVertexShader.h @@ -71,6 +71,7 @@ typedef struct _CxbxVertexShaderInfo { UINT NumberOfVertexStreams; // The number of streams the vertex shader uses CxbxVertexShaderStreamInfo VertexStreams[X_VSH_MAX_STREAMS]; + bool vRegisterInDeclaration[16]; } CxbxVertexShaderInfo;