Skip to content
Permalink
Browse files

Merge pull request #1828 from NZJenkins/vertex_shader_source

Vertex shader runtime cache
  • Loading branch information
LukeUsher committed Feb 8, 2020
2 parents 38b03b3 + 0c6a13e commit 51d5759a1ac9c1b56a7011235346ffb028f810e6
@@ -130,6 +130,7 @@ file (GLOB CXBXR_HEADER_EMU
"${CXBXR_ROOT_DIR}/src/common/XADPCM.h"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/Direct3D9.h"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShader.h"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShaderSource.h"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/WalkIndexBuffer.h"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/ResourceTracker.h"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbConvert.h"
@@ -266,6 +267,7 @@ file (GLOB CXBXR_SOURCE_EMU
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/RenderStates.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/TextureStates.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShader.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShaderSource.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/WalkIndexBuffer.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/ResourceTracker.cpp"
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbConvert.cpp"

Large diffs are not rendered by default.

@@ -58,6 +58,7 @@ const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)] = {
"PSHB ",
"PXSH ",
"VTXSH ",
"VSHCACHE",
"VTXB ",
"DINP ",
"XINP ",
@@ -66,6 +66,7 @@ typedef enum class _CXBXR_MODULE: unsigned int {
PSHB,
PXSH,
VTXSH,
VSHCACHE,
VTXB,
DINP,
XINP,
@@ -62,7 +62,7 @@ namespace xboxkrnl
#include "core\kernel\common\strings.hpp" // For uem_str
#include "common\input\SdlJoystick.h"
#include "common/util/strConverter.hpp" // for utf8_to_utf16
#include "VertexShader.h"
#include "VertexShaderSource.h"

#include <assert.h>
#include <process.h>
@@ -547,19 +547,6 @@ const char *CxbxGetErrorDescription(HRESULT hResult)
return nullptr;
}

// TODO move to shader file. Needs to be called whenever a shader or declaration is set
void SetVertexRegisterDefaultFlags(CxbxVertexShader* pCxbxVertexShader) {
if (pCxbxVertexShader != nullptr && pCxbxVertexShader->pHostVertexShader != nullptr) {
// 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->VertexShaderInfo.vRegisterInDeclaration[i] ? 0.0f : 1.0f;
}
g_pD3DDevice->SetVertexShaderConstantF(CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_BASE, vertexDefaultFlags, 4);
}
}

const char *D3DErrorString(HRESULT hResult)
{
@@ -861,6 +848,7 @@ typedef struct {
typedef std::unordered_map<resource_key_t, resource_info_t, resource_key_hash> resource_cache_t;
resource_cache_t g_Cxbx_Cached_Direct3DResources;
resource_cache_t g_Cxbx_Cached_PaletizedTextures;
VertexShaderSource g_VertexShaderSource = VertexShaderSource();

bool IsResourceAPixelContainer(XTL::DWORD XboxResource_Common)
{
@@ -988,6 +976,48 @@ IDirect3DResource *GetHostResource(XTL::X_D3DResource *pXboxResource, DWORD D3DU
return it->second.pHostResource;
}

void SetCxbxVertexShader(CxbxVertexShader* pCxbxVertexShader) {

LOG_INIT

HRESULT hRet;

// Get vertex shader if we have a key
auto pHostShader = pCxbxVertexShader->VertexShaderKey
? g_VertexShaderSource.GetShader(pCxbxVertexShader->VertexShaderKey)
: nullptr;

// Set vertex shader
hRet = g_pD3DDevice->SetVertexShader(pHostShader);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader");

// Set either FVF or the vertex declaration
if (pCxbxVertexShader->HostFVF)
{
// Set the FVF
hRet = g_pD3DDevice->SetFVF(pCxbxVertexShader->HostFVF);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetFVF");
}
else
{
// Set vertex declaration
hRet = g_pD3DDevice->SetVertexDeclaration(pCxbxVertexShader->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->VertexShaderInfo.vRegisterInDeclaration[i] ? 0.0f : 1.0f;
}
g_pD3DDevice->SetVertexShaderConstantF(CXBX_D3DVS_CONSTREG_VREGDEFAULTS_FLAG_BASE, vertexDefaultFlags, 4);
}
}

// Forward declaration of CxbxGetPixelContainerMeasures to prevent
// polluting the diff too much by reshuffling functions around
VOID CxbxGetPixelContainerMeasures
@@ -2568,6 +2598,9 @@ static DWORD WINAPI EmuCreateDeviceProxy(LPVOID)
// begin scene
hRet = g_pD3DDevice->BeginScene();
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->BeginScene(2nd)");

// Set up cache
g_VertexShaderSource.ResetD3DDevice(g_pD3DDevice);
}

// signal completion
@@ -3554,10 +3587,17 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SelectVertexShader)
if(VshHandleIsVertexShader(Handle))
{
pCxbxVertexShader = GetCxbxVertexShader(Handle);
SetCxbxVertexShader(pCxbxVertexShader);

This comment has been minimized.

Copy link
@CookiePLMonster
}
else if(Handle == xbnull)
{
HostFVF = D3DFVF_XYZ | D3DFVF_TEX0;
// Clear any vertex shader that may be set
hRet = g_pD3DDevice->SetVertexShader(nullptr);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader()");
// Set the FVF
hRet = g_pD3DDevice->SetFVF(HostFVF);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_TEX0)");
}
else if(Address < 136)
{
@@ -3575,28 +3615,6 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SelectVertexShader)
}
}

