From a664a5bb50b6df18641ea06ce3c6bc0cd9b26a0d Mon Sep 17 00:00:00 2001 From: Feifan He Date: Mon, 27 Oct 2025 12:32:19 +0800 Subject: [PATCH] DXMT: backport dynamic CPU encoding heap Backport upstream DXMT commit 998714300fe1144114fd689ce1f7c36be6c58189. The vendored DXMT 0.60 encoder used a single fixed CPU encoding heap and only logged when the heap overflowed, then returned memory past the allocation. Upstream DXMT fixed this by switching to dynamically managed encoding heap chunks and retiring underused chunks after repeated non-use. Origin: https://github.com/3Shain/dxmt/commit/998714300fe1144114fd689ce1f7c36be6c58189 Signed-off-by: Ronnie Nibali --- src/libs/dxmt-0.60/src/dxmt/dxmt_context.cpp | 11 ++++- src/libs/dxmt-0.60/src/dxmt/dxmt_context.hpp | 52 ++++++++++++++++---- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/libs/dxmt-0.60/src/dxmt/dxmt_context.cpp b/src/libs/dxmt-0.60/src/dxmt/dxmt_context.cpp index 4e75c4ee60c9..78c3b05da9cc 100644 --- a/src/libs/dxmt-0.60/src/dxmt/dxmt_context.cpp +++ b/src/libs/dxmt-0.60/src/dxmt/dxmt_context.cpp @@ -37,11 +37,10 @@ ArgumentEncodingContext::ArgumentEncodingContext(CommandQueue &queue, WMT::Devic WMTResourceHazardTrackingModeUntracked; dummy_cbuffer_ = device.newBuffer(dummy_cbuffer_info_); std::memset(dummy_cbuffer_info_.memory.get(), 0, 65536); - cpu_buffer_ = malloc(kEncodingContextCPUHeapSize); + cpu_buffer_chunks_.emplace_back(); }; ArgumentEncodingContext::~ArgumentEncodingContext() { - free(cpu_buffer_); wsi::aligned_free(dummy_cbuffer_host_); }; @@ -679,6 +678,8 @@ ArgumentEncodingContext::currentFrameStatistics() { void ArgumentEncodingContext::$$setEncodingContext(uint64_t seq_id, uint64_t frame_id) { + current_buffer_chunk_ = 0; + cpu_buffer_ = cpu_buffer_chunks_[current_buffer_chunk_].ptr; cpu_buffer_offset_ = 0; seq_id_ = seq_id; frame_id_ = frame_id; @@ -919,6 +920,12 @@ ArgumentEncodingContext::flushCommands(WMT::CommandBuffer cmdbuf, uint64_t seqId cmdbuf.encodeSignalEvent(queue_.event, event_seq_id); + for (size_t i = cpu_buffer_chunks_.size() - 1; i > current_buffer_chunk_; i--) { + if (++cpu_buffer_chunks_[i].underused_times > kEncodingContextCPUHeapLifetime) { + cpu_buffer_chunks_.pop_back(); + } + } + return visibility_readback; } diff --git a/src/libs/dxmt-0.60/src/dxmt/dxmt_context.hpp b/src/libs/dxmt-0.60/src/dxmt/dxmt_context.hpp index 1848adf64b5f..4978b729b866 100644 --- a/src/libs/dxmt-0.60/src/dxmt/dxmt_context.hpp +++ b/src/libs/dxmt-0.60/src/dxmt/dxmt_context.hpp @@ -20,7 +20,8 @@ namespace dxmt { constexpr size_t kCommandChunkCPUHeapSize = 0x400000; constexpr size_t kCommandChunkGPUHeapSize = 0x400000; -constexpr size_t kEncodingContextCPUHeapSize = 0x1000000; +constexpr size_t kEncodingContextCPUHeapSize = 0x100000; +constexpr size_t kEncodingContextCPUHeapLifetime = 600; inline std::size_t align_forward_adjustment(const void *const ptr, const std::size_t &alignment) noexcept { @@ -584,13 +585,24 @@ class ArgumentEncodingContext { void * allocate_cpu_heap(size_t size, size_t alignment) { - std::size_t adjustment = align_forward_adjustment((void *)cpu_buffer_offset_, alignment); - auto aligned = cpu_buffer_offset_ + adjustment; - cpu_buffer_offset_ = aligned + size; - if (cpu_buffer_offset_ >= kEncodingContextCPUHeapSize) { - ERR(cpu_buffer_offset_, " - cpu argument heap overflow, expect error."); + assert(size < kEncodingContextCPUHeapSize); + for (;;) { + std::size_t adjustment = align_forward_adjustment((void *)cpu_buffer_offset_, alignment); + auto aligned = cpu_buffer_offset_ + adjustment; + cpu_buffer_offset_ = aligned + size; + if (unlikely(cpu_buffer_offset_ >= kEncodingContextCPUHeapSize)) { + current_buffer_chunk_++; + while (current_buffer_chunk_ >= cpu_buffer_chunks_.size()) { + cpu_buffer_chunks_.emplace_back(); + } + auto &chunk = cpu_buffer_chunks_[current_buffer_chunk_]; + chunk.underused_times = 0; + cpu_buffer_ = chunk.ptr; + cpu_buffer_offset_ = 0; + continue; + } + return ptr_add(cpu_buffer_, aligned); } - return ptr_add(cpu_buffer_, aligned); } template @@ -693,11 +705,33 @@ class ArgumentEncodingContext { EncoderData *encoder_current = nullptr; unsigned encoder_count_ = 0; - void *cpu_buffer_; - uint64_t cpu_buffer_offset_; uint64_t seq_id_; uint64_t frame_id_; + struct chunk { + void *ptr; + size_t underused_times; + + chunk() { + ptr = malloc(kEncodingContextCPUHeapSize); + underused_times = 0; + } + chunk(const chunk ©) = delete; + chunk(chunk &&move) { + ptr = move.ptr; + underused_times = move.underused_times; + move.ptr = nullptr; + }; + ~chunk() { + free(ptr); + ptr = nullptr; + } + }; + std::vector cpu_buffer_chunks_; + uint32_t current_buffer_chunk_ = 0; + void *cpu_buffer_; + uint64_t cpu_buffer_offset_; + VisibilityResultOffsetBumpState vro_state_; std::vector> pending_queries_; unsigned active_visibility_query_count_ = 0;