mirror of
https://github.com/doitsujin/dxvk.git
synced 2025-01-18 02:52:10 +01:00
[d3d9] Account for vertex declaration size for UP draws
The stride may not give us the full picture here as the stride may not encompass the vertex declaration entirely. Consider a vertex declaration of size 20, and a stride of 12, we may not have covered the whole range of space the draw wants with VertexCount * Stride. Some games such as FF13 Lightning Returns have two float3s in the vertex decl and draw two triangles with the last float being out of bounds. This causes the whole vertex element to be set to 0 on NVIDIA which breaks their fullscreen passes. Instead, take (VertexCount - 1) * Stride + VertexDeclSize for the buffer size and pad with 0s outside of the VertexCount * Stride range. Closes: #2046 Closes: #1908
This commit is contained in:
parent
1ab2565521
commit
0f52c85d21
@ -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<true>(upSize);
|
||||
std::memcpy(upSlice.mapPtr, pVertexStreamZeroData, upSize);
|
||||
auto upSlice = AllocTempBuffer<true>(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<true>(upSize);
|
||||
uint8_t* data = reinterpret_cast<uint8_t*>(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,
|
||||
|
@ -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<uint8_t*>(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 <DxsoProgramType ProgramType,
|
||||
D3D9ConstantType ConstantType>
|
||||
|
Loading…
x
Reference in New Issue
Block a user