Fix vertex conversion when skip tokens are present in the Xbox vertex declaration.

This commit is contained in:
patrickvl 2019-10-12 16:27:11 +02:00 committed by PatrickvL
parent e5dc2e5e13
commit 6ef5b21144
3 changed files with 66 additions and 32 deletions

View File

@ -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");
// No host element data (but Xbox size can be above zero, when used for X_D3DVSD_MASK_SKIP*
break;
}
default: {

View File

@ -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)

View File

@ -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;