From e0fbfdf0e23c87d82ca84ddb864fb328ea871295 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 2 Mar 2018 10:31:08 +0100 Subject: [PATCH] [dxvk] Use linked list for CS chunks Improves memory efficiency and CPU overhead of the CSMT implementation when the average number of bytes per command entry is less than 64 bytes. --- src/dxvk/dxvk_cs.cpp | 22 +++++++++++++++++----- src/dxvk/dxvk_cs.h | 44 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/dxvk/dxvk_cs.cpp b/src/dxvk/dxvk_cs.cpp index 955c2d48..24ad6a85 100644 --- a/src/dxvk/dxvk_cs.cpp +++ b/src/dxvk/dxvk_cs.cpp @@ -8,19 +8,31 @@ namespace dxvk { DxvkCsChunk::~DxvkCsChunk() { - for (size_t i = 0; i < m_commandCount; i++) - m_commandList[i]->~DxvkCsCmd(); + auto cmd = m_head; + + while (cmd != nullptr) { + auto next = cmd->next(); + cmd->~DxvkCsCmd(); + cmd = next; + } } void DxvkCsChunk::executeAll(DxvkContext* ctx) { - for (size_t i = 0; i < m_commandCount; i++) { - m_commandList[i]->exec(ctx); - m_commandList[i]->~DxvkCsCmd(); + auto cmd = m_head; + + while (cmd != nullptr) { + auto next = cmd->next(); + cmd->exec(ctx); + cmd->~DxvkCsCmd(); + cmd = next; } m_commandCount = 0; m_commandOffset = 0; + + m_head = nullptr; + m_tail = nullptr; } diff --git a/src/dxvk/dxvk_cs.h b/src/dxvk/dxvk_cs.h index fec6194b..13c800ad 100644 --- a/src/dxvk/dxvk_cs.h +++ b/src/dxvk/dxvk_cs.h @@ -22,12 +22,35 @@ namespace dxvk { virtual ~DxvkCsCmd() { } + /** + * \brief Retrieves next command in a command chain + * + * This can be used to quickly iterate + * over commands within a chunk. + * \returns Pointer the next command + */ + DxvkCsCmd* next() const { + return m_next; + } + + /** + * \brief Sets next command in a command chain + * \param [in] next Next command + */ + void setNext(DxvkCsCmd* next) { + m_next = next; + } + /** * \brief Executes embedded commands * \param [in] ctx The target context */ virtual void exec(DxvkContext* ctx) const = 0; + private: + + DxvkCsCmd* m_next = nullptr; + }; @@ -65,8 +88,7 @@ namespace dxvk { * Stores a list of commands. */ class DxvkCsChunk : public RcObject { - constexpr static size_t MaxCommands = 1024; - constexpr static size_t MaxBlockSize = 64 * MaxCommands; + constexpr static size_t MaxBlockSize = 65536; public: DxvkCsChunk(); @@ -96,13 +118,18 @@ namespace dxvk { bool push(T& command) { using FuncType = DxvkCsTypedCmd; - if (m_commandCount >= MaxCommands - || m_commandOffset + sizeof(FuncType) > MaxBlockSize) + if (m_commandOffset + sizeof(FuncType) > MaxBlockSize) return false; - m_commandList[m_commandCount] = - new (m_data + m_commandOffset) - FuncType(std::move(command)); + DxvkCsCmd* tail = m_tail; + + m_tail = new (m_data + m_commandOffset) + FuncType(std::move(command)); + + if (tail != nullptr) + tail->setNext(m_tail); + else + m_head = m_tail; m_commandCount += 1; m_commandOffset += sizeof(FuncType); @@ -123,7 +150,8 @@ namespace dxvk { size_t m_commandCount = 0; size_t m_commandOffset = 0; - std::array m_commandList; + DxvkCsCmd* m_head = nullptr; + DxvkCsCmd* m_tail = nullptr; alignas(64) char m_data[MaxBlockSize];