From 868fc805d44c155a540a9c83182c747977e4a770 Mon Sep 17 00:00:00 2001 From: Feifan He Date: Fri, 6 Feb 2026 16:46:05 +0800 Subject: [PATCH 1/9] chore(dxmt, winemetal): use uint32_t as storage type of some enumerations More flexible for bit-fields --- src/dxmt/dxmt_buffer.cpp | 7 ++++--- src/winemetal/winemetal.h | 12 ++++++------ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/dxmt/dxmt_buffer.cpp b/src/dxmt/dxmt_buffer.cpp index d4361d12..b0cd533b 100644 --- a/src/dxmt/dxmt_buffer.cpp +++ b/src/dxmt/dxmt_buffer.cpp @@ -94,15 +94,16 @@ Buffer::prepareAllocationViews(BufferAllocation *allocation) { info.sample_count = 1; info.pixel_format = format; info.options = allocation->info_.options; - info.usage = WMTTextureUsageShaderRead; + auto usage = WMTTextureUsageShaderRead; if (!allocation->flags().test(BufferAllocationFlag::GpuReadonly) && ( allocation->flags().test(BufferAllocationFlag::GpuManaged) || allocation->flags().test(BufferAllocationFlag::GpuPrivate))) { - info.usage |= WMTTextureUsageShaderWrite; + usage |= WMTTextureUsageShaderWrite; if (format == WMTPixelFormatR32Uint || format == WMTPixelFormatR32Sint || (format == WMTPixelFormatRG32Uint && device_.supportsFamily(WMTGPUFamilyApple8))) { - info.usage |= WMTTextureUsageShaderAtomic; + usage |= WMTTextureUsageShaderAtomic; } } + info.usage = usage; auto view = allocation->obj_.newTexture(info, 0, total_length); diff --git a/src/winemetal/winemetal.h b/src/winemetal/winemetal.h index ecc41804..8aa6ad54 100644 --- a/src/winemetal/winemetal.h +++ b/src/winemetal/winemetal.h @@ -455,7 +455,7 @@ enum WMTPixelFormat : uint32_t { #define ORIGINAL_FORMAT(format) (format & ~WMTPixelFormatCustomSwizzle) -enum WMTTextureType : uint8_t { +enum WMTTextureType : uint32_t { WMTTextureType1D = 0, WMTTextureType1DArray = 1, WMTTextureType2D = 2, @@ -468,7 +468,7 @@ enum WMTTextureType : uint8_t { WMTTextureTypeTextureBuffer = 9, }; -enum WMTTextureUsage : uint8_t { +enum WMTTextureUsage : uint32_t { WMTTextureUsageUnknown = 0, WMTTextureUsageShaderRead = 1, WMTTextureUsageShaderWrite = 2, @@ -499,10 +499,10 @@ struct WMTTextureInfo { uint32_t height; uint32_t depth; uint32_t array_length; - enum WMTTextureType type; - uint8_t mipmap_level_count; - uint8_t sample_count; - enum WMTTextureUsage usage; + enum WMTTextureType type : 8; + uint32_t mipmap_level_count : 8; + uint32_t sample_count : 8; + enum WMTTextureUsage usage : 8; enum WMTResourceOptions options; uint32_t reserved; mach_port_t mach_port; // in/out From ceddf297d993b21cc0a91805ed899dbe456e985c Mon Sep 17 00:00:00 2001 From: Feifan He Date: Fri, 6 Feb 2026 16:49:39 +0800 Subject: [PATCH 2/9] chore(winemetal): make WMTPixelFormat fit into 24-bit --- src/winemetal/winemetal.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/winemetal/winemetal.h b/src/winemetal/winemetal.h index 8aa6ad54..198c4135 100644 --- a/src/winemetal/winemetal.h +++ b/src/winemetal/winemetal.h @@ -433,20 +433,20 @@ enum WMTPixelFormat : uint32_t { WMTPixelFormatX32_Stencil8 = 261, WMTPixelFormatX24_Stencil8 = 262, - WMTPixelFormatAlphaIsOne = 0x80000000, + WMTPixelFormatAlphaIsOne = 0x00800000, WMTPixelFormatBGRX8Unorm = WMTPixelFormatAlphaIsOne | WMTPixelFormatBGRA8Unorm, WMTPixelFormatBGRX8Unorm_sRGB = WMTPixelFormatAlphaIsOne | WMTPixelFormatBGRA8Unorm_sRGB, WMTPixelFormatRGB1Swizzle = WMTPixelFormatAlphaIsOne, - WMTPixelFormatR001Swizzle = 0x40000000, - WMTPixelFormat0R01Swizzle = 0x20000000, + WMTPixelFormatR001Swizzle = 0x00400000, + WMTPixelFormat0R01Swizzle = 0x00200000, WMTPixelFormatR32X8X32 = WMTPixelFormatR001Swizzle | WMTPixelFormatDepth32Float_Stencil8, // WMTPixelFormatR24X8 = WMTPixelFormatR001Swizzle | WMTPixelFormatDepth24Unorm_Stencil8, WMTPixelFormatX32G8X32 = WMTPixelFormat0R01Swizzle | WMTPixelFormatX32_Stencil8, // WMTPixelFormatX24G8 = WMTPixelFormat0R01Swizzle | WMTPixelFormatX24_Stencil8, - WMTPixelFormatBGRASwizzle = 0x10000000, + WMTPixelFormatBGRASwizzle = 0x00100000, WMTPixelFormatARGB4Unorm = WMTPixelFormatBGRASwizzle | WMTPixelFormatABGR4Unorm, From a053815053ae56309f4a91ca23c09ebb02b77029 Mon Sep 17 00:00:00 2001 From: Feifan He Date: Fri, 6 Feb 2026 17:19:04 +0800 Subject: [PATCH 3/9] chore(dxmt): compress structure `TextureViewDescriptor` into 8 bytes --- src/dxmt/dxmt_texture.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dxmt/dxmt_texture.hpp b/src/dxmt/dxmt_texture.hpp index af1b7cd5..3ae66033 100644 --- a/src/dxmt/dxmt_texture.hpp +++ b/src/dxmt/dxmt_texture.hpp @@ -23,12 +23,12 @@ enum class TextureAllocationFlag : uint32_t { typedef unsigned TextureViewKey; struct TextureViewDescriptor { - WMTPixelFormat format: 32; - WMTTextureType type; - unsigned firstMiplevel = 0; - unsigned miplevelCount = 1; - unsigned firstArraySlice = 0; - unsigned arraySize = 1; + WMTPixelFormat format : 24; + WMTTextureType type : 8; + uint32_t firstMiplevel : 4 = 0; + uint32_t miplevelCount : 4 = 1; + uint32_t firstArraySlice : 12 = 0; + uint32_t arraySize : 12 = 1; }; struct TextureView { From 1edd529d8a545b99b5677513336c3ebaeed203d0 Mon Sep 17 00:00:00 2001 From: Feifan He Date: Thu, 22 Jan 2026 02:50:44 +0800 Subject: [PATCH 4/9] chore(dxmt, d3d11): remove duplicated `access()` methods on encoding context --- src/d3d11/d3d11_context_impl.cpp | 2 +- src/dxmt/dxmt_context.cpp | 10 +++++----- src/dxmt/dxmt_context.hpp | 14 -------------- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/d3d11/d3d11_context_impl.cpp b/src/d3d11/d3d11_context_impl.cpp index 13a8e6bc..ce7dc64f 100644 --- a/src/d3d11/d3d11_context_impl.cpp +++ b/src/d3d11/d3d11_context_impl.cpp @@ -3908,7 +3908,7 @@ template class MTLD3D11DeviceContextImplBase : p SwitchToBlitEncoder(CommandBufferState::UpdateBlitEncoderActive); EmitOP([=, src = std::move(src), dst = std::move(dst), cmd = std::move(cmd)](ArgumentEncodingContext &enc) { - auto [src_buffer, src_offset] = enc.access(src, DXMT_ENCODER_RESOURCE_ACESS_READ); + auto [src_buffer, src_offset] = enc.access(src, 0, src->length(), DXMT_ENCODER_RESOURCE_ACESS_READ); auto texture = enc.access(dst, cmd.Dst.MipLevel, cmd.Dst.ArraySlice, DXMT_ENCODER_RESOURCE_ACESS_WRITE); auto &cmd_cptex = enc.encodeBlitCommand(); cmd_cptex.type = WMTBlitCommandCopyFromBufferToTexture; diff --git a/src/dxmt/dxmt_context.cpp b/src/dxmt/dxmt_context.cpp index f6b9bcaf..44cfa11d 100644 --- a/src/dxmt/dxmt_context.cpp +++ b/src/dxmt/dxmt_context.cpp @@ -74,11 +74,11 @@ ArgumentEncodingContext::encodeVertexBuffers(uint32_t slot_mask, uint64_t offset entries[index++].length = 0; continue; } - auto length = buffer->length(); - auto [buffer_alloc, buffer_offset] = access(buffer, DXMT_ENCODER_RESOURCE_ACESS_READ); + auto valid_length = buffer->length() > state.offset ? buffer->length() - state.offset : 0; + auto [buffer_alloc, buffer_offset] = access(buffer, state.offset, valid_length, DXMT_ENCODER_RESOURCE_ACESS_READ); entries[index].buffer_handle = buffer_alloc->gpuAddress() + buffer_offset + state.offset; entries[index].stride = state.stride; - entries[index++].length = length > state.offset ? length - state.offset : 0; + entries[index++].length = valid_length; // FIXME: did we intended to use the whole buffer? makeResident(buffer.ptr()); }; @@ -151,8 +151,8 @@ ArgumentEncodingContext::encodeConstantBuffers(const MTL_SHADER_REFLECTION *refl continue; } auto argbuf = cbuf.buffer; - // FIXME: did we intended to use the whole buffer? - auto [argbuf_alloc, argbuf_offset] = access(argbuf, DXMT_ENCODER_RESOURCE_ACESS_READ); + auto valid_length = argbuf->length() > cbuf.offset ? argbuf->length() - cbuf.offset : 0; + auto [argbuf_alloc, argbuf_offset] = access(argbuf, cbuf.offset, valid_length, DXMT_ENCODER_RESOURCE_ACESS_READ); encoded_buffer[arg.StructurePtrOffset] = argbuf_alloc->gpuAddress() + argbuf_offset + cbuf.offset; makeResident(argbuf.ptr()); break; diff --git a/src/dxmt/dxmt_context.hpp b/src/dxmt/dxmt_context.hpp index c5810a08..fd02dc99 100644 --- a/src/dxmt/dxmt_context.hpp +++ b/src/dxmt/dxmt_context.hpp @@ -293,13 +293,6 @@ class ArgumentEncodingContext { return {view, allocation->currentSuballocationOffset(view.suballocation_texel)}; } - std::pair - access(Rc const &buffer, DXMT_ENCODER_RESOURCE_ACESS flags) { - auto allocation = buffer->current(); - trackBuffer(allocation, flags); - return {allocation, allocation->currentSuballocationOffset()}; - } - WMT::Texture access(Rc const &texture, unsigned level, unsigned slice, DXMT_ENCODER_RESOURCE_ACESS flags) { auto allocation = texture->current(); @@ -314,13 +307,6 @@ class ArgumentEncodingContext { return texture->view_(viewId, allocation); } - WMT::Texture - access(Rc const &texture, DXMT_ENCODER_RESOURCE_ACESS flags) { - auto allocation = texture->current(); - trackTexture(allocation, flags); - return allocation->texture(); - } - template void bindConstantBuffer(unsigned slot, unsigned offset, Rc &&buffer) { From 2a5ed76f234cd59e3ea8765858ca123c3aec46c0 Mon Sep 17 00:00:00 2001 From: Feifan He Date: Mon, 2 Feb 2026 18:52:28 +0800 Subject: [PATCH 5/9] feat(dxmt, d3d11): introduce ref-counted `TextureView` object (fat view) --- src/d3d11/d3d11_context_impl.cpp | 8 ++-- src/dxmt/dxmt_command.cpp | 2 +- src/dxmt/dxmt_context.cpp | 6 +-- src/dxmt/dxmt_context.hpp | 10 ++-- src/dxmt/dxmt_texture.cpp | 82 ++++++++++++++++---------------- src/dxmt/dxmt_texture.hpp | 68 ++++++++++++++++++-------- 6 files changed, 103 insertions(+), 73 deletions(-) diff --git a/src/d3d11/d3d11_context_impl.cpp b/src/d3d11/d3d11_context_impl.cpp index ce7dc64f..3967d51d 100644 --- a/src/d3d11/d3d11_context_impl.cpp +++ b/src/d3d11/d3d11_context_impl.cpp @@ -689,7 +689,7 @@ template class MTLD3D11DeviceContextImplBase : p EmitOP([=, texture = pUAV->texture(), viewId = pUAV->viewId(), value = std::array({Values[0], Values[1], Values[2], Values[3]}), dimension = desc.ViewDimension](ArgumentEncodingContext &enc) mutable { - auto view_format = texture->view(viewId).pixelFormat(); + auto view_format = texture->pixelFormat(viewId); auto uint_format = MTLGetUnsignedIntegerFormat((WMTPixelFormat)view_format); /* RG11B10Float is a special case */ if (view_format == WMTPixelFormatRG11B10Float) { @@ -937,7 +937,7 @@ template class MTLD3D11DeviceContextImplBase : p if (tex->pixelFormat(viewId) == WMTPixelFormatA8Unorm) { fixedViewId = tex->checkViewUseFormat(viewId, WMTPixelFormatR8Unorm); } - WMT::Texture texture = enc.access(tex, fixedViewId, DXMT_ENCODER_RESOURCE_ACESS_READ | DXMT_ENCODER_RESOURCE_ACESS_WRITE).texture; + WMT::Texture texture = enc.access(tex, fixedViewId, DXMT_ENCODER_RESOURCE_ACESS_READWRITE).texture; if (texture.mipmapLevelCount() > 1) { auto &cmd = enc.encodeBlitCommand(); cmd.type = WMTBlitCommandGenerateMipmaps; @@ -4163,14 +4163,14 @@ template class MTLD3D11DeviceContextImplBase : p continue; } auto& colorAttachment = info.colors[rtv.RenderTargetIndex]; - colorAttachment.texture = rtv.Texture->view(rtv.viewId); + colorAttachment.texture = rtv.Texture->view(rtv.viewId).texture; colorAttachment.depth_plane = rtv.DepthPlane; colorAttachment.load_action = rtv.LoadAction; colorAttachment.store_action = WMTStoreActionStore; }; if (dsv.Texture.ptr()) { - WMT::Texture texture = dsv.Texture->view(dsv.viewId); + WMT::Texture texture = dsv.Texture->view(dsv.viewId).texture; // TODO: ...should know more about store behavior (e.g. DiscardView) if (dsv_planar_flags & 1) { auto& depthAttachment = info.depth; diff --git a/src/dxmt/dxmt_command.cpp b/src/dxmt/dxmt_command.cpp index b0563acc..cd951ece 100644 --- a/src/dxmt/dxmt_command.cpp +++ b/src/dxmt/dxmt_command.cpp @@ -583,7 +583,7 @@ ClearResourceKernelContext::clear(uint32_t offset_x, uint32_t offset_y, uint32_t meta_temp_.size[1] = height; if (clearing_texture_) { - auto dst_ = ctx_.access(clearing_texture_, clearing_view_, DXMT_ENCODER_RESOURCE_ACESS_WRITE); + auto &dst_ = ctx_.access(clearing_texture_, clearing_view_, DXMT_ENCODER_RESOURCE_ACESS_WRITE); auto &settex = ctx_.encodeComputeCommand(); settex.type = WMTComputeCommandSetTexture; settex.texture = dst_.texture; diff --git a/src/dxmt/dxmt_context.cpp b/src/dxmt/dxmt_context.cpp index 44cfa11d..8806b613 100644 --- a/src/dxmt/dxmt_context.cpp +++ b/src/dxmt/dxmt_context.cpp @@ -286,7 +286,7 @@ ArgumentEncodingContext::encodeShaderResources( assert(arg.Flags & MTL_SM50_SHADER_ARGUMENT_TEXTURE_MINLOD_CLAMP); auto viewIdChecked = srv.texture->checkViewUseArray(srv.viewId, arg.Flags & MTL_SM50_SHADER_ARGUMENT_TEXTURE_ARRAY); encoded_buffer[arg.StructurePtrOffset] = - access(srv.texture, viewIdChecked, DXMT_ENCODER_RESOURCE_ACESS_READ).gpu_resource_id; + access(srv.texture, viewIdChecked, DXMT_ENCODER_RESOURCE_ACESS_READ).gpuResourceID; encoded_buffer[arg.StructurePtrOffset + 1] = TextureMetadata(srv.texture->arrayLength(viewIdChecked), 0); makeResident(srv.texture.ptr(), viewIdChecked); } else { @@ -325,7 +325,7 @@ ArgumentEncodingContext::encodeShaderResources( } else if (uav.texture.ptr()) { assert(arg.Flags & MTL_SM50_SHADER_ARGUMENT_TEXTURE_MINLOD_CLAMP); auto viewIdChecked = uav.texture->checkViewUseArray(uav.viewId, arg.Flags & MTL_SM50_SHADER_ARGUMENT_TEXTURE_ARRAY); - encoded_buffer[arg.StructurePtrOffset] = access(uav.texture, viewIdChecked, access_flags).gpu_resource_id; + encoded_buffer[arg.StructurePtrOffset] = access(uav.texture, viewIdChecked, access_flags).gpuResourceID; encoded_buffer[arg.StructurePtrOffset + 1] = TextureMetadata(uav.texture->arrayLength(viewIdChecked), 0); makeResident(uav.texture.ptr(), viewIdChecked, read, write); } else { @@ -492,7 +492,7 @@ ArgumentEncodingContext::upscaleTemporal( encoder_info->input = input->current()->texture(); encoder_info->output = output->current()->texture(); encoder_info->depth = depth->current()->texture(); - encoder_info->motion_vector = motion_vector->view(mvViewId); + encoder_info->motion_vector = motion_vector->view(mvViewId).texture; encoder_info->scaler = scaler; encoder_info->props = props; diff --git a/src/dxmt/dxmt_context.hpp b/src/dxmt/dxmt_context.hpp index fd02dc99..c31629b6 100644 --- a/src/dxmt/dxmt_context.hpp +++ b/src/dxmt/dxmt_context.hpp @@ -246,6 +246,7 @@ class CommandQueue; enum DXMT_ENCODER_RESOURCE_ACESS { DXMT_ENCODER_RESOURCE_ACESS_READ = 1 <<0, DXMT_ENCODER_RESOURCE_ACESS_WRITE = 1 << 1, + DXMT_ENCODER_RESOURCE_ACESS_READWRITE = DXMT_ENCODER_RESOURCE_ACESS_READ | DXMT_ENCODER_RESOURCE_ACESS_WRITE, }; struct AllocatedTempBufferSlice { @@ -300,11 +301,11 @@ class ArgumentEncodingContext { return allocation->texture(); } - TextureView const & + TextureView & access(Rc const &texture, unsigned viewId, DXMT_ENCODER_RESOURCE_ACESS flags) { auto allocation = texture->current(); trackTexture(allocation, flags); - return texture->view_(viewId, allocation); + return texture->view(viewId, allocation); } template @@ -455,8 +456,9 @@ class ArgumentEncodingContext { auto allocation = texture->current(); uint64_t encoder_id = currentEncoder()->id; DXMT_RESOURCE_RESIDENCY requested = GetResidencyMask(stage, read, write); - if (CheckResourceResidency(texture->residency(viewId, allocation), encoder_id, requested)) { - makeResident(texture->view(viewId, allocation), requested); + auto &view = texture->view(viewId, allocation); + if (CheckResourceResidency(view.residency, encoder_id, requested)) { + makeResident(view.texture, requested); }; } diff --git a/src/dxmt/dxmt_texture.cpp b/src/dxmt/dxmt_texture.cpp index 7c2bea67..3c60e00c 100644 --- a/src/dxmt/dxmt_texture.cpp +++ b/src/dxmt/dxmt_texture.cpp @@ -8,10 +8,40 @@ namespace dxmt { std::atomic_uint64_t global_texture_seq = {0}; +void +TextureView::incRef() { + refcount_.fetch_add(1u, std::memory_order_acquire); +}; + +void +TextureView::decRef() { + if (refcount_.fetch_sub(1u, std::memory_order_release) == 1u) + delete this; +}; + +TextureView::TextureView(TextureAllocation *allocation) : + texture(allocation->texture()), + gpuResourceID(allocation->gpuResourceID), + allocation(allocation), + key(0) {} + +TextureView::TextureView(TextureAllocation *allocation, TextureViewKey key, TextureViewDescriptor descriptor) : + gpuResourceID(0), + allocation(allocation), + key(key) { + auto parent = allocation->texture(); + texture = parent.newTextureView( + descriptor.format, descriptor.type, descriptor.firstMiplevel, descriptor.miplevelCount, + descriptor.firstArraySlice, descriptor.arraySize, + {WMTTextureSwizzleRed, WMTTextureSwizzleGreen, WMTTextureSwizzleBlue, WMTTextureSwizzleAlpha}, gpuResourceID + ); +} + TextureAllocation::TextureAllocation( - WMT::Reference &&buffer, void *mapped_buffer, const WMTTextureInfo &info, unsigned bytes_per_row, - Flags flags + Texture *descriptor, WMT::Reference &&buffer, void *mapped_buffer, const WMTTextureInfo &info, + unsigned bytes_per_row, Flags flags ) : + descriptor(descriptor), mappedMemory(mapped_buffer), buffer_(std::move(buffer)), flags_(flags) { @@ -24,8 +54,10 @@ TextureAllocation::TextureAllocation( }; TextureAllocation::TextureAllocation( - WMT::Reference &&texture, const WMTTextureInfo &textureDescriptor, Flags flags + Texture *descriptor, WMT::Reference &&texture, const WMTTextureInfo &textureDescriptor, + Flags flags ) : + descriptor(descriptor), obj_(std::move(texture)), flags_(flags) { mappedMemory = nullptr; @@ -44,18 +76,11 @@ void Texture::prepareAllocationViews(TextureAllocation *allocaiton) { std::unique_lock lock(mutex_); if (allocaiton->version_ < 1) { - allocaiton->cached_view_.push_back(std::make_unique(allocaiton->obj_, allocaiton->gpuResourceID)); + allocaiton->cached_view_.push_back(new TextureView(allocaiton)); allocaiton->version_ = 1; } for (unsigned version = allocaiton->version_; version < version_; version++) { - auto &texture = allocaiton->obj_; - auto &view = viewDescriptors_[version]; - uint64_t gpu_resource_id; - WMT::Reference ref = texture.newTextureView( - view.format, view.type, view.firstMiplevel, view.miplevelCount, view.firstArraySlice, view.arraySize, - {WMTTextureSwizzleRed, WMTTextureSwizzleGreen, WMTTextureSwizzleBlue, WMTTextureSwizzleAlpha}, gpu_resource_id - ); - allocaiton->cached_view_.push_back(std::make_unique(std::move(ref), gpu_resource_id)); + allocaiton->cached_view_.push_back(new TextureView(allocaiton, version, viewDescriptors_[version])); } allocaiton->version_ = version_; } @@ -159,10 +184,10 @@ Texture::allocate(Flags flags) { buffer_info.memory.set(wsi::aligned_malloc(bytes_per_image_, DXMT_PAGE_SIZE)); #endif auto buffer = device_.newBuffer(buffer_info); - return new TextureAllocation(std::move(buffer), buffer_info.memory.get(), info, bytes_per_row_, flags); + return new TextureAllocation(this, std::move(buffer), buffer_info.memory.get(), info, bytes_per_row_, flags); } auto texture = flags.test(TextureAllocationFlag::Shared) ? device_.newSharedTexture(info) : device_.newTexture(info); - return new TextureAllocation(std::move(texture), info, flags); + return new TextureAllocation(this, std::move(texture), info, flags); } Rc @@ -182,29 +207,19 @@ Texture::import(mach_port_t mach_port) { if (info.options & WMTResourceHazardTrackingModeUntracked) flags.set(TextureAllocationFlag::NoTracking); flags.set(TextureAllocationFlag::Shared); - return new TextureAllocation(std::move(texture), info, flags); + return new TextureAllocation(this, std::move(texture), info, flags); } assert(texture && "failed to import shared texture"); return nullptr; } -WMT::Texture +TextureView & Texture::view(TextureViewKey key) { return view(key, current_.ptr()); } -WMT::Texture +TextureView & Texture::view(TextureViewKey key, TextureAllocation* allocation) { - return view_(key, allocation).texture; -} - -TextureView const & -Texture::view_(TextureViewKey key) { - return view_(key, current_.ptr()); -} - -TextureView const & -Texture::view_(TextureViewKey key, TextureAllocation* allocation) { if (unlikely(allocation->version_ != version_)) { prepareAllocationViews(allocation); } @@ -269,19 +284,6 @@ TextureViewKey Texture::checkViewUseFormat(TextureViewKey key, WMTPixelFormat fo return key; } -DXMT_RESOURCE_RESIDENCY_STATE & -Texture::residency(TextureViewKey key) { - return residency(key, current_.ptr()); -} - -DXMT_RESOURCE_RESIDENCY_STATE & -Texture::residency(TextureViewKey key, TextureAllocation *allocation) { - if (unlikely(allocation->version_ != version_)) { - prepareAllocationViews(allocation); - } - return allocation->cached_view_[key]->residency; -} - Rc Texture::rename(Rc &&newAllocation) { Rc old = std::move(current_); diff --git a/src/dxmt/dxmt_texture.hpp b/src/dxmt/dxmt_texture.hpp index 3ae66033..0ff585fb 100644 --- a/src/dxmt/dxmt_texture.hpp +++ b/src/dxmt/dxmt_texture.hpp @@ -31,17 +31,48 @@ struct TextureViewDescriptor { uint32_t arraySize : 12 = 1; }; -struct TextureView { +class Texture; +class TextureAllocation; + +class TextureView { +public: + virtual ~TextureView() {}; + + void incRef(); + void decRef(); + WMT::Reference texture; - uint64_t gpu_resource_id; + uint64_t gpuResourceID; DXMT_RESOURCE_RESIDENCY_STATE residency{}; + TextureAllocation *allocation; // `TextureAllocation` holds strong reference to `TextureView` + TextureViewKey key; + + TextureView(const TextureView &) = delete; + TextureView(TextureView &&) = delete; + TextureView &operator=(const TextureView &) = delete; + TextureView &operator=(TextureView &&) = delete; + TextureView(TextureAllocation *allocation); + TextureView(TextureAllocation *allocation, TextureViewKey key, TextureViewDescriptor descriptor); - TextureView(WMT::Reference &&texture, uint64_t gpu_resource_id) : - texture(std::move(texture)), - gpu_resource_id(gpu_resource_id) {} - TextureView(const WMT::Reference &texture, uint64_t gpu_resource_id) : - texture(texture), - gpu_resource_id(gpu_resource_id) {} +private: + std::atomic refcount_ = {0u}; +}; + +class TextureViewRef : public Rc { +public: + using Rc::Rc; + + WMT::Texture + texture() const { + if (!*this) + return {}; + return ptr()->texture; + } + + TextureViewRef & + operator=(TextureView &ref) { + return (*this = &ref); + } }; class TextureAllocation : public Allocation { @@ -58,19 +89,19 @@ class TextureAllocation : public Allocation { return flags_; } + Texture *descriptor; void *mappedMemory; uint64_t gpuResourceID; mach_port_t machPort; - DXMT_RESOURCE_RESIDENCY_STATE residencyState; EncoderDepKey depkey; private: TextureAllocation( - WMT::Reference &&buffer, void *mapped_buffer, const WMTTextureInfo &info, unsigned bytes_per_row, - Flags flags + Texture *descriptor, WMT::Reference &&buffer, void *mapped_buffer, const WMTTextureInfo &info, + unsigned bytes_per_row, Flags flags ); TextureAllocation( - WMT::Reference &&texture, const WMTTextureInfo &textureDescriptor, + Texture *descriptor, WMT::Reference &&texture, const WMTTextureInfo &textureDescriptor, Flags flags ); ~TextureAllocation(); @@ -82,10 +113,11 @@ class TextureAllocation : public Allocation { WMT::Reference buffer_; uint32_t version_ = 0; Flags flags_; - std::vector> cached_view_; + std::vector cached_view_; }; class Texture { + public: void incRef(); void decRef(); @@ -168,18 +200,12 @@ class Texture { Rc allocate(Flags flags); Rc import(mach_port_t mach_port); - WMT::Texture view(TextureViewKey key); - WMT::Texture view(TextureViewKey key, TextureAllocation *allocation); - - TextureView const &view_(TextureViewKey key); - TextureView const &view_(TextureViewKey key, TextureAllocation *allocation); + TextureView &view(TextureViewKey key); + TextureView &view(TextureViewKey key, TextureAllocation *allocation); TextureViewKey checkViewUseArray(TextureViewKey key, bool isArray); TextureViewKey checkViewUseFormat(TextureViewKey key, WMTPixelFormat format); - DXMT_RESOURCE_RESIDENCY_STATE &residency(TextureViewKey key); - DXMT_RESOURCE_RESIDENCY_STATE &residency(TextureViewKey key, TextureAllocation *allocation); - Rc rename(Rc &&newAllocation); Texture(const WMTTextureInfo &info, WMT::Device device); From 65562b257f84773bf040a2acba42f01dddb400ea Mon Sep 17 00:00:00 2001 From: Feifan He Date: Mon, 2 Feb 2026 19:06:43 +0800 Subject: [PATCH 6/9] refactor(dxmt, d3d11): store `TextureViewRef` in encoder data instead of raw texture A bit unfortunate, it causes too much changes to `RenderEncoderData` --- src/d3d11/d3d11_context_impl.cpp | 46 ++++------ src/dxmt/dxmt_command.cpp | 14 ++-- src/dxmt/dxmt_context.cpp | 139 ++++++++++++++++++++----------- src/dxmt/dxmt_context.hpp | 54 ++++++++++-- 4 files changed, 163 insertions(+), 90 deletions(-) diff --git a/src/d3d11/d3d11_context_impl.cpp b/src/d3d11/d3d11_context_impl.cpp index 3967d51d..490d6807 100644 --- a/src/d3d11/d3d11_context_impl.cpp +++ b/src/d3d11/d3d11_context_impl.cpp @@ -4156,34 +4156,36 @@ template class MTLD3D11DeviceContextImplBase : p render_target_array, encoder_argbuf_size = std::move(allocated_encoder_argbuf_size)](ArgumentEncodingContext &ctx) { auto pool = WMT::MakeAutoreleasePool(); uint32_t dsv_planar_flags = DepthStencilPlanarFlags(dsv.PixelFormat); - auto& info = ctx.startRenderPass(dsv_planar_flags, dsv.ReadOnlyFlags, rtvs.size(), *encoder_argbuf_size.get())->info; + auto& info = *ctx.startRenderPass(dsv_planar_flags, dsv.ReadOnlyFlags, rtvs.size(), *encoder_argbuf_size.get()); for (auto &rtv : rtvs.span()) { if (rtv.PixelFormat == WMTPixelFormatInvalid) { continue; } - auto& colorAttachment = info.colors[rtv.RenderTargetIndex]; - colorAttachment.texture = rtv.Texture->view(rtv.viewId).texture; - colorAttachment.depth_plane = rtv.DepthPlane; - colorAttachment.load_action = rtv.LoadAction; - colorAttachment.store_action = WMTStoreActionStore; + auto &color = info.colors[rtv.RenderTargetIndex]; + color.attachment = ctx.access(rtv.Texture, rtv.viewId, DXMT_ENCODER_RESOURCE_ACESS_READWRITE); + color.depth_plane = rtv.DepthPlane; + color.load_action = rtv.LoadAction; + color.store_action = WMTStoreActionStore; }; if (dsv.Texture.ptr()) { - WMT::Texture texture = dsv.Texture->view(dsv.viewId).texture; + auto access_flag = ((dsv.ReadOnlyFlags & dsv_planar_flags) == dsv_planar_flags) + ? DXMT_ENCODER_RESOURCE_ACESS_READ + : DXMT_ENCODER_RESOURCE_ACESS_READWRITE; // TODO: ...should know more about store behavior (e.g. DiscardView) if (dsv_planar_flags & 1) { - auto& depthAttachment = info.depth; - depthAttachment.texture = texture; - depthAttachment.load_action = dsv.DepthLoadAction; - depthAttachment.store_action = WMTStoreActionStore; + auto &depth = info.depth; + depth.attachment = ctx.access(dsv.Texture, dsv.viewId, access_flag); + depth.load_action = dsv.DepthLoadAction; + depth.store_action = WMTStoreActionStore; } if (dsv_planar_flags & 2) { - auto& stencilAttachment = info.stencil; - stencilAttachment.texture = texture; - stencilAttachment.load_action = dsv.StencilLoadAction; - stencilAttachment.store_action = WMTStoreActionStore; + auto &stencil = info.stencil; + stencil.attachment = ctx.access(dsv.Texture, dsv.viewId, access_flag); + stencil.load_action = dsv.StencilLoadAction; + stencil.store_action = WMTStoreActionStore; } } if (effective_render_target == 0) { @@ -4195,20 +4197,6 @@ template class MTLD3D11DeviceContextImplBase : p info.render_target_height = render_target_height; info.render_target_width = render_target_width; info.render_target_array_length = render_target_array; - - for (auto &rtv : rtvs.span()) { - if (rtv.PixelFormat == WMTPixelFormatInvalid) { - continue; - } - ctx.access(rtv.Texture, rtv.viewId, DXMT_ENCODER_RESOURCE_ACESS_READ | DXMT_ENCODER_RESOURCE_ACESS_WRITE); - }; - - if (dsv.Texture.ptr()) { - if ((dsv.ReadOnlyFlags & dsv_planar_flags) == dsv_planar_flags) - ctx.access(dsv.Texture, dsv.viewId, DXMT_ENCODER_RESOURCE_ACESS_READ); - else - ctx.access(dsv.Texture, dsv.viewId, DXMT_ENCODER_RESOURCE_ACESS_READ | DXMT_ENCODER_RESOURCE_ACESS_WRITE); - } }); } diff --git a/src/dxmt/dxmt_command.cpp b/src/dxmt/dxmt_command.cpp index cd951ece..9f9467d4 100644 --- a/src/dxmt/dxmt_command.cpp +++ b/src/dxmt/dxmt_command.cpp @@ -180,17 +180,17 @@ ClearRenderTargetContext::begin(Rc texture, TextureViewKey view) { auto width = texture->width(view); auto height = texture->height(view); auto array_length = texture->arrayLength(view); - auto &pass_info = ctx_.startRenderPass(dsv_flag, 0, 1, 0)->info; + auto &pass_info = *ctx_.startRenderPass(dsv_flag, 0, 1, 0); if (dsv_flag) { auto &depth = pass_info.depth; - depth.texture = ctx_.access(texture, view, DXMT_ENCODER_RESOURCE_ACESS_WRITE).texture; + depth.attachment = ctx_.access(texture, view, DXMT_ENCODER_RESOURCE_ACESS_WRITE); depth.depth_plane = 0; depth.load_action = WMTLoadActionLoad; depth.store_action = WMTStoreActionStore; } else { auto &color = pass_info.colors[0]; - color.texture = ctx_.access(texture, view, DXMT_ENCODER_RESOURCE_ACESS_WRITE).texture; + color.attachment = ctx_.access(texture, view, DXMT_ENCODER_RESOURCE_ACESS_WRITE); color.depth_plane = 0; color.load_action = WMTLoadActionLoad; color.store_action = WMTStoreActionStore; @@ -242,7 +242,7 @@ ClearRenderTargetContext::clear( draw.vertex_start = 0; draw.vertex_count = 3; draw.base_instance = 0; - draw.instance_count = ctx_.currentRenderEncoder()->info.render_target_array_length; + draw.instance_count = ctx_.currentRenderEncoder()->render_target_array_length; } void @@ -343,15 +343,15 @@ DepthStencilBlitContext::copyFromBuffer( auto width = depth_stencil->width(view); auto height = depth_stencil->height(view); - auto &pass_info = ctx_.startRenderPass(0b11, 0, 0, 0)->info; + auto &pass_info = *ctx_.startRenderPass(0b11, 0, 0, 0); auto &depth = pass_info.depth; - depth.texture = ctx_.access(depth_stencil, view, DXMT_ENCODER_RESOURCE_ACESS_WRITE).texture; + depth.attachment = ctx_.access(depth_stencil, view, DXMT_ENCODER_RESOURCE_ACESS_WRITE); depth.depth_plane = 0; depth.load_action = WMTLoadActionLoad; depth.store_action = WMTStoreActionStore; auto &stencil = pass_info.stencil; - stencil.texture = depth.texture; + stencil.attachment = ctx_.access(depth_stencil, view, DXMT_ENCODER_RESOURCE_ACESS_WRITE); stencil.depth_plane = 0; stencil.load_action = WMTLoadActionLoad; stencil.store_action = WMTStoreActionStore; diff --git a/src/dxmt/dxmt_context.cpp b/src/dxmt/dxmt_context.cpp index 8806b613..fa6f25f1 100644 --- a/src/dxmt/dxmt_context.cpp +++ b/src/dxmt/dxmt_context.cpp @@ -402,7 +402,7 @@ ArgumentEncodingContext::clearColor(Rc &&texture, unsigned viewId, unsi encoder_info->height = texture->height(); encoder_current = encoder_info; - encoder_info->texture = access(texture, viewId, DXMT_ENCODER_RESOURCE_ACESS_WRITE).texture; + encoder_info->attachment = access(texture, viewId, DXMT_ENCODER_RESOURCE_ACESS_WRITE); currentFrameStatistics().clear_pass_count++; @@ -424,7 +424,7 @@ ArgumentEncodingContext::clearDepthStencil( encoder_info->height = texture->height(); encoder_current = encoder_info; - encoder_info->texture = access(texture, viewId, DXMT_ENCODER_RESOURCE_ACESS_WRITE).texture; + encoder_info->attachment = access(texture, viewId, DXMT_ENCODER_RESOURCE_ACESS_WRITE); currentFrameStatistics().clear_pass_count++; @@ -440,8 +440,8 @@ ArgumentEncodingContext::resolveTexture( encoder_info->type = EncoderType::Resolve; encoder_current = encoder_info; - encoder_info->src = access(src, src_view, DXMT_ENCODER_RESOURCE_ACESS_READ).texture; - encoder_info->dst = access(dst, dst_view, DXMT_ENCODER_RESOURCE_ACESS_WRITE).texture; + encoder_info->src = access(src, src_view, DXMT_ENCODER_RESOURCE_ACESS_READ); + encoder_info->dst = access(dst, dst_view, DXMT_ENCODER_RESOURCE_ACESS_WRITE); endPass(); }; @@ -558,7 +558,6 @@ ArgumentEncodingContext::startRenderPass( auto encoder_info = allocate(); encoder_info->type = EncoderType::Render; encoder_info->id = nextEncoderId(); - WMT::InitializeRenderPassInfo(encoder_info->info); encoder_info->cmd_head.type = WMTRenderCommandNop; encoder_info->cmd_head.next.set(0); encoder_info->cmd_tail = (wmtcmd_base *)&encoder_info->cmd_head; @@ -731,12 +730,58 @@ ArgumentEncodingContext::flushCommands(WMT::CommandBuffer cmdbuf, uint64_t seqId switch (current->type) { case EncoderType::Render: { auto data = static_cast(current); + WMTRenderPassInfo render_pass_info{}; + { + for (unsigned i = 0; i < std::size(render_pass_info.colors); i++) { + auto &color_data = data->colors[i]; + if (!color_data.attachment) + continue; + auto &color_info = render_pass_info.colors[i]; + color_info.texture = color_data.attachment.texture(); + color_info.load_action = color_data.load_action; + color_info.store_action = color_data.store_action; + color_info.level = color_data.level; + color_info.slice = color_data.slice; + color_info.depth_plane = color_data.depth_plane; + color_info.clear_color = color_data.clear_color; + color_info.resolve_texture = color_data.resolve_attachment.texture(); + color_info.resolve_level = color_data.resolve_level; + color_info.resolve_slice = color_data.resolve_slice; + color_info.resolve_depth_plane = color_data.resolve_depth_plane; + } + if (data->depth.attachment) { + auto &depth_info = render_pass_info.depth; + auto &depth_data = data->depth; + depth_info.texture = depth_data.attachment.texture(); + depth_info.load_action = depth_data.load_action; + depth_info.store_action = depth_data.store_action; + depth_info.level = depth_data.level; + depth_info.slice = depth_data.slice; + depth_info.depth_plane = depth_data.depth_plane; + depth_info.clear_depth = depth_data.clear_depth; + } + if (data->stencil.attachment) { + auto &stencil_info = render_pass_info.stencil; + auto &stencil_data = data->stencil; + stencil_info.texture = stencil_data.attachment.texture(); + stencil_info.load_action = stencil_data.load_action; + stencil_info.store_action = stencil_data.store_action; + stencil_info.level = stencil_data.level; + stencil_info.slice = stencil_data.slice; + stencil_info.depth_plane = stencil_data.depth_plane; + stencil_info.clear_stencil = stencil_data.clear_stencil; + } + render_pass_info.default_raster_sample_count = data->default_raster_sample_count; + render_pass_info.render_target_array_length = data->render_target_array_length; + render_pass_info.render_target_width = data->render_target_width; + render_pass_info.render_target_height = data->render_target_height; + } if (data->use_visibility_result) { assert(visibility_readback); - data->info.visibility_buffer = visibility_readback->visibility_result_heap; + render_pass_info.visibility_buffer = visibility_readback->visibility_result_heap; } auto gpu_buffer_ = data->allocated_argbuf; - auto encoder = cmdbuf.renderCommandEncoder(data->info); + auto encoder = cmdbuf.renderCommandEncoder(render_pass_info); encoder.setVertexBuffer(gpu_buffer_, 0, 16); encoder.setVertexBuffer(gpu_buffer_, 0, 29); encoder.setVertexBuffer(gpu_buffer_, 0, 30); @@ -863,13 +908,13 @@ ArgumentEncodingContext::flushCommands(WMT::CommandBuffer cmdbuf, uint64_t seqId if (data->clear_dsv) { if (data->clear_dsv & 1) { info.depth.clear_depth = data->depth_stencil.first; - info.depth.texture = data->texture; + info.depth.texture = data->attachment.texture(); info.depth.load_action = WMTLoadActionClear; info.depth.store_action = WMTStoreActionStore; } if (data->clear_dsv & 2) { info.stencil.clear_stencil = data->depth_stencil.second; - info.stencil.texture = data->texture; + info.stencil.texture = data->attachment.texture(); info.stencil.load_action = WMTLoadActionClear; info.stencil.store_action = WMTStoreActionStore; } @@ -877,7 +922,7 @@ ArgumentEncodingContext::flushCommands(WMT::CommandBuffer cmdbuf, uint64_t seqId info.render_target_height = data->height; } else { info.colors[0].clear_color = data->color; - info.colors[0].texture = data->texture; + info.colors[0].texture = data->attachment.texture(); info.colors[0].load_action = WMTLoadActionClear; info.colors[0].store_action = WMTStoreActionStore; } @@ -894,10 +939,10 @@ ArgumentEncodingContext::flushCommands(WMT::CommandBuffer cmdbuf, uint64_t seqId { WMTRenderPassInfo info; WMT::InitializeRenderPassInfo(info); - info.colors[0].texture = data->src; + info.colors[0].texture = data->src.texture(); info.colors[0].load_action = WMTLoadActionLoad; info.colors[0].store_action = WMTStoreActionStoreAndMultisampleResolve; - info.colors[0].resolve_texture = data->dst; + info.colors[0].resolve_texture = data->dst.texture(); auto encoder = cmdbuf.renderCommandEncoder(info); encoder.setLabel(WMT::String::string("ResolvePass", WMTUTF8StringEncoding)); @@ -970,7 +1015,7 @@ ArgumentEncodingContext::checkEncoderRelation(EncoderData *former, EncoderData * auto render = reinterpret_cast(latter); auto clear = reinterpret_cast(former); - if (render->info.render_target_array_length != clear->array_length) + if (render->render_target_array_length != clear->array_length) break; if (clear->clear_dsv) { @@ -1023,10 +1068,10 @@ ArgumentEncodingContext::checkEncoderRelation(EncoderData *former, EncoderData * // DontCare can be used because it's going to be cleared anyway // just keep in mind DontCare != DontStore - if (clear->clear_dsv & 1 && render->info.depth.texture == clear->texture.handle) - render->info.depth.store_action = WMTStoreActionDontCare; - if (clear->clear_dsv & 2 && render->info.stencil.texture == clear->texture.handle) - render->info.stencil.store_action = WMTStoreActionDontCare; + if (clear->clear_dsv & 1 && render->depth.attachment == clear->attachment) + render->depth.store_action = WMTStoreActionDontCare; + if (clear->clear_dsv & 2 && render->stencil.attachment == clear->attachment) + render->stencil.store_action = WMTStoreActionDontCare; } return hasDataDependency(latter, former) ? DXMT_ENCODER_LIST_OP_SYNCHRONIZE : DXMT_ENCODER_LIST_OP_SWAP; } @@ -1037,18 +1082,18 @@ ArgumentEncodingContext::checkEncoderRelation(EncoderData *former, EncoderData * if (isEncoderSignatureMatched(r0, r1)) { for (unsigned i = 0; i < r0->render_target_count; i++) { - auto &a0 = r0->info.colors[i]; - auto &a1 = r1->info.colors[i]; + auto &a0 = r0->colors[i]; + auto &a1 = r1->colors[i]; a1.load_action = a0.load_action; a1.clear_color = a0.clear_color; } - r1->info.depth.load_action = r0->info.depth.load_action; - r1->info.depth.clear_depth = r0->info.depth.clear_depth; - r1->info.depth.store_action = r0->info.depth.store_action; - r1->info.stencil.load_action = r0->info.stencil.load_action; - r1->info.stencil.clear_stencil = r0->info.stencil.clear_stencil; - r1->info.stencil.store_action = r0->info.stencil.store_action; + r1->depth.load_action = r0->depth.load_action; + r1->depth.clear_depth = r0->depth.clear_depth; + r1->depth.store_action = r0->depth.store_action; + r1->stencil.load_action = r0->stencil.load_action; + r1->stencil.clear_stencil = r0->stencil.clear_stencil; + r1->stencil.store_action = r0->stencil.store_action; if ((void *)r0->cmd_tail != &r0->cmd_head) { r0->cmd_tail->next.set(r1->cmd_head.next.get()); @@ -1122,7 +1167,7 @@ ArgumentEncodingContext::isEncoderSignatureMatched(RenderEncoderData *r0, Render return false; if (r0->dsv_readonly_flags != r1->dsv_readonly_flags) return false; - if (r0->info.render_target_array_length != r1->info.render_target_array_length) + if (r0->render_target_array_length != r1->render_target_array_length) return false; /** In case two encoder has different argument buffer @@ -1132,39 +1177,39 @@ ArgumentEncodingContext::isEncoderSignatureMatched(RenderEncoderData *r0, Render if (r0->allocated_argbuf != r1->allocated_argbuf) return false; if (r0->dsv_planar_flags & 1) { - if (r0->info.depth.texture != r1->info.depth.texture) + if (r0->depth.attachment != r1->depth.attachment) return false; if (r0->dsv_readonly_flags & 1) { - if (r1->info.depth.load_action == WMTLoadActionClear) + if (r1->depth.load_action == WMTLoadActionClear) return false; } else { - if (r0->info.depth.store_action != WMTStoreActionStore) + if (r0->depth.store_action != WMTStoreActionStore) return false; - if (r1->info.depth.load_action != WMTLoadActionLoad) + if (r1->depth.load_action != WMTLoadActionLoad) return false; } } if (r0->dsv_planar_flags & 2) { - if (r0->info.stencil.texture != r1->info.stencil.texture) + if (r0->stencil.attachment != r1->stencil.attachment) return false; if (r0->dsv_readonly_flags & 2) { - if (r1->info.stencil.load_action == WMTLoadActionClear) + if (r1->stencil.load_action == WMTLoadActionClear) return false; } else { - if (r0->info.stencil.store_action != WMTStoreActionStore) + if (r0->stencil.store_action != WMTStoreActionStore) return false; - if (r1->info.stencil.load_action != WMTLoadActionLoad) + if (r1->stencil.load_action != WMTLoadActionLoad) return false; } } for (unsigned i = 0; i < r0->render_target_count; i++) { - auto &a0 = r0->info.colors[i]; - auto &a1 = r1->info.colors[i]; - if (a0.texture != a1.texture) + auto &a0 = r0->colors[i]; + auto &a1 = r1->colors[i]; + if (a0.attachment != a1.attachment) return false; if (a0.depth_plane != a1.depth_plane) return false; - if (!a0.texture) + if (!a0.attachment) continue; if (a0.store_action != WMTStoreActionStore) return false; @@ -1174,33 +1219,33 @@ ArgumentEncodingContext::isEncoderSignatureMatched(RenderEncoderData *r0, Render return true; } -WMTColorAttachmentInfo * +RenderEncoderColorAttachmentData * ArgumentEncodingContext::isClearColorSignatureMatched(ClearEncoderData *clear, RenderEncoderData *render) { for (unsigned i = 0; i < render->render_target_count; i++) { - auto &attachment = render->info.colors[i]; - if (attachment.texture == clear->texture.handle) { + auto &attachment = render->colors[i]; + if (attachment.attachment == clear->attachment) { return &attachment; } } return nullptr; } -WMTDepthAttachmentInfo * +RenderEncoderDepthAttachmentData * ArgumentEncodingContext::isClearDepthSignatureMatched(ClearEncoderData *clear, RenderEncoderData *render) { if ((clear->clear_dsv & 1) == 0) return nullptr; - if (render->info.depth.texture != clear->texture.handle) + if (render->depth.attachment != clear->attachment) return nullptr; - return &render->info.depth; + return &render->depth; } -WMTStencilAttachmentInfo * +RenderEncoderStencilAttachmentData * ArgumentEncodingContext::isClearStencilSignatureMatched(ClearEncoderData *clear, RenderEncoderData *render) { if ((clear->clear_dsv & 2) == 0) return nullptr; - if (render->info.stencil.texture != clear->texture.handle) + if (render->stencil.attachment != clear->attachment) return nullptr; - return &render->info.stencil; + return &render->stencil; } } // namespace dxmt \ No newline at end of file diff --git a/src/dxmt/dxmt_context.hpp b/src/dxmt/dxmt_context.hpp index c31629b6..c3de7f94 100644 --- a/src/dxmt/dxmt_context.hpp +++ b/src/dxmt/dxmt_context.hpp @@ -119,8 +119,48 @@ struct TSDispatchArgumentsMarshal { uint32_t patch_per_group; }; +struct RenderEncoderColorAttachmentData { + TextureViewRef attachment; + enum WMTLoadAction load_action; + enum WMTStoreAction store_action; + uint16_t level; + uint16_t slice; + uint32_t depth_plane; + struct WMTClearColor clear_color; + TextureViewRef resolve_attachment; + uint16_t resolve_level; + uint16_t resolve_slice; + uint32_t resolve_depth_plane; +}; + +struct RenderEncoderDepthAttachmentData { + TextureViewRef attachment; + enum WMTLoadAction load_action; + enum WMTStoreAction store_action; + uint16_t level; + uint16_t slice; + uint32_t depth_plane; + float clear_depth; +}; + +struct RenderEncoderStencilAttachmentData { + TextureViewRef attachment; + enum WMTLoadAction load_action; + enum WMTStoreAction store_action; + uint16_t level; + uint16_t slice; + uint32_t depth_plane; + uint8_t clear_stencil; +}; + struct RenderEncoderData : EncoderData { - WMTRenderPassInfo info; + std::array colors; + RenderEncoderDepthAttachmentData depth; + RenderEncoderStencilAttachmentData stencil; + uint8_t default_raster_sample_count; + uint16_t render_target_array_length; + uint32_t render_target_height; + uint32_t render_target_width; std::vector gs_arg_marshal_tasks; std::vector ts_arg_marshal_tasks; wmtcmd_render_nop cmd_head; @@ -154,7 +194,7 @@ struct ClearEncoderData : EncoderData { WMTClearColor color; std::pair depth_stencil; }; - WMT::Reference texture; + TextureViewRef attachment; unsigned clear_dsv; unsigned array_length; unsigned width; @@ -164,8 +204,8 @@ struct ClearEncoderData : EncoderData { }; struct ResolveEncoderData : EncoderData { - WMT::Reference src; - WMT::Reference dst; + TextureViewRef src; + TextureViewRef dst; }; class Presenter; @@ -683,9 +723,9 @@ class ArgumentEncodingContext { DXMT_ENCODER_LIST_OP checkEncoderRelation(EncoderData* former, EncoderData* latter); bool hasDataDependency(EncoderData* from, EncoderData* to); bool isEncoderSignatureMatched(RenderEncoderData* former, RenderEncoderData* latter); - WMTColorAttachmentInfo *isClearColorSignatureMatched(ClearEncoderData* former, RenderEncoderData* latter); - WMTDepthAttachmentInfo *isClearDepthSignatureMatched(ClearEncoderData* former, RenderEncoderData* latter); - WMTStencilAttachmentInfo *isClearStencilSignatureMatched(ClearEncoderData* former, RenderEncoderData* latter); + RenderEncoderColorAttachmentData *isClearColorSignatureMatched(ClearEncoderData* former, RenderEncoderData* latter); + RenderEncoderDepthAttachmentData *isClearDepthSignatureMatched(ClearEncoderData* former, RenderEncoderData* latter); + RenderEncoderStencilAttachmentData *isClearStencilSignatureMatched(ClearEncoderData* former, RenderEncoderData* latter); std::array vbuf_; Rc ibuf_; From eaef8234a376c3a6c9a9e738a2f4da6502c075c4 Mon Sep 17 00:00:00 2001 From: Feifan He Date: Fri, 6 Feb 2026 16:26:55 +0800 Subject: [PATCH 7/9] feat(dxmt): optimize resolve pass --- src/dxmt/dxmt_context.cpp | 46 ++++++++++++++++++++++++++++++++++++ src/dxmt/dxmt_context.hpp | 7 ++++++ src/dxmt/dxmt_statistics.hpp | 2 ++ 3 files changed, 55 insertions(+) diff --git a/src/dxmt/dxmt_context.cpp b/src/dxmt/dxmt_context.cpp index fa6f25f1..bedab9e5 100644 --- a/src/dxmt/dxmt_context.cpp +++ b/src/dxmt/dxmt_context.cpp @@ -1073,6 +1073,22 @@ ArgumentEncodingContext::checkEncoderRelation(EncoderData *former, EncoderData * if (clear->clear_dsv & 2 && render->stencil.attachment == clear->attachment) render->stencil.store_action = WMTStoreActionDontCare; } + if (former->type == EncoderType::Render && latter->type == EncoderType::Resolve) { + auto render = reinterpret_cast(former); + auto resolve = reinterpret_cast(latter); + auto result = isResolveSignatureMatched(render, resolve); + if (result.src && result.src->store_action == WMTStoreActionStore) { + result.src->store_action = WMTStoreActionStoreAndMultisampleResolve; + result.src->resolve_attachment = result.dst; + render->tex_write.merge(resolve->tex_write); + + currentFrameStatistics().resolve_pass_optimized++; + resolve->~ResolveEncoderData(); + resolve->next = nullptr; + resolve->type = EncoderType::Null; + return DXMT_ENCODER_LIST_OP_SWAP; // carry on (RENDER -> RESOLVE -> RESOLVE -> ...) + } + } return hasDataDependency(latter, former) ? DXMT_ENCODER_LIST_OP_SYNCHRONIZE : DXMT_ENCODER_LIST_OP_SWAP; } @@ -1248,4 +1264,34 @@ ArgumentEncodingContext::isClearStencilSignatureMatched(ClearEncoderData *clear, return &render->stencil; } +ArgumentEncodingContext::ResolveSignatureMatchResult +ArgumentEncodingContext::isResolveSignatureMatched(RenderEncoderData *render, ResolveEncoderData *resolve) { + ResolveSignatureMatchResult ret{}; + for (unsigned i = 0; i < render->render_target_count; i++) { + auto &color = render->colors[i]; + if (color.resolve_attachment) + continue; + if (!color.attachment) + continue; + if (color.attachment->allocation != resolve->src->allocation) + continue; + if (color.attachment->key == resolve->src->key) { + ret.src = &color; + ret.dst = resolve->dst; + break; + }; + auto &descriptor_src = resolve->src->allocation->descriptor; + auto &descriptor_dst = resolve->dst->allocation->descriptor; + auto color_format = descriptor_src->pixelFormat(color.attachment->key); + auto view_src_in_color_format = descriptor_src->checkViewUseFormat(resolve->src->key, color_format); + if (color.attachment->key == view_src_in_color_format) { + auto view_dst_in_color_format = descriptor_dst->checkViewUseFormat(resolve->dst->key, color_format); + ret.src = &color; + ret.dst = descriptor_dst->view(view_dst_in_color_format, resolve->dst->allocation); + break; + } + } + return ret; +} + } // namespace dxmt \ No newline at end of file diff --git a/src/dxmt/dxmt_context.hpp b/src/dxmt/dxmt_context.hpp index c3de7f94..63f35e0e 100644 --- a/src/dxmt/dxmt_context.hpp +++ b/src/dxmt/dxmt_context.hpp @@ -727,6 +727,13 @@ class ArgumentEncodingContext { RenderEncoderDepthAttachmentData *isClearDepthSignatureMatched(ClearEncoderData* former, RenderEncoderData* latter); RenderEncoderStencilAttachmentData *isClearStencilSignatureMatched(ClearEncoderData* former, RenderEncoderData* latter); + class ResolveSignatureMatchResult { + public: + RenderEncoderColorAttachmentData *src{}; + TextureViewRef dst{}; + }; + ResolveSignatureMatchResult isResolveSignatureMatched(RenderEncoderData *former, ResolveEncoderData *latter); + std::array vbuf_; Rc ibuf_; diff --git a/src/dxmt/dxmt_statistics.hpp b/src/dxmt/dxmt_statistics.hpp index 7191c019..425d5ea6 100644 --- a/src/dxmt/dxmt_statistics.hpp +++ b/src/dxmt/dxmt_statistics.hpp @@ -45,6 +45,7 @@ struct FrameStatistics { uint32_t render_pass_optimized = 0; uint32_t clear_pass_count = 0; uint32_t clear_pass_optimized = 0; + uint32_t resolve_pass_optimized = 0; uint32_t compute_pass_count = 0; uint32_t blit_pass_count = 0; uint32_t event_stall = 0; @@ -66,6 +67,7 @@ struct FrameStatistics { render_pass_optimized = 0; clear_pass_count = 0; clear_pass_optimized = 0; + resolve_pass_optimized = 0; compute_pass_count = 0; blit_pass_count = 0; event_stall = 0; From 0d08756eb348f9b790d91f82c639b3e31ece372e Mon Sep 17 00:00:00 2001 From: Feifan He Date: Fri, 6 Feb 2026 20:23:49 +0800 Subject: [PATCH 8/9] feat(util): add `shared_mutex` wrapper --- src/util/thread.hpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/util/thread.hpp b/src/util/thread.hpp index 769c0c6e..eeed7e62 100644 --- a/src/util/thread.hpp +++ b/src/util/thread.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -179,6 +180,37 @@ class mutex { SRWLOCK m_lock = SRWLOCK_INIT; }; +/** + * \brief SRW-based shared mutex implementation + */ +class shared_mutex { + +public: + using native_handle_type = PSRWLOCK; + + shared_mutex() {} + + shared_mutex(const shared_mutex &) = delete; + shared_mutex &operator=(const shared_mutex &) = delete; + + void lock() { AcquireSRWLockExclusive(&m_lock); } + + void lock_shared() { AcquireSRWLockShared(&m_lock); } + + void unlock() { ReleaseSRWLockExclusive(&m_lock); } + + void unlock_shared() { ReleaseSRWLockShared(&m_lock); } + + bool try_lock() { return TryAcquireSRWLockExclusive(&m_lock); } + + bool try_lock_shared() { return TryAcquireSRWLockShared(&m_lock); } + + native_handle_type native_handle() { return &m_lock; } + +private: + SRWLOCK m_lock = SRWLOCK_INIT; +}; + /** * \brief Recursive mutex implementation * @@ -316,6 +348,7 @@ class thread : public std::thread { }; using mutex = std::mutex; +using shared_mutex = std::shared_mutex; using recursive_mutex = std::recursive_mutex; using condition_variable = std::condition_variable; From ab0cb599714bec24972446775b860b07f05e1704 Mon Sep 17 00:00:00 2001 From: Feifan He Date: Fri, 6 Feb 2026 21:39:29 +0800 Subject: [PATCH 9/9] refactor(dxmt): improve thread safety for texture view and descriptor lookups --- src/dxmt/dxmt_texture.cpp | 13 ++++++++----- src/dxmt/dxmt_texture.hpp | 24 +++++++++++++++++------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/dxmt/dxmt_texture.cpp b/src/dxmt/dxmt_texture.cpp index 3c60e00c..bf79e19c 100644 --- a/src/dxmt/dxmt_texture.cpp +++ b/src/dxmt/dxmt_texture.cpp @@ -74,11 +74,11 @@ TextureAllocation::~TextureAllocation(){ void Texture::prepareAllocationViews(TextureAllocation *allocaiton) { - std::unique_lock lock(mutex_); if (allocaiton->version_ < 1) { allocaiton->cached_view_.push_back(new TextureView(allocaiton)); allocaiton->version_ = 1; } + std::shared_lock lock(mutex_); for (unsigned version = allocaiton->version_; version < version_; version++) { allocaiton->cached_view_.push_back(new TextureView(allocaiton, version, viewDescriptors_[version])); } @@ -87,7 +87,7 @@ Texture::prepareAllocationViews(TextureAllocation *allocaiton) { TextureViewKey Texture::createView(TextureViewDescriptor const &descriptor) { - std::unique_lock lock(mutex_); + std::unique_lock lock(mutex_); unsigned i = 0; for (; i < version_; i++) { if (viewDescriptors_[i].format != descriptor.format) @@ -226,9 +226,10 @@ Texture::view(TextureViewKey key, TextureAllocation* allocation) { return *allocation->cached_view_[key]; } - TextureViewKey Texture::checkViewUseArray(TextureViewKey key, bool isArray) { - auto &view = viewDescriptors_[key]; + std::shared_lock shared_lock(mutex_); + auto view = viewDescriptors_[key]; + shared_lock = {}; static constexpr uint32_t ARRAY_TYPE_MASK = 0b0101001010; if (unlikely(bool((1 << uint32_t(view.type)) & ARRAY_TYPE_MASK) != isArray)) { // TODO: this process can be cached @@ -275,7 +276,9 @@ TextureViewKey Texture::checkViewUseArray(TextureViewKey key, bool isArray) { } TextureViewKey Texture::checkViewUseFormat(TextureViewKey key, WMTPixelFormat format) { - auto &view = viewDescriptors_[key]; + std::shared_lock shared_lock(mutex_); + auto view = viewDescriptors_[key]; + shared_lock = {}; if (unlikely(view.format != format)) { auto new_view_desc = view; new_view_desc.format = format; diff --git a/src/dxmt/dxmt_texture.hpp b/src/dxmt/dxmt_texture.hpp index 0ff585fb..ccf28379 100644 --- a/src/dxmt/dxmt_texture.hpp +++ b/src/dxmt/dxmt_texture.hpp @@ -78,6 +78,11 @@ class TextureViewRef : public Rc { class TextureAllocation : public Allocation { friend class Texture; + /** + * notes on thread-safefy: + * all states in `TextureAllocation` is either immutable or only accessed by `dxmt-encode-thread` + */ + public: WMT::Texture texture() const { @@ -140,12 +145,14 @@ class Texture { } WMTTextureType - textureType(TextureViewKey view) const { - return viewDescriptors_.data()[view].type; + textureType(TextureViewKey view) { + std::shared_lock lock(mutex_); + return viewDescriptors_[view].type; } WMTPixelFormat - pixelFormat(TextureViewKey view) const { + pixelFormat(TextureViewKey view) { + std::shared_lock lock(mutex_); return viewDescriptors_[view].format; } @@ -175,12 +182,14 @@ class Texture { } unsigned - width(TextureViewKey view) const { + width(TextureViewKey view) { + std::shared_lock lock(mutex_); return std::max(info_.width >> viewDescriptors_[view].firstMiplevel, 1u); } unsigned - height(TextureViewKey view) const { + height(TextureViewKey view) { + std::shared_lock lock(mutex_); return std::max(info_.height >> viewDescriptors_[view].firstMiplevel, 1u); } @@ -193,7 +202,8 @@ class Texture { } unsigned - arrayLength(TextureViewKey view) const { + arrayLength(TextureViewKey view) { + std::shared_lock lock(mutex_); return viewDescriptors_[view].arraySize; } @@ -224,7 +234,7 @@ class Texture { std::atomic refcount_ = {0u}; std::vector viewDescriptors_; - dxmt::mutex mutex_; + dxmt::shared_mutex mutex_; WMT::Device device_; };