Merge pull request #2048 from CookiePLMonster/vertex-stream-cache-optimization

Optimize vertex stream cache for partial buffer access
This commit is contained in:
Luke Usher 2020-11-27 07:56:15 +00:00 committed by GitHub
commit 362c93801f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 24 additions and 25 deletions

View File

@ -6864,7 +6864,7 @@ void CxbxDrawIndexed(CxbxDrawContext &DrawContext)
// for an explanation on the function of the BaseVertexIndex, MinVertexIndex, NumVertices and StartIndex arguments. // for an explanation on the function of the BaseVertexIndex, MinVertexIndex, NumVertices and StartIndex arguments.
HRESULT hRet = g_pD3DDevice->DrawIndexedPrimitive( HRESULT hRet = g_pD3DDevice->DrawIndexedPrimitive(
/* PrimitiveType = */EmuXB2PC_D3DPrimitiveType(DrawContext.XboxPrimitiveType), /* PrimitiveType = */EmuXB2PC_D3DPrimitiveType(DrawContext.XboxPrimitiveType),
BaseVertexIndex, /* BaseVertexIndex, = */-CacheEntry.LowIndex, // Base vertex index has been accounted for in the stream conversion, now we need to "un-offset" the index buffer
/* MinVertexIndex = */CacheEntry.LowIndex, /* MinVertexIndex = */CacheEntry.LowIndex,
/* NumVertices = */(CacheEntry.HighIndex - CacheEntry.LowIndex) + 1, /* NumVertices = */(CacheEntry.HighIndex - CacheEntry.LowIndex) + 1,
/* startIndex = DrawContext.dwStartVertex = */0, /* startIndex = DrawContext.dwStartVertex = */0,
@ -7516,9 +7516,6 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_DrawVertices)
// Draw quadlists using a single 'quad-to-triangle mapping' index buffer : // Draw quadlists using a single 'quad-to-triangle mapping' index buffer :
// Assure & activate that special index buffer : // Assure & activate that special index buffer :
CxbxAssureQuadListD3DIndexBuffer(/*NrOfQuadIndices=*/DrawContext.dwVertexCount); CxbxAssureQuadListD3DIndexBuffer(/*NrOfQuadIndices=*/DrawContext.dwVertexCount);
// This API's StartVertex argument is multiplied by vertex stride and added to the start of the vertex buffer;
// BaseVertexIndex offers the same functionality on host :
UINT BaseVertexIndex = DrawContext.dwStartVertex;
// Convert quad vertex count to triangle vertex count : // Convert quad vertex count to triangle vertex count :
UINT NumVertices = QuadToTriangleVertexCount(DrawContext.dwVertexCount); UINT NumVertices = QuadToTriangleVertexCount(DrawContext.dwVertexCount);
// Convert quad primitive count to triangle primitive count : // Convert quad primitive count to triangle primitive count :
@ -7528,7 +7525,7 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_DrawVertices)
// Emulate drawing quads by drawing each quad with two indexed triangles : // Emulate drawing quads by drawing each quad with two indexed triangles :
HRESULT hRet = g_pD3DDevice->DrawIndexedPrimitive( HRESULT hRet = g_pD3DDevice->DrawIndexedPrimitive(
/*PrimitiveType=*/D3DPT_TRIANGLELIST, /*PrimitiveType=*/D3DPT_TRIANGLELIST,
BaseVertexIndex, /*BaseVertexIndex=*/0, // Base vertex index has been accounted for in the stream conversion
/*MinVertexIndex=*/0, /*MinVertexIndex=*/0,
NumVertices, NumVertices,
/*startIndex=*/0, /*startIndex=*/0,
@ -7542,7 +7539,7 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_DrawVertices)
// if (StartVertex > 0) LOG_TEST_CASE("StartVertex > 0 (non-quad)"); // Verified test case : XDK Sample (PlayField) // if (StartVertex > 0) LOG_TEST_CASE("StartVertex > 0 (non-quad)"); // Verified test case : XDK Sample (PlayField)
HRESULT hRet = g_pD3DDevice->DrawPrimitive( HRESULT hRet = g_pD3DDevice->DrawPrimitive(
EmuXB2PC_D3DPrimitiveType(DrawContext.XboxPrimitiveType), EmuXB2PC_D3DPrimitiveType(DrawContext.XboxPrimitiveType),
DrawContext.dwStartVertex, /*StartVertex=*/0, // Start vertex has been accounted for in the stream conversion
DrawContext.dwHostPrimitiveCount DrawContext.dwHostPrimitiveCount
); );
DEBUG_D3DRESULT(hRet, "g_pD3DDevice->DrawPrimitive"); DEBUG_D3DRESULT(hRet, "g_pD3DDevice->DrawPrimitive");
@ -7553,8 +7550,8 @@ xbox::void_xt WINAPI xbox::EMUPATCH(D3DDevice_DrawVertices)
LOG_TEST_CASE("X_D3DPT_LINELOOP"); // TODO : Text-cases needed LOG_TEST_CASE("X_D3DPT_LINELOOP"); // TODO : Text-cases needed
assert(DrawContext.dwBaseVertexIndex == 0); // if this fails, it needs to be added to LowIndex and HighIndex : assert(DrawContext.dwBaseVertexIndex == 0); // if this fails, it needs to be added to LowIndex and HighIndex :
INDEX16 LowIndex = (INDEX16)DrawContext.dwStartVertex; INDEX16 LowIndex = 0;
INDEX16 HighIndex = (INDEX16)(DrawContext.dwStartVertex + DrawContext.dwHostPrimitiveCount); INDEX16 HighIndex = (INDEX16)(DrawContext.dwHostPrimitiveCount);
// Draw the closing line using a helper function (which will SetIndices) // Draw the closing line using a helper function (which will SetIndices)
CxbxDrawIndexedClosingLine(LowIndex, HighIndex); CxbxDrawIndexedClosingLine(LowIndex, HighIndex);
// NOTE : We don't restore the previously active index buffer // NOTE : We don't restore the previously active index buffer

View File

@ -261,9 +261,7 @@ void CxbxVertexBufferConverter::ConvertStream
UINT HostStreamNumber = XboxStreamNumber; // Use Xbox stream index on host UINT HostStreamNumber = XboxStreamNumber; // Use Xbox stream index on host
uint8_t *pXboxVertexData = xbox::zeroptr; uint8_t *pXboxVertexData = xbox::zeroptr;
UINT uiXboxVertexStride = 0; UINT uiXboxVertexStride = 0;
UINT uiVertexCount = 0;
UINT uiHostVertexStride = 0; UINT uiHostVertexStride = 0;
DWORD dwHostVertexDataSize = 0;
uint8_t *pHostVertexData = nullptr; uint8_t *pHostVertexData = nullptr;
IDirect3DVertexBuffer *pNewHostVertexBuffer = nullptr; IDirect3DVertexBuffer *pNewHostVertexBuffer = nullptr;
@ -275,9 +273,7 @@ void CxbxVertexBufferConverter::ConvertStream
pXboxVertexData = (uint8_t *)pDrawContext->pXboxVertexStreamZeroData; pXboxVertexData = (uint8_t *)pDrawContext->pXboxVertexStreamZeroData;
uiXboxVertexStride = pDrawContext->uiXboxVertexStreamZeroStride; uiXboxVertexStride = pDrawContext->uiXboxVertexStreamZeroStride;
uiVertexCount = pDrawContext->VerticesInBuffer;
uiHostVertexStride = (bNeedVertexPatching) ? pVertexShaderStreamInfo->HostVertexStride : uiXboxVertexStride; uiHostVertexStride = (bNeedVertexPatching) ? pVertexShaderStreamInfo->HostVertexStride : uiXboxVertexStride;
dwHostVertexDataSize = uiVertexCount * uiHostVertexStride;
} else { } else {
xbox::X_STREAMINPUT& XboxStreamInput = GetXboxVertexStreamInput(XboxStreamNumber); xbox::X_STREAMINPUT& XboxStreamInput = GetXboxVertexStreamInput(XboxStreamNumber);
xbox::X_D3DVertexBuffer *pXboxVertexBuffer = XboxStreamInput.VertexBuffer; xbox::X_D3DVertexBuffer *pXboxVertexBuffer = XboxStreamInput.VertexBuffer;
@ -298,14 +294,11 @@ void CxbxVertexBufferConverter::ConvertStream
pXboxVertexData += XboxStreamInput.Offset; pXboxVertexData += XboxStreamInput.Offset;
uiXboxVertexStride = XboxStreamInput.Stride; uiXboxVertexStride = XboxStreamInput.Stride;
// Set a new (exact) vertex count
uiVertexCount = pDrawContext->VerticesInBuffer;
// Dxbx note : Don't overwrite pDrawContext.dwVertexCount with uiVertexCount, because an indexed draw // Dxbx note : Don't overwrite pDrawContext.dwVertexCount with uiVertexCount, because an indexed draw
// can (and will) use less vertices than the supplied nr of indexes. Thix fixes // can (and will) use less vertices than the supplied nr of indexes. Thix fixes
// the missing parts in the CompressedVertices sample (in Vertex shader mode). // the missing parts in the CompressedVertices sample (in Vertex shader mode).
uiHostVertexStride = (bNeedVertexPatching) ? pVertexShaderStreamInfo->HostVertexStride : uiXboxVertexStride; uiHostVertexStride = (bNeedVertexPatching) ? pVertexShaderStreamInfo->HostVertexStride : uiXboxVertexStride;
dwHostVertexDataSize = uiVertexCount * uiHostVertexStride;
// Copy stream for patching and caching. // Copy stream for patching and caching.
bNeedStreamCopy = true; bNeedStreamCopy = true;
@ -327,7 +320,17 @@ void CxbxVertexBufferConverter::ConvertStream
} }
// Now we have enough information to hash the existing resource and find it in our cache! // Now we have enough information to hash the existing resource and find it in our cache!
DWORD xboxVertexDataSize = uiVertexCount * uiXboxVertexStride; // To avoid hashing and converting unused vertices, identify the "interesting" region
// basing on the index/starting vertex data
if (pDrawContext->pXboxIndexData != nullptr) {
pXboxVertexData += (pDrawContext->dwBaseVertexIndex + pDrawContext->LowIndex) * uiXboxVertexStride;
} else {
pXboxVertexData += pDrawContext->dwStartVertex * uiXboxVertexStride;
}
const UINT uiVertexCount = pDrawContext->NumVerticesToUse;
const DWORD dwHostVertexDataSize = uiVertexCount * uiHostVertexStride;
const DWORD xboxVertexDataSize = uiVertexCount * uiXboxVertexStride;
uint64_t vertexDataHash = ComputeHash(pXboxVertexData, xboxVertexDataSize); uint64_t vertexDataHash = ComputeHash(pXboxVertexData, xboxVertexDataSize);
uint64_t pVertexShaderSteamInfoHash = 0; uint64_t pVertexShaderSteamInfoHash = 0;
@ -634,9 +637,6 @@ void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext)
m_pCxbxVertexDeclaration = CxbxGetVertexDeclaration(); m_pCxbxVertexDeclaration = CxbxGetVertexDeclaration();
// 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 // When this is an indexed draw, take the index buffer into account
if (pDrawContext->pXboxIndexData) { if (pDrawContext->pXboxIndexData) {
// Is the highest index in this buffer not set yet? // Is the highest index in this buffer not set yet?
@ -646,11 +646,13 @@ void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext)
LOG_TEST_CASE("HighIndex == 0"); // TODO : If this is never hit, replace entire block by assert(pDrawContext->HighIndex > 0); 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); WalkIndexBuffer(pDrawContext->LowIndex, pDrawContext->HighIndex, pDrawContext->pXboxIndexData, pDrawContext->dwVertexCount);
} }
// Convert highest index (including the base offset) into a count // Convert the range of indices into a count
DWORD dwHighestVertexCount = pDrawContext->dwBaseVertexIndex + pDrawContext->HighIndex + 1; pDrawContext->NumVerticesToUse = pDrawContext->HighIndex - pDrawContext->LowIndex + 1;
// Use the biggest vertex count that can be reached }
if (pDrawContext->VerticesInBuffer < dwHighestVertexCount) else {
pDrawContext->VerticesInBuffer = dwHighestVertexCount; // If we are drawing from an offset, we know that the vertex count must have
// 'offset' vertices before the first drawn vertices
pDrawContext->NumVerticesToUse = pDrawContext->dwVertexCount;
} }
// Get the number of streams // Get the number of streams

