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.
HRESULT hRet = g_pD3DDevice->DrawIndexedPrimitive(
/* 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,
/* NumVertices = */(CacheEntry.HighIndex - CacheEntry.LowIndex) + 1,
/* 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 :
// Assure & activate that special index buffer :
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 :
UINT NumVertices = QuadToTriangleVertexCount(DrawContext.dwVertexCount);
// 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 :
HRESULT hRet = g_pD3DDevice->DrawIndexedPrimitive(
/*PrimitiveType=*/D3DPT_TRIANGLELIST,
BaseVertexIndex,
/*BaseVertexIndex=*/0, // Base vertex index has been accounted for in the stream conversion
/*MinVertexIndex=*/0,
NumVertices,
/*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)
HRESULT hRet = g_pD3DDevice->DrawPrimitive(
EmuXB2PC_D3DPrimitiveType(DrawContext.XboxPrimitiveType),
DrawContext.dwStartVertex,
/*StartVertex=*/0, // Start vertex has been accounted for in the stream conversion
DrawContext.dwHostPrimitiveCount
);
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
assert(DrawContext.dwBaseVertexIndex == 0); // if this fails, it needs to be added to LowIndex and HighIndex :
INDEX16 LowIndex = (INDEX16)DrawContext.dwStartVertex;
INDEX16 HighIndex = (INDEX16)(DrawContext.dwStartVertex + DrawContext.dwHostPrimitiveCount);
INDEX16 LowIndex = 0;
INDEX16 HighIndex = (INDEX16)(DrawContext.dwHostPrimitiveCount);
// Draw the closing line using a helper function (which will SetIndices)
CxbxDrawIndexedClosingLine(LowIndex, HighIndex);
// 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
uint8_t *pXboxVertexData = xbox::zeroptr;
UINT uiXboxVertexStride = 0;
UINT uiVertexCount = 0;
UINT uiHostVertexStride = 0;
DWORD dwHostVertexDataSize = 0;
uint8_t *pHostVertexData = nullptr;
IDirect3DVertexBuffer *pNewHostVertexBuffer = nullptr;
@ -275,9 +273,7 @@ void CxbxVertexBufferConverter::ConvertStream
pXboxVertexData = (uint8_t *)pDrawContext->pXboxVertexStreamZeroData;
uiXboxVertexStride = pDrawContext->uiXboxVertexStreamZeroStride;
uiVertexCount = pDrawContext->VerticesInBuffer;
uiHostVertexStride = (bNeedVertexPatching) ? pVertexShaderStreamInfo->HostVertexStride : uiXboxVertexStride;
dwHostVertexDataSize = uiVertexCount * uiHostVertexStride;
} else {
xbox::X_STREAMINPUT& XboxStreamInput = GetXboxVertexStreamInput(XboxStreamNumber);
xbox::X_D3DVertexBuffer *pXboxVertexBuffer = XboxStreamInput.VertexBuffer;
@ -298,14 +294,11 @@ void CxbxVertexBufferConverter::ConvertStream
pXboxVertexData += XboxStreamInput.Offset;
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
// 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).
uiHostVertexStride = (bNeedVertexPatching) ? pVertexShaderStreamInfo->HostVertexStride : uiXboxVertexStride;
dwHostVertexDataSize = uiVertexCount * uiHostVertexStride;
// Copy stream for patching and caching.
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!
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 pVertexShaderSteamInfoHash = 0;
@ -634,9 +637,6 @@ void CxbxVertexBufferConverter::Apply(CxbxDrawContext *pDrawContext)
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
if (pDrawContext->pXboxIndexData) {
// 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);
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;
// Convert the range of indices into a count
pDrawContext->NumVerticesToUse = pDrawContext->HighIndex - pDrawContext->LowIndex + 1;
}
else {
// 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

View File

@ -40,7 +40,7 @@ typedef struct _CxbxDrawContext
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 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
IN PVOID pXboxVertexStreamZeroData;
IN UINT uiXboxVertexStreamZeroStride;