@@ -534,7 +534,7 @@ class VulkanCaptureManager : public ApiCaptureManager
534
534
}
535
535
536
536
void PostProcess_vkQueueBindSparse (
537
- VkResult result, VkQueue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence)
537
+ VkResult result, VkQueue queue , uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence)
538
538
{
539
539
if (IsCaptureModeTrack () && (result == VK_SUCCESS))
540
540
{
@@ -546,6 +546,110 @@ class VulkanCaptureManager : public ApiCaptureManager
546
546
pBindInfo[i].signalSemaphoreCount ,
547
547
pBindInfo[i].pSignalSemaphores );
548
548
}
549
+
550
+ // In default mode, the capture manager uses a shared mutex to capture every API function. As a result,
551
+ // multiple threads may access the sparse resource maps concurrently. Therefore, we use a dedicated mutex
552
+ // for write access to these maps.
553
+ const std::lock_guard<std::mutex> lock (sparse_resource_mutex);
554
+ for (uint32_t bind_info_index = 0 ; bind_info_index < bindInfoCount; bind_info_index++)
555
+ {
556
+ auto & bind_info = pBindInfo[bind_info_index];
557
+
558
+ // TODO: add device group support. In the following handling, we assume that the system only has one
559
+ // physical device or that resourceDeviceIndex and memoryDeviceIndex of VkDeviceGroupBindSparseInfo in
560
+ // the pnext chain are zero.
561
+
562
+ if (bind_info.pBufferBinds != nullptr )
563
+ {
564
+ // The title binds sparse buffers to memory ranges, so we need to track the buffer binding
565
+ // information. The following updates will reflect the latest binding states for all buffers in this
566
+ // vkQueueBindSparse command, covering both fully-resident and partially-resident buffers.
567
+ for (uint32_t buffer_bind_index = 0 ; buffer_bind_index < bind_info.bufferBindCount ;
568
+ buffer_bind_index++)
569
+ {
570
+ auto & buffer_bind = bind_info.pBufferBinds [buffer_bind_index];
571
+ auto sparse_buffer = buffer_bind.buffer ;
572
+ auto wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::BufferWrapper>(sparse_buffer);
573
+
574
+ if (wrapper != nullptr )
575
+ {
576
+ wrapper->sparse_bind_queue = queue;
577
+ for (uint32_t bind_memory_range_index = 0 ; bind_memory_range_index < buffer_bind.bindCount ;
578
+ bind_memory_range_index++)
579
+ {
580
+ auto & bind_memory_range = buffer_bind.pBinds [bind_memory_range_index];
581
+ graphics::UpdateSparseMemoryBindMap (wrapper->sparse_memory_bind_map , bind_memory_range);
582
+ }
583
+ }
584
+ }
585
+ }
586
+
587
+ if (bind_info.pImageOpaqueBinds != nullptr )
588
+ {
589
+ // The title binds sparse images to opaque memory ranges, so we need to track the image binding
590
+ // information. The following handling will update the latest binding states for all images in this
591
+ // vkQueueBindSparse command, which utilizes opaque memory binding. There are two cases covered by
592
+ // the tracking. In the first case, the sparse image exclusively uses opaque memory binding. For
593
+ // this case, the target title treats the binding memory ranges as a linear unified region. This
594
+ // should represent a fully-resident binding because this linear region is entirely opaque, meaning
595
+ // there is no application-visible mapping between texel locations and memory offsets. In another
596
+ // case, the image utilizes subresource sparse memory binding, just binding only its mip tail region
597
+ // to an opaque memory range. For this situation, we use the sparse_opaque_memory_bind_map and
598
+ // sparse_subresource_memory_bind_map of the image wrapper to track the subresource bindings and
599
+ // opaque bindings separately.
600
+ for (uint32_t image_opaque_bind_index = 0 ; image_opaque_bind_index < bind_info.imageOpaqueBindCount ;
601
+ image_opaque_bind_index++)
602
+ {
603
+ auto & image_opaque_bind = bind_info.pImageOpaqueBinds [image_opaque_bind_index];
604
+ auto sparse_image = image_opaque_bind.image ;
605
+ auto wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::ImageWrapper>(sparse_image);
606
+
607
+ if (wrapper != nullptr )
608
+ {
609
+ wrapper->sparse_bind_queue = queue;
610
+
611
+ for (uint32_t bind_memory_range_index = 0 ;
612
+ bind_memory_range_index < image_opaque_bind.bindCount ;
613
+ bind_memory_range_index++)
614
+ {
615
+ auto & bind_memory_range = image_opaque_bind.pBinds [bind_memory_range_index];
616
+ graphics::UpdateSparseMemoryBindMap (wrapper->sparse_opaque_memory_bind_map ,
617
+ bind_memory_range);
618
+ }
619
+ }
620
+ }
621
+ }
622
+
623
+ if (bind_info.pImageBinds != nullptr )
624
+ {
625
+ // The title binds subresources of a sparse image to memory ranges, which requires us to keep track
626
+ // of the sparse image subresource binding information. It's important to note that while the image
627
+ // mainly use subresource sparse memory binding, its mip tail region must be bound to an opaque
628
+ // memory range. Therefore, we use the sparse_opaque_memory_bind_map and
629
+ // sparse_subresource_memory_bind_map of the image wrapper to separately track both the
630
+ // subresource bindings and the opaque bindings.
631
+ for (uint32_t image_bind_index = 0 ; image_bind_index < bind_info.imageBindCount ; image_bind_index++)
632
+ {
633
+ auto & image_bind = bind_info.pImageBinds [image_bind_index];
634
+ auto sparse_image = image_bind.image ;
635
+ auto wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::ImageWrapper>(sparse_image);
636
+
637
+ if (wrapper != nullptr )
638
+ {
639
+ wrapper->sparse_bind_queue = queue;
640
+
641
+ for (uint32_t bind_memory_range_index = 0 ; bind_memory_range_index < image_bind.bindCount ;
642
+ bind_memory_range_index++)
643
+ {
644
+ auto & bind_memory_range = image_bind.pBinds [bind_memory_range_index];
645
+ // TODO: Implement handling for tracking binding information of sparse image
646
+ // subresources.
647
+ GFXRECON_LOG_ERROR_ONCE (" Binding of sparse image blocks is not supported!" );
648
+ }
649
+ }
650
+ }
651
+ }
652
+ }
549
653
}
550
654
}
551
655
@@ -816,6 +920,50 @@ class VulkanCaptureManager : public ApiCaptureManager
816
920
}
817
921
}
818
922
923
+ void PostProcess_vkCreateBuffer (VkResult result,
924
+ VkDevice device,
925
+ const VkBufferCreateInfo* pCreateInfo,
926
+ const VkAllocationCallbacks* pAllocator,
927
+ VkBuffer* pBuffer)
928
+ {
929
+ if (IsCaptureModeTrack () && (result == VK_SUCCESS) && (pCreateInfo != nullptr ))
930
+ {
931
+ assert (state_tracker_ != nullptr );
932
+
933
+ auto buffer_wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::BufferWrapper>(*pBuffer);
934
+
935
+ if (buffer_wrapper->is_sparse_buffer )
936
+ {
937
+ // We will need to set the bind_device for handling sparse buffers. There will be no subsequent
938
+ // vkBindBufferMemory, vkBindBufferMemory2 or vkBindBufferMemory2KHR calls for sparse buffer, so we
939
+ // assign bind_device to the device that created the buffer.
940
+ buffer_wrapper->bind_device = vulkan_wrappers::GetWrapper<vulkan_wrappers::DeviceWrapper>(device);
941
+ }
942
+ }
943
+ }
944
+
945
+ void PostProcess_vkCreateImage (VkResult result,
946
+ VkDevice device,
947
+ const VkImageCreateInfo* pCreateInfo,
948
+ const VkAllocationCallbacks* pAllocator,
949
+ VkImage* pImage)
950
+ {
951
+ if (IsCaptureModeTrack () && (result == VK_SUCCESS) && (pCreateInfo != nullptr ))
952
+ {
953
+ assert (state_tracker_ != nullptr );
954
+
955
+ auto image_wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::ImageWrapper>(*pImage);
956
+
957
+ if (image_wrapper->is_sparse_image )
958
+ {
959
+ // We will need to set the bind_device for handling sparse images. There will be no subsequent
960
+ // vkBindImageMemory, vkBindImageMemory2, or vkBindImageMemory2KHR calls for sparse image, so we assign
961
+ // bind_device to the device that created the image.
962
+ image_wrapper->bind_device = vulkan_wrappers::GetWrapper<vulkan_wrappers::DeviceWrapper>(device);
963
+ }
964
+ }
965
+ }
966
+
819
967
void PostProcess_vkCmdBeginRenderPass (VkCommandBuffer commandBuffer,
820
968
const VkRenderPassBeginInfo* pRenderPassBegin,
821
969
VkSubpassContents)
@@ -1380,6 +1528,7 @@ class VulkanCaptureManager : public ApiCaptureManager
1380
1528
std::unique_ptr<VulkanStateTracker> state_tracker_;
1381
1529
HardwareBufferMap hardware_buffers_;
1382
1530
std::mutex deferred_operation_mutex;
1531
+ std::mutex sparse_resource_mutex;
1383
1532
};
1384
1533
1385
1534
GFXRECON_END_NAMESPACE (encode)
0 commit comments