diff --git a/src/d3d11/d3d11_context_imm.cpp b/src/d3d11/d3d11_context_imm.cpp
index 15005f40f..dc95a1af5 100644
--- a/src/d3d11/d3d11_context_imm.cpp
+++ b/src/d3d11/d3d11_context_imm.cpp
@@ -1126,7 +1126,7 @@ namespace dxvk {
     ] (DxvkContext* ctx) {
       ctx->signal(cSubmissionFence, cSubmissionId);
       ctx->signal(cStagingFence, cStagingMemory);
-      ctx->flushCommandList(cSubmissionStatus);
+      ctx->flushCommandList(nullptr, cSubmissionStatus);
     });
 
     FlushCsChunk();
diff --git a/src/d3d11/d3d11_initializer.cpp b/src/d3d11/d3d11_initializer.cpp
index 585705f75..60e6fda5f 100644
--- a/src/d3d11/d3d11_initializer.cpp
+++ b/src/d3d11/d3d11_initializer.cpp
@@ -337,7 +337,7 @@ namespace dxvk {
       cSignalValue  = stats.allocatedTotal
     ] (DxvkContext* ctx) {
       ctx->signal(cSignal, cSignalValue);
-      ctx->flushCommandList(nullptr);
+      ctx->flushCommandList(nullptr, nullptr);
     });
 
     FlushCsChunk();
diff --git a/src/d3d11/d3d11_swapchain.cpp b/src/d3d11/d3d11_swapchain.cpp
index a2d356067..0b533c93e 100644
--- a/src/d3d11/d3d11_swapchain.cpp
+++ b/src/d3d11/d3d11_swapchain.cpp
@@ -445,7 +445,7 @@ namespace dxvk {
 
       // Submit current command list and present
       ctx->synchronizeWsi(cSync);
-      ctx->flushCommandList(nullptr);
+      ctx->flushCommandList(nullptr, nullptr);
 
       cDevice->presentImage(cPresenter, cLatency, cFrameId, nullptr);
     });
diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp
index 51e190405..aadb94be1 100644
--- a/src/d3d9/d3d9_device.cpp
+++ b/src/d3d9/d3d9_device.cpp
@@ -6102,7 +6102,7 @@ namespace dxvk {
     ] (DxvkContext* ctx) {
       ctx->signal(cSubmissionFence, cSubmissionId);
       ctx->signal(cStagingBufferFence, cStagingBufferAllocated);
-      ctx->flushCommandList(cSubmissionStatus);
+      ctx->flushCommandList(nullptr, cSubmissionStatus);
     });
 
     FlushCsChunk();
