Optimize vertex stream cache for partial buffer access
Drastically reduces the amount of copied and converted data in cases where any of the following apply: * BaseVertexIndex is not 0 * LowIndex is not 0 * dwStartVertex is not 0 Also potentially fixes an issue where data past an indexed vertex buffer was hashed and converted, leading to potential false positives on dirty checks, maybe more.
This commit is contained in:
parent
b2ca28198e
commit
2480582b0c
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue