Skip to content

Commit

Permalink
[d3d9] Treat draws from SYSMEM+DYNAMIC buffers similar to Up-Draws
Browse files Browse the repository at this point in the history
  • Loading branch information
K0bin committed Dec 25, 2023
1 parent 9ea827e commit 8e555ea
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 10 deletions.
4 changes: 4 additions & 0 deletions src/d3d9/d3d9_common_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,10 @@ namespace dxvk {
: DxvkCsThread::SynchronizeAll;
}

bool PromoteToUpDraws() const {
return m_desc.Pool == D3DPOOL_SYSTEMMEM && m_desc.Usage == D3DUSAGE_DYNAMIC;
}

private:

Rc<DxvkBuffer> CreateBuffer() const;
Expand Down
149 changes: 147 additions & 2 deletions src/d3d9/d3d9_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2615,6 +2615,60 @@ namespace dxvk {
if (unlikely(!PrimitiveCount))
return S_OK;

bool promoteToUpDraw = true;
for (uint32_t i = 0; i < caps::MaxStreams && promoteToUpDraw; i++) {
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
promoteToUpDraw &= vbo == nullptr || vbo->PromoteToUpDraws();
}
if (unlikely(promoteToUpDraw)) {
// If this draw only uses D3DPOOL_SYSTEMMEM + D3DUSAGE_DYNAMIC buffers,
// we only upload the bits of data that this specific draw actually uses.
// Similar to DrawPrimitiveUp

PrepareDraw(PrimitiveType, true);
uint32_t vertexCount = GetVertexCount(PrimitiveType, PrimitiveCount);

for (uint32_t i = 0; i < caps::MaxStreams; i++) {
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
const uint32_t vertexStride = m_state.vertexDecl->GetSize(i);
uint32_t offset = StartVertex * vertexStride;
const uint32_t vertexBufferSize = vbo ? vbo->Desc()->Size : 0;
if (vbo == nullptr || offset >= vertexBufferSize) {
EmitCs([
cStream = i
](DxvkContext* ctx) {
ctx->bindVertexBuffer(cStream, DxvkBufferSlice(), 0);
});
continue;
}

const uint32_t vertexDataSize = std::min(GetUPBufferSize(vertexCount, vertexStride), vertexBufferSize - offset);

auto upSlice = AllocUPBuffer(vertexDataSize);
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr);
uint8_t* src = reinterpret_cast<uint8_t*>(vbo->GetMappedSlice().mapPtr) + offset;
std::memcpy(data, src, vertexDataSize);

EmitCs([
cStream = i,
cBufferSlice = std::move(upSlice.slice),
cStride = vertexStride
](DxvkContext* ctx) mutable {
ctx->bindVertexBuffer(cStream, std::move(cBufferSlice), cStride);
});
}

EmitCs([
cVertexCount = vertexCount
](DxvkContext* ctx) {
ctx->draw(cVertexCount, 1, 0, 0);
});

m_flags.set(D3D9DeviceFlag::DirtyVertexBuffers);

return D3D_OK;
}

PrepareDraw(PrimitiveType, false);