IDirect3DVertexDeclaration* pHostVertexDeclaration = nullptr;
IDirect3DVertexShader* pHostVertexShader = nullptr;

if (pCxbxVertexShader)
{
pHostVertexDeclaration = pCxbxVertexShader->pHostVertexDeclaration;
pHostVertexShader = pCxbxVertexShader->pHostVertexShader;
HostFVF = pCxbxVertexShader->HostFVF;

SetVertexRegisterDefaultFlags(pCxbxVertexShader);
}

hRet = g_pD3DDevice->SetVertexDeclaration(pHostVertexDeclaration);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexDeclaration()");
hRet = g_pD3DDevice->SetVertexShader(pHostVertexShader);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader()");
if (HostFVF) // should equal (pHostVertexShader == nullptr)
{
hRet = g_pD3DDevice->SetFVF(HostFVF);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_TEX0)");
}

if (FAILED(hRet))
{
EmuLog(LOG_LEVEL::WARNING, "We're lying about setting a vertext shader!");
@@ -4247,6 +4265,8 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreateVertexShader)

// Create the vertex declaration
hRet = g_pD3DDevice->CreateVertexDeclaration(pRecompiledDeclaration, &pCxbxVertexShader->pHostVertexDeclaration);
free(pRecompiledDeclaration);

DEBUG_D3DRESULT(hRet, "g_pD3DDevice->CreateVertexDeclaration");

if (FAILED(hRet)) {
@@ -4256,67 +4276,21 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreateVertexShader)
g_pD3DDevice->SetVertexDeclaration(pCxbxVertexShader->pHostVertexDeclaration);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexDeclaration");

ID3DBlob *pRecompiledBuffer = nullptr;
uint64_t vertexShaderKey = 0;
DWORD XboxFunctionSize = 0;
DWORD *pRecompiledFunction = nullptr;
if (SUCCEEDED(hRet) && pFunction)
{
auto intermediateShader = IntermediateVertexShader();

// TOOD handle parse return value?
hRet = EmuParseVshFunction((DWORD*)pFunction,
&XboxFunctionSize,
&intermediateShader);

// Try to compile the shader
hRet = EmuCompileShader(
&intermediateShader,
&pRecompiledBuffer
);

if (SUCCEEDED(hRet))
{
if (pRecompiledBuffer)
pRecompiledFunction = (DWORD*)pRecompiledBuffer->GetBufferPointer();
else
pRecompiledFunction = nullptr;
}
else
{
pRecompiledFunction = nullptr;
EmuLog(LOG_LEVEL::WARNING, "Couldn't recompile vertex shader function.");
}
}

//EmuLog(LOG_LEVEL::DEBUG, "MaxVertexShaderConst = %d", g_D3DCaps.MaxVertexShaderConst);

IDirect3DVertexShader* pHostVertexShader = nullptr;
if (SUCCEEDED(hRet) && pRecompiledFunction != nullptr)
{
hRet = g_pD3DDevice->CreateVertexShader
(
pRecompiledFunction,
&pHostVertexShader
);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->CreateVertexShader");
vertexShaderKey = g_VertexShaderSource.CreateShader(pFunction, &XboxFunctionSize);
}

if (pRecompiledBuffer != nullptr)
{
pRecompiledBuffer->Release();
pRecompiledBuffer = nullptr;
}

free(pRecompiledDeclaration);

pCxbxVertexShader->pXboxDeclarationCopy = (DWORD*)malloc(XboxDeclarationCount * sizeof(DWORD));
memcpy(pCxbxVertexShader->pXboxDeclarationCopy, pDeclaration, XboxDeclarationCount * sizeof(DWORD));
pCxbxVertexShader->XboxFunctionSize = 0;
pCxbxVertexShader->pXboxFunctionCopy = nullptr;
pCxbxVertexShader->XboxVertexShaderType = X_VST_NORMAL; // TODO : This can vary
pCxbxVertexShader->XboxNrAddressSlots = (XboxFunctionSize - sizeof(X_VSH_SHADER_HEADER)) / X_VSH_INSTRUCTION_SIZE_BYTES;
pCxbxVertexShader->HostFVF = 0;
pCxbxVertexShader->pHostVertexShader = nullptr;
pCxbxVertexShader->VertexShaderKey = vertexShaderKey;
pCxbxVertexShader->XboxDeclarationCount = XboxDeclarationCount;
// Save the status, to remove things later
// pCxbxVertexShader->XboxStatus = hRet; // Not even used by VshHandleIsValidShader()
@@ -4329,8 +4303,6 @@ HRESULT WINAPI XTL::EMUPATCH(D3DDevice_CreateVertexShader)
pCxbxVertexShader->pXboxFunctionCopy = (DWORD*)malloc(XboxFunctionSize);
memcpy(pCxbxVertexShader->pXboxFunctionCopy, pFunction, XboxFunctionSize);
}

