[dxvk] Clean up CS chunk allocation

This also makes it more robust w.r.t. alignment.
This commit is contained in:
Philip Rebohle 2025-02-18 15:37:11 +01:00
parent 4c8ee300b5
commit 23067c48c7
2 changed files with 54 additions and 48 deletions

View file

@ -31,7 +31,7 @@ namespace dxvk {
} }
m_head = nullptr; m_head = nullptr;
m_tail = nullptr; m_next = &m_head;
} else { } else {
while (cmd != nullptr) { while (cmd != nullptr) {
cmd->exec(ctx); cmd->exec(ctx);
@ -51,7 +51,7 @@ namespace dxvk {
} }
m_head = nullptr; m_head = nullptr;
m_tail = nullptr; m_next = &m_head;
m_commandOffset = 0; m_commandOffset = 0;
} }
@ -263,4 +263,4 @@ namespace dxvk {
} }
} }
} }

View file

@ -19,14 +19,14 @@ namespace dxvk {
* that can be recorded into a command list. * that can be recorded into a command list.
*/ */
class DxvkCsCmd { class DxvkCsCmd {
public: public:
virtual ~DxvkCsCmd() { } virtual ~DxvkCsCmd() { }
/** /**
* \brief Retrieves next command in a command chain * \brief Retrieves next command in a command chain
* *
* This can be used to quickly iterate * This can be used to quickly iterate
* over commands within a chunk. * over commands within a chunk.
* \returns Pointer the next command * \returns Pointer the next command
@ -34,25 +34,27 @@ namespace dxvk {
DxvkCsCmd* next() const { DxvkCsCmd* next() const {
return m_next; return m_next;
} }
/** /**
* \brief Sets next command in a command chain * \brief Retrieves pointer to next chain
* \param [in] next Next command *
* Used to chain commands.
* \returns Pointer the next command
*/ */
void setNext(DxvkCsCmd* next) { DxvkCsCmd** chain() {
m_next = next; return &m_next;
} }
/** /**
* \brief Executes embedded commands * \brief Executes embedded commands
* \param [in] ctx The target context * \param [in] ctx The target context
*/ */
virtual void exec(DxvkContext* ctx) = 0; virtual void exec(DxvkContext* ctx) = 0;
private: private:
DxvkCsCmd* m_next = nullptr; DxvkCsCmd* m_next = nullptr;
}; };
@ -63,7 +65,7 @@ namespace dxvk {
* used to execute an embedded command. * used to execute an embedded command.
*/ */
template<typename T> template<typename T>
class alignas(16) DxvkCsTypedCmd : public DxvkCsCmd { class DxvkCsTypedCmd : public DxvkCsCmd {
public: public:
@ -92,7 +94,7 @@ namespace dxvk {
* submitting the command to a cs chunk. * submitting the command to a cs chunk.
*/ */
template<typename T, typename M> template<typename T, typename M>
class alignas(16) DxvkCsDataCmd : public DxvkCsCmd { class DxvkCsDataCmd : public DxvkCsCmd {
public: public:
@ -165,21 +167,13 @@ namespace dxvk {
template<typename T> template<typename T>
bool push(T& command) { bool push(T& command) {
using FuncType = DxvkCsTypedCmd<T>; using FuncType = DxvkCsTypedCmd<T>;
void* ptr = alloc<FuncType>();
if (unlikely(m_commandOffset > MaxBlockSize - sizeof(FuncType)))
if (unlikely(!ptr))
return false; return false;
DxvkCsCmd* tail = m_tail; auto next = new (ptr) FuncType(std::move(command));
append(next);
m_tail = new (m_data + m_commandOffset)
FuncType(std::move(command));
if (likely(tail != nullptr))
tail->setNext(m_tail);
else
m_head = m_tail;
m_commandOffset += sizeof(FuncType);
return true; return true;
} }
@ -198,21 +192,15 @@ namespace dxvk {
template<typename M, typename T, typename... Args> template<typename M, typename T, typename... Args>
M* pushCmd(T& command, Args&&... args) { M* pushCmd(T& command, Args&&... args) {
using FuncType = DxvkCsDataCmd<T, M>; using FuncType = DxvkCsDataCmd<T, M>;
void* ptr = alloc<FuncType>();
if (unlikely(m_commandOffset > MaxBlockSize - sizeof(FuncType)))
return nullptr;
FuncType* func = new (m_data + m_commandOffset)
FuncType(std::move(command), std::forward<Args>(args)...);
if (likely(m_tail != nullptr))
m_tail->setNext(func);
else
m_head = func;
m_tail = func;
m_commandOffset += sizeof(FuncType); if (unlikely(!ptr))
return func->data(); return nullptr;
auto next = new (ptr) FuncType(std::move(command), std::forward<Args>(args)...);
append(next);
return next->data();
} }
/** /**
@ -243,13 +231,31 @@ namespace dxvk {
size_t m_commandOffset = 0; size_t m_commandOffset = 0;
DxvkCsCmd* m_head = nullptr; DxvkCsCmd* m_head = nullptr;
DxvkCsCmd* m_tail = nullptr; DxvkCsCmd** m_next = &m_head;
DxvkCsChunkFlags m_flags; DxvkCsChunkFlags m_flags;
alignas(64) alignas(64)
char m_data[MaxBlockSize]; char m_data[MaxBlockSize];
template<typename T>
void* alloc() {
if (alignof(T) > alignof(DxvkCsCmd))
m_commandOffset = dxvk::align(m_commandOffset, alignof(T));
if (unlikely(m_commandOffset + sizeof(T) > MaxBlockSize))
return nullptr;
void* result = &m_data[m_commandOffset];
m_commandOffset += sizeof(T);
return result;
}
void append(DxvkCsCmd* cmd) {
*m_next = cmd;
m_next = cmd->chain();
}
}; };