mirror of
https://github.com/doitsujin/dxvk.git
synced 2024-12-11 19:24:11 +01:00
[d3d11] Use multiDrawIndirect for subsequent indirect draw calls
Significantly improves performance in AC:Odyssey when CPU bound. Only has an effect when no state changes between draw calls, and when the draw parameter buffer is tightly packed.
This commit is contained in:
parent
ad6233f74c
commit
bbc3b3fb2b
21
src/d3d11/d3d11_cmd.h
Normal file
21
src/d3d11/d3d11_cmd.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "d3d11_include.h"
|
||||||
|
|
||||||
|
namespace dxvk {
|
||||||
|
|
||||||
|
enum class D3D11CmdType {
|
||||||
|
DrawIndirect,
|
||||||
|
DrawIndirectIndexed,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct D3D11CmdData {
|
||||||
|
D3D11CmdType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct D3D11CmdDrawIndirectData : public D3D11CmdData {
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -18,7 +18,8 @@ namespace dxvk {
|
|||||||
m_multithread(this, false),
|
m_multithread(this, false),
|
||||||
m_device (Device),
|
m_device (Device),
|
||||||
m_csFlags (CsFlags),
|
m_csFlags (CsFlags),
|
||||||
m_csChunk (AllocCsChunk()) {
|
m_csChunk (AllocCsChunk()),
|
||||||
|
m_cmdData (nullptr) {
|
||||||
// Create default state objects. We won't ever return them
|
// Create default state objects. We won't ever return them
|
||||||
// to the application, but we'll use them to apply state.
|
// to the application, but we'll use them to apply state.
|
||||||
Com<ID3D11BlendState> defaultBlendState;
|
Com<ID3D11BlendState> defaultBlendState;
|
||||||
@ -1401,10 +1402,27 @@ namespace dxvk {
|
|||||||
|
|
||||||
SetDrawBuffer(pBufferForArgs);
|
SetDrawBuffer(pBufferForArgs);
|
||||||
|
|
||||||
EmitCs([cOffset = AlignedByteOffsetForArgs]
|
// If possible, batch up multiple indirect draw calls of
|
||||||
(DxvkContext* ctx) {
|
// the same type into one single multiDrawIndirect call
|
||||||
ctx->drawIndexedIndirect(cOffset, 1, 0);
|
constexpr VkDeviceSize stride = sizeof(VkDrawIndexedIndirectCommand);
|
||||||
|
auto cmdData = static_cast<D3D11CmdDrawIndirectData*>(m_cmdData);
|
||||||
|
|
||||||
|
bool useMultiDraw = cmdData && cmdData->type == D3D11CmdType::DrawIndirectIndexed
|
||||||
|
&& cmdData->offset + cmdData->count * stride == AlignedByteOffsetForArgs
|
||||||
|
&& m_device->features().core.features.multiDrawIndirect;
|
||||||
|
|
||||||
|
if (useMultiDraw) {
|
||||||
|
cmdData->count += 1;
|
||||||
|
} else {
|
||||||
|
cmdData = EmitCsCmd<D3D11CmdDrawIndirectData>(
|
||||||
|
[] (DxvkContext* ctx, const D3D11CmdDrawIndirectData* data) {
|
||||||
|
ctx->drawIndexedIndirect(data->offset, data->count, stride);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cmdData->type = D3D11CmdType::DrawIndirectIndexed;
|
||||||
|
cmdData->offset = AlignedByteOffsetForArgs;
|
||||||
|
cmdData->count = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1415,10 +1433,27 @@ namespace dxvk {
|
|||||||
|
|
||||||
SetDrawBuffer(pBufferForArgs);
|
SetDrawBuffer(pBufferForArgs);
|
||||||
|
|
||||||
EmitCs([cOffset = AlignedByteOffsetForArgs]
|
// If possible, batch up multiple indirect draw calls of
|
||||||
(DxvkContext* ctx) {
|
// the same type into one single multiDrawIndirect call
|
||||||
ctx->drawIndirect(cOffset, 1, 0);
|
constexpr VkDeviceSize stride = sizeof(VkDrawIndirectCommand);
|
||||||
|
auto cmdData = static_cast<D3D11CmdDrawIndirectData*>(m_cmdData);
|
||||||
|
|
||||||
|
bool useMultiDraw = cmdData && cmdData->type == D3D11CmdType::DrawIndirectIndexed
|
||||||
|
&& cmdData->offset + cmdData->count * stride == AlignedByteOffsetForArgs
|
||||||
|
&& m_device->features().core.features.multiDrawIndirect;
|
||||||
|
|
||||||
|
if (useMultiDraw) {
|
||||||
|
cmdData->count += 1;
|
||||||
|
} else {
|
||||||
|
cmdData = EmitCsCmd<D3D11CmdDrawIndirectData>(
|
||||||
|
[] (DxvkContext* ctx, const D3D11CmdDrawIndirectData* data) {
|
||||||
|
ctx->drawIndirect(data->offset, data->count, stride);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
cmdData->type = D3D11CmdType::DrawIndirect;
|
||||||
|
cmdData->offset = AlignedByteOffsetForArgs;
|
||||||
|
cmdData->count = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "../d3d10/d3d10_multithread.h"
|
#include "../d3d10/d3d10_multithread.h"
|
||||||
|
|
||||||
#include "d3d11_annotation.h"
|
#include "d3d11_annotation.h"
|
||||||
|
#include "d3d11_cmd.h"
|
||||||
#include "d3d11_context_state.h"
|
#include "d3d11_context_state.h"
|
||||||
#include "d3d11_device_child.h"
|
#include "d3d11_device_child.h"
|
||||||
#include "d3d11_texture.h"
|
#include "d3d11_texture.h"
|
||||||
@ -662,6 +663,7 @@ namespace dxvk {
|
|||||||
Com<D3D11RasterizerState> m_defaultRasterizerState;
|
Com<D3D11RasterizerState> m_defaultRasterizerState;
|
||||||
|
|
||||||
D3D11ContextState m_state;
|
D3D11ContextState m_state;
|
||||||
|
D3D11CmdData* m_cmdData;
|
||||||
|
|
||||||
void ApplyInputLayout();
|
void ApplyInputLayout();
|
||||||
|
|
||||||
@ -814,6 +816,8 @@ namespace dxvk {
|
|||||||
|
|
||||||
template<typename Cmd>
|
template<typename Cmd>
|
||||||
void EmitCs(Cmd&& command) {
|
void EmitCs(Cmd&& command) {
|
||||||
|
m_cmdData = nullptr;
|
||||||
|
|
||||||
if (!m_csChunk->push(command)) {
|
if (!m_csChunk->push(command)) {
|
||||||
EmitCsChunk(std::move(m_csChunk));
|
EmitCsChunk(std::move(m_csChunk));
|
||||||
|
|
||||||
@ -822,10 +826,28 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename M, typename Cmd, typename... Args>
|
||||||
|
M* EmitCsCmd(Cmd&& command, Args&&... args) {
|
||||||
|
M* data = m_csChunk->pushCmd<M, Cmd, Args...>(
|
||||||
|
command, std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
EmitCsChunk(std::move(m_csChunk));
|
||||||
|
|
||||||
|
m_csChunk = AllocCsChunk();
|
||||||
|
data = m_csChunk->pushCmd<M, Cmd, Args...>(
|
||||||
|
command, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_cmdData = data;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
void FlushCsChunk() {
|
void FlushCsChunk() {
|
||||||
if (m_csChunk->commandCount() != 0) {
|
if (m_csChunk->commandCount() != 0) {
|
||||||
EmitCsChunk(std::move(m_csChunk));
|
EmitCsChunk(std::move(m_csChunk));
|
||||||
m_csChunk = AllocCsChunk();
|
m_csChunk = AllocCsChunk();
|
||||||
|
m_cmdData = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user