diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 7f385d373..f7723723d 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -2399,10 +2399,11 @@ namespace dxvk { auto drawInfo = GenerateDrawInfo(PrimitiveType, PrimitiveCount, 0); - const uint32_t upSize = drawInfo.vertexCount * VertexStreamZeroStride; + const uint32_t dataSize = GetUPDataSize(drawInfo.vertexCount, VertexStreamZeroStride); + const uint32_t bufferSize = GetUPBufferSize(drawInfo.vertexCount, VertexStreamZeroStride); - auto upSlice = AllocTempBuffer(upSize); - std::memcpy(upSlice.mapPtr, pVertexStreamZeroData, upSize); + auto upSlice = AllocTempBuffer(bufferSize); + FillUPVertexBuffer(upSlice.mapPtr, pVertexStreamZeroData, dataSize, bufferSize); EmitCs([this, cBufferSlice = std::move(upSlice.slice), @@ -2445,21 +2446,21 @@ namespace dxvk { auto drawInfo = GenerateDrawInfo(PrimitiveType, PrimitiveCount, 0); - const uint32_t vertexSize = (MinVertexIndex + NumVertices) * VertexStreamZeroStride; + const uint32_t vertexDataSize = GetUPDataSize(MinVertexIndex + NumVertices, VertexStreamZeroStride); + const uint32_t vertexBufferSize = GetUPBufferSize(MinVertexIndex + NumVertices, VertexStreamZeroStride); const uint32_t indexSize = IndexDataFormat == D3DFMT_INDEX16 ? 2 : 4; const uint32_t indicesSize = drawInfo.vertexCount * indexSize; - const uint32_t upSize = vertexSize + indicesSize; + const uint32_t upSize = vertexBufferSize + indicesSize; auto upSlice = AllocTempBuffer(upSize); uint8_t* data = reinterpret_cast(upSlice.mapPtr); - - std::memcpy(data, pVertexStreamZeroData, vertexSize); - std::memcpy(data + vertexSize, pIndexData, indicesSize); + FillUPVertexBuffer(data, pVertexStreamZeroData, vertexDataSize, vertexBufferSize); + std::memcpy(data + vertexBufferSize, pIndexData, indicesSize); EmitCs([this, - cVertexSize = vertexSize, + cVertexSize = vertexBufferSize, cBufferSlice = std::move(upSlice.slice), cPrimType = PrimitiveType, cPrimCount = PrimitiveCount, diff --git a/src/d3d9/d3d9_device.h b/src/d3d9/d3d9_device.h index d79f0955e..0a318a2a0 100644 --- a/src/d3d9/d3d9_device.h +++ b/src/d3d9/d3d9_device.h @@ -1085,6 +1085,31 @@ namespace dxvk { const DWORD* pShaderBytecode, const DxsoModuleInfo* pModuleInfo); + inline uint32_t GetUPDataSize(uint32_t vertexCount, uint32_t stride) { + return vertexCount * stride; + } + + inline uint32_t GetUPBufferSize(uint32_t vertexCount, uint32_t stride) { + return (vertexCount - 1) * stride + m_state.vertexDecl->GetSize(); + } + + inline void FillUPVertexBuffer(void* buffer, const void* userData, uint32_t dataSize, uint32_t bufferSize) { + uint8_t* data = reinterpret_cast(buffer); + // Don't copy excess data if we don't end up needing it. + dataSize = std::min(dataSize, bufferSize); + std::memcpy(data, userData, dataSize); + // Pad out with 0 to make buffer range checks happy + // Some games have components out of range in the vertex decl + // that they don't read from the shader. + // My tests show that these are read back as 0 always if out of range of + // the dataSize. + // + // So... make the actual buffer the range that satisfies the range of the vertex + // declaration and pad with 0s outside of it. + if (dataSize < bufferSize) + std::memset(data + dataSize, 0, bufferSize - dataSize); + } + // So we don't do OOB. template