Repository: KhronosGroup/Vulkan-ValidationLayers
Pull request #9637: gpuav: Misc optimisations
Author: login: arno-lunarg
Created: 2025-03-11T10:31:47Z | Merged: 2025-03-11T17:59:53Z

Some small optimizations I made while investigating GPU-AV performance. For the lightest instrumentation, done for "out of bounds vertex attributes fetching", went from 20 -> 30 fps on Doom Eternal. 
When enabling other types of instrumentation, unfortunately bottlenecks totally shift to other spots specific to instrumentation types.


Diff:
diff --git a/layers/containers/custom_containers.h b/layers/containers/custom_containers.h
index e16eec83aad..f44623b64af 100644
--- a/layers/containers/custom_containers.h
+++ b/layers/containers/custom_containers.h
@@ -170,7 +170,10 @@ class small_vector {
         }
     }
 
-    ~small_vector() { clear(); }
+    ~small_vector() {
+        clear();
+        delete[] large_store_;
+    }
 
     bool operator==(const small_vector &rhs) const {
         if (size_ != rhs.size_) return false;
@@ -332,13 +335,14 @@ class small_vector {
         // Since this can't shrink, if we're growing we're newing
         if (new_cap > capacity_) {
             assert(capacity_ >= kSmallCapacity);
-            auto new_store = std::unique_ptr<BackingStore[]>(new BackingStore[new_cap]);
+            auto new_store = new BackingStore[new_cap];
             auto working_store = GetWorkingStore();
             for (size_type i = 0; i < size_; i++) {
                 new (new_store[i].data) value_type(std::move(working_store[i]));
                 working_store[i].~value_type();
             }
-            large_store_ = std::move(new_store);
+            delete[] large_store_;
+            large_store_ = new_store;
             assert(new_cap > kSmallCapacity);
             capacity_ = new_cap;
         }
@@ -371,17 +375,19 @@ class small_vector {
         if (size_ == 0) {
             // shrink resets to small when empty
             capacity_ = kSmallCapacity;
-            large_store_.reset();
+            delete[] large_store_;
+            large_store_ = nullptr;
             UpdateWorkingStore();
         } else if ((capacity_ > kSmallCapacity) && (capacity_ > size_)) {
             auto source = GetWorkingStore();
             // Keep the source from disappearing until the end of the function
-            auto old_store = std::unique_ptr<BackingStore[]>(std::move(large_store_));
+            auto old_store = large_store_;
+            large_store_ = nullptr;
             assert(!large_store_);
             if (size_ < kSmallCapacity) {
                 capacity_ = kSmallCapacity;
             } else {
-                large_store_ = std::unique_ptr<BackingStore[]>(new BackingStore[size_]);
+                large_store_ = new BackingStore[size_];
                 capacity_ = size_;
             }
             UpdateWorkingStore();
@@ -390,6 +396,7 @@ class small_vector {
                 dest[i] = std::move(source[i]);
                 source[i].~value_type();
             }
+            delete[] old_store;
         }
     }
 
@@ -410,13 +417,13 @@ class small_vector {
     inline const_pointer ComputeWorkingStore() const {
         assert(large_store_ || (capacity_ == kSmallCapacity));
 
-        const BackingStore *store = large_store_ ? large_store_.get() : small_store_;
+        const BackingStore *store = large_store_ ? large_store_ : small_store_;
         return &store->object;
     }
     inline pointer ComputeWorkingStore() {
         assert(large_store_ || (capacity_ == kSmallCapacity));
 
-        BackingStore *store = large_store_ ? large_store_.get() : small_store_;
+        BackingStore *store = large_store_ ? large_store_ : small_store_;
         return &store->object;
     }
 
@@ -440,11 +447,13 @@ class small_vector {
         uint8_t data[sizeof(value_type)];
         value_type object;
     };
-    size_type size_;
-    size_type capacity_;
-    BackingStore small_store_[N];
-    std::unique_ptr<BackingStore[]> large_store_;
-    value_type *working_store_;
+    size_type size_ = 0;
+    size_type capacity_ = 0;
+    BackingStore small_store_[N]{};
+    // Even an empty std::unique_ptr can be costly to construct,
+    // so use a raw pointer
+    BackingStore *large_store_ = nullptr;
+    value_type *working_store_ = nullptr;
 
 #ifndef NDEBUG
     void DbgWorkingStoreCheck() const { assert(ComputeWorkingStore() == working_store_); };
@@ -457,7 +466,9 @@ class small_vector {
         assert(other.large_store_);
         assert(other.capacity_ > kSmallCapacity);
         // In move operations, from a small vector with a large store, we can move from it
-        large_store_ = std::move(other.large_store_);
+        delete[] large_store_;
+        large_store_ = other.large_store_;
+        other.large_store_ = nullptr;
         capacity_ = other.capacity_;
         size_ = other.size_;
         UpdateWorkingStore();
diff --git a/layers/gpuav/core/gpuav_setup.cpp b/layers/gpuav/core/gpuav_setup.cpp
index 1743789eae3..258663a2a99 100644
--- a/layers/gpuav/core/gpuav_setup.cpp
+++ b/layers/gpuav/core/gpuav_setup.cpp
@@ -307,13 +307,11 @@ void Validator::FinishDeviceSetup(const VkDeviceCreateInfo *pCreateInfo, const L
             return;
         }
 
-        auto indices_ptr = (uint32_t *)indices_buffer_.MapMemory(loc);
+        auto indices_ptr = (uint32_t *)indices_buffer_.GetMappedPtr(loc);
 
         for (uint32_t i = 0; i < buffer_info.size / sizeof(uint32_t); ++i) {
             indices_ptr[i] = i / (indices_buffer_alignment_ / sizeof(uint32_t));
         }
-
-        indices_buffer_.UnmapMemory();
     }
 }
 
diff --git a/layers/gpuav/debug_printf/debug_printf.cpp b/layers/gpuav/debug_printf/debug_printf.cpp
index b8843f396df..7aba50fd64f 100644
--- a/layers/gpuav/debug_printf/debug_printf.cpp
+++ b/layers/gpuav/debug_printf/debug_printf.cpp
@@ -390,9 +390,8 @@ bool UpdateInstrumentationDescSet(Validator &gpuav, CommandBuffer &cb_state, VkD
     }
 
     // Clear the output block to zeros so that only printf values from the gpu will be present
-    auto printf_output_ptr = (uint32_t *)debug_printf_output_buffer.MapMemory(loc);
+    auto printf_output_ptr = (uint32_t *)debug_printf_output_buffer.GetMappedPtr(loc);
     memset(printf_output_ptr, 0, gpuav.gpuav_settings.debug_printf_buffer_size);
-    debug_printf_output_buffer.UnmapMemory();
 
     VkDescriptorBufferInfo debug_printf_desc_buffer_info = {};
     debug_printf_desc_buffer_info.range = gpuav.gpuav_settings.debug_printf_buffer_size;
diff --git a/layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp b/layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
index eb75a2f1312..3e56a60de6e 100644
--- a/layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
+++ b/layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
@@ -23,6 +23,8 @@
 #include "gpuav/shaders/gpuav_shaders_constants.h"
 #include "state_tracker/descriptor_sets.h"
 
+#include "profiling/profiling.h"
+
 using vvl::DescriptorClass;
 
 namespace gpuav {
@@ -217,7 +219,7 @@ VkDeviceAddress DescriptorSet::GetTypeAddress(Validator &gpuav, const Location &
         return 0;
     }
 
-    auto data = (glsl::DescriptorState *)input_buffer_.MapMemory(loc);
+    auto data = (glsl::DescriptorState *)input_buffer_.GetMappedPtr(loc);
 
     uint32_t index = 0;
     for (uint32_t i = 0; i < bindings_.size(); i++) {
@@ -254,7 +256,6 @@ VkDeviceAddress DescriptorSet::GetTypeAddress(Validator &gpuav, const Location &
 
     // Flush the descriptor state buffer before unmapping so that the new state is visible to the GPU
     input_buffer_.FlushAllocation(loc);
-    input_buffer_.UnmapMemory();
 
     return input_buffer_.Address();
 }
@@ -293,11 +294,12 @@ VkDeviceAddress DescriptorSet::GetPostProcessBuffer(Validator &gpuav, const Loca
         return 0;
     }
 
-    void *data = post_process_buffer_.MapMemory(loc);
+    VVL_TracyPlot("Post process buffer size (bytes)", int64_t(buffer_info.size));
+
+    void *data = post_process_buffer_.GetMappedPtr(loc);
     memset(data, 0, static_cast<size_t>(buffer_info.size));
 
     post_process_buffer_.FlushAllocation(loc);
-    post_process_buffer_.UnmapMemory();
 
     return post_process_buffer_.Address();
 }
@@ -305,12 +307,13 @@ VkDeviceAddress DescriptorSet::GetPostProcessBuffer(Validator &gpuav, const Loca
 // cross checks the two buffers (our layout with the output from the GPU-AV run) and builds a map of which indexes in which binding
 // where accessed
 std::vector<DescriptorAccess> DescriptorSet::GetDescriptorAccesses(const Location &loc, uint32_t shader_set) const {
+    VVL_ZoneScoped;
     std::vector<DescriptorAccess> descriptor_accesses;
     if (post_process_buffer_.IsDestroyed()) {
         return descriptor_accesses;
     }
 
-    auto slot_ptr = (glsl::PostProcessDescriptorIndexSlot *)post_process_buffer_.MapMemory(loc);
+    auto slot_ptr = (glsl::PostProcessDescriptorIndexSlot *)post_process_buffer_.GetMappedPtr(loc);
     post_process_buffer_.InvalidateAllocation(loc);
 
     for (uint32_t binding = 0; binding < binding_layouts_.size(); binding++) {
@@ -325,7 +328,6 @@ std::vector<DescriptorAccess> DescriptorSet::GetDescriptorAccesses(const Locatio
         }
     }
 
-    post_process_buffer_.UnmapMemory();
     return descriptor_accesses;
 }
 
@@ -363,13 +365,12 @@ DescriptorHeap::DescriptorHeap(Validator &gpuav, uint32_t max_descriptors, const
         return;
     }
 
-    gpu_heap_state_ = (uint32_t *)buffer_.MapMemory(loc);
+    gpu_heap_state_ = (uint32_t *)buffer_.GetMappedPtr(loc);
     memset(gpu_heap_state_, 0, static_cast<size_t>(buffer_info.size));
 }
 
 DescriptorHeap::~DescriptorHeap() {
     if (max_descriptors_ > 0) {
-        buffer_.UnmapMemory();
         buffer_.Destroy();
         gpu_heap_state_ = nullptr;
     }
diff --git a/layers/gpuav/descriptor_validation/gpuav_descriptor_validation.cpp b/layers/gpuav/descriptor_validation/gpuav_descriptor_validation.cpp
index bbfe61f7555..1738a2cd3d4 100644
--- a/layers/gpuav/descriptor_validation/gpuav_descriptor_validation.cpp
+++ b/layers/gpuav/descriptor_validation/gpuav_descriptor_validation.cpp
@@ -23,6 +23,8 @@
 #include "gpuav/resources/gpuav_shader_resources.h"
 #include "state_tracker/shader_module.h"
 
+#include "profiling/profiling.h"
+
 namespace gpuav {
 namespace descriptor {
 
@@ -88,7 +90,7 @@ void UpdateBoundDescriptorsPostProcess(Validator &gpuav, CommandBuffer &cb_state
         return;
     }
 
-    auto ssbo_buffer_ptr = (glsl::PostProcessSSBO *)descriptor_command_binding.post_process_ssbo_buffer.MapMemory(loc);
+    auto ssbo_buffer_ptr = (glsl::PostProcessSSBO *)descriptor_command_binding.post_process_ssbo_buffer.GetMappedPtr(loc);
     memset(ssbo_buffer_ptr, 0, sizeof(glsl::PostProcessSSBO));
 
     cb_state.post_process_buffer_lut = descriptor_command_binding.post_process_ssbo_buffer.VkHandle();
@@ -103,8 +105,6 @@ void UpdateBoundDescriptorsPostProcess(Validator &gpuav, CommandBuffer &cb_state
         auto bound_descriptor_set = static_cast<DescriptorSet *>(ds_slot.ds_state.get());
         ssbo_buffer_ptr->descriptor_index_post_process_buffers[i] = bound_descriptor_set->GetPostProcessBuffer(gpuav, loc);
     }
-
-    descriptor_command_binding.post_process_ssbo_buffer.UnmapMemory();
 }
 
 void UpdateBoundDescriptorsDescriptorChecks(Validator &gpuav, CommandBuffer &cb_state, const LastBound &last_bound,
@@ -123,7 +123,7 @@ void UpdateBoundDescriptorsDescriptorChecks(Validator &gpuav, CommandBuffer &cb_
         return;
     }
 
-    auto ssbo_buffer_ptr = (glsl::DescriptorStateSSBO *)descriptor_command_binding.descritpor_state_ssbo_buffer.MapMemory(loc);
+    auto ssbo_buffer_ptr = (glsl::DescriptorStateSSBO *)descriptor_command_binding.descritpor_state_ssbo_buffer.GetMappedPtr(loc);
     memset(ssbo_buffer_ptr, 0, sizeof(glsl::DescriptorStateSSBO));
 
     cb_state.descriptor_indexing_buffer = descriptor_command_binding.descritpor_state_ssbo_buffer.VkHandle();
@@ -143,8 +143,6 @@ void UpdateBoundDescriptorsDescriptorChecks(Validator &gpuav, CommandBuffer &cb_
             ssbo_buffer_ptr->descriptor_set_types[i] = bound_descriptor_set->GetTypeAddress(gpuav, loc);
         }
     }
-
-    descriptor_command_binding.descritpor_state_ssbo_buffer.UnmapMemory();
 }
 
 void UpdateBoundDescriptors(Validator &gpuav, CommandBuffer &cb_state, VkPipelineBindPoint pipeline_bind_point,
@@ -190,12 +188,12 @@ void UpdateBoundDescriptors(Validator &gpuav, CommandBuffer &cb_state, VkPipelin
     if (!need_descriptor_checks) return true;
 
     for (auto &descriptor_command_binding : cb_state.descriptor_command_bindings) {
-        auto ssbo_buffer_ptr = (glsl::DescriptorStateSSBO *)descriptor_command_binding.descritpor_state_ssbo_buffer.MapMemory(loc);
+        auto ssbo_buffer_ptr =
+            (glsl::DescriptorStateSSBO *)descriptor_command_binding.descritpor_state_ssbo_buffer.GetMappedPtr(loc);
         for (size_t i = 0; i < descriptor_command_binding.bound_descriptor_sets.size(); i++) {
             DescriptorSet &ds_state = *descriptor_command_binding.bound_descriptor_sets[i];
             ssbo_buffer_ptr->descriptor_set_types[i] = ds_state.GetTypeAddress(gpuav, loc);
         }
-        descriptor_command_binding.descritpor_state_ssbo_buffer.UnmapMemory();
     }
     return true;
 }
@@ -203,6 +201,7 @@ void UpdateBoundDescriptors(Validator &gpuav, CommandBuffer &cb_state, VkPipelin
 
 // After the GPU executed, we know which descriptor indexes were accessed and can validate with normal Core Validation logic
 [[nodiscard]] bool CommandBuffer::ValidateBindlessDescriptorSets(const Location &loc) {
+    VVL_ZoneScoped;
     for (uint32_t action_index = 0; action_index < action_command_snapshots.size(); action_index++) {
         const auto &action_command_snapshot = action_command_snapshots[action_index];
         const auto &descriptor_command_binding =
diff --git a/layers/gpuav/instrumentation/gpuav_instrumentation.cpp b/layers/gpuav/instrumentation/gpuav_instrumentation.cpp
index a1d0cd65d7f..1df71ce9f5a 100644
--- a/layers/gpuav/instrumentation/gpuav_instrumentation.cpp
+++ b/layers/gpuav/instrumentation/gpuav_instrumentation.cpp
@@ -183,7 +183,7 @@ static std::pair<std::optional<VertexAttributeFetchLimit>, std::optional<VertexA
     std::optional<VertexAttributeFetchLimit> vertex_attribute_fetch_limit_vertex_input_rate;
     std::optional<VertexAttributeFetchLimit> vertex_attribute_fetch_limit_instance_input_rate;
 
-    vvl::unordered_set<uint32_t> vertex_shader_used_locations;
+    small_vector<uint32_t, 32> vertex_shader_used_locations;
     {
         const ::spirv::EntryPoint *vertex_entry_point = last_bound.GetVertexEntryPoint();
         if (!vertex_entry_point) {
@@ -191,7 +191,11 @@ static std::pair<std::optional<VertexAttributeFetchLimit>, std::optional<VertexA
         }
         for (const ::spirv::StageInterfaceVariable &interface_var : vertex_entry_point->stage_interface_variables) {
             for (const ::spirv::InterfaceSlot &interface_slot : interface_var.interface_slots) {
-                vertex_shader_used_locations.insert(interface_slot.Location());
+                const uint32_t location = interface_slot.Location();
+                if (std::find(vertex_shader_used_locations.begin(), vertex_shader_used_locations.end(), location) ==
+                    vertex_shader_used_locations.end()) {
+                    vertex_shader_used_locations.emplace_back(location);
+                }
             }
         }
     }
@@ -204,7 +208,8 @@ static std::pair<std::optional<VertexAttributeFetchLimit>, std::optional<VertexA
         }
 
         for (const auto &[location, attrib] : vertex_binding_desc.locations) {
-            if (vertex_shader_used_locations.find(location) == vertex_shader_used_locations.end()) {
+            if (std::find(vertex_shader_used_locations.begin(), vertex_shader_used_locations.end(), location) ==
+                vertex_shader_used_locations.end()) {
                 continue;
             }
             const VkDeviceSize attribute_size = GetVertexInputFormatSize(attrib.desc.format);
@@ -251,7 +256,7 @@ static std::pair<std::optional<VertexAttributeFetchLimit>, std::optional<VertexA
 
 void UpdateInstrumentationDescSet(Validator &gpuav, CommandBuffer &cb_state, VkDescriptorSet instrumentation_desc_set,
                                   const Location &loc, InstrumentationErrorBlob &out_instrumentation_error_blob) {
-    std::vector<VkWriteDescriptorSet> desc_writes = {};
+    small_vector<VkWriteDescriptorSet, 8> desc_writes = {};
 
     // Error output buffer
     VkDescriptorBufferInfo error_output_desc_buffer_info = {};
@@ -377,7 +382,7 @@ void UpdateInstrumentationDescSet(Validator &gpuav, CommandBuffer &cb_state, VkD
 
         const auto [vertex_attribute_fetch_limit_vertex_input_rate, vertex_attribute_fetch_limit_instance_input_rate] =
             GetVertexAttributeFetchLimits(cb_state);
-        auto vertex_attribute_fetch_limits_buffer_ptr = (uint32_t *)vertex_attribute_fetch_limits_buffer.MapMemory(loc);
+        auto vertex_attribute_fetch_limits_buffer_ptr = (uint32_t *)vertex_attribute_fetch_limits_buffer.GetMappedPtr(loc);
         if (vertex_attribute_fetch_limit_vertex_input_rate.has_value()) {
             vertex_attribute_fetch_limits_buffer_ptr[0] = 1u;
             vertex_attribute_fetch_limits_buffer_ptr[1] =
@@ -395,7 +400,6 @@ void UpdateInstrumentationDescSet(Validator &gpuav, CommandBuffer &cb_state, VkD
             vertex_attribute_fetch_limits_buffer_ptr[3] = std::numeric_limits<uint32_t>::max();
         }
 
-        vertex_attribute_fetch_limits_buffer.UnmapMemory();
         out_instrumentation_error_blob.vertex_attribute_fetch_limit_vertex_input_rate =
             vertex_attribute_fetch_limit_vertex_input_rate;
         out_instrumentation_error_blob.vertex_attribute_fetch_limit_instance_input_rate =
diff --git a/layers/gpuav/resources/gpuav_state_trackers.cpp b/layers/gpuav/resources/gpuav_state_trackers.cpp
index e60d707a777..7039287ca64 100644
--- a/layers/gpuav/resources/gpuav_state_trackers.cpp
+++ b/layers/gpuav/resources/gpuav_state_trackers.cpp
@@ -148,14 +148,13 @@ static bool AllocateErrorLogsBuffer(Validator &gpuav, VkCommandBuffer command_bu
         return false;
     }
 
-    auto output_buffer_ptr = (uint32_t *)error_output_buffer.MapMemory(loc);
+    auto output_buffer_ptr = (uint32_t *)error_output_buffer.GetMappedPtr(loc);
 
     memset(output_buffer_ptr, 0, glsl::kErrorBufferByteSize);
     if (gpuav.gpuav_settings.shader_instrumentation.descriptor_checks) {
         output_buffer_ptr[cst::stream_output_flags_offset] = cst::inst_buffer_oob_enabled;
     }
 
-    error_output_buffer.UnmapMemory();
     return true;
 }
 
@@ -311,7 +310,7 @@ bool CommandBuffer::UpdateBdaRangesBuffer(const Location &loc) {
 
     // Update buffer device address table
     // ---
-    auto bda_table_ptr = (VkDeviceAddress *)bda_ranges_snapshot_.MapMemory(loc);
+    auto bda_table_ptr = (VkDeviceAddress *)bda_ranges_snapshot_.GetMappedPtr(loc);
 
     // Buffer device address table layout
     // Ranges are sorted from low to high, and do not overlap
@@ -343,7 +342,6 @@ bool CommandBuffer::UpdateBdaRangesBuffer(const Location &loc) {
     // ---
     // Flush the BDA buffer before un-mapping so that the new state is visible to the GPU
     bda_ranges_snapshot_.FlushAllocation(loc);
-    bda_ranges_snapshot_.UnmapMemory();
     bda_ranges_snapshot_version_ = gpuav->buffer_device_address_ranges_version;
 
     return true;
@@ -362,21 +360,21 @@ CommandBuffer::~CommandBuffer() { Destroy(); }
 void CommandBuffer::Destroy() {
     {
         auto guard = WriteLock();
-        ResetCBState();
+        ResetCBState(true);
     }
     vvl::CommandBuffer::Destroy();
 }
 
 void CommandBuffer::Reset(const Location &loc) {
     vvl::CommandBuffer::Reset(loc);
-    ResetCBState();
+    ResetCBState(false);
     // TODO: Calling AllocateResources in Reset like so is a kind of a hack,
     // relying on CommandBuffer internal logic to work.
     // Tried to call it in ResetCBState, hang on command buffer mutex :/
     AllocateResources(loc);
 }
 
-void CommandBuffer::ResetCBState() {
+void CommandBuffer::ResetCBState(bool should_destroy) {
     auto gpuav = static_cast<Validator *>(&dev_data);
 
     // Free the device memory and descriptor set(s) associated with a command buffer.
@@ -385,8 +383,11 @@ void CommandBuffer::ResetCBState() {
     }
     debug_printf_buffer_infos.clear();
 
-    // Free the device memory and descriptor set(s) associated with a command buffer.
-    gpu_resources_manager.DestroyResources();
+    if (should_destroy) {
+        gpu_resources_manager.DestroyResources();
+    } else {
+        gpu_resources_manager.ReturnResources();
+    }
     per_command_error_loggers.clear();
 
     for (DescriptorCommandBinding &descriptor_command_binding : descriptor_command_bindings) {
@@ -409,7 +410,7 @@ void CommandBuffer::ResetCBState() {
         error_logging_desc_set_ = VK_NULL_HANDLE;
     }
 
-    if (instrumentation_desc_set_layout_ != VK_NULL_HANDLE) {
+    if (should_destroy && instrumentation_desc_set_layout_ != VK_NULL_HANDLE) {
         DispatchDestroyDescriptorSetLayout(gpuav->device, instrumentation_desc_set_layout_, nullptr);
         instrumentation_desc_set_layout_ = VK_NULL_HANDLE;
     }
@@ -426,9 +427,8 @@ void CommandBuffer::ResetCBState() {
 }
 
 void CommandBuffer::ClearCmdErrorsCountsBuffer(const Location &loc) const {
-    auto cmd_errors_counts_buffer_ptr = (uint32_t *)cmd_errors_counts_buffer_.MapMemory(loc);
+    auto cmd_errors_counts_buffer_ptr = (uint32_t *)cmd_errors_counts_buffer_.GetMappedPtr(loc);
     std::memset(cmd_errors_counts_buffer_ptr, 0, static_cast<size_t>(GetCmdErrorsCountsBufferByteSize()));
-    cmd_errors_counts_buffer_.UnmapMemory();
 }
 
 void CommandBuffer::IncrementCommandCount(VkPipelineBindPoint bind_point) {
@@ -482,13 +482,13 @@ bool CommandBuffer::NeedsPostProcess() { return !error_output_buffer_.IsDestroye
 
 // For the given command buffer, map its debug data buffers and read their contents for analysis.
 void CommandBuffer::PostProcess(VkQueue queue, const std::vector<std::string> &initial_label_stack, const Location &loc) {
+    VVL_ZoneScoped;
     auto gpuav = static_cast<Validator *>(&dev_data);
 
     // For the given command buffer, map its debug data buffers and read their contents for analysis.
     for (DebugPrintfBufferInfo &printf_buffer_info : debug_printf_buffer_infos) {
-        auto printf_output_ptr = (char *)printf_buffer_info.output_mem_buffer.MapMemory(loc);
+        auto printf_output_ptr = (char *)printf_buffer_info.output_mem_buffer.GetMappedPtr(loc);
         debug_printf::AnalyzeAndGenerateMessage(*gpuav, VkHandle(), queue, printf_buffer_info, (uint32_t *)printf_output_ptr, loc);
-        printf_buffer_info.output_mem_buffer.UnmapMemory();
     }
 
     // CommandBuffer::Destroy can happen on an other thread,
@@ -500,7 +500,7 @@ void CommandBuffer::PostProcess(VkQueue queue, const std::vector<std::string> &i
 
     bool skip = false;
     {
-        auto error_output_buffer_ptr = (uint32_t *)error_output_buffer_.MapMemory(loc);
+        auto error_output_buffer_ptr = (uint32_t *)error_output_buffer_.GetMappedPtr(loc);
 
         // The second word in the debug output buffer is the number of words that would have
         // been written by the shader instrumentation, if there was enough room in the buffer we provided.
@@ -540,7 +540,6 @@ void CommandBuffer::PostProcess(VkQueue queue, const std::vector<std::string> &i
                    glsl::kErrorBufferByteSize - cst::stream_output_data_offset * sizeof(uint32_t));
         }
         error_output_buffer_ptr[cst::stream_output_size_offset] = 0;
-        error_output_buffer_.UnmapMemory();
     }
 
     ClearCmdErrorsCountsBuffer(loc);
diff --git a/layers/gpuav/resources/gpuav_state_trackers.h b/layers/gpuav/resources/gpuav_state_trackers.h
index 0de3d3dde0f..1008760e3aa 100644
--- a/layers/gpuav/resources/gpuav_state_trackers.h
+++ b/layers/gpuav/resources/gpuav_state_trackers.h
@@ -136,7 +136,7 @@ class CommandBuffer : public vvl::CommandBuffer {
 
   private:
     void AllocateResources(const Location &loc);
-    void ResetCBState();
+    void ResetCBState(bool should_destroy);
     bool NeedsPostProcess();
 
     VkDeviceSize GetBdaRangesBufferByteSize() const;
diff --git a/layers/gpuav/resources/gpuav_vulkan_objects.cpp b/layers/gpuav/resources/gpuav_vulkan_objects.cpp
index ee6317ac58f..8a9353d224b 100644
--- a/layers/gpuav/resources/gpuav_vulkan_objects.cpp
+++ b/layers/gpuav/resources/gpuav_vulkan_objects.cpp
@@ -1,6 +1,6 @@
-/* Copyright (c) 2018-2024 The Khronos Group Inc.
- * Copyright (c) 2018-2024 Valve Corporation
- * Copyright (c) 2018-2024 LunarG, Inc.
+/* Copyright (c) 2018-2025 The Khronos Group Inc.
+ * Copyright (c) 2018-2025 Valve Corporation
+ * Copyright (c) 2018-2025 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -145,17 +145,7 @@ void SharedResourcesCache::Clear() {
     shared_validation_resources_map_.clear();
 }
 
-void *Buffer::MapMemory(const Location &loc) const {
-    void *buffer_ptr = nullptr;
-    VkResult result = vmaMapMemory(gpuav.vma_allocator_, allocation, &buffer_ptr);
-    if (result != VK_SUCCESS) {
-        gpuav.InternalVmaError(gpuav.device, loc, "Unable to map device memory.");
-        return nullptr;
-    }
-    return buffer_ptr;
-}
-
-void Buffer::UnmapMemory() const { vmaUnmapMemory(gpuav.vma_allocator_, allocation); }
+void *Buffer::GetMappedPtr(const Location &loc) const { return mapped_ptr; }
 
 void Buffer::FlushAllocation(const Location &loc, VkDeviceSize offset, VkDeviceSize size) const {
     VkResult result = vmaFlushAllocation(gpuav.vma_allocator_, allocation, offset, size);
@@ -188,11 +178,22 @@ bool Buffer::Create(const Location &loc, const VkBufferCreateInfo *buffer_create
             return false;
         }
     }
+    if (allocation_create_info->requiredFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
+        result = vmaMapMemory(gpuav.vma_allocator_, allocation, &mapped_ptr);
+        if (result != VK_SUCCESS) {
+            mapped_ptr = nullptr;
+            gpuav.InternalVmaError(gpuav.device, loc, "Unable to map device memory.");
+            return false;
+        }
+    }
     return true;
 }
 
 void Buffer::Destroy() {
     if (buffer != VK_NULL_HANDLE) {
+        if (mapped_ptr != nullptr) {
+            vmaUnmapMemory(gpuav.vma_allocator_, allocation);
+        }
         vmaDestroyBuffer(gpuav.vma_allocator_, buffer, allocation);
         buffer = VK_NULL_HANDLE;
         allocation = VK_NULL_HANDLE;
@@ -201,33 +202,97 @@ void Buffer::Destroy() {
 }
 
 VkDescriptorSet GpuResourcesManager::GetManagedDescriptorSet(VkDescriptorSetLayout desc_set_layout) {
-    std::pair<VkDescriptorPool, VkDescriptorSet> descriptor;
-    descriptor_set_manager_.GetDescriptorSet(&descriptor.first, desc_set_layout, &descriptor.second);
-    descriptors_.emplace_back(descriptor);
-    return descriptor.second;
+    // Look for a descriptor set layout matching input,
+    // if found get or add an associated descriptor set
+    for (LayoutToSets &layout_to_sets : cache_layouts_to_sets_) {
+        if (layout_to_sets.desc_set_layout != desc_set_layout) {
+            continue;
+        }
+
+        if (layout_to_sets.first_available_desc_set == layout_to_sets.cached_descriptors.size()) {
+            CachedDescriptor cached_descriptor;
+            const VkResult result = descriptor_set_manager_.GetDescriptorSet(&cached_descriptor.desc_pool, desc_set_layout,
+                                                                             &cached_descriptor.desc_set);
+            if (result != VK_SUCCESS) {
+                return VK_NULL_HANDLE;
+            }
+            layout_to_sets.cached_descriptors.emplace_back(cached_descriptor);
+        }
+
+        assert(layout_to_sets.first_available_desc_set < layout_to_sets.cached_descriptors.size());
+        return layout_to_sets.cached_descriptors[layout_to_sets.first_available_desc_set++].desc_set;
+    }
+
+    // Did not find input descriptor set layout,
+    // add a new cache entry and just re-run search
+    LayoutToSets layout_to_sets;
+    layout_to_sets.desc_set_layout = desc_set_layout;
+    cache_layouts_to_sets_.emplace_back(layout_to_sets);
+    return GetManagedDescriptorSet(desc_set_layout);
 }
 
-vko::Buffer GpuResourcesManager::GetManagedBuffer(Validator &gpuav, const Location &loc, const VkBufferCreateInfo &ci,
-                                                  const VmaAllocationCreateInfo &vma_ci) {
-    vko::Buffer buffer(gpuav);
-    const bool success = buffer.Create(loc, &ci, &vma_ci);
-    if (success) {
-        buffers_.emplace_back(buffer);
+vko::Buffer GpuResourcesManager::GetManagedBuffer(Validator &gpuav, const Location &loc, const VkBufferCreateInfo &buffer_ci,
+                                                  const VmaAllocationCreateInfo &alloc_ci) {
+    assert(buffer_ci.pNext == nullptr);
+    assert(buffer_ci.sharingMode == VK_SHARING_MODE_EXCLUSIVE);
+    assert(alloc_ci.pUserData == nullptr);
+
+    // Try to find a cached and available buffer created with equivalent characteristics
+    for (CachedBuffer &cached_buffer : cached_buffers_) {
+        if (!(cached_buffer.status == CachedStatus::Available)) {
+            continue;
+        }
+        const bool same_buffer_ci = buffer_ci.flags == cached_buffer.buffer_ci.flags &&
+                                    buffer_ci.size <= cached_buffer.buffer_ci.size &&
+                                    buffer_ci.usage == cached_buffer.buffer_ci.usage;
+
+        const bool same_alloc_ci =
+            alloc_ci.flags == cached_buffer.allocation_ci.flags && alloc_ci.usage == cached_buffer.allocation_ci.usage &&
+            alloc_ci.requiredFlags == cached_buffer.allocation_ci.requiredFlags &&
+            alloc_ci.preferredFlags == cached_buffer.allocation_ci.preferredFlags &&
+            alloc_ci.memoryTypeBits == cached_buffer.allocation_ci.memoryTypeBits &&
+            alloc_ci.pool == cached_buffer.allocation_ci.pool && alloc_ci.priority == cached_buffer.allocation_ci.priority;
+
+        if (same_buffer_ci && same_alloc_ci) {
+            cached_buffer.status = CachedStatus::InUse;
+            return cached_buffer.buffer;
+        }
     }
 
+    // Did not find a cached buffer, create one, cache it and return its handle
+    Buffer buffer(gpuav);
+    const bool success = buffer.Create(loc, &buffer_ci, &alloc_ci);
+    if (!success) {
+        return buffer;
+    }
+    CachedBuffer cached_buffer = {buffer_ci, alloc_ci, buffer, CachedStatus::InUse};
+    cached_buffers_.emplace_back(cached_buffer);
     return buffer;
 }
 
+void GpuResourcesManager::ReturnResources() {
+    for (LayoutToSets &layout_to_set : cache_layouts_to_sets_) {
+        layout_to_set.first_available_desc_set = 0;
+    }
+
+    for (CachedBuffer &cached_buffer : cached_buffers_) {
+        cached_buffer.status = CachedStatus::Available;
+    }
+}
+
 void GpuResourcesManager::DestroyResources() {
-    for (auto &[desc_pool, desc_set] : descriptors_) {
-        descriptor_set_manager_.PutBackDescriptorSet(desc_pool, desc_set);
+    for (LayoutToSets &layout_to_set : cache_layouts_to_sets_) {
+        for (CachedDescriptor &cached_descriptor : layout_to_set.cached_descriptors) {
+            descriptor_set_manager_.PutBackDescriptorSet(cached_descriptor.desc_pool, cached_descriptor.desc_set);
+        }
+        layout_to_set.cached_descriptors.clear();
     }
-    descriptors_.clear();
+    cache_layouts_to_sets_.clear();
 
-    for (auto &buffer : buffers_) {
-        buffer.Destroy();
+    for (CachedBuffer &cached_buffer : cached_buffers_) {
+        cached_buffer.buffer.Destroy();
     }
-    buffers_.clear();
+    cached_buffers_.clear();
 }
 }  // namespace vko
 }  // namespace gpuav
diff --git a/layers/gpuav/resources/gpuav_vulkan_objects.h b/layers/gpuav/resources/gpuav_vulkan_objects.h
index 92409e30912..427905c9334 100644
--- a/layers/gpuav/resources/gpuav_vulkan_objects.h
+++ b/layers/gpuav/resources/gpuav_vulkan_objects.h
@@ -1,6 +1,6 @@
-/* Copyright (c) 2018-2024 The Khronos Group Inc.
- * Copyright (c) 2018-2024 Valve Corporation
- * Copyright (c) 2018-2024 LunarG, Inc.
+/* Copyright (c) 2018-2025 The Khronos Group Inc.
+ * Copyright (c) 2018-2025 Valve Corporation
+ * Copyright (c) 2018-2025 LunarG, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -60,8 +60,7 @@ class Buffer {
     // Warps VMA calls to simplify error reporting.
     // No error propagation, but if hitting a VMA error, GPU-AV is likely not going to recover anyway.
 
-    [[nodiscard]] void *MapMemory(const Location &loc) const;
-    void UnmapMemory() const;
+    [[nodiscard]] void *GetMappedPtr(const Location &loc) const;
     void FlushAllocation(const Location &loc, VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE) const;
     void InvalidateAllocation(const Location &loc, VkDeviceSize offset = 0, VkDeviceSize size = VK_WHOLE_SIZE) const;
 
@@ -80,6 +79,7 @@ class Buffer {
     VmaAllocation allocation = VK_NULL_HANDLE;
     // If buffer was not created with VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT then this will not be zero
     VkDeviceAddress device_address = 0;
+    void *mapped_ptr = nullptr;
 };
 
 // Register/Create and register GPU resources, all to be destroyed upon a call to DestroyResources
@@ -91,12 +91,34 @@ class GpuResourcesManager {
     vko::Buffer GetManagedBuffer(Validator &gpuav, const Location &loc, const VkBufferCreateInfo &ci,
                                  const VmaAllocationCreateInfo &vma_ci);
 
+    void ReturnResources();
     void DestroyResources();
 
   private:
     DescriptorSetManager &descriptor_set_manager_;
-    std::vector<std::pair<VkDescriptorPool, VkDescriptorSet>> descriptors_;
-    std::vector<vko::Buffer> buffers_;
+    enum class CachedStatus { Undefined, InUse, Available };
+    struct CachedDescriptor {
+        // VkDescriptorSetLayout desc_set_layout = VK_NULL_HANDLE;
+        VkDescriptorPool desc_pool = VK_NULL_HANDLE;
+        VkDescriptorSet desc_set = VK_NULL_HANDLE;
+        // CachedStatus status = CachedStatus::Undefined;
+    };
+    struct LayoutToSets {
+        VkDescriptorSetLayout desc_set_layout = VK_NULL_HANDLE;
+        std::vector<CachedDescriptor> cached_descriptors;
+        size_t first_available_desc_set = 0;
+    };
+    std::vector<LayoutToSets> cache_layouts_to_sets_;
+    // std::vector<CachedDescriptor> cached_descriptors_;
+
+    struct CachedBuffer {
+        VkBufferCreateInfo buffer_ci{};
+        VmaAllocationCreateInfo allocation_ci{};
+        vko::Buffer buffer;
+
+        CachedStatus status = CachedStatus::Undefined;
+    };
+    std::vector<CachedBuffer> cached_buffers_;
 };
 
 // Cache a single object of type T. Key is *only* based on typeid(T)
diff --git a/layers/gpuav/validation_cmd/gpuav_copy_buffer_to_image.cpp b/layers/gpuav/validation_cmd/gpuav_copy_buffer_to_image.cpp
index d6f63752e71..f8f1ca196cd 100644
--- a/layers/gpuav/validation_cmd/gpuav_copy_buffer_to_image.cpp
+++ b/layers/gpuav/validation_cmd/gpuav_copy_buffer_to_image.cpp
@@ -201,7 +201,7 @@ void InsertCopyBufferToImageValidation(Validator &gpuav, const Location &loc, Co
             return;
         }
 
-        auto gpu_regions_u32_ptr = (uint32_t *)copy_src_regions_mem_buffer.MapMemory(loc);
+        auto gpu_regions_u32_ptr = (uint32_t *)copy_src_regions_mem_buffer.GetMappedPtr(loc);
 
         const uint32_t block_size = image_state->create_info.format == VK_FORMAT_D32_SFLOAT ? 4 : 5;
         uint32_t gpu_regions_count = 0;
@@ -245,7 +245,6 @@ void InsertCopyBufferToImageValidation(Validator &gpuav, const Location &loc, Co
 
         if (gpu_regions_count == 0) {
             // Nothing to validate
-            copy_src_regions_mem_buffer.UnmapMemory();
             return;
         }
 
@@ -257,8 +256,6 @@ void InsertCopyBufferToImageValidation(Validator &gpuav, const Location &loc, Co
         gpu_regions_u32_ptr[5] = gpu_regions_count;
         gpu_regions_u32_ptr[6] = 0;
         gpu_regions_u32_ptr[7] = 0;
-
-        copy_src_regions_mem_buffer.UnmapMemory();
     }
 
     // Update descriptor set
diff --git a/layers/gpuav/validation_cmd/gpuav_draw.cpp b/layers/gpuav/validation_cmd/gpuav_draw.cpp
index cfd4f8fefa0..97803a83fa2 100644
--- a/layers/gpuav/validation_cmd/gpuav_draw.cpp
+++ b/layers/gpuav/validation_cmd/gpuav_draw.cpp
@@ -171,8 +171,6 @@ struct ComputeValidationPipeline {
 };
 
 void FlushValidationCmds(Validator &gpuav, CommandBuffer &cb_state) {
-    VVL_TracyPlot("gpuav::valcmd::FlushValidationCmds", int64_t(cb_state.per_render_pass_validation_commands.size()));
-    VVL_ZoneScoped;
     RestorablePipelineState restorable_state(cb_state, VK_PIPELINE_BIND_POINT_COMPUTE);
 
     for (CommandBuffer::ValidationCommandFunc &validation_cmd : cb_state.per_render_pass_validation_commands) {
diff --git a/layers/profiling/profiling.h b/layers/profiling/profiling.h
index 08262158abd..2484db2eb40 100644
--- a/layers/profiling/profiling.h
+++ b/layers/profiling/profiling.h
@@ -21,6 +21,7 @@
 #include "tracy/Tracy.hpp"
 #include "tracy/TracyC.h"
 #include "tracy/../client/TracyProfiler.hpp"
+#include "common/TracySystem.hpp"
 
 // Define CPU zones
 #define VVL_ZoneScoped ZoneScoped
@@ -29,6 +30,9 @@
 #define VVL_TracyCZoneEnd(zone_name) TracyCZoneEnd(zone_name)
 #define VVL_TracyCFrameMark TracyCFrameMark
 
+// Thread naming
+#define VVL_TracySetThreadName(name) tracy::SetThreadName(name)
+
 // Print messages
 #define VVL_TracyMessage TracyMessage
 #define VVL_TracyMessageL TracyMessageL
@@ -64,6 +68,7 @@
 #define VVL_TracyCZone(zone_name, active)
 #define VVL_TracyCZoneEnd(zone_name)
 #define VVL_TracyCFrameMark
+#define VVL_TracySetThreadName(name)
 #define VVL_TracyMessage
 #define VVL_TracyMessageL
 #define VVL_TracyPlot(name, value)
diff --git a/layers/state_tracker/queue_state.cpp b/layers/state_tracker/queue_state.cpp
index 18806cd36b3..ca568745783 100644
--- a/layers/state_tracker/queue_state.cpp
+++ b/layers/state_tracker/queue_state.cpp
@@ -1,7 +1,7 @@
-/* Copyright (c) 2015-2024 The Khronos Group Inc.
- * Copyright (c) 2015-2024 Valve Corporation
- * Copyright (c) 2015-2024 LunarG, Inc.
- * Copyright (C) 2015-2024 Google Inc.
+/* Copyright (c) 2015-2025 The Khronos Group Inc.
+ * Copyright (c) 2015-2025 Valve Corporation
+ * Copyright (c) 2015-2025 LunarG, Inc.
+ * Copyright (C) 2015-2025 Google Inc.
  * Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +19,8 @@
 #include "state_tracker/queue_state.h"
 #include "state_tracker/cmd_buffer_state.h"
 
+#include "profiling/profiling.h"
+
 void vvl::QueueSubmission::BeginUse() {
     for (SemaphoreInfo &wait : wait_semaphores) {
         wait.semaphore->BeginUse();
@@ -260,6 +262,8 @@ void vvl::Queue::Retire(QueueSubmission &submission) {
 }
 
 void vvl::Queue::ThreadFunc() {
+    VVL_TracySetThreadName(__FUNCTION__);
+
     QueueSubmission *submission = nullptr;
 
     // Roll this queue forward, one submission at a time.


Reviews:
user: login: artem-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T11:04:20Z
user: login: arno-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T11:37:04Z
user: login: spencer-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T13:49:07Z
user: login: spencer-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T13:49:12Z
user: login: spencer-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T13:49:22Z
user: login: spencer-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T13:49:30Z
user: login: spencer-lunarg
body: looks good, waiting for CI and cleanup of trailing tracy debug lines to be removed
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T13:51:50Z
user: login: arno-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T14:29:43Z
user: login: spencer-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T14:31:20Z
user: login: spencer-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T14:32:23Z
user: login: spencer-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T14:34:06Z
user: login: arno-lunarg
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T14:43:38Z
user: login: spencer-lunarg
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-11T14:47:11Z

Review comments:
diff_hunk: @@ -260,6 +262,8 @@ void vvl::Queue::Retire(QueueSubmission &submission) {
 }
 
 void vvl::Queue::ThreadFunc() {
+    VVL_TracySetThreadName(__FUNCTION__);
path: layers/state_tracker/queue_state.cpp
user: login: artem-lunarg
body: Can VVL_TracySetThreadName be used to address https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8446? Is it always available of need some define? What we need to address that issues is some implementation of cross-platform set-thread-name, which is not hard to do at elast for windows+linux, but I saw some ready to use options, so I'm wondering maybe we can use tracy's implementation
created_at: 2025-03-11T11:04:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -260,6 +262,8 @@ void vvl::Queue::Retire(QueueSubmission &submission) {
 }
 
 void vvl::Queue::ThreadFunc() {
+    VVL_TracySetThreadName(__FUNCTION__);
path: layers/state_tracker/queue_state.cpp
user: login: arno-lunarg
body: We could steal the implementation, but not directly use `VVL_TracySetThreadName` or the underlying `tracy::SetThreadName` function since they belong to Tracy
created_at: 2025-03-11T11:37:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -293,24 +294,26 @@ VkDeviceAddress DescriptorSet::GetPostProcessBuffer(Validator &gpuav, const Loca
         return 0;
     }
 
-    void *data = post_process_buffer_.MapMemory(loc);
+    VVL_TracyPlot("Post process buffer size (bytes)", int64_t(buffer_info.size));
+
+    void *data = post_process_buffer_.GetMappedPtr(loc);
     memset(data, 0, static_cast<size_t>(buffer_info.size));
 
     post_process_buffer_.FlushAllocation(loc);
-    post_process_buffer_.UnmapMemory();
 
     return post_process_buffer_.Address();
 }
 
 // cross checks the two buffers (our layout with the output from the GPU-AV run) and builds a map of which indexes in which binding
 // where accessed
 std::vector<DescriptorAccess> DescriptorSet::GetDescriptorAccesses(const Location &loc, uint32_t shader_set) const {
+    VVL_ZoneScoped;
path: layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
user: login: spencer-lunarg
body: remove
created_at: 2025-03-11T13:49:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -293,24 +294,26 @@ VkDeviceAddress DescriptorSet::GetPostProcessBuffer(Validator &gpuav, const Loca
         return 0;
     }
 
-    void *data = post_process_buffer_.MapMemory(loc);
+    VVL_TracyPlot("Post process buffer size (bytes)", int64_t(buffer_info.size));
path: layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
user: login: spencer-lunarg
body: remove
created_at: 2025-03-11T13:49:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,6 +23,8 @@
 #include "gpuav/shaders/gpuav_shaders_constants.h"
 #include "state_tracker/descriptor_sets.h"
 
+#include "profiling/profiling.h"
path: layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
user: login: spencer-lunarg
body: remove
created_at: 2025-03-11T13:49:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -23,6 +23,8 @@
 #include "gpuav/resources/gpuav_shader_resources.h"
 #include "state_tracker/shader_module.h"
 
+#include "profiling/profiling.h"
path: layers/gpuav/descriptor_validation/gpuav_descriptor_validation.cpp
user: login: spencer-lunarg
body: remove
created_at: 2025-03-11T13:49:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -293,24 +294,26 @@ VkDeviceAddress DescriptorSet::GetPostProcessBuffer(Validator &gpuav, const Loca
         return 0;
     }
 
-    void *data = post_process_buffer_.MapMemory(loc);
+    VVL_TracyPlot("Post process buffer size (bytes)", int64_t(buffer_info.size));
+
+    void *data = post_process_buffer_.GetMappedPtr(loc);
     memset(data, 0, static_cast<size_t>(buffer_info.size));
 
     post_process_buffer_.FlushAllocation(loc);
-    post_process_buffer_.UnmapMemory();
 
     return post_process_buffer_.Address();
 }
 
 // cross checks the two buffers (our layout with the output from the GPU-AV run) and builds a map of which indexes in which binding
 // where accessed
 std::vector<DescriptorAccess> DescriptorSet::GetDescriptorAccesses(const Location &loc, uint32_t shader_set) const {
+    VVL_ZoneScoped;
path: layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
user: login: arno-lunarg
body: No for every Tracy comment, we need to keep an eye on those problematic areas. It is not debug stuff, and only turns into code when VVL is compiled with Tracy, so I don't pollute release code
created_at: 2025-03-11T14:29:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -293,24 +294,26 @@ VkDeviceAddress DescriptorSet::GetPostProcessBuffer(Validator &gpuav, const Loca
         return 0;
     }
 
-    void *data = post_process_buffer_.MapMemory(loc);
+    VVL_TracyPlot("Post process buffer size (bytes)", int64_t(buffer_info.size));
+
+    void *data = post_process_buffer_.GetMappedPtr(loc);
     memset(data, 0, static_cast<size_t>(buffer_info.size));
 
     post_process_buffer_.FlushAllocation(loc);
-    post_process_buffer_.UnmapMemory();
 
     return post_process_buffer_.Address();
 }
 
 // cross checks the two buffers (our layout with the output from the GPU-AV run) and builds a map of which indexes in which binding
 // where accessed
 std::vector<DescriptorAccess> DescriptorSet::GetDescriptorAccesses(const Location &loc, uint32_t shader_set) const {
+    VVL_ZoneScoped;
path: layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
user: login: spencer-lunarg
body: sure
created_at: 2025-03-11T14:31:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -293,24 +294,26 @@ VkDeviceAddress DescriptorSet::GetPostProcessBuffer(Validator &gpuav, const Loca
         return 0;
     }
 
-    void *data = post_process_buffer_.MapMemory(loc);
+    VVL_TracyPlot("Post process buffer size (bytes)", int64_t(buffer_info.size));
path: layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
user: login: spencer-lunarg
body: these `VVL_TracyPlot` I rather not keep, we have nothing automatically tracking this... one day when you are done with Post Process no one will remove this and we will have a world where no one knows which `VVL_TracyPlot` to  keep or not
created_at: 2025-03-11T14:32:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -293,24 +294,26 @@ VkDeviceAddress DescriptorSet::GetPostProcessBuffer(Validator &gpuav, const Loca
         return 0;
     }
 
-    void *data = post_process_buffer_.MapMemory(loc);
+    VVL_TracyPlot("Post process buffer size (bytes)", int64_t(buffer_info.size));
path: layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
user: login: spencer-lunarg
body: unless we agree every so often we just go by and clear them all, when do we ever remove them, or is the idea to just leave them anywhere anyone wants?
created_at: 2025-03-11T14:34:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -293,24 +294,26 @@ VkDeviceAddress DescriptorSet::GetPostProcessBuffer(Validator &gpuav, const Loca
         return 0;
     }
 
-    void *data = post_process_buffer_.MapMemory(loc);
+    VVL_TracyPlot("Post process buffer size (bytes)", int64_t(buffer_info.size));
path: layers/gpuav/descriptor_validation/gpuav_descriptor_set.cpp
user: login: arno-lunarg
body: That's a legit worry, and it also applies to the manually placed `VVL_ZoneScoped`. I will remove this one, since we are likely to make changes in that area this plot might soon get obsolete. 
The idea behind keeping a plot would be "is it always useful to know that or just needed for my current work". Always plotting instrumentations counts could be nice, it would help correlate to pipeline compilation times.
created_at: 2025-03-11T14:43:37Z
author_association: CONTRIBUTOR

PR comments:
user: login: ci-tester-lunarg
created_at: 2025-03-11T10:31:51Z
body: CI Vulkan-ValidationLayers build queued with queue ID 392290.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T10:35:01Z
body: CI Vulkan-ValidationLayers build # 19328 running.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T10:42:28Z
body: CI Vulkan-ValidationLayers build queued with queue ID 392307.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T10:45:01Z
body: CI Vulkan-ValidationLayers build # 19329 running.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T11:21:14Z
body: CI Vulkan-ValidationLayers build # 19329 failed.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T11:38:44Z
body: CI Vulkan-ValidationLayers build queued with queue ID 392350.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T11:40:01Z
body: CI Vulkan-ValidationLayers build # 19331 running.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T12:15:54Z
body: CI Vulkan-ValidationLayers build # 19331 passed.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T14:27:40Z
body: CI Vulkan-ValidationLayers build queued with queue ID 392590.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T14:30:01Z
body: CI Vulkan-ValidationLayers build # 19334 running.
author_association: COLLABORATOR
user: login: ci-tester-lunarg
created_at: 2025-03-11T14:59:11Z
body: CI Vulkan-ValidationLayers build # 19334 passed.
author_association: COLLABORATOR