Merge pull request #1757 from PatrickvL/indexed_quads

Speed up drawing indexed quads
This commit is contained in:
Luke Usher 2019-10-30 10:48:08 +00:00 committed by GitHub
commit ff5e0d3441
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 521 additions and 425 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1181,36 +1181,40 @@ D3DMULTISAMPLE_TYPE EmuXB2PC_D3DMultiSampleFormat(DWORD Type)
}
// lookup table for converting vertex count to primitive count
UINT EmuD3DVertexToPrimitive[11][2] =
{
const unsigned g_XboxPrimitiveTypeInfo[11][2] =
{
// First number is the starting number of vertices the draw requires
// Second number the number of vertices per primitive
// Example : Triangle list, has no starting vertices, and uses 3 vertices for each triangle
// Example : Triangle strip, starts with 2 vertices, and adds 1 for each triangle
{0, 0}, // NULL
{1, 0}, // X_D3DPT_POINTLIST
{2, 0}, // X_D3DPT_LINELIST
{1, 1}, // X_D3DPT_LINELOOP
{1, 1}, // X_D3DPT_LINESTRIP
{3, 0}, // X_D3DPT_TRIANGLELIST
{1, 2}, // X_D3DPT_TRIANGLESTRIP
{1, 2}, // X_D3DPT_TRIANGLEFAN
{4, 0}, // X_D3DPT_QUADLIST
{2, 2}, // X_D3DPT_QUADSTRIP
{1, 0}, // X_D3DPT_POLYGON
{0, 1}, // X_D3DPT_POINTLIST
{0, 2}, // X_D3DPT_LINELIST
{1, 1}, // X_D3DPT_LINELOOP
{1, 1}, // X_D3DPT_LINESTRIP
{0, 3}, // X_D3DPT_TRIANGLELIST
{2, 1}, // X_D3DPT_TRIANGLESTRIP
{2, 1}, // X_D3DPT_TRIANGLEFAN
{0, 4}, // X_D3DPT_QUADLIST
{2, 2}, // X_D3DPT_QUADSTRIP
{0, 1}, // X_D3DPT_POLYGON
};
// conversion table for xbox->pc primitive types
D3DPRIMITIVETYPE EmuPrimitiveTypeLookup[] =
const D3DPRIMITIVETYPE g_XboxPrimitiveTypeToHost[] =
{
/* NULL = 0 */ (D3DPRIMITIVETYPE)0,
/* D3DPT_POINTLIST = 1, */ D3DPT_POINTLIST,
/* D3DPT_LINELIST = 2, */ D3DPT_LINELIST,
/* D3DPT_LINELOOP = 3, Xbox */ D3DPT_LINESTRIP,
/* D3DPT_LINESTRIP = 4, */ D3DPT_LINESTRIP,
/* D3DPT_TRIANGLELIST = 5, */ D3DPT_TRIANGLELIST,
/* D3DPT_TRIANGLESTRIP = 6, */ D3DPT_TRIANGLESTRIP,
/* D3DPT_TRIANGLEFAN = 7, */ D3DPT_TRIANGLEFAN,
/* D3DPT_QUADLIST = 8, Xbox */ D3DPT_TRIANGLELIST,
/* D3DPT_QUADSTRIP = 9, Xbox */ D3DPT_TRIANGLESTRIP,
/* D3DPT_POLYGON = 10, Xbox */ D3DPT_TRIANGLEFAN,
/* D3DPT_MAX = 11, */ (D3DPRIMITIVETYPE)11
/* NULL = 0 */ (D3DPRIMITIVETYPE)0,
/* X_D3DPT_POINTLIST = 1, */ D3DPT_POINTLIST,
/* X_D3DPT_LINELIST = 2, */ D3DPT_LINELIST,
/* X_D3DPT_LINELOOP = 3, Xbox */ D3DPT_LINESTRIP,
/* X_D3DPT_LINESTRIP = 4, */ D3DPT_LINESTRIP,
/* X_D3DPT_TRIANGLELIST = 5, */ D3DPT_TRIANGLELIST,
/* X_D3DPT_TRIANGLESTRIP = 6, */ D3DPT_TRIANGLESTRIP,
/* X_D3DPT_TRIANGLEFAN = 7, */ D3DPT_TRIANGLEFAN,
/* X_D3DPT_QUADLIST = 8, Xbox */ D3DPT_TRIANGLELIST,
/* X_D3DPT_QUADSTRIP = 9, Xbox */ D3DPT_TRIANGLESTRIP,
/* X_D3DPT_POLYGON = 10, Xbox */ D3DPT_TRIANGLEFAN,
/* X_D3DPT_MAX = 11, */ (D3DPRIMITIVETYPE)11
};
void EmuUnswizzleBox

View File

@ -29,6 +29,8 @@
#include "core\hle\D3D8\XbD3D8Types.h"
#define VERTICES_PER_DOT 1
#define VERTICES_PER_LINE 2
#define VERTICES_PER_TRIANGLE 3
#define VERTICES_PER_QUAD 4
#define TRIANGLES_PER_QUAD 2
@ -231,46 +233,41 @@ inline D3DSTENCILOP EmuXB2PC_D3DSTENCILOP(XTL::X_D3DSTENCILOP Value)
}
// table used for vertex->primitive count conversion
extern UINT EmuD3DVertexToPrimitive[XTL::X_D3DPT_POLYGON + 1][2];
extern const UINT g_XboxPrimitiveTypeInfo[XTL::X_D3DPT_POLYGON + 1][2];
inline bool IsValidXboxVertexCount(XTL::X_D3DPRIMITIVETYPE XboxPrimitiveType, UINT VertexCount)
{
assert(XboxPrimitiveType < XTL::X_D3DPT_MAX);
inline bool EmuD3DValidVertexCount(XTL::X_D3DPRIMITIVETYPE XboxPrimitiveType, UINT VertexCount)
{
// Are there more vertices than required for setup?
if (VertexCount > EmuD3DVertexToPrimitive[XboxPrimitiveType][1])
if (VertexCount > g_XboxPrimitiveTypeInfo[XboxPrimitiveType][0])
// Are the additional vertices exact multiples of the required additional vertices per primitive?
if (0 == ((VertexCount - EmuD3DVertexToPrimitive[XboxPrimitiveType][1]) % EmuD3DVertexToPrimitive[XboxPrimitiveType][0]))
if (0 == ((VertexCount - g_XboxPrimitiveTypeInfo[XboxPrimitiveType][0]) % g_XboxPrimitiveTypeInfo[XboxPrimitiveType][1]))
return true;
return false;
}
// convert from vertex count to primitive count (Xbox)
inline int EmuD3DVertex2PrimitiveCount(XTL::X_D3DPRIMITIVETYPE PrimitiveType, int VertexCount)
inline unsigned ConvertXboxVertexCountToPrimitiveCount(XTL::X_D3DPRIMITIVETYPE XboxPrimitiveType, unsigned VertexCount)
{
return (VertexCount - EmuD3DVertexToPrimitive[PrimitiveType][1]) / EmuD3DVertexToPrimitive[PrimitiveType][0];
assert(XboxPrimitiveType < XTL::X_D3DPT_MAX);
return (VertexCount - g_XboxPrimitiveTypeInfo[XboxPrimitiveType][0]) / g_XboxPrimitiveTypeInfo[XboxPrimitiveType][1];
}
// convert from primitive count to vertex count (Xbox)
inline int EmuD3DPrimitive2VertexCount(XTL::X_D3DPRIMITIVETYPE PrimitiveType, int PrimitiveCount)
{
return (PrimitiveCount * EmuD3DVertexToPrimitive[PrimitiveType][0]) + EmuD3DVertexToPrimitive[PrimitiveType][1];
}
// conversion table for xbox->pc primitive types
extern D3DPRIMITIVETYPE EmuPrimitiveTypeLookup[];
extern const D3DPRIMITIVETYPE g_XboxPrimitiveTypeToHost[];
// convert xbox->pc primitive type
inline D3DPRIMITIVETYPE EmuXB2PC_D3DPrimitiveType(XTL::X_D3DPRIMITIVETYPE PrimitiveType)
inline D3DPRIMITIVETYPE EmuXB2PC_D3DPrimitiveType(XTL::X_D3DPRIMITIVETYPE XboxPrimitiveType)
{
if((DWORD)PrimitiveType == 0x7FFFFFFF)
return D3DPT_FORCE_DWORD;
return EmuPrimitiveTypeLookup[PrimitiveType];
}
inline int EmuD3DIndexCountToVertexCount(XTL::X_D3DPRIMITIVETYPE XboxPrimitiveType, int IndexCount)
{
return IndexCount;
if (XboxPrimitiveType >= XTL::X_D3DPT_MAX) {
LOG_TEST_CASE("XboxPrimitiveType too large");
return D3DPT_FORCE_DWORD;
}
return g_XboxPrimitiveTypeToHost[XboxPrimitiveType];
}
extern void EmuUnswizzleBox

View File

@ -258,8 +258,8 @@ void HLE_draw_inline_elements(NV2AState *d)
CxbxDrawContext DrawContext = {};
DrawContext.XboxPrimitiveType = (XTL::X_D3DPRIMITIVETYPE)pg->primitive_mode;
DrawContext.dwVertexCount = EmuD3DIndexCountToVertexCount(DrawContext.XboxPrimitiveType, uiIndexCount);
DrawContext.pIndexData = d->pgraph.inline_elements; // Used by GetVerticesInBuffer
DrawContext.dwVertexCount = uiIndexCount;
DrawContext.pXboxIndexData = d->pgraph.inline_elements;
CxbxDrawIndexed(DrawContext);
}