diff --git a/src/d3d9/d3d9_initializer.cpp b/src/d3d9/d3d9_initializer.cpp
index d2e9f37ea..26bb0c0fc 100644
--- a/src/d3d9/d3d9_initializer.cpp
+++ b/src/d3d9/d3d9_initializer.cpp
@@ -162,7 +162,7 @@ namespace dxvk {
 
   void D3D9Initializer::ExecuteFlushLocked() {
     EmitCs([] (DxvkContext* ctx) {
-      ctx->flushCommandList(nullptr);
+      ctx->flushCommandList(nullptr, nullptr);
     });
 
     FlushCsChunk();
diff --git a/src/d3d9/d3d9_swapchain.cpp b/src/d3d9/d3d9_swapchain.cpp
index 84236b36c..8f97079be 100644
--- a/src/d3d9/d3d9_swapchain.cpp
+++ b/src/d3d9/d3d9_swapchain.cpp
@@ -892,7 +892,7 @@ namespace dxvk {
 
         // Submit command list and present
         ctx->synchronizeWsi(cSync);
-        ctx->flushCommandList(nullptr);
+        ctx->flushCommandList(nullptr, nullptr);
 
         uint64_t frameId = cRepeat ? 0 : cFrameId;
 
diff --git a/src/dxvk/dxvk_buffer.h b/src/dxvk/dxvk_buffer.h
index 4ea76fca6..805cfa76e 100644
--- a/src/dxvk/dxvk_buffer.h
+++ b/src/dxvk/dxvk_buffer.h
@@ -418,6 +418,14 @@ namespace dxvk {
      */
     void setDebugName(const char* name);
 
+    /**
+     * \brief Retrieves debug name
+     * \returns Debug name
+     */
+    const char* getDebugName() const {
+      return m_debugName.c_str();
+    }
+
   private:
 
     Rc<vk::DeviceFn>            m_vkd;
@@ -684,4 +692,4 @@ namespace dxvk {
     m_buffer->decRef();
   }
 
-}
\ No newline at end of file
+}
diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp
index a05bacc32..c05b5c281 100644
--- a/src/dxvk/dxvk_context.cpp
+++ b/src/dxvk/dxvk_context.cpp
@@ -76,7 +76,8 @@ namespace dxvk {
   }
   
   
-  Rc<DxvkCommandList> DxvkContext::endRecording() {
+  Rc<DxvkCommandList> DxvkContext::endRecording(
+    const VkDebugUtilsLabelEXT*       reason) {
     this->endCurrentCommands();
     this->relocateQueuedResources();
 
@@ -85,6 +86,12 @@ namespace dxvk {
       m_descriptorPool = m_descriptorManager->getDescriptorPool();
     }
 
+    if (unlikely(m_features.test(DxvkContextFeature::DebugUtils))) {
+      // Make sure to emit the submission reason always at the very end
+      if (reason && reason->pLabelName && reason->pLabelName[0])
+        m_cmd->cmdInsertDebugUtilsLabel(DxvkCmdBuffer::ExecBuffer, *reason);
+    }
+
     m_cmd->finalize();
     return std::exchange(m_cmd, nullptr);
   }
@@ -121,13 +128,15 @@ namespace dxvk {
   }
 
 
-  void DxvkContext::flushCommandList(DxvkSubmitStatus* status) {
+  void DxvkContext::flushCommandList(
+    const VkDebugUtilsLabelEXT*       reason,
+          DxvkSubmitStatus*           status) {
     // Need to call this before submitting so that the last GPU
     // submission does not happen before the render end signal.
     if (m_endLatencyTracking && m_latencyTracker)
       m_latencyTracker->notifyCsRenderEnd(m_latencyFrameId);
 
-    m_device->submitCommandList(this->endRecording(),
+    m_device->submitCommandList(this->endRecording(reason),
       m_latencyTracker, m_latencyFrameId, status);
 
     // Ensure that subsequent submissions do not see the tracker.
diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h
index b32a12b50..ce6005b42 100644
--- a/src/dxvk/dxvk_context.h
+++ b/src/dxvk/dxvk_context.h
@@ -59,9 +59,11 @@ namespace dxvk {
      * 
      * This will not change any context state
      * other than the active command list.
+     * \param [in] reason Optional debug label describing the reason
      * \returns Active command list
      */
-    Rc<DxvkCommandList> endRecording();
+    Rc<DxvkCommandList> endRecording(
+      const VkDebugUtilsLabelEXT*       reason);
 
     /**
      * \brief Ends frame
@@ -100,9 +102,12 @@ namespace dxvk {
      * 
      * Transparently submits the current command
      * buffer and allocates a new one.
+     * \param [in] reason Optional debug label describing the reason
      * \param [out] status Submission feedback
      */
-    void flushCommandList(DxvkSubmitStatus* status);
+    void flushCommandList(
+      const VkDebugUtilsLabelEXT*       reason,
+            DxvkSubmitStatus*           status);
 
     /**
      * \brief Synchronizes command list with WSI
diff --git a/src/dxvk/dxvk_image.h b/src/dxvk/dxvk_image.h
index 9a19bfddd..1bd2730ac 100644
--- a/src/dxvk/dxvk_image.h
+++ b/src/dxvk/dxvk_image.h
@@ -616,6 +616,14 @@ namespace dxvk {
      */
     void setDebugName(const char* name);
 
+    /**
+     * \brief Retrieves debug name
+     * \returns Debug name
+     */
+    const char* getDebugName() const {
+      return m_debugName.c_str();
+    }
+
   private:
 
     Rc<vk::DeviceFn>            m_vkd;
diff --git a/src/dxvk/dxvk_sparse.h b/src/dxvk/dxvk_sparse.h
index d6e71ca17..e9f6f919f 100644
--- a/src/dxvk/dxvk_sparse.h
+++ b/src/dxvk/dxvk_sparse.h
@@ -637,6 +637,14 @@ namespace dxvk {
      */
     virtual void setDebugName(const char* name) = 0;
 
+    /**
+     * \brief Retrieves debug name
+     *
+     * May return an empty string if debug support is disabled.
+     * \returns The resource debug name
+     */
+    virtual const char* getDebugName() const = 0;
+
   private:
 
     std::atomic<uint64_t> m_useCount = { 0u };