-
Notifications
You must be signed in to change notification settings - Fork 124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add sparse image and buffer support #1877
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -534,7 +534,7 @@ class VulkanCaptureManager : public ApiCaptureManager | |
} | ||
|
||
void PostProcess_vkQueueBindSparse( | ||
VkResult result, VkQueue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence) | ||
VkResult result, VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence) | ||
{ | ||
if (IsCaptureModeTrack() && (result == VK_SUCCESS)) | ||
{ | ||
|
@@ -546,6 +546,110 @@ class VulkanCaptureManager : public ApiCaptureManager | |
pBindInfo[i].signalSemaphoreCount, | ||
pBindInfo[i].pSignalSemaphores); | ||
} | ||
|
||
// In default mode, the capture manager uses a shared mutex to capture every API function. As a result, | ||
// multiple threads may access the sparse resource maps concurrently. Therefore, we use a dedicated mutex | ||
// for write access to these maps. | ||
const std::lock_guard<std::mutex> lock(sparse_resource_mutex); | ||
for (uint32_t bind_info_index = 0; bind_info_index < bindInfoCount; bind_info_index++) | ||
{ | ||
auto& bind_info = pBindInfo[bind_info_index]; | ||
|
||
// TODO: add device group support. In the following handling, we assume that the system only has one | ||
// physical device or that resourceDeviceIndex and memoryDeviceIndex of VkDeviceGroupBindSparseInfo in | ||
// the pnext chain are zero. | ||
|
||
if (bind_info.pBufferBinds != nullptr) | ||
{ | ||
// The title binds sparse buffers to memory ranges, so we need to track the buffer binding | ||
// information. The following updates will reflect the latest binding states for all buffers in this | ||
// vkQueueBindSparse command, covering both fully-resident and partially-resident buffers. | ||
for (uint32_t buffer_bind_index = 0; buffer_bind_index < bind_info.bufferBindCount; | ||
buffer_bind_index++) | ||
{ | ||
auto& buffer_bind = bind_info.pBufferBinds[buffer_bind_index]; | ||
auto sparse_buffer = buffer_bind.buffer; | ||
auto wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::BufferWrapper>(sparse_buffer); | ||
|
||
if (wrapper != nullptr) | ||
{ | ||
wrapper->sparse_bind_queue = queue; | ||
for (uint32_t bind_memory_range_index = 0; bind_memory_range_index < buffer_bind.bindCount; | ||
bind_memory_range_index++) | ||
{ | ||
auto& bind_memory_range = buffer_bind.pBinds[bind_memory_range_index]; | ||
graphics::UpdateSparseMemoryBindMap(wrapper->sparse_memory_bind_map, bind_memory_range); | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (bind_info.pImageOpaqueBinds != nullptr) | ||
{ | ||
// The title binds sparse images to opaque memory ranges, so we need to track the image binding | ||
// information. The following handling will update the latest binding states for all images in this | ||
// vkQueueBindSparse command, which utilizes opaque memory binding. There are two cases covered by | ||
// the tracking. In the first case, the sparse image exclusively uses opaque memory binding. For | ||
// this case, the target title treats the binding memory ranges as a linear unified region. This | ||
// should represent a fully-resident binding because this linear region is entirely opaque, meaning | ||
// there is no application-visible mapping between texel locations and memory offsets. In another | ||
// case, the image utilizes subresource sparse memory binding, just binding only its mip tail region | ||
// to an opaque memory range. For this situation, we use the sparse_opaque_memory_bind_map and | ||
// sparse_subresource_memory_bind_map of the image wrapper to track the subresource bindings and | ||
// opaque bindings separately. | ||
for (uint32_t image_opaque_bind_index = 0; image_opaque_bind_index < bind_info.imageOpaqueBindCount; | ||
image_opaque_bind_index++) | ||
{ | ||
auto& image_opaque_bind = bind_info.pImageOpaqueBinds[image_opaque_bind_index]; | ||
auto sparse_image = image_opaque_bind.image; | ||
auto wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::ImageWrapper>(sparse_image); | ||
|
||
if (wrapper != nullptr) | ||
{ | ||
wrapper->sparse_bind_queue = queue; | ||
|
||
for (uint32_t bind_memory_range_index = 0; | ||
bind_memory_range_index < image_opaque_bind.bindCount; | ||
bind_memory_range_index++) | ||
{ | ||
auto& bind_memory_range = image_opaque_bind.pBinds[bind_memory_range_index]; | ||
graphics::UpdateSparseMemoryBindMap(wrapper->sparse_opaque_memory_bind_map, | ||
bind_memory_range); | ||
} | ||
} | ||
} | ||
} | ||
|
||
if (bind_info.pImageBinds != nullptr) | ||
{ | ||
// The title binds subresources of a sparse image to memory ranges, which requires us to keep track | ||
// of the sparse image subresource binding information. It's important to note that while the image | ||
// mainly use subresource sparse memory binding, its mip tail region must be bound to an opaque | ||
// memory range. Therefore, we use the sparse_opaque_memory_bind_map and | ||
// sparse_subresource_memory_bind_map of the image wrapper to separately track both the | ||
// subresource bindings and the opaque bindings. | ||
for (uint32_t image_bind_index = 0; image_bind_index < bind_info.imageBindCount; image_bind_index++) | ||
{ | ||
auto& image_bind = bind_info.pImageBinds[image_bind_index]; | ||
auto sparse_image = image_bind.image; | ||
auto wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::ImageWrapper>(sparse_image); | ||
|
||
if (wrapper != nullptr) | ||
{ | ||
wrapper->sparse_bind_queue = queue; | ||
|
||
for (uint32_t bind_memory_range_index = 0; bind_memory_range_index < image_bind.bindCount; | ||
bind_memory_range_index++) | ||
{ | ||
auto& bind_memory_range = image_bind.pBinds[bind_memory_range_index]; | ||
// TODO: Implement handling for tracking binding information of sparse image | ||
// subresources. | ||
GFXRECON_LOG_ERROR_ONCE("Binding of sparse image blocks is not supported!"); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
@@ -816,6 +920,50 @@ class VulkanCaptureManager : public ApiCaptureManager | |
} | ||
} | ||
|
||
void PostProcess_vkCreateBuffer(VkResult result, | ||
VkDevice device, | ||
const VkBufferCreateInfo* pCreateInfo, | ||
const VkAllocationCallbacks* pAllocator, | ||
VkBuffer* pBuffer) | ||
{ | ||
if (IsCaptureModeTrack() && (result == VK_SUCCESS) && (pCreateInfo != nullptr)) | ||
{ | ||
assert(state_tracker_ != nullptr); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
auto buffer_wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::BufferWrapper>(*pBuffer); | ||
|
||
if (buffer_wrapper->is_sparse_buffer) | ||
{ | ||
// We will need to set the bind_device for handling sparse buffers. There will be no subsequent | ||
// vkBindBufferMemory, vkBindBufferMemory2 or vkBindBufferMemory2KHR calls for sparse buffer, so we | ||
// assign bind_device to the device that created the buffer. | ||
buffer_wrapper->bind_device = vulkan_wrappers::GetWrapper<vulkan_wrappers::DeviceWrapper>(device); | ||
} | ||
} | ||
} | ||
|
||
void PostProcess_vkCreateImage(VkResult result, | ||
VkDevice device, | ||
const VkImageCreateInfo* pCreateInfo, | ||
const VkAllocationCallbacks* pAllocator, | ||
VkImage* pImage) | ||
{ | ||
if (IsCaptureModeTrack() && (result == VK_SUCCESS) && (pCreateInfo != nullptr)) | ||
{ | ||
assert(state_tracker_ != nullptr); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||
|
||
auto image_wrapper = vulkan_wrappers::GetWrapper<vulkan_wrappers::ImageWrapper>(*pImage); | ||
|
||
if (image_wrapper->is_sparse_image) | ||
{ | ||
// We will need to set the bind_device for handling sparse images. There will be no subsequent | ||
// vkBindImageMemory, vkBindImageMemory2, or vkBindImageMemory2KHR calls for sparse image, so we assign | ||
// bind_device to the device that created the image. | ||
image_wrapper->bind_device = vulkan_wrappers::GetWrapper<vulkan_wrappers::DeviceWrapper>(device); | ||
} | ||
} | ||
} | ||
|
||
void PostProcess_vkCmdBeginRenderPass(VkCommandBuffer commandBuffer, | ||
const VkRenderPassBeginInfo* pRenderPassBegin, | ||
VkSubpassContents) | ||
|
@@ -1380,6 +1528,7 @@ class VulkanCaptureManager : public ApiCaptureManager | |
std::unique_ptr<VulkanStateTracker> state_tracker_; | ||
HardwareBufferMap hardware_buffers_; | ||
std::mutex deferred_operation_mutex; | ||
std::mutex sparse_resource_mutex; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about moving the comment in
|
||
}; | ||
|
||
GFXRECON_END_NAMESPACE(encode) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want snake case here?