EmitCs([this,
Expand Down Expand Up @@ -2652,6 +2706,89 @@ namespace dxvk {
if (unlikely(!PrimitiveCount))
return S_OK;

bool promoteToUpDraw = true;
for (uint32_t i = 0; i < caps::MaxStreams && promoteToUpDraw; i++) {
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
promoteToUpDraw &= vbo == nullptr || vbo->PromoteToUpDraws();
}
D3D9CommonBuffer* ibo = GetCommonBuffer(m_state.indices);
promoteToUpDraw &= ibo->PromoteToUpDraws();
if (unlikely(promoteToUpDraw)) {
// If this draw only uses D3DPOOL_SYSTEMMEM + D3DUSAGE_DYNAMIC buffers,
// we only upload the bits of data that this specific draw actually uses.
// Similar to DrawPrimitiveUp

PrepareDraw(PrimitiveType, true);

for (uint32_t i = 0; i < caps::MaxStreams; i++) {
auto* vbo = GetCommonBuffer(m_state.vertexBuffers[i].vertexBuffer);
const uint32_t vertexStride = m_state.vertexDecl->GetSize(i);
uint32_t offset = BaseVertexIndex * vertexStride;
const uint32_t vertexBufferSize = vbo ? vbo->Desc()->Size : 0;
if (vbo == nullptr || offset >= vertexBufferSize) {
EmitCs([
cStream = i
](DxvkContext* ctx) {
ctx->bindVertexBuffer(cStream, DxvkBufferSlice(), 0);
});
continue;
}

const uint32_t vertexDataSize = std::min(GetUPBufferSize(NumVertices, vertexStride), vertexBufferSize - offset);

auto upSlice = AllocUPBuffer(vertexDataSize);
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr);
uint8_t* src = reinterpret_cast<uint8_t*>(vbo->GetMappedSlice().mapPtr) + offset;
std::memcpy(data, src, vertexDataSize);

EmitCs([
cStream = i,
cBufferSlice = std::move(upSlice.slice),
cStride = vertexStride
](DxvkContext* ctx) mutable {
ctx->bindVertexBuffer(cStream, std::move(cBufferSlice), cStride);
});
}

uint32_t indexStride = ibo && ibo->Desc()->Format == D3D9Format::INDEX16 ? 2 : 4;
VkIndexType indexType = ibo && ibo->Desc()->Format == D3D9Format::INDEX16 ? VK_INDEX_TYPE_UINT16 : VK_INDEX_TYPE_UINT32;
uint32_t offset = indexStride * StartIndex;
uint32_t indexBufferSize = ibo ? ibo->Desc()->Size - offset : 0;
uint32_t vertexCount = GetVertexCount(PrimitiveType, PrimitiveCount);
if (ibo == nullptr || offset >= indexBufferSize) {
EmitCs([
cIndexType = indexType
](DxvkContext* ctx) {
ctx->bindIndexBuffer(DxvkBufferSlice(), cIndexType);
});
} else {
uint32_t indexDataSize = vertexCount * indexStride;

auto upSlice = AllocUPBuffer(indexDataSize);
uint8_t* data = reinterpret_cast<uint8_t*>(upSlice.mapPtr);
uint8_t* src = reinterpret_cast<uint8_t*>(ibo->GetMappedSlice().mapPtr) + offset;

std::memcpy(data, src, indexDataSize);
EmitCs([
cBufferSlice = std::move(upSlice.slice),
cIndexType = indexType
](DxvkContext* ctx) mutable {
ctx->bindIndexBuffer(std::move(cBufferSlice), cIndexType);
});
}

EmitCs([
cVertexCount = vertexCount,
cInstanceCount = GetInstanceCount()
](DxvkContext* ctx) {
ctx->drawIndexed(cVertexCount, cInstanceCount, 0, 0, 0);
});

m_flags.set(D3D9DeviceFlag::DirtyVertexBuffers);

return D3D_OK;
}

PrepareDraw(PrimitiveType, false);

EmitCs([this,
Expand Down Expand Up @@ -2842,7 +2979,7 @@ namespace dxvk {
decl = iter->second.ptr();
}

uint32_t offset = DestIndex * decl->GetSize();
uint32_t offset = DestIndex * decl->GetSize(0);

auto slice = dst->GetBufferSlice<D3D9_COMMON_BUFFER_TYPE_REAL>();
slice = slice.subSlice(offset, slice.length() - offset);
Expand Down Expand Up @@ -2889,7 +3026,7 @@ namespace dxvk {
}

if (dst->GetMapMode() == D3D9_COMMON_BUFFER_MAP_MODE_BUFFER) {
uint32_t copySize = VertexCount * decl->GetSize();
uint32_t copySize = VertexCount * decl->GetSize(0);

EmitCs([
cSrcBuffer = dst->GetBuffer<D3D9_COMMON_BUFFER_TYPE_REAL>(),
Expand Down Expand Up @@ -6616,6 +6753,14 @@ namespace dxvk {
}

BindSpecConstants();

if (unlikely(m_flags.test(D3D9DeviceFlag::DirtyVertexBuffers))) {
for (uint32_t i = 0; i < caps::MaxStreams; i++) {
const D3D9VBO& vbo = m_state.vertexBuffers[i];
BindVertexBuffer(i, vbo.vertexBuffer.ptr(), vbo.offset, vbo.stride);
}
m_flags.clr(D3D9DeviceFlag::DirtyVertexBuffers);
}
}


Expand Down
3 changes: 2 additions & 1 deletion src/d3d9/d3d9_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ namespace dxvk {
DirtyInputLayout,
DirtyViewportScissor,
DirtyMultiSampleState,
DirtyVertexBuffers,

DirtyFogState,
DirtyFogColor,
Expand Down Expand Up @@ -1063,7 +1064,7 @@ namespace dxvk {
}

inline uint32_t GetUPBufferSize(uint32_t vertexCount, uint32_t stride) {
return (vertexCount - 1) * stride + std::max(m_state.vertexDecl->GetSize(), stride);
return (vertexCount - 1) * stride + std::max(m_state.vertexDecl->GetSize(0), stride);
}

inline void FillUPVertexBuffer(void* buffer, const void* userData, uint32_t dataSize, uint32_t bufferSize) {
Expand Down
2 changes: 1 addition & 1 deletion src/d3d9/d3d9_swvp_emu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ namespace dxvk {
uint32_t primitiveId = m_module.opLoad(uint_t, primitiveIdPtr);

// The size of any given vertex
uint32_t vertexSize = m_module.constu32(pDecl->GetSize() / sizeof(uint32_t));
uint32_t vertexSize = m_module.constu32(pDecl->GetSize(0) / sizeof(uint32_t));

//The offset of this vertex from the beginning of the buffer
uint32_t thisVertexOffset = m_module.opIMul(uint_t, vertexSize, primitiveId);
Expand Down
4 changes: 2 additions & 2 deletions src/d3d9/d3d9_vertex_declaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,8 @@ namespace dxvk {

void D3D9VertexDecl::Classify() {
for (const auto& element : m_elements) {
if (element.Stream == 0 && element.Type != D3DDECLTYPE_UNUSED)
m_size = std::max(m_size, element.Offset + GetDecltypeSize(D3DDECLTYPE(element.Type)));
if (element.Type != D3DDECLTYPE_UNUSED)
m_sizes[element.Stream] = std::max(m_sizes[element.Stream], element.Offset + GetDecltypeSize(D3DDECLTYPE(element.Type)));

if (element.Usage == D3DDECLUSAGE_COLOR && element.UsageIndex == 0)
m_flags.set(D3D9VertexDeclFlag::HasColor0);
Expand Down
7 changes: 3 additions & 4 deletions src/d3d9/d3d9_vertex_declaration.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ namespace dxvk {
return m_elements;
}

UINT GetSize() const {
return m_size;
UINT GetSize(UINT Stream) const {
return m_sizes[Stream];
}

bool TestFlag(D3D9VertexDeclFlag flag) const {
Expand Down Expand Up @@ -94,8 +94,7 @@ namespace dxvk {

uint32_t m_texcoordMask = 0;

// The size of Stream 0. That's all we care about.
uint32_t m_size = 0;
std::array<uint32_t, caps::MaxStreams> m_sizes = {};

};

Expand Down

0 comments on commit 8e555ea

Please sign in to comment.