1
0
mirror of https://github.com/EduApps-CDG/OpenDX synced 2024-12-30 09:45:37 +01:00

[dxvk] Refactor indirect draw/dispatch commands

Introduces an OpenGL-style bind point for the argument buffer, which
means we can avoid a lot of unnecessary reference tracking in games
that do a lot of indirect draw calls.

Reduces CPU overhead in Assassin's Creed Odyssey.
This commit is contained in:
Philip Rebohle 2018-10-08 09:23:11 +02:00
parent eb55325640
commit 781ee00f5c
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
6 changed files with 117 additions and 52 deletions

View File

@ -165,6 +165,9 @@ namespace dxvk {
m_state.ps.unorderedAccessViews[i] = nullptr; m_state.ps.unorderedAccessViews[i] = nullptr;
m_state.cs.unorderedAccessViews[i] = nullptr; m_state.cs.unorderedAccessViews[i] = nullptr;
} }
// Default ID state
m_state.id.argBuffer = nullptr;
// Default IA state // Default IA state
m_state.ia.inputLayout = nullptr; m_state.ia.inputLayout = nullptr;
@ -1325,12 +1328,11 @@ namespace dxvk {
void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstancedIndirect( void STDMETHODCALLTYPE D3D11DeviceContext::DrawIndexedInstancedIndirect(
ID3D11Buffer* pBufferForArgs, ID3D11Buffer* pBufferForArgs,
UINT AlignedByteOffsetForArgs) { UINT AlignedByteOffsetForArgs) {
D3D11Buffer* buffer = static_cast<D3D11Buffer*>(pBufferForArgs); SetDrawBuffer(pBufferForArgs);
EmitCs([bufferSlice = buffer->GetBufferSlice(AlignedByteOffsetForArgs)] EmitCs([cOffset = AlignedByteOffsetForArgs]
(DxvkContext* ctx) { (DxvkContext* ctx) {
ctx->drawIndexedIndirect( ctx->drawIndexedIndirect(cOffset, 1, 0);
bufferSlice, 1, 0);
}); });
} }
@ -1338,11 +1340,11 @@ namespace dxvk {
void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstancedIndirect( void STDMETHODCALLTYPE D3D11DeviceContext::DrawInstancedIndirect(
ID3D11Buffer* pBufferForArgs, ID3D11Buffer* pBufferForArgs,
UINT AlignedByteOffsetForArgs) { UINT AlignedByteOffsetForArgs) {
D3D11Buffer* buffer = static_cast<D3D11Buffer*>(pBufferForArgs); SetDrawBuffer(pBufferForArgs);
EmitCs([bufferSlice = buffer->GetBufferSlice(AlignedByteOffsetForArgs)] EmitCs([cOffset = AlignedByteOffsetForArgs]
(DxvkContext* ctx) { (DxvkContext* ctx) {
ctx->drawIndirect(bufferSlice, 1, 0); ctx->drawIndirect(cOffset, 1, 0);
}); });
} }
@ -1363,11 +1365,11 @@ namespace dxvk {
void STDMETHODCALLTYPE D3D11DeviceContext::DispatchIndirect( void STDMETHODCALLTYPE D3D11DeviceContext::DispatchIndirect(
ID3D11Buffer* pBufferForArgs, ID3D11Buffer* pBufferForArgs,
UINT AlignedByteOffsetForArgs) { UINT AlignedByteOffsetForArgs) {
D3D11Buffer* buffer = static_cast<D3D11Buffer*>(pBufferForArgs); SetDrawBuffer(pBufferForArgs);
EmitCs([bufferSlice = buffer->GetBufferSlice(AlignedByteOffsetForArgs)] EmitCs([cOffset = AlignedByteOffsetForArgs]
(DxvkContext* ctx) { (DxvkContext* ctx) {
ctx->dispatchIndirect(bufferSlice); ctx->dispatchIndirect(cOffset);
}); });
} }
@ -2809,6 +2811,18 @@ namespace dxvk {
} }
void D3D11DeviceContext::BindDrawBuffer(
D3D11Buffer* pBuffer) {
EmitCs([
cBufferSlice = pBuffer != nullptr
? pBuffer->GetBufferSlice()
: DxvkBufferSlice()
] (DxvkContext* ctx) {
ctx->bindDrawBuffer(cBufferSlice);
});
}
void D3D11DeviceContext::BindVertexBuffer( void D3D11DeviceContext::BindVertexBuffer(
UINT Slot, UINT Slot,
D3D11Buffer* pBuffer, D3D11Buffer* pBuffer,
@ -2937,6 +2951,17 @@ namespace dxvk {
} }
void D3D11DeviceContext::SetDrawBuffer(
ID3D11Buffer* pBuffer) {
auto buffer = static_cast<D3D11Buffer*>(pBuffer);
if (m_state.id.argBuffer != buffer) {
m_state.id.argBuffer = buffer;
BindDrawBuffer(buffer);
}
}
void D3D11DeviceContext::SetConstantBuffers( void D3D11DeviceContext::SetConstantBuffers(
DxbcProgramType ShaderStage, DxbcProgramType ShaderStage,
D3D11ConstantBufferBindings& Bindings, D3D11ConstantBufferBindings& Bindings,
@ -3101,6 +3126,9 @@ namespace dxvk {
ApplyStencilRef(); ApplyStencilRef();
ApplyRasterizerState(); ApplyRasterizerState();
ApplyViewportState(); ApplyViewportState();
BindDrawBuffer(
m_state.id.argBuffer.ptr());
BindIndexBuffer( BindIndexBuffer(
m_state.ia.indexBuffer.buffer.ptr(), m_state.ia.indexBuffer.buffer.ptr(),

View File

@ -676,6 +676,9 @@ namespace dxvk {
void BindFramebuffer( void BindFramebuffer(
BOOL Spill); BOOL Spill);
void BindDrawBuffer(
D3D11Buffer* pBuffer);
void BindVertexBuffer( void BindVertexBuffer(
UINT Slot, UINT Slot,
D3D11Buffer* pBuffer, D3D11Buffer* pBuffer,
@ -711,6 +714,9 @@ namespace dxvk {
void DiscardTexture( void DiscardTexture(
D3D11CommonTexture* pTexture); D3D11CommonTexture* pTexture);
void SetDrawBuffer(
ID3D11Buffer* pBuffer);
void SetConstantBuffers( void SetConstantBuffers(
DxbcProgramType ShaderStage, DxbcProgramType ShaderStage,
D3D11ConstantBufferBindings& Bindings, D3D11ConstantBufferBindings& Bindings,

View File

@ -99,6 +99,11 @@ namespace dxvk {
UINT offset = 0; UINT offset = 0;
DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
}; };
struct D3D11ContextStateID {
Com<D3D11Buffer> argBuffer = nullptr;
};
struct D3D11ContextStateIA { struct D3D11ContextStateIA {
@ -158,6 +163,7 @@ namespace dxvk {
D3D11ContextStatePS ps; D3D11ContextStatePS ps;
D3D11ContextStateVS vs; D3D11ContextStateVS vs;
D3D11ContextStateID id;
D3D11ContextStateIA ia; D3D11ContextStateIA ia;
D3D11ContextStateOM om; D3D11ContextStateOM om;
D3D11ContextStateRS rs; D3D11ContextStateRS rs;

View File

@ -46,13 +46,13 @@ namespace dxvk {
DxvkContextFlag::GpDirtyIndexBuffer, DxvkContextFlag::GpDirtyIndexBuffer,
DxvkContextFlag::CpDirtyPipeline, DxvkContextFlag::CpDirtyPipeline,
DxvkContextFlag::CpDirtyPipelineState, DxvkContextFlag::CpDirtyPipelineState,
DxvkContextFlag::CpDirtyResources); DxvkContextFlag::CpDirtyResources,
DxvkContextFlag::DirtyDrawBuffer);
} }
Rc<DxvkCommandList> DxvkContext::endRecording() { Rc<DxvkCommandList> DxvkContext::endRecording() {
this->spillRenderPass(); this->spillRenderPass();
this->trackDrawBuffer(DxvkBufferSlice(), VK_NULL_HANDLE);
m_queries.trackQueryPools(m_cmd); m_queries.trackQueryPools(m_cmd);
@ -104,6 +104,16 @@ namespace dxvk {
} }
void DxvkContext::bindDrawBuffer(
const DxvkBufferSlice& buffer) {
if (!m_state.id.argBuffer.matches(buffer)) {
m_state.id.argBuffer = buffer;
m_flags.set(DxvkContextFlag::DirtyDrawBuffer);
}
}
void DxvkContext::bindIndexBuffer( void DxvkContext::bindIndexBuffer(
const DxvkBufferSlice& buffer, const DxvkBufferSlice& buffer,
VkIndexType indexType) { VkIndexType indexType) {
@ -880,10 +890,11 @@ namespace dxvk {
void DxvkContext::dispatchIndirect( void DxvkContext::dispatchIndirect(
const DxvkBufferSlice& buffer) { VkDeviceSize offset) {
this->commitComputeState(); this->commitComputeState();
auto physicalSlice = buffer.physicalSlice(); auto physicalSlice = m_state.id.argBuffer.physicalSlice()
.subSlice(offset, sizeof(VkDispatchIndirectCommand));
if (m_barriers.isBufferDirty(physicalSlice, DxvkAccess::Read)) if (m_barriers.isBufferDirty(physicalSlice, DxvkAccess::Read))
m_barriers.recordCommands(m_cmd); m_barriers.recordCommands(m_cmd);
@ -898,9 +909,6 @@ namespace dxvk {
physicalSlice.handle(), physicalSlice.handle(),
physicalSlice.offset()); physicalSlice.offset());
m_cmd->trackResource(
physicalSlice.resource());
m_queries.endQueries(m_cmd, m_queries.endQueries(m_cmd,
VK_QUERY_TYPE_PIPELINE_STATISTICS); VK_QUERY_TYPE_PIPELINE_STATISTICS);
@ -909,8 +917,10 @@ namespace dxvk {
m_barriers.accessBuffer(physicalSlice, m_barriers.accessBuffer(physicalSlice,
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT,
VK_ACCESS_INDIRECT_COMMAND_READ_BIT, VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
buffer.bufferInfo().stages, m_state.id.argBuffer.bufferInfo().stages,
buffer.bufferInfo().access); m_state.id.argBuffer.bufferInfo().access);
this->trackDrawBuffer();
} }
m_cmd->addStatCtr(DxvkStatCounter::CmdDispatchCalls, 1); m_cmd->addStatCtr(DxvkStatCounter::CmdDispatchCalls, 1);
@ -935,20 +945,20 @@ namespace dxvk {
void DxvkContext::drawIndirect( void DxvkContext::drawIndirect(
const DxvkBufferSlice& buffer, VkDeviceSize offset,
uint32_t count, uint32_t count,
uint32_t stride) { uint32_t stride) {
this->commitGraphicsState(); this->commitGraphicsState();
if (this->validateGraphicsState()) { if (this->validateGraphicsState()) {
auto descriptor = buffer.getDescriptor(); auto descriptor = m_state.id.argBuffer.getDescriptor();
m_cmd->cmdDrawIndirect( m_cmd->cmdDrawIndirect(
descriptor.buffer.buffer, descriptor.buffer.buffer,
descriptor.buffer.offset, descriptor.buffer.offset + offset,
count, stride); count, stride);
this->trackDrawBuffer(buffer, descriptor.buffer.buffer); this->trackDrawBuffer();
} }
m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1); m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1);
@ -975,20 +985,20 @@ namespace dxvk {
void DxvkContext::drawIndexedIndirect( void DxvkContext::drawIndexedIndirect(
const DxvkBufferSlice& buffer, VkDeviceSize offset,
uint32_t count, uint32_t count,
uint32_t stride) { uint32_t stride) {
this->commitGraphicsState(); this->commitGraphicsState();
if (this->validateGraphicsState()) { if (this->validateGraphicsState()) {
auto descriptor = buffer.getDescriptor(); auto descriptor = m_state.id.argBuffer.getDescriptor();
m_cmd->cmdDrawIndexedIndirect( m_cmd->cmdDrawIndexedIndirect(
descriptor.buffer.buffer, descriptor.buffer.buffer,
descriptor.buffer.offset, descriptor.buffer.offset + offset,
count, stride); count, stride);
this->trackDrawBuffer(buffer, descriptor.buffer.buffer); this->trackDrawBuffer();
} }
m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1); m_cmd->addStatCtr(DxvkStatCounter::CmdDrawCalls, 1);
@ -1121,6 +1131,9 @@ namespace dxvk {
// may be bound to either directly or through views. // may be bound to either directly or through views.
const VkBufferUsageFlags usage = buffer->info().usage; const VkBufferUsageFlags usage = buffer->info().usage;
if (usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT)
m_flags.set(DxvkContextFlag::DirtyDrawBuffer);
if (usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT) if (usage & VK_BUFFER_USAGE_INDEX_BUFFER_BIT)
m_flags.set(DxvkContextFlag::GpDirtyIndexBuffer); m_flags.set(DxvkContextFlag::GpDirtyIndexBuffer);
@ -2840,14 +2853,12 @@ namespace dxvk {
} }
void DxvkContext::trackDrawBuffer( void DxvkContext::trackDrawBuffer() {
const DxvkBufferSlice& buffer, if (m_flags.test(DxvkContextFlag::DirtyDrawBuffer)) {
VkBuffer handle) { m_flags.clr(DxvkContextFlag::DirtyDrawBuffer);
if (m_lastIndirectDrawBuffer != handle) {
m_lastIndirectDrawBuffer = handle;
if (handle != VK_NULL_HANDLE) if (m_state.id.argBuffer.defined())
m_cmd->trackResource(buffer.resource()); m_cmd->trackResource(m_state.id.argBuffer.resource());
} }
} }

View File

@ -91,6 +91,16 @@ namespace dxvk {
const DxvkRenderTargets& targets, const DxvkRenderTargets& targets,
bool spill); bool spill);
/**
* \brief Binds indirect argument buffer
*
* Sets the buffer that is going to be used
* for indirect draw and dispatch operations.
* \param [in] buffer New argument buffer
*/
void bindDrawBuffer(
const DxvkBufferSlice& buffer);
/** /**
* \brief Binds index buffer * \brief Binds index buffer
* *
@ -392,19 +402,19 @@ namespace dxvk {
* \param [in] z Number of threads in Z direction * \param [in] z Number of threads in Z direction
*/ */
void dispatch( void dispatch(
uint32_t x, uint32_t x,
uint32_t y, uint32_t y,
uint32_t z); uint32_t z);
/** /**
* \brief Indirect dispatch call * \brief Indirect dispatch call
* *
* Takes arguments from a buffer. The buffer must contain * Takes arguments from a buffer. The buffer must contain
* a structure of the type \c VkDispatchIndirectCommand. * a structure of the type \c VkDispatchIndirectCommand.
* \param [in] buffer The buffer slice * \param [in] offset Draw buffer offset
*/ */
void dispatchIndirect( void dispatchIndirect(
const DxvkBufferSlice& buffer); VkDeviceSize offset);
/** /**
* \brief Draws primitive without using an index buffer * \brief Draws primitive without using an index buffer
@ -415,22 +425,22 @@ namespace dxvk {
* \param [in] firstInstance First instance ID * \param [in] firstInstance First instance ID
*/ */
void draw( void draw(
uint32_t vertexCount, uint32_t vertexCount,
uint32_t instanceCount, uint32_t instanceCount,
uint32_t firstVertex, uint32_t firstVertex,
uint32_t firstInstance); uint32_t firstInstance);
/** /**
* \brief Indirect indexed draw call * \brief Indirect indexed draw call
* *
* Takes arguments from a buffer. The structure stored * Takes arguments from a buffer. The structure stored
* in the buffer must be of type \c VkDrawIndirectCommand. * in the buffer must be of type \c VkDrawIndirectCommand.
* \param [in] buffer The buffer slice * \param [in] offset Draw buffer offset
* \param [in] count Number of dispatch calls * \param [in] count Number of dispatch calls
* \param [in] stride Stride between dispatch calls * \param [in] stride Stride between dispatch calls
*/ */
void drawIndirect( void drawIndirect(
const DxvkBufferSlice& buffer, VkDeviceSize offset,
uint32_t count, uint32_t count,
uint32_t stride); uint32_t stride);
@ -455,12 +465,12 @@ namespace dxvk {
* *
* Takes arguments from a buffer. The structure type for * Takes arguments from a buffer. The structure type for
* the draw buffer is \c VkDrawIndexedIndirectCommand. * the draw buffer is \c VkDrawIndexedIndirectCommand.
* \param [in] buffer The buffer slice * \param [in] offset Draw buffer offset
* \param [in] count Number of dispatch calls * \param [in] count Number of dispatch calls
* \param [in] stride Stride between dispatch calls * \param [in] stride Stride between dispatch calls
*/ */
void drawIndexedIndirect( void drawIndexedIndirect(
const DxvkBufferSlice& buffer, VkDeviceSize offset,
uint32_t count, uint32_t count,
uint32_t stride); uint32_t stride);
@ -704,8 +714,6 @@ namespace dxvk {
VkDescriptorSet m_gpSet = VK_NULL_HANDLE; VkDescriptorSet m_gpSet = VK_NULL_HANDLE;
VkDescriptorSet m_cpSet = VK_NULL_HANDLE; VkDescriptorSet m_cpSet = VK_NULL_HANDLE;
VkBuffer m_lastIndirectDrawBuffer = VK_NULL_HANDLE;
std::array<DxvkShaderResourceSlot, MaxNumResourceSlots> m_rc; std::array<DxvkShaderResourceSlot, MaxNumResourceSlots> m_rc;
std::array<DxvkDescriptorInfo, MaxNumActiveBindings> m_descInfos; std::array<DxvkDescriptorInfo, MaxNumActiveBindings> m_descInfos;
std::array<uint32_t, MaxNumActiveBindings> m_descOffsets; std::array<uint32_t, MaxNumActiveBindings> m_descOffsets;
@ -812,9 +820,7 @@ namespace dxvk {
void commitComputeInitBarriers(); void commitComputeInitBarriers();
void commitComputePostBarriers(); void commitComputePostBarriers();
void trackDrawBuffer( void trackDrawBuffer();
const DxvkBufferSlice& buffer,
VkBuffer handle);
}; };

View File

@ -41,9 +41,16 @@ namespace dxvk {
CpDirtyResources, ///< Compute pipeline resource bindings are out of date CpDirtyResources, ///< Compute pipeline resource bindings are out of date
CpDirtyDescriptorOffsets, ///< Compute descriptor set needs to be rebound CpDirtyDescriptorOffsets, ///< Compute descriptor set needs to be rebound
CpDirtyDescriptorSet, ///< Compute descriptor set needs to be updated CpDirtyDescriptorSet, ///< Compute descriptor set needs to be updated
DirtyDrawBuffer, ///< Indirect argument buffer is dirty
}; };
using DxvkContextFlags = Flags<DxvkContextFlag>; using DxvkContextFlags = Flags<DxvkContextFlag>;
struct DxvkIndirectDrawState {
DxvkBufferSlice argBuffer;
};
struct DxvkVertexInputState { struct DxvkVertexInputState {
@ -113,6 +120,7 @@ namespace dxvk {
* and constant pipeline state objects. * and constant pipeline state objects.
*/ */
struct DxvkContextState { struct DxvkContextState {
DxvkIndirectDrawState id;
DxvkVertexInputState vi; DxvkVertexInputState vi;
DxvkViewportState vp; DxvkViewportState vp;
DxvkDynamicDepthState ds; DxvkDynamicDepthState ds;