View File

@ -40,7 +40,7 @@ typedef struct _CxbxDrawContext
IN PWORD pXboxIndexData; // Set by D3DDevice_DrawIndexedVertices, D3DDevice_DrawIndexedVerticesUP and HLE_draw_inline_elements IN PWORD pXboxIndexData; // Set by D3DDevice_DrawIndexedVertices, D3DDevice_DrawIndexedVerticesUP and HLE_draw_inline_elements
IN DWORD dwBaseVertexIndex; // Set to g_Xbox_BaseVertexIndex in D3DDevice_DrawIndexedVertices IN DWORD dwBaseVertexIndex; // Set to g_Xbox_BaseVertexIndex in D3DDevice_DrawIndexedVertices
IN INDEX16 LowIndex, HighIndex; // Set when pXboxIndexData is set IN INDEX16 LowIndex, HighIndex; // Set when pXboxIndexData is set
IN size_t VerticesInBuffer; // Set by CxbxVertexBufferConverter::Apply IN UINT NumVerticesToUse; // Set by CxbxVertexBufferConverter::Apply
// Data if Draw...UP call // Data if Draw...UP call
IN PVOID pXboxVertexStreamZeroData; IN PVOID pXboxVertexStreamZeroData;
IN UINT uiXboxVertexStreamZeroStride; IN UINT uiXboxVertexStreamZeroStride;