View File

@ -32,6 +32,7 @@
#include "common\util\hasher.h"
#include "core\kernel\support\Emu.h"
#include "core\hle\D3D8\Direct3D9\Direct3D9.h" // For g_pD3DDevice
#include "core\hle\D3D8\Direct3D9\WalkIndexBuffer.h" // for WalkIndexBuffer
#include "core\hle\D3D8\ResourceTracker.h"
#include "core\hle\D3D8\XbPushBuffer.h" // for DxbxFVF_GetNumberOfTextureCoordinates
#include "core\hle\D3D8\XbVertexBuffer.h"
@ -84,7 +85,7 @@ void CxbxPatchedStream::Activate(CxbxDrawContext *pDrawContext, UINT uiStream) c
//DEBUG_D3DRESULT(hRet, "g_pD3DDevice->SetStreamSource");
if (FAILED(hRet)) {
CxbxKrnlCleanup("Failed to set the type patched buffer as the new stream source!\n");
// TODO : Cartoon hits the above case when the vertex cache size is 0.
// TODO : test-case : XDK Cartoon hits the above case when the vertex cache size is 0.
}
}
}
@ -115,27 +116,6 @@ CxbxVertexBufferConverter::CxbxVertexBufferConverter()
m_pVertexShaderInfo = nullptr;
}
size_t GetVerticesInBuffer(DWORD dwOffset, DWORD dwVertexCount, PWORD pIndexData, DWORD dwIndexBase)
{
// If we are drawing from an offset, we know that the vertex count must have offset vertices
// before the first drawn vertices
dwVertexCount += dwOffset;
if (pIndexData == xbnullptr) {
return dwVertexCount;
}
// We are an indexed draw, so we have to parse the index buffer
// The highest index we see can be used to determine the vertex buffer size
DWORD highestVertexIndex = 0;
for (DWORD i = 0; i < dwVertexCount; i++) {
if (highestVertexIndex < pIndexData[i]) {
highestVertexIndex = pIndexData[i];
}
}
return dwIndexBase + highestVertexIndex + 1;
}
int CountActiveD3DStreams()
{
int lastStreamIndex = 0;
@ -630,7 +610,8 @@ void CxbxVertexBufferConverter::ConvertStream
break;
}
case XTL::X_D3DVSDT_NONE: { // 0x02:
// Test-case : WWE RAW2
// Test-case : WWE RAW2
// Test-case : PetitCopter
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;
@ -783,12 +764,24 @@ void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext)
m_pVertexShaderInfo = &(GetCxbxVertexShader(g_Xbox_VertexShader_Handle)->VertexShaderInfo);
}
pDrawContext->VerticesInBuffer = GetVerticesInBuffer(
pDrawContext->dwStartVertex,
pDrawContext->dwVertexCount,
pDrawContext->pIndexData,
pDrawContext->dwIndexBase
);
// If we are drawing from an offset, we know that the vertex count must have
// 'offset' vertices before the first drawn vertices
pDrawContext->VerticesInBuffer = pDrawContext->dwStartVertex + pDrawContext->dwVertexCount;
// When this is an indexed draw, take the index buffer into account
if (pDrawContext->pXboxIndexData) {
// Is the highest index in this buffer not set yet?
if (pDrawContext->HighIndex == 0) {
// TODO : Instead of calling WalkIndexBuffer here, set LowIndex and HighIndex
// in all callers that end up here (since they might be able to avoid the call)
LOG_TEST_CASE("HighIndex == 0"); // TODO : If this is never hit, replace entire block by assert(pDrawContext->HighIndex > 0);
WalkIndexBuffer(pDrawContext->LowIndex, pDrawContext->HighIndex, pDrawContext->pXboxIndexData, pDrawContext->dwVertexCount);
}
// Convert highest index (including the base offset) into a count
DWORD dwHighestVertexCount = pDrawContext->dwBaseVertexIndex + pDrawContext->HighIndex + 1;
// Use the biggest vertex count that can be reached
if (pDrawContext->VerticesInBuffer < dwHighestVertexCount)
pDrawContext->VerticesInBuffer = dwHighestVertexCount;
}
// Get the number of streams
m_uiNbrStreams = GetNbrStreams(pDrawContext);
@ -812,9 +805,9 @@ void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext)
// handled by d3d :
// Test-case : XDK Samples (FocusBlur, MotionBlur, Trees, PaintEffect, PlayField)
// No need to set : pDrawContext->XboxPrimitiveType = X_D3DPT_TRIANGLESTRIP;
pDrawContext->dwHostPrimitiveCount = EmuD3DVertex2PrimitiveCount(XTL::X_D3DPT_TRIANGLESTRIP, pDrawContext->dwVertexCount);
pDrawContext->dwHostPrimitiveCount = ConvertXboxVertexCountToPrimitiveCount(XTL::X_D3DPT_TRIANGLESTRIP, pDrawContext->dwVertexCount);
} else {
pDrawContext->dwHostPrimitiveCount = EmuD3DVertex2PrimitiveCount(pDrawContext->XboxPrimitiveType, pDrawContext->dwVertexCount);
pDrawContext->dwHostPrimitiveCount = ConvertXboxVertexCountToPrimitiveCount(pDrawContext->XboxPrimitiveType, pDrawContext->dwVertexCount);
}
if (pDrawContext->XboxPrimitiveType == XTL::X_D3DPT_POLYGON) {

View File

@ -36,16 +36,17 @@ typedef struct _CxbxDrawContext
IN XTL::X_D3DPRIMITIVETYPE XboxPrimitiveType;
IN DWORD dwVertexCount;
IN DWORD dwStartVertex; // Only D3DDevice_DrawVertices sets this (potentially higher than default 0)
IN PWORD pIndexData;
IN DWORD dwIndexBase;
IN size_t VerticesInBuffer;
IN PWORD pXboxIndexData; // Set by D3DDevice_DrawIndexedVertices, D3DDevice_DrawIndexedVerticesUP and HLE_draw_inline_elements
IN DWORD dwBaseVertexIndex; // Set to g_XboxBaseVertexIndex in D3DDevice_DrawIndexedVertices
IN INDEX16 LowIndex, HighIndex; // Set when pXboxIndexData is set
IN size_t VerticesInBuffer; // Set by CxbxVertexBufferConverter::Apply
// Data if Draw...UP call
IN PVOID pXboxVertexStreamZeroData;
IN UINT uiXboxVertexStreamZeroStride;
// Values to be used on host
OUT PVOID pHostVertexStreamZeroData;
OUT UINT uiHostVertexStreamZeroStride;
OUT DWORD dwHostPrimitiveCount;
OUT DWORD dwHostPrimitiveCount; // Set by CxbxVertexBufferConverter::Apply
}
CxbxDrawContext;

