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.
|
// 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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue