- Reset shader when shader slots are overwritten

- Keep track of the shader slot address
This commit is contained in:
Anthony Miles 2020-05-04 18:55:51 +12:00
parent e60d11959c
commit 1087b3e645
1 changed files with 54 additions and 36 deletions

View File

@ -1251,6 +1251,8 @@ extern boolean IsValidCurrentShader(void)
return VshHandleIsValidShader(g_Xbox_VertexShader_Handle); return VshHandleIsValidShader(g_Xbox_VertexShader_Handle);
} }
// Vertex shader state
static DWORD g_CxbxVertexShaderSlotAddress = 0;
static DWORD g_CxbxVertexShaderSlots[X_VSH_MAX_INSTRUCTION_COUNT * X_VSH_INSTRUCTION_SIZE] = { 0 }; static DWORD g_CxbxVertexShaderSlots[X_VSH_MAX_INSTRUCTION_COUNT * X_VSH_INSTRUCTION_SIZE] = { 0 };
DWORD* GetCxbxVertexShaderSlotPtr(const DWORD SlotIndexAddress) DWORD* GetCxbxVertexShaderSlotPtr(const DWORD SlotIndexAddress)
@ -1301,7 +1303,41 @@ void SetCxbxVertexShader(DWORD XboxVertexShaderHandle, CxbxVertexShader* shader)
g_CxbxVertexShaders[XboxVertexShaderHandle] = shader; g_CxbxVertexShaders[XboxVertexShaderHandle] = shader;
} }
void SetCxbxVertexShader(CxbxVertexShader* pCxbxVertexShader) void SetCxbxVertexShaderHandleDeclaration(CxbxVertexShader* pCxbxVertexShader) {
LOG_INIT
HRESULT hRet;
// Set vertex declaration
hRet = g_pD3DDevice->SetVertexDeclaration(pCxbxVertexShader->Declaration.pHostVertexDeclaration);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexDeclaration");
// Titles can specify default values for registers via calls like SetVertexData4f
// HLSL shaders need to know whether to use vertex data or default vertex shader values
// Any register not in the vertex declaration should be set to the default value
float vertexDefaultFlags[16];
for (int i = 0; i < 16; i++) {
vertexDefaultFlags[i] = pCxbxVertexShader->Declaration.vRegisterInDeclaration[i] ? 0.0f : 1.0f;
}
g_pD3DDevice->SetVertexShaderConstantF(CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_BASE, vertexDefaultFlags, 4);
}
// TODO Call this when state is dirty in UpdateNativeD3DResources
// Rather than every time state changes
void SetVertexShaderFromSlots() {
LOG_INIT
auto pTokens = GetCxbxVertexShaderSlotPtr(g_CxbxVertexShaderSlotAddress);
if (pTokens) {
// Create a vertex shader from the tokens
DWORD shaderSize;
auto shaderKey = g_VertexShaderSource.CreateShader(pTokens, &shaderSize);
HRESULT hRet = g_pD3DDevice->SetVertexShader(g_VertexShaderSource.GetShader(shaderKey));
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader");
}
}
void SetCxbxVertexShaderHandle(CxbxVertexShader* pCxbxVertexShader)
{ {
LOG_INIT LOG_INIT
@ -1316,21 +1352,7 @@ void SetCxbxVertexShader(CxbxVertexShader* pCxbxVertexShader)
hRet = g_pD3DDevice->SetVertexShader(pHostShader); hRet = g_pD3DDevice->SetVertexShader(pHostShader);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader"); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader");
// Set vertex declaration SetCxbxVertexShaderHandleDeclaration(pCxbxVertexShader);
hRet = g_pD3DDevice->SetVertexDeclaration(pCxbxVertexShader->Declaration.pHostVertexDeclaration);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexDeclaration");
// Set vertex shader constants if necessary
if (pHostShader) {
// Titles can specify default values for registers via calls like SetVertexData4f
// HLSL shaders need to know whether to use vertex data or default vertex shader values
// Any register not in the vertex declaration should be set to the default value
float vertexDefaultFlags[16];
for (int i = 0; i < 16; i++) {
vertexDefaultFlags[i] = pCxbxVertexShader->Declaration.vRegisterInDeclaration[i] ? 0.0f : 1.0f;
}
g_pD3DDevice->SetVertexShaderConstantF(CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_BASE, vertexDefaultFlags, 4);
}
} }
void CxbxImpl_SetVertexShaderInput void CxbxImpl_SetVertexShaderInput
@ -1364,8 +1386,6 @@ void CxbxImpl_SelectVertexShaderDirect
void CxbxImpl_SelectVertexShader(DWORD Handle, DWORD Address) void CxbxImpl_SelectVertexShader(DWORD Handle, DWORD Address)
{ {
HRESULT hRet = D3D_OK;
// Address always indicates a previously loaded vertex shader slot (from where the program is used). // Address always indicates a previously loaded vertex shader slot (from where the program is used).
// Handle can be null if the current Xbox VertexShader is assigned // Handle can be null if the current Xbox VertexShader is assigned
// Handle can be an address of an Xbox VertexShader struct, or-ed with 1 (X_D3DFVF_RESERVED0) // Handle can be an address of an Xbox VertexShader struct, or-ed with 1 (X_D3DFVF_RESERVED0)
@ -1373,6 +1393,7 @@ void CxbxImpl_SelectVertexShader(DWORD Handle, DWORD Address)
// which resets a bit of state (nv2a execution mode, viewport, ?) // which resets a bit of state (nv2a execution mode, viewport, ?)
// Either way, the given address slot is selected as the start of the current vertex shader program // Either way, the given address slot is selected as the start of the current vertex shader program
g_Xbox_VertexShader_Handle = Handle; g_Xbox_VertexShader_Handle = Handle;
g_CxbxVertexShaderSlotAddress = Address;
CxbxVertexShader* pCxbxVertexShader = nullptr; CxbxVertexShader* pCxbxVertexShader = nullptr;
@ -1382,25 +1403,13 @@ void CxbxImpl_SelectVertexShader(DWORD Handle, DWORD Address)
if (pCxbxVertexShader == nullptr) { if (pCxbxVertexShader == nullptr) {
LOG_TEST_CASE("Shader handle has not been created"); LOG_TEST_CASE("Shader handle has not been created");
} }
else {
// TODO we should only set the vertex declaration here? // Set the shader handle declaration
SetCxbxVertexShader(pCxbxVertexShader); SetCxbxVertexShaderHandleDeclaration(pCxbxVertexShader);
}
} }
auto pTokens = GetCxbxVertexShaderSlotPtr(Address); SetVertexShaderFromSlots();
if (pTokens) {
// Create a vertex shader from the tokens
DWORD shaderSize;
auto shaderKey = g_VertexShaderSource.CreateShader(pTokens, &shaderSize);
g_pD3DDevice->SetVertexShader(g_VertexShaderSource.GetShader(shaderKey));
}
if (FAILED(hRet))
{
EmuLog(LOG_LEVEL::WARNING, "We're lying about setting a vertext shader!");
hRet = D3D_OK;
}
} }
void CxbxImpl_LoadVertexShaderProgram(CONST DWORD* pFunction, DWORD Address) void CxbxImpl_LoadVertexShaderProgram(CONST DWORD* pFunction, DWORD Address)
@ -1415,6 +1424,8 @@ void CxbxImpl_LoadVertexShaderProgram(CONST DWORD* pFunction, DWORD Address)
auto shaderHeader = *((XTL::X_VSH_SHADER_HEADER*) pFunction); auto shaderHeader = *((XTL::X_VSH_SHADER_HEADER*) pFunction);
auto tokens = &pFunction[1]; auto tokens = &pFunction[1];
memcpy(CxbxVertexShaderSlotPtr, tokens, shaderHeader.NumInst * X_VSH_INSTRUCTION_SIZE_BYTES); memcpy(CxbxVertexShaderSlotPtr, tokens, shaderHeader.NumInst * X_VSH_INSTRUCTION_SIZE_BYTES);
SetVertexShaderFromSlots();
} }
void CxbxImpl_LoadVertexShader(DWORD Handle, DWORD Address) void CxbxImpl_LoadVertexShader(DWORD Handle, DWORD Address)
@ -1458,11 +1469,18 @@ void CxbxImpl_SetVertexShader(DWORD Handle)
HRESULT hRet = D3D_OK; HRESULT hRet = D3D_OK;
g_Xbox_VertexShader_Handle = Handle; g_Xbox_VertexShader_Handle = Handle;
g_CxbxVertexShaderSlotAddress = 0;
if (VshHandleIsVertexShader(Handle)) { if (VshHandleIsVertexShader(Handle)) {
CxbxVertexShader* pCxbxVertexShader = GetCxbxVertexShader(Handle); CxbxVertexShader* pCxbxVertexShader = GetCxbxVertexShader(Handle);
SetCxbxVertexShader(pCxbxVertexShader); SetCxbxVertexShaderHandle(pCxbxVertexShader);
auto CxbxVertexShaderSlotPtr = GetCxbxVertexShaderSlotPtr(g_CxbxVertexShaderSlotAddress);
if (CxbxVertexShaderSlotPtr) {
// Skip the header DWORD at the beginning
auto pTokens = &pCxbxVertexShader->pXboxFunctionCopy[1];
memcpy(CxbxVertexShaderSlotPtr, pTokens, pCxbxVertexShader->XboxNrAddressSlots * X_VSH_INSTRUCTION_SIZE_BYTES);
}
} }
else { else {
hRet = g_pD3DDevice->SetVertexShader(nullptr); hRet = g_pD3DDevice->SetVertexShader(nullptr);