1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2025-02-22 07:54:15 +01:00

[d3d9] Rework uploading dynamic sysmem buffers at draw time

... and handle mismatching vertex sizes and vertex strides.
This commit is contained in:
Robin Kertels 2024-03-21 21:11:10 +01:00 committed by Philip Rebohle
parent a1ce690c5c
commit 889802887f

View File

@ -5191,25 +5191,58 @@ namespace dxvk {
// First we calculate the size of that UP buffer slice // First we calculate the size of that UP buffer slice
// and store all sizes and offsets into it. // and store all sizes and offsets into it.
uint32_t upBufferSize = 0; struct VBOCopy {
std::array<uint32_t, caps::MaxStreams> vboUPBufferOffsets = {}; uint32_t srcOffset;
std::array<uint32_t, caps::MaxStreams> vboUPBufferSizes = {}; uint32_t dstOffset;
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) { uint32_t copyBufferLength;
vboUPBufferOffsets[i] = upBufferSize; uint32_t copyElementCount;
uint32_t copyElementSize;
uint32_t copyElementStride;
};
uint32_t totalUpBufferSize = 0;
std::array<VBOCopy, caps::MaxStreams> vboCopies = {};
for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer); auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
if (likely(vbo == nullptr)) { if (likely(vbo == nullptr)) {
vboUPBufferSizes[i] = 0;
continue; continue;
} }
const uint32_t vertexStride = m_state.vertexDecl->GetSize(i); const uint32_t vertexSize = m_state.vertexDecl->GetSize(i);
uint32_t offset = (FirstVertexIndex + BaseVertexIndex) * vertexStride; const uint32_t vertexStride = m_state.vertexBuffers[i].stride;
const uint32_t vertexBufferSize = vbo->Desc()->Size; const uint32_t srcStride = vertexStride;
if (offset < vertexBufferSize) { const uint32_t dstStride = std::min(vertexStride, vertexSize);
const uint32_t vertexDataSize = std::min(NumVertices * vertexStride, vertexBufferSize - offset);
vboUPBufferSizes[i] = vertexDataSize; uint32_t elementCount = NumVertices;
upBufferSize += vertexDataSize; if (m_state.streamFreq[i] & D3DSTREAMSOURCE_INSTANCEDATA) {
elementCount = GetInstanceCount();
} }
const uint32_t vboOffset = m_state.vertexBuffers[i].offset;
const uint32_t vertexOffset = (FirstVertexIndex + BaseVertexIndex) * srcStride;
const uint32_t vertexBufferSize = vbo->Desc()->Size;
const uint32_t srcOffset = vboOffset + vertexOffset;
if (unlikely(srcOffset > vertexBufferSize)) {
// All vertices are out of bounds
vboCopies[i].copyBufferLength = 0;
} else if (unlikely(srcOffset + elementCount * srcStride > vertexBufferSize)) {
// Some vertices are (partially) out of bounds
uint32_t boundVertexBufferRange = vertexBufferSize - vboOffset;
elementCount = boundVertexBufferRange / srcStride;
// Copy all complete vertices
vboCopies[i].copyBufferLength = elementCount * dstStride;
// Copy the remaining partial vertex
vboCopies[i].copyBufferLength += std::min(dstStride, boundVertexBufferRange % srcStride);
} else {
// No vertices are out of bounds
vboCopies[i].copyBufferLength = elementCount * dstStride;
}
vboCopies[i].copyElementCount = elementCount;
vboCopies[i].copyElementStride = srcStride;
vboCopies[i].copyElementSize = dstStride;
vboCopies[i].srcOffset = srcOffset;
vboCopies[i].dstOffset = totalUpBufferSize;
totalUpBufferSize += vboCopies[i].copyBufferLength;
} }
uint32_t iboUPBufferSize = 0; uint32_t iboUPBufferSize = 0;
@ -5222,13 +5255,13 @@ namespace dxvk {
uint32_t indexBufferSize = ibo->Desc()->Size; uint32_t indexBufferSize = ibo->Desc()->Size;
if (offset < indexBufferSize) { if (offset < indexBufferSize) {
iboUPBufferSize = std::min(NumIndices * indexStride, indexBufferSize - offset); iboUPBufferSize = std::min(NumIndices * indexStride, indexBufferSize - offset);
iboUPBufferOffset = upBufferSize; iboUPBufferOffset = totalUpBufferSize;
upBufferSize += iboUPBufferSize; totalUpBufferSize += iboUPBufferSize;
} }
} }
} }
if (unlikely(upBufferSize == 0)) { if (unlikely(totalUpBufferSize == 0)) {
*pDynamicVBOs = false; *pDynamicVBOs = false;
if (pDynamicIBO) if (pDynamicIBO)
*pDynamicIBO = false; *pDynamicIBO = false;
@ -5236,35 +5269,38 @@ namespace dxvk {
return; return;
} }
auto upSlice = AllocUPBuffer(upBufferSize); auto upSlice = AllocUPBuffer(totalUpBufferSize);
// Now copy the actual data and bind it. // Now copy the actual data and bind it.
if (dynamicSysmemVBOs) { for (uint32_t i = 0; i < caps::MaxStreams && dynamicSysmemVBOs; i++) {
for (uint32_t i = 0; i < caps::MaxStreams; i++) { const VBOCopy& copy = vboCopies[i];
if (unlikely(vboUPBufferSizes[i] == 0)) {
EmitCs([ if (likely(copy.copyBufferLength != 0)) {
cStream = i const auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
](DxvkContext* ctx) { uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + copy.dstOffset;
ctx->bindVertexBuffer(cStream, DxvkBufferSlice(), 0); const uint8_t* src = reinterpret_cast<uint8_t*>(vbo->GetMappedSlice().mapPtr) + copy.srcOffset;
});
m_flags.set(D3D9DeviceFlag::DirtyVertexBuffers); if (likely(copy.copyElementStride == copy.copyElementSize)) {
continue; std::memcpy(data, src, copy.copyBufferLength);
} else {
for (uint32_t j = 0; j * copy.copyElementCount; j++) {
std::memcpy(data + j * copy.copyElementSize, src + j * copy.copyElementStride, copy.copyElementSize);
}
if (unlikely(copy.copyBufferLength > copy.copyElementCount * copy.copyElementSize)) {
// Partial vertex at the end
std::memcpy(
data + copy.copyElementCount * copy.copyElementSize,
src + copy.copyElementCount * copy.copyElementStride,
copy.copyBufferLength - copy.copyElementCount * copy.copyElementSize);
}
}
} }
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer); auto vboSlice = upSlice.slice.subSlice(copy.dstOffset, copy.copyBufferLength);
const uint32_t vertexStride = m_state.vertexDecl->GetSize(i);
uint32_t offset = (BaseVertexIndex + FirstVertexIndex) * vertexStride + m_state.vertexBuffers[i].offset;
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr) + vboUPBufferOffsets[i];
uint8_t* src = reinterpret_cast<uint8_t*>(vbo->GetMappedSlice().mapPtr) + offset;
std::memcpy(data, src, vboUPBufferSizes[i]);
auto vboSlice = upSlice.slice.subSlice(vboUPBufferOffsets[i], vboUPBufferSizes[i]);
EmitCs([ EmitCs([
cStream = i, cStream = i,
cBufferSlice = std::move(vboSlice), cBufferSlice = std::move(vboSlice),
cStride = vertexStride cStride = copy.copyElementSize
](DxvkContext* ctx) mutable { ](DxvkContext* ctx) mutable {
ctx->bindVertexBuffer(cStream, std::move(cBufferSlice), cStride); ctx->bindVertexBuffer(cStream, std::move(cBufferSlice), cStride);
}); });
@ -5277,7 +5313,6 @@ namespace dxvk {
} else { } else {
FirstVertexIndex = 0; FirstVertexIndex = 0;
} }
}
if (dynamicSysmemIBO) { if (dynamicSysmemIBO) {
if (unlikely(iboUPBufferSize == 0)) { if (unlikely(iboUPBufferSize == 0)) {