Enable fixed function vertex shader

- Various bits of glue code
- Toggle Shader/D3D9 with F2
- Replace vertex shader mode flags with enum
This commit is contained in:
Anthony Miles 2020-10-27 23:06:27 +13:00 committed by Anthony
parent 5720444c6b
commit f98d040a65
4 changed files with 59 additions and 34 deletions

View File

@ -1908,6 +1908,10 @@ static LRESULT WINAPI EmuMsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lPar
extern void DSound_PrintStats(); //TODO: move into plugin class usage.
DSound_PrintStats();
}
else if (wParam == VK_F2)
{
g_UseFixedFunctionVertexShader = !g_UseFixedFunctionVertexShader;
}
else if (wParam == VK_F3)
{
g_bClipCursor = !g_bClipCursor;
@ -2885,8 +2889,6 @@ void GetMultiSampleScaleRaw(float& xScale, float& yScale) {
// Titles can render pre-transformed vertices to screen space (using XYZRHW vertex position data or otherwise)
// so we need to know the space they are in to interpret it correctly
void GetScreenScaleFactors(float& scaleX, float& scaleY) {
extern bool g_Xbox_VertexShader_IsPassthrough;
// Example:
// NFS HP2 renders in-game at 640*480
// The title uses MSAA, which increases the rendertarget size, but leaves the screen scale unaffected
@ -2916,7 +2918,7 @@ void GetScreenScaleFactors(float& scaleX, float& scaleY) {
// - Antialias sample (background gradient)
// Vertex program passthrough equivalent (title does apply backbuffer scale):
// - NFS:HP2 (car speed and other in-game UI elements)
if (!g_Xbox_VertexShader_IsPassthrough) {
if (g_Xbox_VertexShaderMode != VertexShaderMode::Passthrough) {
scaleX *= g_Xbox_BackbufferScaleX;
scaleY *= g_Xbox_BackbufferScaleY;
}
@ -4169,8 +4171,6 @@ void GetXboxViewportOffsetAndScale(float (&vOffset)[4], float(&vScale)[4])
void CxbxUpdateHostViewPortOffsetAndScaleConstants()
{
extern bool g_Xbox_VertexShader_IsPassthrough;
float vScaleOffset[2][4]; // 0 - scale 1 - offset
GetXboxViewportOffsetAndScale(vScaleOffset[1], vScaleOffset[0]);
@ -4196,7 +4196,7 @@ void CxbxUpdateHostViewPortOffsetAndScaleConstants()
// Passthrough should range 0 to 1, instead of 0 to zbuffer depth
// Test case: DoA3 character select
float zOutputScale = g_Xbox_VertexShader_IsPassthrough ? 1 : g_ZScale;
float zOutputScale = g_Xbox_VertexShaderMode == VertexShaderMode::Passthrough ? 1 : g_ZScale;
float screenspaceScale[4] = { xboxScreenspaceWidth / 2, -xboxScreenspaceHeight / 2, zOutputScale, 1 };
float screenspaceOffset[4] = { xboxScreenspaceWidth / 2 + aaOffsetX, xboxScreenspaceHeight / 2 + aaOffsetY, 0, 0 };
@ -7343,7 +7343,7 @@ void CxbxUpdateHostTextureScaling()
// Texcoord index. Just the texture stage unless fixed function mode
int texCoordIndex = stage;
if (g_Xbox_VertexShader_IsFixedFunction) {
if (g_Xbox_VertexShaderMode == VertexShaderMode::FixedFunction) {
// Get TEXCOORDINDEX for the current texture stage's state
// Stores both the texture stage index and information for generating coordinates
// See D3DTSS_TEXCOORDINDEX
@ -7434,7 +7434,7 @@ void CxbxUpdateHostViewport() {
aaScaleX *= g_RenderTargetUpscaleFactor;
aaScaleY *= g_RenderTargetUpscaleFactor;
if (g_Xbox_VertexShader_IsFixedFunction) {
if (g_Xbox_VertexShaderMode == VertexShaderMode::FixedFunction) {
// Set viewport
D3DVIEWPORT hostViewport = g_Xbox_Viewport;
hostViewport.X *= aaScaleX;
@ -7495,6 +7495,11 @@ void CxbxUpdateNativeD3DResources()
CxbxUpdateHostVertexShaderConstants();
CxbxUpdateHostViewport();
// Update fixed function vertex shader state
if (g_Xbox_VertexShaderMode == VertexShaderMode::FixedFunction && g_UseFixedFunctionVertexShader) {
UpdateFixedFunctionVertexShaderState();
}
// NOTE: Order is important here
// Some Texture States depend on RenderState values (Point Sprites)

View File

@ -844,7 +844,7 @@ void CxbxImpl_End()
// Arrange for g_InlineVertexBuffer_AttributeFormat to be returned in CxbxGetVertexDeclaration,
// so that our above composed declaration will be used for the next draw :
g_InlineVertexBuffer_DeclarationOverride = true;
// Note, that g_Xbox_VertexShader_IsFixedFunction should be left untouched,
// Note, that g_Xbox_VertexShaderMode should be left untouched,
// because except for the declaration override, the Xbox shader (either FVF
// or a program, or even passthrough shaders) should still be in effect!

View File

@ -58,9 +58,9 @@ extern XboxRenderStateConverter XboxRenderStates; // Declared in Direct3D9.cpp
xbox::X_STREAMINPUT g_Xbox_SetVertexShaderInput_Data[X_VSH_MAX_STREAMS] = { 0 }; // Active when g_Xbox_SetVertexShaderInput_Count > 0
xbox::X_VERTEXATTRIBUTEFORMAT g_Xbox_SetVertexShaderInput_Attributes = { 0 }; // Read by GetXboxVertexAttributes when g_Xbox_SetVertexShaderInput_Count > 0
// Variables set by [D3DDevice|CxbxImpl]_SetVertexShader() and [D3DDevice|CxbxImpl]_SelectVertexShader() :
bool g_Xbox_VertexShader_IsFixedFunction = true;
bool g_Xbox_VertexShader_IsPassthrough = false;
VertexShaderMode g_Xbox_VertexShaderMode = VertexShaderMode::FixedFunction;
bool g_UseFixedFunctionVertexShader = true;
xbox::dword_xt g_Xbox_VertexShader_Handle = 0;
#ifdef CXBX_USE_GLOBAL_VERTEXSHADER_POINTER // TODO : Would this be more accurate / simpler?
xbox::X_D3DVertexShader *g_Xbox_VertexShader_Ptr = nullptr;
@ -1092,7 +1092,9 @@ VertexDeclarationKey GetXboxVertexAttributesKey(xbox::X_VERTEXATTRIBUTEFORMAT* p
auto attributeHash = ComputeHash((void*)pXboxVertexAttributeFormat, sizeof(xbox::X_VERTEXATTRIBUTEFORMAT));
// For now, we use different declarations depending on if the fixed function pipeline
// is in use, even if the attributes are the same
return attributeHash ^ (VertexDeclarationKey)g_Xbox_VertexShader_IsFixedFunction;
return g_Xbox_VertexShaderMode == VertexShaderMode::FixedFunction
? attributeHash
: attributeHash ^ 1;
}
std::unordered_map<VertexDeclarationKey, CxbxVertexDeclaration*> g_CxbxVertexDeclarations;
@ -1139,18 +1141,27 @@ void CxbxUpdateHostVertexShader()
LOG_INIT; // Allows use of DEBUG_D3DRESULT
if (g_Xbox_VertexShader_IsFixedFunction) {
HRESULT hRet = g_pD3DDevice->SetVertexShader(nullptr);
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetVertexShader");
// TODO : Once available, start using host Fixed Function HLSL shader
// instead of using deprecated host fixed function (by setting a null
// vertex shader).
// As for the required host vertex declaration :
// CxbxUpdateHostVertexDeclaration already been
// called, which sets host vertex declaration based on the
// declaration that XboxVertexShaderFromFVF generated.
if (g_Xbox_VertexShaderMode == VertexShaderMode::FixedFunction) {
IDirect3DVertexShader* fixedFunctionShader = nullptr;
HRESULT hRet;
if (g_UseFixedFunctionVertexShader) {
static IDirect3DVertexShader* ffHlsl = nullptr;
if (ffHlsl == nullptr) {
ID3DBlob* pBlob = nullptr;
EmuCompileFixedFunction(&pBlob);
if (pBlob) {
hRet = g_pD3DDevice->CreateVertexShader((DWORD*)pBlob->GetBufferPointer(), &ffHlsl);
if (FAILED(hRet)) CxbxKrnlCleanup("Failed to create fixed-function shader");
}
}
fixedFunctionShader = ffHlsl;
}
hRet = g_pD3DDevice->SetVertexShader(fixedFunctionShader);
if (FAILED(hRet)) CxbxKrnlCleanup("Failed to set fixed-function shader");
}
else if (g_Xbox_VertexShader_IsPassthrough && g_bUsePassthroughHLSL) {
else if (g_Xbox_VertexShaderMode == VertexShaderMode::Passthrough && g_bUsePassthroughHLSL) {
if (passthroughshader == nullptr) {
ID3DBlob* pBlob = nullptr;
EmuCompileXboxPassthrough(&pBlob);
@ -1264,7 +1275,7 @@ CxbxVertexDeclaration* CxbxGetVertexDeclaration()
// Convert Xbox vertex attributes towards host Direct3D 9 vertex element
D3DVERTEXELEMENT* pRecompiledVertexElements = EmuRecompileVshDeclaration(
pXboxVertexAttributeFormat,
g_Xbox_VertexShader_IsFixedFunction,
g_Xbox_VertexShaderMode == VertexShaderMode::FixedFunction,
pCxbxVertexDeclaration);
// Create the vertex declaration
@ -1354,6 +1365,8 @@ void CxbxImpl_SelectVertexShader(DWORD Handle, DWORD Address)
// Either way, the given address slot is selected as the start of the current vertex shader program
g_Xbox_VertexShader_FunctionSlots_StartAddress = Address;
g_Xbox_VertexShaderMode = VertexShaderMode::ShaderProgram;
if (Handle) {
if (!VshHandleIsVertexShader(Handle))
LOG_TEST_CASE("Non-zero handle must be a VertexShader!");
@ -1362,8 +1375,6 @@ void CxbxImpl_SelectVertexShader(DWORD Handle, DWORD Address)
g_Xbox_VertexShader_Ptr = VshHandleToXboxVertexShader(Handle);
#endif
g_Xbox_VertexShader_Handle = Handle;
g_Xbox_VertexShader_IsFixedFunction = false;
g_Xbox_VertexShader_IsPassthrough = false;
}
}
@ -1450,7 +1461,6 @@ void CxbxImpl_SetVertexShader(DWORD Handle)
HRESULT hRet = D3D_OK;
xbox::X_D3DVertexShader* pXboxVertexShader = CxbxGetXboxVertexShaderForHandle(Handle);
g_Xbox_VertexShader_IsPassthrough = false;
if ((pXboxVertexShader->Flags & g_X_VERTEXSHADER_FLAG_VALID_MASK) != pXboxVertexShader->Flags) {
LOG_TEST_CASE("Unknown vertex shader flag");
@ -1470,8 +1480,8 @@ void CxbxImpl_SetVertexShader(DWORD Handle)
LOG_TEST_CASE("g_Xbox_VertexShader_FunctionSlots_StartAddress != 0");
bHackCallSelectAgain = true;
}
if (g_Xbox_VertexShader_IsFixedFunction != false) {
LOG_TEST_CASE("g_Xbox_VertexShader_IsFixedFunction != false");
if (g_Xbox_VertexShaderMode != VertexShaderMode::ShaderProgram) {
LOG_TEST_CASE("Not in shader program mode after SetVertexShader trampoline");
bHackCallSelectAgain = true;
}
@ -1480,7 +1490,6 @@ void CxbxImpl_SetVertexShader(DWORD Handle)
// _SelectVertexShader isn't applied;
// 'solve' that by calling it here instead.
CxbxImpl_SelectVertexShader(Handle, 0);
g_Xbox_VertexShader_IsFixedFunction = false;
}
#endif
} else {
@ -1511,12 +1520,11 @@ void CxbxImpl_SetVertexShader(DWORD Handle)
// Switch to passthrough program, if so required
if (pXboxVertexShader->Flags & X_VERTEXSHADER_FLAG_PASSTHROUGH) {
CxbxSetVertexShaderPassthroughProgram();
g_Xbox_VertexShader_IsFixedFunction = false;
g_Xbox_VertexShader_IsPassthrough = true;
g_Xbox_VertexShaderMode = VertexShaderMode::Passthrough;
} else {
// Test-case : Many XDK samples, Crazy taxi 3
//LOG_TEST_CASE("Other or no vertex shader flags");
g_Xbox_VertexShader_IsFixedFunction = true;
g_Xbox_VertexShaderMode = VertexShaderMode::FixedFunction;
}
}
}

View File

@ -80,6 +80,17 @@ typedef struct _CxbxVertexDeclaration
}
CxbxVertexDeclaration;
enum class VertexShaderMode {
FixedFunction,
// When titles use Xbox fixed function with pre-transformed vertices
// it actually uses a special "passthrough" shader program
Passthrough,
ShaderProgram
};
extern VertexShaderMode g_Xbox_VertexShaderMode;
extern bool g_UseFixedFunctionVertexShader;
// Intermediate vertex shader structures
enum VSH_OREG_NAME {
@ -217,4 +228,5 @@ extern void CxbxImpl_SetVertexShaderInput(DWORD Handle, UINT StreamCount, xbox::
extern void CxbxImpl_SetVertexShaderConstant(INT Register, PVOID pConstantData, DWORD ConstantCount);
extern void CxbxImpl_DeleteVertexShader(DWORD Handle);
extern void CxbxVertexShaderSetFlags();
extern HRESULT SetVertexShader(IDirect3DVertexShader* pShader);
#endif