View File

@ -911,6 +911,11 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader,
// We count down from the highest available on the host because Xbox titles don't use values that high, and we read from c192 (one above maximum Xbox c191 constant) and up
static int temporaryRegisterBase = g_D3DCaps.VS20Caps.NumTemps - 13;
moveConstantsToTemporaries << "mov r" << (temporaryRegisterBase + i) << ", c" << (CXBX_D3DVS_CONSTREG_VERTEXDATA4F_BASE + i) << "\n";
// test-case : Blade II (before menu's)
// test-case : Namco Museum 50th Anniversary (at boot)
// test-case : Pac-Man World 2 (at boot)
// test-case : The Simpsons Road Rage (leaving menu's, before entering in-game)
// test-case : The SpongeBob SquarePants Movie (before menu's)
LOG_TEST_CASE("Shader uses undeclared Vertex Input Registers");
i++;
continue;
@ -1813,7 +1818,8 @@ private:
{
DWORD regNum = (XboxToken & X_D3DVSD_VERTEXREGMASK) >> X_D3DVSD_VERTEXREGSHIFT;
if (regNum >= hostTemporaryRegisterCount /*12 for D3D8, D3D9 value depends on host GPU */) {
// Lego Star Wars hits this
// test-case : BLiNX: the time sweeper
// test-case : Lego Star Wars
LOG_TEST_CASE("RegNum > NumTemps");
}
return regNum;
@ -1823,7 +1829,7 @@ private:
{
DWORD regNum = (XboxToken & X_D3DVSD_VERTEXREGINMASK) >> X_D3DVSD_VERTEXREGINSHIFT;
if (regNum >= hostTemporaryRegisterCount /*12 for D3D8, D3D9 value depends on host GPU */) {
// Lego Star Wars hits this
// test-case : Lego Star Wars
LOG_TEST_CASE("RegNum > NumTemps");
}
return regNum;

View File

@ -147,10 +147,9 @@ bool VerifySymbolAddressAgainstXRef(char *SymbolName, xbaddr Address, int XRef)
return true;
}
// For XREF_D3DTSS_TEXCOORDINDEX, Kabuki Warriors hits this case
CxbxPopupMessage(LOG_LEVEL::WARNING, CxbxMsgDlgIcon_Warn,
"Verification of %s failed : XREF was 0x%.8X while lookup gave 0x%.8X", SymbolName, XRefAddr, Address);
// For XREF_D3DTSS_TEXCOORDINDEX, Kabuki Warriors hits this case
// test case : Kabuki Warriors (for XREF_D3DTSS_TEXCOORDINDEX)
return false;
}*/

View File

@ -3282,7 +3282,7 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
// We do not emulate processor specific registers just yet
// Some titles attempt to manually set the TSC via this instruction
// This needs fixing eventually, but should be acceptible to ignore for now!
// Chase: Hollywood Stunt Driver hits this
// test-case : Chase: Hollywood Stunt Driver
EmuLog(LOG_LEVEL::WARNING, "WRMSR instruction ignored");
break;
case I_XOR: