From 6ef5b211441671be21a33a6248aa36ab6a7db8fa Mon Sep 17 00:00:00 2001 From: patrickvl Date: Sat, 12 Oct 2019 16:27:11 +0200 Subject: [PATCH] Fix vertex conversion when skip tokens are present in the Xbox vertex declaration. --- src/core/hle/D3D8/XbVertexBuffer.cpp | 22 ++------- src/core/hle/D3D8/XbVertexShader.cpp | 73 +++++++++++++++++++++++----- src/core/hle/D3D8/XbVertexShader.h | 3 +- 3 files changed, 66 insertions(+), 32 deletions(-) diff --git a/src/core/hle/D3D8/XbVertexBuffer.cpp b/src/core/hle/D3D8/XbVertexBuffer.cpp index b63f9b969..6efcd71e2 100644 --- a/src/core/hle/D3D8/XbVertexBuffer.cpp +++ b/src/core/hle/D3D8/XbVertexBuffer.cpp @@ -437,7 +437,7 @@ void CxbxVertexBufferConverter::ConvertStream for (UINT uiElement = 0; uiElement < pVertexShaderStreamInfo->NumberOfVertexElements; uiElement++) { FLOAT *pXboxVertexAsFloat = (FLOAT*)pXboxVertexAsByte; SHORT *pXboxVertexAsShort = (SHORT*)pXboxVertexAsByte; - int XboxElementByteSize = pVertexShaderStreamInfo->VertexElements[uiElement].HostByteSize; + const int XboxElementByteSize = pVertexShaderStreamInfo->VertexElements[uiElement].XboxByteSize; FLOAT *pHostVertexAsFloat = (FLOAT*)pHostVertexAsByte; SHORT *pHostVertexAsShort = (SHORT*)pHostVertexAsByte; // Dxbx note : The following code handles only the D3DVSDT enums that need conversion; @@ -445,7 +445,6 @@ void CxbxVertexBufferConverter::ConvertStream switch (pVertexShaderStreamInfo->VertexElements[uiElement].XboxType) { case XTL::X_D3DVSDT_NORMSHORT1: { // 0x11: // Test-cases : Halo - Combat Evolved - XboxElementByteSize = 1 * sizeof(SHORT); if (g_D3DCaps.DeclTypes & D3DDTCAPS_SHORT2N) { // Make it SHORT2N pHostVertexAsShort[0] = pXboxVertexAsShort[0]; @@ -461,11 +460,9 @@ void CxbxVertexBufferConverter::ConvertStream } case XTL::X_D3DVSDT_NORMSHORT2: { // 0x21: // Test-cases : Baldur's Gate: Dark Alliance 2, F1 2002, Gun, Halo - Combat Evolved, Scrapland - XboxElementByteSize = 2 * sizeof(SHORT); if (g_D3DCaps.DeclTypes & D3DDTCAPS_SHORT2N) { // No need for patching when D3D9 supports D3DDECLTYPE_SHORT2N // TODO : goto default; // ?? - //assert(XboxElementByteSize == 2 * sizeof(SHORT)); //memcpy(pHostVertexAsByte, pXboxVertexAsByte, XboxElementByteSize); // Make it SHORT2N pHostVertexAsShort[0] = pXboxVertexAsShort[0]; @@ -481,7 +478,6 @@ void CxbxVertexBufferConverter::ConvertStream } case XTL::X_D3DVSDT_NORMSHORT3: { // 0x31: // Test-cases : Cel Damage, Constantine, Destroy All Humans! - XboxElementByteSize = 3 * sizeof(SHORT); if (g_D3DCaps.DeclTypes & D3DDTCAPS_SHORT4N) { // Make it SHORT4N pHostVertexAsShort[0] = pXboxVertexAsShort[0]; @@ -500,11 +496,9 @@ void CxbxVertexBufferConverter::ConvertStream } case XTL::X_D3DVSDT_NORMSHORT4: { // 0x41: // Test-cases : Judge Dredd: Dredd vs Death, NHL Hitz 2002, Silent Hill 2, Sneakers, Tony Hawk Pro Skater 4 - XboxElementByteSize = 4 * sizeof(SHORT); if (g_D3DCaps.DeclTypes & D3DDTCAPS_SHORT4N) { // No need for patching when D3D9 supports D3DDECLTYPE_SHORT4N // TODO : goto default; // ?? - //assert(XboxElementByteSize == 4 * sizeof(SHORT)); //memcpy(pHostVertexAsByte, pXboxVertexAsByte, XboxElementByteSize); // Make it SHORT4N pHostVertexAsShort[0] = pXboxVertexAsShort[0]; @@ -524,7 +518,6 @@ void CxbxVertexBufferConverter::ConvertStream } case XTL::X_D3DVSDT_NORMPACKED3: { // 0x16: // Test-cases : Dashboard - XboxElementByteSize = 1 * sizeof(int32_t); // Make it FLOAT3 union { int32_t value; @@ -543,7 +536,6 @@ void CxbxVertexBufferConverter::ConvertStream break; } case XTL::X_D3DVSDT_SHORT1: { // 0x15: - XboxElementByteSize = 1 * sizeof(SHORT); // Make it SHORT2 and set the second short to 0 pHostVertexAsShort[0] = pXboxVertexAsShort[0]; pHostVertexAsShort[1] = 0; @@ -551,7 +543,6 @@ void CxbxVertexBufferConverter::ConvertStream } case XTL::X_D3DVSDT_SHORT3: { // 0x35: // Test-cases : Turok - XboxElementByteSize = 3 * sizeof(SHORT); // Make it a SHORT4 and set the fourth short to 1 pHostVertexAsShort[0] = pXboxVertexAsShort[0]; pHostVertexAsShort[1] = pXboxVertexAsShort[1]; @@ -560,7 +551,6 @@ void CxbxVertexBufferConverter::ConvertStream break; } case XTL::X_D3DVSDT_PBYTE1: { // 0x14: - XboxElementByteSize = 1 * sizeof(BYTE); if (g_D3DCaps.DeclTypes & D3DDTCAPS_UBYTE4N) { // Make it UBYTE4N pHostVertexAsByte[0] = pXboxVertexAsByte[0]; @@ -576,7 +566,6 @@ void CxbxVertexBufferConverter::ConvertStream break; } case XTL::X_D3DVSDT_PBYTE2: { // 0x24: - XboxElementByteSize = 2 * sizeof(BYTE); if (g_D3DCaps.DeclTypes & D3DDTCAPS_UBYTE4N) { // Make it UBYTE4N pHostVertexAsByte[0] = pXboxVertexAsByte[0]; @@ -594,7 +583,6 @@ void CxbxVertexBufferConverter::ConvertStream } case XTL::X_D3DVSDT_PBYTE3: { // 0x34: // Test-cases : Turok - XboxElementByteSize = 3 * sizeof(BYTE); if (g_D3DCaps.DeclTypes & D3DDTCAPS_UBYTE4N) { // Make it UBYTE4N pHostVertexAsByte[0] = pXboxVertexAsByte[0]; @@ -613,11 +601,9 @@ void CxbxVertexBufferConverter::ConvertStream } case XTL::X_D3DVSDT_PBYTE4: { // 0x44: // Test-case : Jet Set Radio Future - XboxElementByteSize = 4 * sizeof(BYTE); if (g_D3DCaps.DeclTypes & D3DDTCAPS_UBYTE4N) { // No need for patching when D3D9 supports D3DDECLTYPE_UBYTE4N // TODO : goto default; // ?? - //assert(XboxElementByteSize == 4 * sizeof(BYTE)); //memcpy(pHostVertexAsByte, pXboxVertexAsByte, XboxElementByteSize); // Make it UBYTE4N pHostVertexAsByte[0] = pXboxVertexAsByte[0]; @@ -636,7 +622,6 @@ void CxbxVertexBufferConverter::ConvertStream break; } case XTL::X_D3DVSDT_FLOAT2H: { // 0x72: - XboxElementByteSize = 3 * sizeof(FLOAT); // Make it FLOAT4 and set the third float to 0.0 pHostVertexAsFloat[0] = pXboxVertexAsFloat[0]; pHostVertexAsFloat[1] = pXboxVertexAsFloat[1]; @@ -644,9 +629,10 @@ void CxbxVertexBufferConverter::ConvertStream pHostVertexAsFloat[3] = pXboxVertexAsFloat[2]; break; } - case XTL::X_D3DVSDT_NONE: { // 0x02: // Skip it + case XTL::X_D3DVSDT_NONE: { // 0x02: // Test-case : WWE RAW2 - LOG_TEST_CASE("X_D3DVSDT_NONE"); + LOG_TEST_CASE("X_D3DVSDT_NONE"); + // No host element data (but Xbox size can be above zero, when used for X_D3DVSD_MASK_SKIP* break; } default: { diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index 279af71ec..5cfad3196 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -1899,11 +1899,48 @@ private: } } + void VshConvert_RegisterVertexElement( + UINT XboxVertexElementDataType, + UINT XboxVertexElementByteSize, + UINT HostVertexElementByteSize, + BOOL NeedPatching) + { + CxbxVertexShaderStreamElement* pCurrentElement = &(pCurrentVertexShaderStreamInfo->VertexElements[pCurrentVertexShaderStreamInfo->NumberOfVertexElements]); + pCurrentElement->XboxType = XboxVertexElementDataType; + pCurrentElement->XboxByteSize = XboxVertexElementByteSize; + pCurrentElement->HostByteSize = HostVertexElementByteSize; + pCurrentVertexShaderStreamInfo->NumberOfVertexElements++; + pCurrentVertexShaderStreamInfo->NeedPatch |= NeedPatching; + } + + void VshConvert_SkipBytes(int SkipBytesCount) + { + if (SkipBytesCount % sizeof(DWORD)) { + LOG_TEST_CASE("D3DVSD_SKIPBYTES not divisble by 4!"); + } +#if 0 // Potential optimization, for now disabled for simplicity : + else { + // Skip size is a whole multiple of 4 bytes; + // Is stream patching not needed up until this element? + if (!pCurrentVertexShaderStreamInfo->NeedPatch) { + // Then we can get away with increasing the host stride, + // which avoids otherwise needless vertex buffer patching : + pCurrentVertexShaderStreamInfo->HostVertexStride += SkipBytesCount; + return; + } + } +#endif + + // Register a 'skip' element, so that Xbox data will be skipped + // without increasing host stride - this does require patching : + VshConvert_RegisterVertexElement(XTL::X_D3DVSDT_NONE, SkipBytesCount, /*HostSize=*/0, /*NeedPatching=*/TRUE); + } + void VshConvertToken_STREAMDATA_SKIP(DWORD *pXboxToken) { WORD SkipCount = (*pXboxToken & X_D3DVSD_SKIPCOUNTMASK) >> X_D3DVSD_SKIPCOUNTSHIFT; DbgVshPrintf("\tD3DVSD_SKIP(%d),\n", SkipCount); - pCurrentVertexShaderStreamInfo->HostVertexStride += (SkipCount * sizeof(DWORD)); + VshConvert_SkipBytes(SkipCount * sizeof(DWORD)); } void VshConvertToken_STREAMDATA_SKIPBYTES(DWORD* pXboxToken) @@ -1911,11 +1948,7 @@ private: WORD SkipBytesCount = (*pXboxToken & X_D3DVSD_SKIPCOUNTMASK) >> X_D3DVSD_SKIPCOUNTSHIFT; DbgVshPrintf("\tD3DVSD_SKIPBYTES(%d), /* xbox ext. */\n", SkipBytesCount); - if (SkipBytesCount % sizeof(DWORD)) { - EmuLog(LOG_LEVEL::WARNING, "D3DVSD_SKIPBYTES can't be converted to D3DVSD_SKIP, not divisble by 4."); - } - - pCurrentVertexShaderStreamInfo->HostVertexStride += SkipBytesCount; + VshConvert_SkipBytes(SkipBytesCount); } void VshConvertToken_STREAMDATA_REG(DWORD *pXboxToken) @@ -1945,6 +1978,7 @@ private: RegVIsPresentInDeclaration[VertexRegister] = true; DWORD XboxVertexElementDataType = (*pXboxToken & X_D3DVSD_DATATYPEMASK) >> X_D3DVSD_DATATYPESHIFT; + WORD XboxVertexElementByteSize = 0; BYTE HostVertexElementDataType = 0; WORD HostVertexElementByteSize = 0; @@ -1996,6 +2030,7 @@ private: HostVertexElementDataType = D3DDECLTYPE_FLOAT1; HostVertexElementByteSize = 1 * sizeof(FLOAT); } + XboxVertexElementByteSize = 1 * sizeof(XTL::SHORT); NeedPatching = TRUE; break; case XTL::X_D3DVSDT_NORMSHORT2: // 0x21: @@ -2010,6 +2045,7 @@ private: DbgVshPrintf("D3DVSDT_NORMSHORT2 /* xbox ext. */"); HostVertexElementDataType = D3DDECLTYPE_FLOAT2; HostVertexElementByteSize = 2 * sizeof(FLOAT); + XboxVertexElementByteSize = 2 * sizeof(XTL::SHORT); NeedPatching = TRUE; } break; @@ -2024,6 +2060,7 @@ private: HostVertexElementDataType = D3DDECLTYPE_FLOAT3; HostVertexElementByteSize = 3 * sizeof(FLOAT); } + XboxVertexElementByteSize = 3 * sizeof(XTL::SHORT); NeedPatching = TRUE; break; case XTL::X_D3DVSDT_NORMSHORT4: // 0x41: @@ -2038,6 +2075,7 @@ private: DbgVshPrintf("D3DVSDT_NORMSHORT4 /* xbox ext. */"); HostVertexElementDataType = D3DDECLTYPE_FLOAT4; HostVertexElementByteSize = 4 * sizeof(FLOAT); + XboxVertexElementByteSize = 4 * sizeof(XTL::SHORT); NeedPatching = TRUE; } break; @@ -2045,18 +2083,21 @@ private: DbgVshPrintf("D3DVSDT_NORMPACKED3 /* xbox ext. */"); HostVertexElementDataType = D3DDECLTYPE_FLOAT3; HostVertexElementByteSize = 3 * sizeof(FLOAT); + XboxVertexElementByteSize = 1 * sizeof(XTL::DWORD); NeedPatching = TRUE; break; case XTL::X_D3DVSDT_SHORT1: // 0x15: DbgVshPrintf("D3DVSDT_SHORT1 /* xbox ext. */"); HostVertexElementDataType = D3DDECLTYPE_SHORT2; HostVertexElementByteSize = 2 * sizeof(SHORT); + XboxVertexElementByteSize = 1 * sizeof(XTL::SHORT); NeedPatching = TRUE; break; case XTL::X_D3DVSDT_SHORT3: // 0x35: DbgVshPrintf("D3DVSDT_SHORT3 /* xbox ext. */"); HostVertexElementDataType = D3DDECLTYPE_SHORT4; HostVertexElementByteSize = 4 * sizeof(SHORT); + XboxVertexElementByteSize = 3 * sizeof(XTL::SHORT); NeedPatching = TRUE; break; case XTL::X_D3DVSDT_PBYTE1: // 0x14: @@ -2070,6 +2111,7 @@ private: HostVertexElementDataType = D3DDECLTYPE_FLOAT1; HostVertexElementByteSize = 1 * sizeof(FLOAT); } + XboxVertexElementByteSize = 1 * sizeof(XTL::BYTE); NeedPatching = TRUE; break; case XTL::X_D3DVSDT_PBYTE2: // 0x24: @@ -2083,6 +2125,7 @@ private: HostVertexElementDataType = D3DDECLTYPE_FLOAT2; HostVertexElementByteSize = 2 * sizeof(FLOAT); } + XboxVertexElementByteSize = 2 * sizeof(XTL::BYTE); NeedPatching = TRUE; break; case XTL::X_D3DVSDT_PBYTE3: // 0x34: @@ -2096,6 +2139,7 @@ private: HostVertexElementDataType = D3DDECLTYPE_FLOAT3; HostVertexElementByteSize = 3 * sizeof(FLOAT); } + XboxVertexElementByteSize = 3 * sizeof(XTL::BYTE); NeedPatching = TRUE; break; case XTL::X_D3DVSDT_PBYTE4: // 0x44: @@ -2111,6 +2155,7 @@ private: DbgVshPrintf("D3DVSDT_PBYTE4 /* xbox ext. */"); HostVertexElementDataType = D3DDECLTYPE_FLOAT4; HostVertexElementByteSize = 4 * sizeof(FLOAT); + XboxVertexElementByteSize = 4 * sizeof(XTL::BYTE); NeedPatching = TRUE; } break; @@ -2118,11 +2163,12 @@ private: DbgVshPrintf("D3DVSDT_FLOAT2H /* xbox ext. */"); HostVertexElementDataType = D3DDECLTYPE_FLOAT4; HostVertexElementByteSize = 4 * sizeof(FLOAT); + XboxVertexElementByteSize = 3 * sizeof(FLOAT); NeedPatching = TRUE; break; case XTL::X_D3DVSDT_NONE: // 0x02: DbgVshPrintf("D3DVSDT_NONE /* xbox ext. */"); - // Ignore token + // No host element data, so no patching break; default: DbgVshPrintf("Unknown data type for D3DVSD_REG: 0x%02X\n", XboxVertexElementDataType); @@ -2134,15 +2180,17 @@ private: // On X_D3DVSDT_NONE skip this token if (XboxVertexElementDataType == XTL::X_D3DVSDT_NONE) { + // Xbox elements with X_D3DVSDT_NONE have size zero, so there's no need to register those. + // Note, that for skip tokens, we DO call VshConvert_RegisterVertexElement with a X_D3DVSDT_NONE! return; } // save patching information - CxbxVertexShaderStreamElement *pCurrentElement = &(pCurrentVertexShaderStreamInfo->VertexElements[pCurrentVertexShaderStreamInfo->NumberOfVertexElements]); - pCurrentElement->XboxType = XboxVertexElementDataType; - pCurrentElement->HostByteSize = HostVertexElementByteSize; - pCurrentVertexShaderStreamInfo->NumberOfVertexElements++; - pCurrentVertexShaderStreamInfo->NeedPatch |= NeedPatching; + VshConvert_RegisterVertexElement( + XboxVertexElementDataType, + NeedPatching ? XboxVertexElementByteSize : HostVertexElementByteSize, + HostVertexElementByteSize, + NeedPatching); pRecompiled->Stream = pCurrentVertexShaderStreamInfo->CurrentStreamNumber; pRecompiled->Offset = pCurrentVertexShaderStreamInfo->HostVertexStride; @@ -2154,7 +2202,6 @@ private: pRecompiled++; pCurrentVertexShaderStreamInfo->HostVertexStride += HostVertexElementByteSize; - } void VshConvertToken_STREAMDATA(DWORD *pXboxToken) diff --git a/src/core/hle/D3D8/XbVertexShader.h b/src/core/hle/D3D8/XbVertexShader.h index e6ca069dc..2d49bf163 100644 --- a/src/core/hle/D3D8/XbVertexShader.h +++ b/src/core/hle/D3D8/XbVertexShader.h @@ -37,6 +37,7 @@ typedef struct _CxbxVertexShaderStreamElement { UINT XboxType; // The stream element data types (xbox) + UINT XboxByteSize; // The stream element data sizes (xbox) UINT HostByteSize; // The stream element data sizes (pc) } CxbxVertexShaderStreamElement; @@ -59,7 +60,7 @@ typedef struct _CxbxVertexShaderStreamInfo WORD HostVertexStride; DWORD NumberOfVertexElements; // Number of the stream data types WORD CurrentStreamNumber; - CxbxVertexShaderStreamElement VertexElements[X_VSH_MAX_ATTRIBUTES + 16]; // TODO : Why 16 extrahost additions?) + CxbxVertexShaderStreamElement VertexElements[X_VSH_MAX_ATTRIBUTES + 16]; // TODO : Why 16 extra host additions?) } CxbxVertexShaderStreamInfo;