pCxbxVertexShader->pHostVertexShader = pHostVertexShader;
}
else
{
@@ -6804,20 +6776,7 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_SetVertexShader)

if (VshHandleIsVertexShader(Handle)) {
CxbxVertexShader *pCxbxVertexShader = GetCxbxVertexShader(Handle);
hRet = g_pD3DDevice->SetVertexDeclaration(pCxbxVertexShader->pHostVertexDeclaration);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexDeclaration");
if (pCxbxVertexShader->HostFVF)
{
hRet = g_pD3DDevice->SetFVF(pCxbxVertexShader->HostFVF);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetFVF(VshHandleIsVertexShader)");
}
else
{
SetVertexRegisterDefaultFlags(pCxbxVertexShader);

hRet = g_pD3DDevice->SetVertexShader(pCxbxVertexShader->pHostVertexShader);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader(VshHandleIsVertexShader)");
}
SetCxbxVertexShader(pCxbxVertexShader);

} else {
hRet = g_pD3DDevice->SetVertexShader(nullptr);
@@ -8059,10 +8018,8 @@ VOID WINAPI XTL::EMUPATCH(D3DDevice_DeleteVertexShader)
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->DeleteVertexShader(pHostVertexDeclaration)");
}

if (pCxbxVertexShader->pHostVertexShader) {
HRESULT hRet = pCxbxVertexShader->pHostVertexShader->Release();
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->DeleteVertexShader(pHostVertexShader)");
}
// Release the host vertex shader
g_VertexShaderSource.ReleaseShader(pCxbxVertexShader->VertexShaderKey);

if (pCxbxVertexShader->pXboxDeclarationCopy)
{
@@ -192,6 +192,32 @@ std::string DebugPrependLineNumbers(std::string shaderString) {
return debugShader.str();
}


extern ShaderType EmuGetShaderInfo(IntermediateVertexShader* pIntermediateShader) {

if (pIntermediateShader->Instructions.size() == 0) {
// Do not attempt to compile empty shaders
// This is a declaration only shader, so there is no function to compile
return ShaderType::Empty;
}

switch (pIntermediateShader->Header.Version) {
case VERSION_XVS:
break;
case VERSION_XVSS:
LOG_TEST_CASE("Might not support vertex state shaders?");
break;
case VERSION_XVSW:
EmuLog(LOG_LEVEL::WARNING, "Might not support vertex read/write shaders?");
return ShaderType::Unsupported;
default:
EmuLog(LOG_LEVEL::WARNING, "Unknown vertex shader version 0x%02X", pIntermediateShader->Header.Version);
return ShaderType::Unsupported;
}

return ShaderType::Compilable;
}

// recompile xbox vertex shader function
extern HRESULT EmuCompileShader
(
@@ -204,31 +230,6 @@ extern HRESULT EmuCompileShader
ID3DBlob* pErrors = nullptr;
HRESULT hRet = 0;

switch (pIntermediateShader->Header.Version) {
case VERSION_XVS:
break;
case VERSION_XVSS:
LOG_TEST_CASE("Might not support vertex state shaders?");
break;
case VERSION_XVSW:
EmuLog(LOG_LEVEL::WARNING, "Might not support vertex read/write shaders?");
hRet = E_FAIL;
break;
default:
EmuLog(LOG_LEVEL::WARNING, "Unknown vertex shader version 0x%02X", pIntermediateShader->Header.Version);
hRet = E_FAIL;
break;
}

if (!SUCCEEDED(hRet)) return hRet;

if (pIntermediateShader->Instructions.size() == 0) {
// Do not attempt to compile empty shaders
// This is a declaration only shader, so there is no function to recompile
ppHostShader = nullptr;
return D3D_OK;
}

// Include HLSL header and footer as raw strings :
static std::string hlsl_template[2] = {
#include "core\hle\D3D8\Direct3D9\CxbxVertexShaderTemplate.hlsl"
@@ -4,6 +4,14 @@

#include "core\hle\D3D8\XbVertexShader.h"

enum class ShaderType {
Empty = 0,
Compilable,
Unsupported,
};

extern ShaderType EmuGetShaderInfo(IntermediateVertexShader* pIntermediateShader);

extern HRESULT EmuCompileShader
(
IntermediateVertexShader* pIntermediateShader,

0 comments on commit 51d5759

Please sign in to comment.
You can’t perform that action at this time.