From cf999a94135f8bcce0281a833cee6bed67ae2d2a Mon Sep 17 00:00:00 2001 From: Robin Kertels Date: Thu, 21 Mar 2024 21:11:10 +0100 Subject: [PATCH] [d3d9] Handle mismatching vertex layout and vbo strides ...when uploading dynamic sysmem buffers at draw time. --- src/d3d9/d3d9_device.cpp | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index e99ad383..d0d8f062 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -5202,13 +5202,26 @@ namespace dxvk { continue; } const uint32_t vertexStride = m_state.vertexDecl->GetSize(i); - uint32_t offset = (FirstVertexIndex + BaseVertexIndex) * vertexStride; + const uint32_t vboStride = m_state.vertexBuffers[i].stride; + const uint32_t vboOffset = m_state.vertexBuffers[i].offset; + const uint32_t vertexOffset = (FirstVertexIndex + BaseVertexIndex) * vboStride; const uint32_t vertexBufferSize = vbo->Desc()->Size; - if (offset < vertexBufferSize) { - const uint32_t vertexDataSize = std::min(NumVertices * vertexStride, vertexBufferSize - offset); - vboUPBufferSizes[i] = vertexDataSize; - upBufferSize += vertexDataSize; + + uint32_t vertexDataSize; + if (unlikely(vboOffset + vertexOffset > vertexBufferSize)) { + // All vertices are out of bounds + vertexDataSize = 0; + } else if (unlikely(vboOffset + vertexOffset + NumVertices * vboStride > vertexBufferSize)) { + // Some vertices are (partially) out of bounds + uint32_t boundVertexBufferRange = vertexBufferSize - vboOffset; + uint32_t vertexCount = boundVertexBufferRange / vboStride; + vertexDataSize = vertexCount * vertexStride + (boundVertexBufferRange % vboStride); + } else { + // No vertices are out of bounds + vertexDataSize = NumVertices * vertexStride; } + vboUPBufferSizes[i] = vertexDataSize; + upBufferSize += vertexDataSize; } uint32_t iboUPBufferSize = 0; @@ -5253,11 +5266,22 @@ namespace dxvk { auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer); const uint32_t vertexStride = m_state.vertexDecl->GetSize(i); - uint32_t offset = (BaseVertexIndex + FirstVertexIndex) * vertexStride + m_state.vertexBuffers[i].offset; + const uint32_t vboStride = m_state.vertexBuffers[i].stride; + uint32_t offset = (BaseVertexIndex + FirstVertexIndex) * vboStride + m_state.vertexBuffers[i].offset; uint8_t* data = reinterpret_cast(upSlice.mapPtr) + vboUPBufferOffsets[i]; uint8_t* src = reinterpret_cast(vbo->GetMappedSlice().mapPtr) + offset; - std::memcpy(data, src, vboUPBufferSizes[i]); + if (vertexStride == vboStride) { + std::memcpy(data, src, vboUPBufferSizes[i]); + } else { + const uint32_t vertexBufferSize = vbo->Desc()->Size; + const uint32_t boundVertexBufferRange = vertexBufferSize - offset; + for (uint32_t j = 0; j * vertexStride < vboUPBufferSizes[i]; j += 1) { + // We made sure this isn't gonna go out of bounds earlier when determining the size. + uint32_t copySize = std::min(vertexStride, boundVertexBufferRange - j * std::max(vertexStride, vboStride)); + std::memcpy(data + j * vertexStride, src + j * vboStride, copySize); + } + } auto vboSlice = upSlice.slice.subSlice(vboUPBufferOffsets[i], vboUPBufferSizes[i]); EmitCs([