venus: Enable VK_KHR_synchronization2

Signed-off-by: Chad Versace <chadversary@chromium.org>
Reviewed-by: Yiwei Zhang <zzyiwei@chromium.org>
Reviewed-by: Ryan Neph <ryanneph@google.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/19046>
This commit is contained in:
Chad Versace
2022-10-11 19:01:13 -07:00
parent 58eb3ac666
commit 85a6a2461d
5 changed files with 475 additions and 2 deletions
+219
View File
@@ -41,6 +41,24 @@ vn_image_memory_barrier_has_present_src(
return false;
}
static bool
vn_dependency_info_has_present_src(uint32_t dep_count,
const VkDependencyInfo *dep_infos)
{
for (uint32_t i = 0; i < dep_count; i++) {
for (uint32_t j = 0; j < dep_infos[i].imageMemoryBarrierCount; j++) {
const VkImageMemoryBarrier2 *b =
&dep_infos[i].pImageMemoryBarriers[j];
if (b->oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ||
b->newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
return true;
}
}
}
return false;
}
static void *
vn_cmd_get_tmp_data(struct vn_command_buffer *cmd, size_t size)
{
@@ -207,6 +225,79 @@ vn_cmd_fix_image_memory_barrier(const struct vn_command_buffer *cmd,
}
}
/** See vn_cmd_fix_image_memory_barrier(). */
static void
vn_cmd_fix_image_memory_barrier2(const struct vn_command_buffer *cmd,
VkImageMemoryBarrier2 *b)
{
if (VN_PRESENT_SRC_INTERNAL_LAYOUT == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
return;
if (b->oldLayout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR &&
b->newLayout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
return;
const struct vn_image *img = vn_image_from_handle(b->image);
assert(img->wsi.is_wsi);
if (img->wsi.is_prime_blit_src || b->oldLayout == b->newLayout) {
if (b->oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
b->oldLayout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
if (b->newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
b->newLayout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
return;
}
if (b->oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
b->oldLayout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
/* no availability operation needed */
b->srcStageMask = 0;
b->srcAccessMask = 0;
if (img->sharing_mode == VK_SHARING_MODE_CONCURRENT) {
b->srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT;
b->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
} else if (b->dstQueueFamilyIndex == b->srcQueueFamilyIndex ||
b->dstQueueFamilyIndex == cmd->queue_family_index) {
b->srcQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT;
b->dstQueueFamilyIndex = cmd->queue_family_index;
} else {
/* The barrier also defines a queue family ownership transfer, and
* this is the one that gets submitted to the source queue family to
* release the ownership. Skip both the transfer and the transition.
*/
b->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
b->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
b->newLayout = b->oldLayout;
}
} else {
b->newLayout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
/* no visibility operation needed */
b->dstStageMask = 0;
b->dstAccessMask = 0;
if (img->sharing_mode == VK_SHARING_MODE_CONCURRENT) {
b->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
b->dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT;
} else if (b->srcQueueFamilyIndex == b->dstQueueFamilyIndex ||
b->srcQueueFamilyIndex == cmd->queue_family_index) {
b->srcQueueFamilyIndex = cmd->queue_family_index;
b->dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT;
} else {
/* The barrier also defines a queue family ownership transfer, and
* this is the one that gets submitted to the destination queue
* family to acquire the ownership. Skip both the transfer and the
* transition.
*/
b->srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
b->dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
b->oldLayout = b->newLayout;
}
}
}
static const VkImageMemoryBarrier *
vn_cmd_wait_events_fix_image_memory_barriers(
struct vn_command_buffer *cmd,
@@ -288,6 +379,49 @@ vn_cmd_pipeline_barrier_fix_image_memory_barriers(
return img_barriers;
}
static const VkDependencyInfo *
vn_cmd_fix_dependency_infos(struct vn_command_buffer *cmd,
uint32_t dep_count,
const VkDependencyInfo *dep_infos)
{
if (cmd->builder.render_pass ||
!vn_dependency_info_has_present_src(dep_count, dep_infos))
return dep_infos;
uint32_t total_barrier_count = 0;
for (uint32_t i = 0; i < dep_count; i++)
total_barrier_count += dep_infos[i].imageMemoryBarrierCount;
size_t tmp_size = dep_count * sizeof(VkDependencyInfo) +
total_barrier_count * sizeof(VkImageMemoryBarrier2);
void *tmp = vn_cmd_get_tmp_data(cmd, tmp_size);
if (!tmp) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return dep_infos;
}
VkDependencyInfo *new_dep_infos = tmp;
tmp += dep_count * sizeof(VkDependencyInfo);
memcpy(new_dep_infos, dep_infos, dep_count * sizeof(VkDependencyInfo));
for (uint32_t i = 0; i < dep_count; i++) {
uint32_t barrier_count = dep_infos[i].imageMemoryBarrierCount;
VkImageMemoryBarrier2 *new_barriers = tmp;
tmp += barrier_count * sizeof(VkImageMemoryBarrier2);
memcpy(new_barriers, dep_infos[i].pImageMemoryBarriers,
barrier_count * sizeof(VkImageMemoryBarrier2));
new_dep_infos[i].pImageMemoryBarriers = new_barriers;
for (uint32_t j = 0; j < barrier_count; j++) {
vn_cmd_fix_image_memory_barrier2(cmd, &new_barriers[j]);
}
}
return new_dep_infos;
}
static void
vn_cmd_encode_memory_barriers(struct vn_command_buffer *cmd,
VkPipelineStageFlags src_stage_mask,
@@ -1312,6 +1446,43 @@ vn_CmdSetEvent(VkCommandBuffer commandBuffer,
VK_EVENT_SET);
}
static VkPipelineStageFlags2
vn_dependency_info_collect_src_stage_mask(const VkDependencyInfo *dep_info)
{
VkPipelineStageFlags2 mask = 0;
for (uint32_t i = 0; i < dep_info->memoryBarrierCount; i++)
mask |= dep_info->pMemoryBarriers[i].srcStageMask;
for (uint32_t i = 0; i < dep_info->bufferMemoryBarrierCount; i++)
mask |= dep_info->pBufferMemoryBarriers[i].srcStageMask;
for (uint32_t i = 0; i < dep_info->imageMemoryBarrierCount; i++)
mask |= dep_info->pImageMemoryBarriers[i].srcStageMask;
return mask;
}
void
vn_CmdSetEvent2(VkCommandBuffer commandBuffer,
VkEvent event,
const VkDependencyInfo *pDependencyInfo)
{
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
pDependencyInfo = vn_cmd_fix_dependency_infos(cmd, 1, pDependencyInfo);
VN_CMD_ENQUEUE(vkCmdSetEvent2, commandBuffer, event, pDependencyInfo);
VkPipelineStageFlags2 src_stage_mask =
vn_dependency_info_collect_src_stage_mask(pDependencyInfo);
vn_feedback_event_cmd_record2(commandBuffer, event, src_stage_mask,
VK_EVENT_SET);
}
void
vn_CmdResetEvent(VkCommandBuffer commandBuffer,
VkEvent event,
@@ -1323,6 +1494,16 @@ vn_CmdResetEvent(VkCommandBuffer commandBuffer,
VK_EVENT_RESET);
}
void
vn_CmdResetEvent2(VkCommandBuffer commandBuffer,
VkEvent event,
VkPipelineStageFlags2 stageMask)
{
VN_CMD_ENQUEUE(vkCmdResetEvent2, commandBuffer, event, stageMask);
vn_feedback_event_cmd_record2(commandBuffer, event, stageMask,
VK_EVENT_RESET);
}
void
vn_CmdWaitEvents(VkCommandBuffer commandBuffer,
uint32_t eventCount,
@@ -1357,6 +1538,22 @@ vn_CmdWaitEvents(VkCommandBuffer commandBuffer,
}
}
void
vn_CmdWaitEvents2(VkCommandBuffer commandBuffer,
uint32_t eventCount,
const VkEvent *pEvents,
const VkDependencyInfo *pDependencyInfos)
{
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
pDependencyInfos =
vn_cmd_fix_dependency_infos(cmd, eventCount, pDependencyInfos);
VN_CMD_ENQUEUE(vkCmdWaitEvents2, commandBuffer, eventCount, pEvents,
pDependencyInfos);
}
void
vn_CmdPipelineBarrier(VkCommandBuffer commandBuffer,
VkPipelineStageFlags srcStageMask,
@@ -1382,6 +1579,18 @@ vn_CmdPipelineBarrier(VkCommandBuffer commandBuffer,
pImageMemoryBarriers);
}
void
vn_CmdPipelineBarrier2(VkCommandBuffer commandBuffer,
const VkDependencyInfo *pDependencyInfo)
{
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
pDependencyInfo = vn_cmd_fix_dependency_infos(cmd, 1, pDependencyInfo);
VN_CMD_ENQUEUE(vkCmdPipelineBarrier2, commandBuffer, pDependencyInfo);
}
void
vn_CmdBeginQuery(VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
@@ -1419,6 +1628,16 @@ vn_CmdWriteTimestamp(VkCommandBuffer commandBuffer,
queryPool, query);
}
void
vn_CmdWriteTimestamp2(VkCommandBuffer commandBuffer,
VkPipelineStageFlagBits2 stage,
VkQueryPool queryPool,
uint32_t query)
{
VN_CMD_ENQUEUE(vkCmdWriteTimestamp2, commandBuffer, stage, queryPool,
query);
}
void
vn_CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
+66
View File
@@ -264,6 +264,7 @@ vn_feedback_pool_free(struct vn_feedback_pool *pool,
simple_mtx_unlock(&pool->mutex);
}
/** See also vn_feedback_event_cmd_record2(). */
void
vn_feedback_event_cmd_record(VkCommandBuffer cmd_handle,
VkEvent ev_handle,
@@ -322,6 +323,71 @@ vn_feedback_event_cmd_record(VkCommandBuffer cmd_handle,
&buf_barrier_after, 0, NULL);
}
/** See also vn_feedback_event_cmd_record(). */
void
vn_feedback_event_cmd_record2(VkCommandBuffer cmd_h,
VkEvent event_h,
VkPipelineStageFlags2 src_stage_mask,
VkResult status)
{
struct vn_event *event = vn_event_from_handle(event_h);
struct vn_feedback_slot *slot = event->feedback_slot;
if (!slot)
return;
STATIC_ASSERT(sizeof(*slot->status) == 4);
const VkDependencyInfo dep_before = {
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
.dependencyFlags = 0,
.bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers =
(VkBufferMemoryBarrier2[]){
{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
.srcStageMask = src_stage_mask | VK_PIPELINE_STAGE_HOST_BIT |
VK_PIPELINE_STAGE_TRANSFER_BIT,
.srcAccessMask =
VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = slot->buffer,
.offset = slot->offset,
.size = 4,
},
},
};
const VkDependencyInfo dep_after = {
.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO,
.dependencyFlags = 0,
.bufferMemoryBarrierCount = 1,
.pBufferMemoryBarriers =
(VkBufferMemoryBarrier2[]){
{
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER_2,
.srcStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.dstStageMask = VK_PIPELINE_STAGE_HOST_BIT,
.dstAccessMask =
VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.buffer = slot->buffer,
.offset = slot->offset,
.size = 4,
},
},
};
vn_CmdPipelineBarrier2(cmd_h, &dep_before);
vn_CmdFillBuffer(cmd_h, slot->buffer, slot->offset, 4, status);
vn_CmdPipelineBarrier2(cmd_h, &dep_after);
}
static VkResult
vn_feedback_fence_cmd_record(VkCommandBuffer cmd_handle,
struct vn_feedback_slot *slot)
+6
View File
@@ -113,6 +113,12 @@ vn_feedback_event_cmd_record(VkCommandBuffer cmd_handle,
VkPipelineStageFlags stage_mask,
VkResult status);
void
vn_feedback_event_cmd_record2(VkCommandBuffer cmd_handle,
VkEvent event,
VkPipelineStageFlags2 src_stage_mask,
VkResult status);
VkResult
vn_feedback_fence_cmd_alloc(VkDevice dev_handle,
struct vn_feedback_cmd_pool *pool,
+19 -2
View File
@@ -116,6 +116,7 @@ vn_physical_device_init_features(struct vn_physical_device *physical_dev)
shader_integer_dot_product;
VkPhysicalDeviceShaderTerminateInvocationFeatures
shader_terminate_invocation;
VkPhysicalDeviceSynchronization2Features synchronization2;
VkPhysicalDeviceSubgroupSizeControlFeatures subgroup_size_control;
VkPhysicalDeviceTextureCompressionASTCHDRFeatures
texture_compression_astc_hdr;
@@ -172,6 +173,7 @@ vn_physical_device_init_features(struct vn_physical_device *physical_dev)
VN_ADD_EXT_TO_PNEXT_OF(features2, SHADER_INTEGER_DOT_PRODUCT_FEATURES, local_feats.shader_integer_dot_product, KHR_shader_integer_dot_product);
VN_ADD_EXT_TO_PNEXT_OF(features2, SHADER_TERMINATE_INVOCATION_FEATURES, local_feats.shader_terminate_invocation, KHR_shader_terminate_invocation);
VN_ADD_EXT_TO_PNEXT_OF(features2, SUBGROUP_SIZE_CONTROL_FEATURES, local_feats.subgroup_size_control, EXT_subgroup_size_control);
VN_ADD_EXT_TO_PNEXT_OF(features2, SYNCHRONIZATION_2_FEATURES, local_feats.synchronization2, KHR_synchronization2);
VN_ADD_EXT_TO_PNEXT_OF(features2, TEXTURE_COMPRESSION_ASTC_HDR_FEATURES, local_feats.texture_compression_astc_hdr, EXT_texture_compression_astc_hdr);
VN_ADD_EXT_TO_PNEXT_OF(features2, ZERO_INITIALIZE_WORKGROUP_MEMORY_FEATURES, local_feats.zero_initialize_workgroup_memory, KHR_zero_initialize_workgroup_memory);
}
@@ -371,8 +373,9 @@ vn_physical_device_init_features(struct vn_physical_device *physical_dev)
VN_SET_CORE_FIELD(vk13_feats, subgroupSizeControl, local_feats.subgroup_size_control);
VN_SET_CORE_FIELD(vk13_feats, computeFullSubgroups, local_feats.subgroup_size_control);
}
/* TODO(VK_KHR_synchronization2): Support extension */
VN_SET_CORE_VALUE(vk13_feats, synchronization2, false);
if (exts->KHR_synchronization2) {
VN_SET_CORE_FIELD(vk13_feats, synchronization2, local_feats.synchronization2);
}
if (exts->EXT_texture_compression_astc_hdr) {
VN_SET_CORE_FIELD(vk13_feats, textureCompressionASTC_HDR, local_feats.texture_compression_astc_hdr);
}
@@ -933,6 +936,19 @@ vn_physical_device_init_external_semaphore_handles(
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
}
#endif
if (!(physical_dev->renderer_sync_fd_semaphore_features &
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT)) {
/* Disable VK_KHR_synchronization2, because
* out implementation requires semaphore sync fd import.
*/
physical_dev->base.base.supported_extensions.KHR_synchronization2 =
false;
/* Clamp to 1.2 because 1.3 requires VK_KHR_synchronization2. */
physical_dev->properties.vulkan_1_0.apiVersion = MIN2(
VK_API_VERSION_1_2, physical_dev->properties.vulkan_1_0.apiVersion);
}
}
static void
@@ -1044,6 +1060,7 @@ vn_physical_device_get_passthrough_extensions(
.KHR_shader_integer_dot_product = true,
.KHR_shader_non_semantic_info = true,
.KHR_shader_terminate_invocation = true,
.KHR_synchronization2 = true,
.KHR_zero_initialize_workgroup_memory = true,
.EXT_4444_formats = true,
.EXT_extended_dynamic_state = true,
+165
View File
@@ -525,6 +525,171 @@ vn_QueueSubmit(VkQueue queue_h,
return VK_SUCCESS;
}
static bool ATTRIBUTE_PURE
vn_submit_info2_has_external_signal_semaphore(uint32_t submit_count,
const VkSubmitInfo2 *submits)
{
for (uint32_t i = 0; i < submit_count; i++) {
const VkSubmitInfo2 *submit = submits + i;
for (uint32_t j = 0; j < submit->signalSemaphoreInfoCount; j++) {
VkSemaphore sem_h = submit->pSignalSemaphoreInfos[j].semaphore;
struct vn_semaphore *sem = vn_semaphore_from_handle(sem_h);
if (sem->is_external)
return true;
}
}
return false;
}
static VkResult
vn_queue_submit2_import_semaphores(struct vn_device *dev, uint32_t submit_count, const VkSubmitInfo2 *submits)
{
struct vn_instance *instance = dev->instance;
VkDevice dev_h = vn_device_to_handle(dev);
assert(dev->physical_device->renderer_sync_fd_semaphore_features &
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
for (uint32_t i = 0; i < submit_count; i++) {
const VkSubmitInfo2 *submit = submits + i;
for (uint32_t j = 0; j < submit->waitSemaphoreInfoCount; j++) {
VkSemaphore sem_h = submit->pWaitSemaphoreInfos[j].semaphore;
struct vn_semaphore *sem = vn_semaphore_from_handle(sem_h);
if (sem->payload->type != VN_SYNC_TYPE_IMPORTED_SYNC_FD)
continue;
if (!vn_semaphore_wait_external(dev, sem))
return VK_ERROR_DEVICE_LOST;
const VkImportSemaphoreResourceInfo100000MESA res_info = {
.sType =
VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_RESOURCE_INFO_100000_MESA,
.semaphore = sem_h,
.resourceId = 0,
};
vn_async_vkImportSemaphoreResource100000MESA(instance, dev_h, &res_info);
}
}
return VK_SUCCESS;
}
static VkResult
vn_queue_submit2_low(VkQueue queue_h,
uint32_t submit_count,
const VkSubmitInfo2 *submits,
VkFence fence_h,
bool sync)
{
struct vn_queue *queue = vn_queue_from_handle(queue_h);
struct vn_instance *instance = queue->device->instance;
if (!submit_count && !fence_h)
return VK_SUCCESS;
if (sync || VN_PERF(NO_ASYNC_QUEUE_SUBMIT))
return vn_call_vkQueueSubmit2(instance, queue_h, submit_count, submits,
fence_h);
vn_async_vkQueueSubmit2(instance, queue_h, submit_count, submits, fence_h);
return VK_SUCCESS;
}
static VkResult
vn_queue_submit2_feedback_fence(struct vn_queue *queue,
struct vn_fence *fence,
bool sync)
{
VkQueue queue_h = vn_queue_to_handle(queue);
VkFence fence_h = vn_fence_to_handle(fence);
assert(fence->feedback.slot);
const VkSubmitInfo2 submit = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2,
.commandBufferInfoCount = 1,
.pCommandBufferInfos =
(VkCommandBufferSubmitInfo[]){
{
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO,
.commandBuffer = vn_get_fence_feedback_cmd(queue, fence),
.deviceMask = 0,
},
},
};
return vn_queue_submit2_low(queue_h, 1, &submit, fence_h, sync);
}
VkResult
vn_QueueSubmit2(VkQueue queue_h,
uint32_t submitCount,
const VkSubmitInfo2 *pSubmits,
VkFence fence_h)
{
VN_TRACE_FUNC();
struct vn_fence *fence = vn_fence_from_handle(fence_h);
struct vn_queue *queue = vn_queue_from_handle(queue_h);
struct vn_device *dev = queue->device;
struct vn_instance *instance = dev->instance;
VkResult result;
assert(dev->physical_device->renderer_sync_fd_semaphore_features &
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT);
const struct wsi_memory_signal_submit_info *wsi_info = NULL;
if (submitCount == 1)
wsi_info = vk_find_struct_const(pSubmits[0].pNext, WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA);
const bool has_external_fence = fence && fence->is_external;
const bool has_feedback_fence = fence && fence->feedback.slot;
assert(!has_external_fence || !has_feedback_fence);
const bool sync =
has_external_fence || wsi_info ||
vn_submit_info2_has_external_signal_semaphore(submitCount, pSubmits);
result = vn_queue_submit2_import_semaphores(dev, submitCount, pSubmits);
if (result != VK_SUCCESS)
return vn_error(instance, result);
result =
vn_queue_submit2_low(queue_h, submitCount, pSubmits,
has_feedback_fence ? VK_NULL_HANDLE : fence_h,
sync && !has_feedback_fence);
if (result != VK_SUCCESS)
return vn_error(instance, result);
if (has_feedback_fence) {
result = vn_queue_submit2_feedback_fence(queue, fence, sync);
if (result != VK_SUCCESS)
return vn_error(instance, result);
}
if (wsi_info) {
if (dev->instance->renderer->info.has_implicit_fencing) {
struct vn_device_memory *wsi_mem =
vn_device_memory_from_handle(wsi_info->memory);
assert(!wsi_mem->base_memory && wsi_mem->base_bo);
vn_renderer_submit(dev->renderer, &(const struct vn_renderer_submit){
.bos = &wsi_mem->base_bo,
.bo_count = 1,
});
} else {
vn_queue_wait_idle_before_present(queue);
}
}
return VK_SUCCESS;
}
VkResult
vn_QueueBindSparse(VkQueue _queue,
uint32_t bindInfoCount,