mesa/src/virtio/vulkan/vn_command_buffer.c
Ryan Neph 969cb02de7 venus: chain VkExternalMemoryAcquireUnmodifiedEXT for wsi ownership transfers
Venus implements guest WSI on host external memory and thus cannot
transition guest wsi images to/from VK_IMAGE_LAYOUT_PRESENT_SRC_KHR.

Thus, when a client would attempt to transition a Venus wsi image
to/from VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, Venus instead transitions
to/from VK_IMAGE_LAYOUT_GENERAL and performs an explicit ownership
transfer to/from VK_QUEUE_FAMILY_FOREIGN_EXT. Unfortunately, the
read-only guarantee of VK_IMAGE_LAYOUT_PRESENT_SRC_KHR is lost.

Upon the "acquire from foreign queue" side of that symmetry, when a
client would attempt to retain the contents of the image (i.e.
transition from VK_IMAGE_LAYOUT_PRESENT_SRC_KHR instead of
VK_IMAGE_LAYOUT_UNDEFINED), Venus knows that the image's backing memory
has not been modified. Thus, when those "acquire from FOREIGN queue"
ownership transfers flow to the native driver, Venus can signal it to
skip any acquisition-time validation of an image's internal data,
obtaining the same optimization as native WSI.

This is useful for drivers such as ARM's Mali (with Transaction
Elimination) that would otherwise need to recompute costly per-tile
checksums (CRCs) to ensure that they haven't gone stale during FOREIGN
ownership of the image's memory.

Signed-off-by: Ryan Neph <ryanneph@google.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/29777>
2024-07-10 18:57:27 +00:00

2541 lines
84 KiB
C

/*
* Copyright 2019 Google LLC
* SPDX-License-Identifier: MIT
*
* based in part on anv and radv which are:
* Copyright © 2015 Intel Corporation
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*/
#include "vn_command_buffer.h"
#include "venus-protocol/vn_protocol_driver_command_buffer.h"
#include "venus-protocol/vn_protocol_driver_command_pool.h"
#include "vn_descriptor_set.h"
#include "vn_device.h"
#include "vn_feedback.h"
#include "vn_image.h"
#include "vn_physical_device.h"
#include "vn_query_pool.h"
#include "vn_render_pass.h"
static void
vn_cmd_submit(struct vn_command_buffer *cmd);
#define VN_CMD_ENQUEUE(cmd_name, commandBuffer, ...) \
do { \
struct vn_command_buffer *_cmd = \
vn_command_buffer_from_handle(commandBuffer); \
const size_t _cmd_size = \
vn_sizeof_##cmd_name(commandBuffer, ##__VA_ARGS__); \
\
if (likely(vn_cs_encoder_reserve(&_cmd->cs, _cmd_size))) \
vn_encode_##cmd_name(&_cmd->cs, 0, commandBuffer, ##__VA_ARGS__); \
else \
_cmd->state = VN_COMMAND_BUFFER_STATE_INVALID; \
\
if (unlikely(VN_PERF(NO_CMD_BATCHING))) \
vn_cmd_submit(_cmd); \
} while (0)
static bool
vn_image_memory_barriers_needs_present_fix(
const VkImageMemoryBarrier *img_barriers, uint32_t count)
{
if (VN_PRESENT_SRC_INTERNAL_LAYOUT == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
return false;
for (uint32_t i = 0; i < count; i++) {
if (img_barriers[i].oldLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR ||
img_barriers[i].newLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
return true;
}
return false;
}
static bool
vn_dependency_infos_needs_present_fix(uint32_t dep_count,
const VkDependencyInfo *dep_infos)
{
if (VN_PRESENT_SRC_INTERNAL_LAYOUT == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
return false;
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;
}
struct vn_cmd_fix_image_memory_barrier_result {
bool availability_op_needed; // set src access/stage (flush)
bool visibility_op_needed; // set dst access/stage (invalidate)
bool external_acquire_unmodified;
};
struct vn_cmd_cached_storage {
VkDependencyInfo *dep_infos;
union {
VkImageMemoryBarrier *barriers;
VkImageMemoryBarrier2 *barriers2;
};
uint32_t acquire_unmodified_count;
uint32_t used_acquire_unmodified;
VkExternalMemoryAcquireUnmodifiedEXT *acquire_unmodified_infos;
};
static inline bool
vn_cmd_get_cached_storage(struct vn_command_buffer *cmd,
VkStructureType barrier_type,
uint32_t barrier_count,
uint32_t dep_info_count,
struct vn_cmd_cached_storage *out_storage)
{
size_t dep_infos_size = dep_info_count * sizeof(VkDependencyInfo);
size_t barriers_size;
switch (barrier_type) {
case VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER:
assert(!dep_info_count);
barriers_size = barrier_count * sizeof(VkImageMemoryBarrier);
break;
case VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2:
barriers_size = barrier_count * sizeof(VkImageMemoryBarrier2);
break;
default:
unreachable("invalid barrier_type");
}
size_t total_size =
dep_infos_size + barriers_size +
barrier_count * sizeof(VkExternalMemoryAcquireUnmodifiedEXT);
void *data = vn_cached_storage_get(&cmd->pool->storage, total_size);
if (!data)
return false;
memset(out_storage, 0, sizeof(*out_storage));
if (dep_info_count) {
out_storage->dep_infos = data;
data += dep_infos_size;
}
out_storage->barriers = data;
data += barriers_size;
out_storage->acquire_unmodified_count = barrier_count;
out_storage->acquire_unmodified_infos = data;
return true;
}
static inline VkExternalMemoryAcquireUnmodifiedEXT *
vn_cached_get_acquire_unmodified(struct vn_cmd_cached_storage *storage)
{
VkExternalMemoryAcquireUnmodifiedEXT *acquire_unmodified =
&storage->acquire_unmodified_infos[storage->used_acquire_unmodified++];
assert(storage->used_acquire_unmodified <=
storage->acquire_unmodified_count);
return acquire_unmodified;
}
/* About VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, the spec says
*
* VK_IMAGE_LAYOUT_PRESENT_SRC_KHR must only be used for presenting a
* presentable image for display. A swapchain's image must be transitioned
* to this layout before calling vkQueuePresentKHR, and must be
* transitioned away from this layout after calling vkAcquireNextImageKHR.
*
* That allows us to treat the layout internally as
*
* - VK_IMAGE_LAYOUT_GENERAL
* - VK_QUEUE_FAMILY_FOREIGN_EXT has the ownership, if the image is not a
* prime blit source
*
* while staying performant.
*
* About queue family ownerships, the spec says
*
* A queue family can take ownership of an image subresource or buffer
* range of a resource created with VK_SHARING_MODE_EXCLUSIVE, without an
* ownership transfer, in the same way as for a resource that was just
* created; however, taking ownership in this way has the effect that the
* contents of the image subresource or buffer range are undefined.
*
* It is unclear if that is applicable to external resources, which supposedly
* have the same semantics
*
* Binding a resource to a memory object shared between multiple Vulkan
* instances or other APIs does not change the ownership of the underlying
* memory. The first entity to access the resource implicitly acquires
* ownership. Accessing a resource backed by memory that is owned by a
* particular instance or API has the same semantics as accessing a
* VK_SHARING_MODE_EXCLUSIVE resource[...]
*
* We should get the spec clarified, or get rid of this completely broken code
* (TODO).
*
* Assuming a queue family can acquire the ownership implicitly when the
* contents are not needed, we do not need to worry about
* VK_IMAGE_LAYOUT_UNDEFINED. We can use VK_IMAGE_LAYOUT_PRESENT_SRC_KHR as
* the sole signal to trigger queue family ownership transfers.
*
* When the image has VK_SHARING_MODE_CONCURRENT, we can, and are required to,
* use VK_QUEUE_FAMILY_IGNORED as the other queue family whether we are
* transitioning to or from VK_IMAGE_LAYOUT_PRESENT_SRC_KHR.
*
* When the image has VK_SHARING_MODE_EXCLUSIVE, we have to work out who the
* other queue family is. It is easier when the barrier does not also define
* a queue family ownership transfer (i.e., srcQueueFamilyIndex equals to
* dstQueueFamilyIndex). The other queue family must be the queue family the
* command buffer was allocated for.
*
* When the barrier also defines a queue family ownership transfer, it is
* submitted both to the source queue family to release the ownership and to
* the destination queue family to acquire the ownership. Depending on
* whether the barrier transitions to or from VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
* we are only interested in the ownership release or acquire respectively and
* should be careful to avoid double releases/acquires.
*
* I haven't followed all transition paths mentally to verify the correctness.
* I likely also violate some VUs or miss some cases below. They are
* hopefully fixable and are left as TODOs.
*/
static struct vn_cmd_fix_image_memory_barrier_result
vn_cmd_fix_image_memory_barrier_common(const struct vn_image *img,
uint32_t cmd_pool_qfi,
VkImageLayout *old_layout,
VkImageLayout *new_layout,
uint32_t *src_qfi,
uint32_t *dst_qfi)
{
assert(VN_PRESENT_SRC_INTERNAL_LAYOUT != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
struct vn_cmd_fix_image_memory_barrier_result result = {
.availability_op_needed = true,
.visibility_op_needed = true,
};
/* no fix needed */
if (*old_layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR &&
*new_layout != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
return result;
assert(img->wsi.is_wsi);
/* prime blit src or no layout transition */
if (img->wsi.is_prime_blit_src || *old_layout == *new_layout) {
if (*old_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
*old_layout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
if (*new_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR)
*new_layout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
return result;
}
if (*old_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
*old_layout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
result.availability_op_needed = false;
result.external_acquire_unmodified = true;
if (img->sharing_mode == VK_SHARING_MODE_CONCURRENT) {
*src_qfi = VK_QUEUE_FAMILY_FOREIGN_EXT;
*dst_qfi = VK_QUEUE_FAMILY_IGNORED;
} else if (*dst_qfi == *src_qfi || *dst_qfi == cmd_pool_qfi) {
*src_qfi = VK_QUEUE_FAMILY_FOREIGN_EXT;
*dst_qfi = cmd_pool_qfi;
} 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.
*/
*src_qfi = VK_QUEUE_FAMILY_IGNORED;
*dst_qfi = VK_QUEUE_FAMILY_IGNORED;
*new_layout = *old_layout;
}
} else {
*new_layout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
result.visibility_op_needed = false;
if (img->sharing_mode == VK_SHARING_MODE_CONCURRENT) {
*src_qfi = VK_QUEUE_FAMILY_IGNORED;
*dst_qfi = VK_QUEUE_FAMILY_FOREIGN_EXT;
} else if (*src_qfi == *dst_qfi || *src_qfi == cmd_pool_qfi) {
*src_qfi = cmd_pool_qfi;
*dst_qfi = 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.
*/
*src_qfi = VK_QUEUE_FAMILY_IGNORED;
*dst_qfi = VK_QUEUE_FAMILY_IGNORED;
*old_layout = *new_layout;
}
}
return result;
}
static void
vn_cmd_set_external_acquire_unmodified(VkBaseOutStructure *chain,
struct vn_cmd_cached_storage *storage)
{
VkExternalMemoryAcquireUnmodifiedEXT *acquire_unmodified =
vk_find_struct(chain->pNext, EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXT);
if (acquire_unmodified) {
acquire_unmodified->acquireUnmodifiedMemory = VK_TRUE;
} else {
acquire_unmodified = vn_cached_get_acquire_unmodified(storage);
*acquire_unmodified = (VkExternalMemoryAcquireUnmodifiedEXT){
.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_ACQUIRE_UNMODIFIED_EXT,
.pNext = chain->pNext,
.acquireUnmodifiedMemory = VK_TRUE,
};
chain->pNext = (void *)acquire_unmodified;
}
}
static void
vn_cmd_fix_image_memory_barrier(const struct vn_command_buffer *cmd,
VkImageMemoryBarrier *barrier,
struct vn_cmd_cached_storage *storage)
{
const struct vn_physical_device *physical_dev =
cmd->pool->device->physical_device;
const struct vn_image *img = vn_image_from_handle(barrier->image);
struct vn_cmd_fix_image_memory_barrier_result result =
vn_cmd_fix_image_memory_barrier_common(
img, cmd->pool->queue_family_index, &barrier->oldLayout,
&barrier->newLayout, &barrier->srcQueueFamilyIndex,
&barrier->dstQueueFamilyIndex);
if (!result.availability_op_needed)
barrier->srcAccessMask = 0;
if (!result.visibility_op_needed)
barrier->dstAccessMask = 0;
if (result.external_acquire_unmodified &&
physical_dev->renderer_extensions
.EXT_external_memory_acquire_unmodified)
vn_cmd_set_external_acquire_unmodified((VkBaseOutStructure *)barrier,
storage);
}
static void
vn_cmd_fix_image_memory_barrier2(const struct vn_command_buffer *cmd,
VkImageMemoryBarrier2 *barrier,
struct vn_cmd_cached_storage *storage)
{
const struct vn_physical_device *physical_dev =
cmd->pool->device->physical_device;
const struct vn_image *img = vn_image_from_handle(barrier->image);
struct vn_cmd_fix_image_memory_barrier_result result =
vn_cmd_fix_image_memory_barrier_common(
img, cmd->pool->queue_family_index, &barrier->oldLayout,
&barrier->newLayout, &barrier->srcQueueFamilyIndex,
&barrier->dstQueueFamilyIndex);
if (!result.availability_op_needed) {
barrier->srcStageMask = 0;
barrier->srcAccessMask = 0;
}
if (!result.visibility_op_needed) {
barrier->dstStageMask = 0;
barrier->dstAccessMask = 0;
}
if (result.external_acquire_unmodified &&
physical_dev->renderer_extensions
.EXT_external_memory_acquire_unmodified) {
vn_cmd_set_external_acquire_unmodified((VkBaseOutStructure *)barrier,
storage);
}
}
static const VkImageMemoryBarrier *
vn_cmd_wait_events_fix_image_memory_barriers(
struct vn_command_buffer *cmd,
const VkImageMemoryBarrier *src_barriers,
uint32_t count,
uint32_t *out_transfer_count)
{
*out_transfer_count = 0;
if (cmd->builder.in_render_pass ||
!vn_image_memory_barriers_needs_present_fix(src_barriers, count))
return src_barriers;
struct vn_cmd_cached_storage storage;
if (!vn_cmd_get_cached_storage(cmd, VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
count * 2, /*dep_info_count=*/0,
&storage)) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return src_barriers;
}
VkImageMemoryBarrier *img_barriers = storage.barriers;
VkImageMemoryBarrier *transfer_barriers = storage.barriers + count;
/* vkCmdWaitEvents cannot be used for queue family ownership transfers.
* Nothing appears to be said about the submission order of image memory
* barriers in the same array. We take the liberty to move queue family
* ownership transfers to the tail.
*/
uint32_t transfer_count = 0;
uint32_t valid_count = 0;
for (uint32_t i = 0; i < count; i++) {
VkImageMemoryBarrier *img_barrier = &img_barriers[valid_count];
*img_barrier = src_barriers[i];
vn_cmd_fix_image_memory_barrier(cmd, img_barrier, &storage);
if (img_barrier->srcQueueFamilyIndex ==
img_barrier->dstQueueFamilyIndex) {
valid_count++;
} else {
transfer_barriers[transfer_count++] = *img_barrier;
}
}
assert(valid_count + transfer_count == count);
if (transfer_count) {
/* copy back to the tail */
memcpy(&img_barriers[valid_count], transfer_barriers,
sizeof(*transfer_barriers) * transfer_count);
*out_transfer_count = transfer_count;
}
return img_barriers;
}
static const VkImageMemoryBarrier *
vn_cmd_pipeline_barrier_fix_image_memory_barriers(
struct vn_command_buffer *cmd,
const VkImageMemoryBarrier *src_barriers,
uint32_t count)
{
if (cmd->builder.in_render_pass ||
!vn_image_memory_barriers_needs_present_fix(src_barriers, count))
return src_barriers;
struct vn_cmd_cached_storage storage;
if (!vn_cmd_get_cached_storage(cmd, VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
count, /*dep_info_count=*/0, &storage)) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return src_barriers;
}
memcpy(storage.barriers, src_barriers,
count * sizeof(VkImageMemoryBarrier));
for (uint32_t i = 0; i < count; i++)
vn_cmd_fix_image_memory_barrier(cmd, &storage.barriers[i], &storage);
return storage.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.in_render_pass ||
!vn_dependency_infos_needs_present_fix(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;
struct vn_cmd_cached_storage storage;
if (!vn_cmd_get_cached_storage(cmd,
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
total_barrier_count, dep_count, &storage)) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return dep_infos;
}
memcpy(storage.dep_infos, dep_infos, dep_count * sizeof(VkDependencyInfo));
uint32_t barrier_index = 0;
for (uint32_t i = 0; i < dep_count; i++) {
uint32_t barrier_count = dep_infos[i].imageMemoryBarrierCount;
VkImageMemoryBarrier2 *new_barriers = &storage.barriers2[barrier_index];
barrier_index += barrier_count;
memcpy(new_barriers, dep_infos[i].pImageMemoryBarriers,
barrier_count * sizeof(VkImageMemoryBarrier2));
storage.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], &storage);
}
}
return storage.dep_infos;
}
static void
vn_cmd_encode_memory_barriers(struct vn_command_buffer *cmd,
VkPipelineStageFlags src_stage_mask,
VkPipelineStageFlags dst_stage_mask,
uint32_t buf_barrier_count,
const VkBufferMemoryBarrier *buf_barriers,
uint32_t img_barrier_count,
const VkImageMemoryBarrier *img_barriers)
{
const VkCommandBuffer cmd_handle = vn_command_buffer_to_handle(cmd);
VN_CMD_ENQUEUE(vkCmdPipelineBarrier, cmd_handle, src_stage_mask,
dst_stage_mask, 0, 0, NULL, buf_barrier_count, buf_barriers,
img_barrier_count, img_barriers);
}
static void
vn_present_src_attachment_to_image_memory_barrier(
const struct vn_image *img,
const struct vn_present_src_attachment *att,
VkImageMemoryBarrier *img_barrier,
bool acquire)
{
*img_barrier = (VkImageMemoryBarrier)
{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = att->src_access_mask,
.dstAccessMask = att->dst_access_mask,
.oldLayout = acquire ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
: VN_PRESENT_SRC_INTERNAL_LAYOUT,
.newLayout = acquire ? VN_PRESENT_SRC_INTERNAL_LAYOUT
: VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.image = vn_image_to_handle((struct vn_image *)img),
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.levelCount = 1,
.layerCount = 1,
},
};
}
static void
vn_cmd_transfer_present_src_images(
struct vn_command_buffer *cmd,
bool acquire,
const struct vn_image *const *images,
const struct vn_present_src_attachment *atts,
uint32_t count)
{
struct vn_cmd_cached_storage storage;
if (!vn_cmd_get_cached_storage(cmd, VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
count, /*dep_info_count=*/0, &storage)) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return;
}
VkPipelineStageFlags src_stage_mask = 0;
VkPipelineStageFlags dst_stage_mask = 0;
for (uint32_t i = 0; i < count; i++) {
src_stage_mask |= atts[i].src_stage_mask;
dst_stage_mask |= atts[i].dst_stage_mask;
vn_present_src_attachment_to_image_memory_barrier(
images[i], &atts[i], &storage.barriers[i], acquire);
vn_cmd_fix_image_memory_barrier(cmd, &storage.barriers[i], &storage);
}
vn_cmd_encode_memory_barriers(cmd, src_stage_mask, dst_stage_mask, 0, NULL,
count, storage.barriers);
}
struct vn_cmd_query_record *
vn_cmd_pool_alloc_query_record(struct vn_command_pool *cmd_pool,
struct vn_query_pool *query_pool,
uint32_t query,
uint32_t query_count,
bool copy)
{
struct vn_cmd_query_record *record;
if (list_is_empty(&cmd_pool->free_query_records)) {
record = vk_alloc(&cmd_pool->allocator, sizeof(*record),
VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!record)
return NULL;
} else {
record = list_first_entry(&cmd_pool->free_query_records,
struct vn_cmd_query_record, head);
list_del(&record->head);
}
record->query_pool = query_pool;
record->query = query;
record->query_count = query_count;
record->copy = copy;
return record;
}
static inline void
vn_cmd_merge_query_records(struct vn_command_buffer *primary_cmd,
struct vn_command_buffer *secondary_cmd)
{
list_for_each_entry_safe(struct vn_cmd_query_record, secondary_record,
&secondary_cmd->builder.query_records, head) {
struct vn_cmd_query_record *record = vn_cmd_pool_alloc_query_record(
primary_cmd->pool, secondary_record->query_pool,
secondary_record->query, secondary_record->query_count,
secondary_record->copy);
if (!record) {
primary_cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return;
}
list_addtail(&record->head, &primary_cmd->builder.query_records);
}
}
static void
vn_cmd_begin_render_pass(struct vn_command_buffer *cmd,
const struct vn_render_pass *pass,
const struct vn_framebuffer *fb,
const VkRenderPassBeginInfo *begin_info)
{
assert(begin_info);
assert(cmd->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
cmd->builder.render_pass = pass;
cmd->builder.in_render_pass = true;
cmd->builder.subpass_index = 0;
cmd->builder.view_mask = vn_render_pass_get_subpass_view_mask(pass, 0);
if (!pass->present_count)
return;
/* find fb attachments */
const VkImageView *views;
ASSERTED uint32_t view_count;
if (fb->image_view_count) {
views = fb->image_views;
view_count = fb->image_view_count;
} else {
const VkRenderPassAttachmentBeginInfo *imageless_info =
vk_find_struct_const(begin_info->pNext,
RENDER_PASS_ATTACHMENT_BEGIN_INFO);
assert(imageless_info);
views = imageless_info->pAttachments;
view_count = imageless_info->attachmentCount;
}
const struct vn_image **images =
vk_alloc(&cmd->pool->allocator, sizeof(*images) * pass->present_count,
VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!images) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return;
}
for (uint32_t i = 0; i < pass->present_count; i++) {
const uint32_t index = pass->present_attachments[i].index;
assert(index < view_count);
images[i] = vn_image_view_from_handle(views[index])->image;
}
if (pass->present_acquire_count) {
vn_cmd_transfer_present_src_images(cmd, true, images,
pass->present_acquire_attachments,
pass->present_acquire_count);
}
cmd->builder.present_src_images = images;
}
static void
vn_cmd_end_render_pass(struct vn_command_buffer *cmd)
{
const struct vn_render_pass *pass = cmd->builder.render_pass;
const struct vn_image **images = cmd->builder.present_src_images;
cmd->builder.render_pass = NULL;
cmd->builder.present_src_images = NULL;
cmd->builder.in_render_pass = false;
cmd->builder.subpass_index = 0;
cmd->builder.view_mask = 0;
if (!pass->present_count || !images)
return;
if (pass->present_release_count) {
vn_cmd_transfer_present_src_images(
cmd, false, images + pass->present_acquire_count,
pass->present_release_attachments, pass->present_release_count);
}
vk_free(&cmd->pool->allocator, images);
}
static inline void
vn_cmd_next_subpass(struct vn_command_buffer *cmd)
{
cmd->builder.view_mask = vn_render_pass_get_subpass_view_mask(
cmd->builder.render_pass, ++cmd->builder.subpass_index);
}
static inline void
vn_cmd_begin_rendering(struct vn_command_buffer *cmd,
const VkRenderingInfo *rendering_info)
{
cmd->builder.in_render_pass = true;
cmd->builder.view_mask = rendering_info->viewMask;
}
static inline void
vn_cmd_end_rendering(struct vn_command_buffer *cmd)
{
cmd->builder.in_render_pass = false;
cmd->builder.view_mask = 0;
}
/* command pool commands */
VkResult
vn_CreateCommandPool(VkDevice device,
const VkCommandPoolCreateInfo *pCreateInfo,
const VkAllocationCallbacks *pAllocator,
VkCommandPool *pCommandPool)
{
VN_TRACE_FUNC();
struct vn_device *dev = vn_device_from_handle(device);
const VkAllocationCallbacks *alloc =
pAllocator ? pAllocator : &dev->base.base.alloc;
struct vn_command_pool *pool =
vk_zalloc(alloc, sizeof(*pool), VN_DEFAULT_ALIGN,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!pool)
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
vn_object_base_init(&pool->base, VK_OBJECT_TYPE_COMMAND_POOL, &dev->base);
pool->allocator = *alloc;
pool->device = dev;
pool->queue_family_index = pCreateInfo->queueFamilyIndex;
list_inithead(&pool->command_buffers);
list_inithead(&pool->free_query_records);
vn_cached_storage_init(&pool->storage, alloc);
VkCommandPool pool_handle = vn_command_pool_to_handle(pool);
vn_async_vkCreateCommandPool(dev->primary_ring, device, pCreateInfo, NULL,
&pool_handle);
vn_tls_set_async_pipeline_create();
*pCommandPool = pool_handle;
return VK_SUCCESS;
}
static void
vn_cmd_reset(struct vn_command_buffer *cmd)
{
vn_cs_encoder_reset(&cmd->cs);
cmd->state = VN_COMMAND_BUFFER_STATE_INITIAL;
/* reset cmd builder */
vk_free(&cmd->pool->allocator, cmd->builder.present_src_images);
vn_cmd_pool_free_query_records(cmd->pool, &cmd->builder.query_records);
memset(&cmd->builder, 0, sizeof(cmd->builder));
list_inithead(&cmd->builder.query_records);
if (cmd->linked_qfb_cmd) {
vn_query_feedback_cmd_free(cmd->linked_qfb_cmd);
cmd->linked_qfb_cmd = NULL;
}
}
void
vn_DestroyCommandPool(VkDevice device,
VkCommandPool commandPool,
const VkAllocationCallbacks *pAllocator)
{
VN_TRACE_FUNC();
struct vn_device *dev = vn_device_from_handle(device);
struct vn_command_pool *pool = vn_command_pool_from_handle(commandPool);
const VkAllocationCallbacks *alloc;
if (!pool)
return;
alloc = pAllocator ? pAllocator : &pool->allocator;
vn_async_vkDestroyCommandPool(dev->primary_ring, device, commandPool,
NULL);
list_for_each_entry_safe(struct vn_command_buffer, cmd,
&pool->command_buffers, head) {
vn_cmd_reset(cmd);
vn_cs_encoder_fini(&cmd->cs);
vn_object_base_fini(&cmd->base);
vk_free(alloc, cmd);
}
list_for_each_entry_safe(struct vn_cmd_query_record, record,
&pool->free_query_records, head)
vk_free(alloc, record);
vn_cached_storage_fini(&pool->storage);
vn_object_base_fini(&pool->base);
vk_free(alloc, pool);
}
VkResult
vn_ResetCommandPool(VkDevice device,
VkCommandPool commandPool,
VkCommandPoolResetFlags flags)
{
VN_TRACE_FUNC();
struct vn_device *dev = vn_device_from_handle(device);
struct vn_command_pool *pool = vn_command_pool_from_handle(commandPool);
list_for_each_entry_safe(struct vn_command_buffer, cmd,
&pool->command_buffers, head)
vn_cmd_reset(cmd);
if (flags & VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT) {
list_for_each_entry_safe(struct vn_cmd_query_record, record,
&pool->free_query_records, head)
vk_free(&pool->allocator, record);
vn_cached_storage_fini(&pool->storage);
vn_cached_storage_init(&pool->storage, &pool->allocator);
}
vn_async_vkResetCommandPool(dev->primary_ring, device, commandPool, flags);
return VK_SUCCESS;
}
void
vn_TrimCommandPool(VkDevice device,
VkCommandPool commandPool,
VkCommandPoolTrimFlags flags)
{
VN_TRACE_FUNC();
struct vn_device *dev = vn_device_from_handle(device);
vn_async_vkTrimCommandPool(dev->primary_ring, device, commandPool, flags);
}
/* command buffer commands */
VkResult
vn_AllocateCommandBuffers(VkDevice device,
const VkCommandBufferAllocateInfo *pAllocateInfo,
VkCommandBuffer *pCommandBuffers)
{
VN_TRACE_FUNC();
struct vn_device *dev = vn_device_from_handle(device);
struct vn_command_pool *pool =
vn_command_pool_from_handle(pAllocateInfo->commandPool);
const VkAllocationCallbacks *alloc = &pool->allocator;
for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; i++) {
struct vn_command_buffer *cmd =
vk_zalloc(alloc, sizeof(*cmd), VN_DEFAULT_ALIGN,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!cmd) {
for (uint32_t j = 0; j < i; j++) {
cmd = vn_command_buffer_from_handle(pCommandBuffers[j]);
vn_cs_encoder_fini(&cmd->cs);
list_del(&cmd->head);
vn_object_base_fini(&cmd->base);
vk_free(alloc, cmd);
}
memset(pCommandBuffers, 0,
sizeof(*pCommandBuffers) * pAllocateInfo->commandBufferCount);
return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
}
vn_object_base_init(&cmd->base, VK_OBJECT_TYPE_COMMAND_BUFFER,
&dev->base);
cmd->pool = pool;
cmd->level = pAllocateInfo->level;
cmd->state = VN_COMMAND_BUFFER_STATE_INITIAL;
vn_cs_encoder_init(&cmd->cs, dev->instance,
VN_CS_ENCODER_STORAGE_SHMEM_POOL, 16 * 1024);
list_inithead(&cmd->builder.query_records);
list_addtail(&cmd->head, &pool->command_buffers);
VkCommandBuffer cmd_handle = vn_command_buffer_to_handle(cmd);
pCommandBuffers[i] = cmd_handle;
}
vn_async_vkAllocateCommandBuffers(dev->primary_ring, device, pAllocateInfo,
pCommandBuffers);
return VK_SUCCESS;
}
void
vn_FreeCommandBuffers(VkDevice device,
VkCommandPool commandPool,
uint32_t commandBufferCount,
const VkCommandBuffer *pCommandBuffers)
{
VN_TRACE_FUNC();
struct vn_device *dev = vn_device_from_handle(device);
struct vn_command_pool *pool = vn_command_pool_from_handle(commandPool);
const VkAllocationCallbacks *alloc = &pool->allocator;
vn_async_vkFreeCommandBuffers(dev->primary_ring, device, commandPool,
commandBufferCount, pCommandBuffers);
for (uint32_t i = 0; i < commandBufferCount; i++) {
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(pCommandBuffers[i]);
if (!cmd)
continue;
list_del(&cmd->head);
vn_cmd_reset(cmd);
vn_cs_encoder_fini(&cmd->cs);
vn_object_base_fini(&cmd->base);
vk_free(alloc, cmd);
}
}
VkResult
vn_ResetCommandBuffer(VkCommandBuffer commandBuffer,
VkCommandBufferResetFlags flags)
{
VN_TRACE_FUNC();
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
struct vn_ring *ring = cmd->pool->device->primary_ring;
vn_cmd_reset(cmd);
vn_async_vkResetCommandBuffer(ring, commandBuffer, flags);
return VK_SUCCESS;
}
struct vn_command_buffer_begin_info {
VkCommandBufferBeginInfo begin;
VkCommandBufferInheritanceInfo inheritance;
VkCommandBufferInheritanceConditionalRenderingInfoEXT conditional_rendering;
bool has_inherited_pass;
bool in_render_pass;
};
static const VkCommandBufferBeginInfo *
vn_fix_command_buffer_begin_info(struct vn_command_buffer *cmd,
const VkCommandBufferBeginInfo *begin_info,
struct vn_command_buffer_begin_info *local)
{
local->has_inherited_pass = false;
if (!begin_info->pInheritanceInfo)
return begin_info;
const bool is_cmd_secondary =
cmd->level == VK_COMMAND_BUFFER_LEVEL_SECONDARY;
const bool has_continue =
begin_info->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
const bool has_renderpass =
is_cmd_secondary &&
begin_info->pInheritanceInfo->renderPass != VK_NULL_HANDLE;
/* Per spec 1.3.255: "VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT
* specifies that a secondary command buffer is considered to be
* entirely inside a render pass. If this is a primary command buffer,
* then this bit is ignored."
*/
local->in_render_pass = has_continue && is_cmd_secondary;
/* Can early-return if dynamic rendering is used and no structures need to
* be dropped from the pNext chain of VkCommandBufferInheritanceInfo.
*/
if (is_cmd_secondary && has_continue && !has_renderpass)
return begin_info;
local->begin = *begin_info;
if (!is_cmd_secondary) {
local->begin.pInheritanceInfo = NULL;
return &local->begin;
}
local->inheritance = *begin_info->pInheritanceInfo;
local->begin.pInheritanceInfo = &local->inheritance;
if (!has_continue) {
local->inheritance.framebuffer = VK_NULL_HANDLE;
local->inheritance.renderPass = VK_NULL_HANDLE;
local->inheritance.subpass = 0;
} else {
/* With early-returns above, it must be an inherited pass. */
local->has_inherited_pass = true;
}
/* Per spec, about VkCommandBufferInheritanceRenderingInfo:
*
* If VkCommandBufferInheritanceInfo::renderPass is not VK_NULL_HANDLE, or
* VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT is not specified in
* VkCommandBufferBeginInfo::flags, parameters of this structure are
* ignored.
*/
VkBaseOutStructure *head = NULL;
VkBaseOutStructure *tail = NULL;
vk_foreach_struct_const(src, local->inheritance.pNext) {
void *pnext = NULL;
switch (src->sType) {
case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT:
memcpy(
&local->conditional_rendering, src,
sizeof(VkCommandBufferInheritanceConditionalRenderingInfoEXT));
pnext = &local->conditional_rendering;
break;
case VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_RENDERING_INFO:
default:
break;
}
if (pnext) {
if (!head)
head = pnext;
else
tail->pNext = pnext;
tail = pnext;
}
}
local->inheritance.pNext = head;
return &local->begin;
}
VkResult
vn_BeginCommandBuffer(VkCommandBuffer commandBuffer,
const VkCommandBufferBeginInfo *pBeginInfo)
{
VN_TRACE_FUNC();
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
struct vn_instance *instance = cmd->pool->device->instance;
size_t cmd_size;
/* reset regardless of VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT */
vn_cmd_reset(cmd);
struct vn_command_buffer_begin_info local_begin_info;
pBeginInfo =
vn_fix_command_buffer_begin_info(cmd, pBeginInfo, &local_begin_info);
cmd_size = vn_sizeof_vkBeginCommandBuffer(commandBuffer, pBeginInfo);
if (!vn_cs_encoder_reserve(&cmd->cs, cmd_size)) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return vn_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
}
cmd->builder.is_simultaneous =
pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
vn_encode_vkBeginCommandBuffer(&cmd->cs, 0, commandBuffer, pBeginInfo);
cmd->state = VN_COMMAND_BUFFER_STATE_RECORDING;
const VkCommandBufferInheritanceInfo *inheritance_info =
pBeginInfo->pInheritanceInfo;
if (inheritance_info) {
cmd->builder.in_render_pass = local_begin_info.in_render_pass;
if (local_begin_info.has_inherited_pass) {
/* Store the viewMask from the inherited render pass subpass for
* query feedback.
*/
cmd->builder.view_mask = vn_render_pass_get_subpass_view_mask(
vn_render_pass_from_handle(inheritance_info->renderPass),
inheritance_info->subpass);
} else {
/* Store the viewMask from the
* VkCommandBufferInheritanceRenderingInfo.
*/
const VkCommandBufferInheritanceRenderingInfo
*inheritance_rendering_info = vk_find_struct_const(
inheritance_info->pNext,
COMMAND_BUFFER_INHERITANCE_RENDERING_INFO);
if (inheritance_rendering_info)
cmd->builder.view_mask = inheritance_rendering_info->viewMask;
}
}
return VK_SUCCESS;
}
static void
vn_cmd_submit(struct vn_command_buffer *cmd)
{
struct vn_ring *ring = cmd->pool->device->primary_ring;
if (cmd->state != VN_COMMAND_BUFFER_STATE_RECORDING)
return;
vn_cs_encoder_commit(&cmd->cs);
if (vn_cs_encoder_get_fatal(&cmd->cs)) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
vn_cs_encoder_reset(&cmd->cs);
return;
}
if (vn_cs_encoder_needs_roundtrip(&cmd->cs))
vn_ring_roundtrip(ring);
if (vn_ring_submit_command_simple(ring, &cmd->cs) != VK_SUCCESS) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return;
}
vn_cs_encoder_reset(&cmd->cs);
}
VkResult
vn_EndCommandBuffer(VkCommandBuffer commandBuffer)
{
VN_TRACE_FUNC();
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
struct vn_instance *instance = cmd->pool->device->instance;
size_t cmd_size;
if (cmd->state != VN_COMMAND_BUFFER_STATE_RECORDING)
return vn_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
cmd_size = vn_sizeof_vkEndCommandBuffer(commandBuffer);
if (!vn_cs_encoder_reserve(&cmd->cs, cmd_size)) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return vn_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
}
vn_encode_vkEndCommandBuffer(&cmd->cs, 0, commandBuffer);
vn_cmd_submit(cmd);
if (cmd->state == VN_COMMAND_BUFFER_STATE_INVALID)
return vn_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY);
cmd->state = VN_COMMAND_BUFFER_STATE_EXECUTABLE;
return VK_SUCCESS;
}
void
vn_CmdBindPipeline(VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipeline pipeline)
{
VN_CMD_ENQUEUE(vkCmdBindPipeline, commandBuffer, pipelineBindPoint,
pipeline);
}
void
vn_CmdSetViewport(VkCommandBuffer commandBuffer,
uint32_t firstViewport,
uint32_t viewportCount,
const VkViewport *pViewports)
{
VN_CMD_ENQUEUE(vkCmdSetViewport, commandBuffer, firstViewport,
viewportCount, pViewports);
}
void
vn_CmdSetScissor(VkCommandBuffer commandBuffer,
uint32_t firstScissor,
uint32_t scissorCount,
const VkRect2D *pScissors)
{
VN_CMD_ENQUEUE(vkCmdSetScissor, commandBuffer, firstScissor, scissorCount,
pScissors);
}
void
vn_CmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth)
{
VN_CMD_ENQUEUE(vkCmdSetLineWidth, commandBuffer, lineWidth);
}
void
vn_CmdSetDepthBias(VkCommandBuffer commandBuffer,
float depthBiasConstantFactor,
float depthBiasClamp,
float depthBiasSlopeFactor)
{
VN_CMD_ENQUEUE(vkCmdSetDepthBias, commandBuffer, depthBiasConstantFactor,
depthBiasClamp, depthBiasSlopeFactor);
}
void
vn_CmdSetBlendConstants(VkCommandBuffer commandBuffer,
const float blendConstants[4])
{
VN_CMD_ENQUEUE(vkCmdSetBlendConstants, commandBuffer, blendConstants);
}
void
vn_CmdSetDepthBounds(VkCommandBuffer commandBuffer,
float minDepthBounds,
float maxDepthBounds)
{
VN_CMD_ENQUEUE(vkCmdSetDepthBounds, commandBuffer, minDepthBounds,
maxDepthBounds);
}
void
vn_CmdSetStencilCompareMask(VkCommandBuffer commandBuffer,
VkStencilFaceFlags faceMask,
uint32_t compareMask)
{
VN_CMD_ENQUEUE(vkCmdSetStencilCompareMask, commandBuffer, faceMask,
compareMask);
}
void
vn_CmdSetStencilWriteMask(VkCommandBuffer commandBuffer,
VkStencilFaceFlags faceMask,
uint32_t writeMask)
{
VN_CMD_ENQUEUE(vkCmdSetStencilWriteMask, commandBuffer, faceMask,
writeMask);
}
void
vn_CmdSetStencilReference(VkCommandBuffer commandBuffer,
VkStencilFaceFlags faceMask,
uint32_t reference)
{
VN_CMD_ENQUEUE(vkCmdSetStencilReference, commandBuffer, faceMask,
reference);
}
void
vn_CmdBindDescriptorSets(VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t firstSet,
uint32_t descriptorSetCount,
const VkDescriptorSet *pDescriptorSets,
uint32_t dynamicOffsetCount,
const uint32_t *pDynamicOffsets)
{
VN_CMD_ENQUEUE(vkCmdBindDescriptorSets, commandBuffer, pipelineBindPoint,
layout, firstSet, descriptorSetCount, pDescriptorSets,
dynamicOffsetCount, pDynamicOffsets);
}
void
vn_CmdBindIndexBuffer(VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkIndexType indexType)
{
VN_CMD_ENQUEUE(vkCmdBindIndexBuffer, commandBuffer, buffer, offset,
indexType);
}
void
vn_CmdBindIndexBuffer2KHR(VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkDeviceSize size,
VkIndexType indexType)
{
VN_CMD_ENQUEUE(vkCmdBindIndexBuffer2KHR, commandBuffer, buffer, offset,
size, indexType);
}
void
vn_CmdBindVertexBuffers(VkCommandBuffer commandBuffer,
uint32_t firstBinding,
uint32_t bindingCount,
const VkBuffer *pBuffers,
const VkDeviceSize *pOffsets)
{
VN_CMD_ENQUEUE(vkCmdBindVertexBuffers, commandBuffer, firstBinding,
bindingCount, pBuffers, pOffsets);
}
void
vn_CmdDraw(VkCommandBuffer commandBuffer,
uint32_t vertexCount,
uint32_t instanceCount,
uint32_t firstVertex,
uint32_t firstInstance)
{
VN_CMD_ENQUEUE(vkCmdDraw, commandBuffer, vertexCount, instanceCount,
firstVertex, firstInstance);
}
void
vn_CmdBeginRendering(VkCommandBuffer commandBuffer,
const VkRenderingInfo *pRenderingInfo)
{
vn_cmd_begin_rendering(vn_command_buffer_from_handle(commandBuffer),
pRenderingInfo);
VN_CMD_ENQUEUE(vkCmdBeginRendering, commandBuffer, pRenderingInfo);
}
void
vn_CmdEndRendering(VkCommandBuffer commandBuffer)
{
VN_CMD_ENQUEUE(vkCmdEndRendering, commandBuffer);
vn_cmd_end_rendering(vn_command_buffer_from_handle(commandBuffer));
}
void
vn_CmdDrawIndexed(VkCommandBuffer commandBuffer,
uint32_t indexCount,
uint32_t instanceCount,
uint32_t firstIndex,
int32_t vertexOffset,
uint32_t firstInstance)
{
VN_CMD_ENQUEUE(vkCmdDrawIndexed, commandBuffer, indexCount, instanceCount,
firstIndex, vertexOffset, firstInstance);
}
void
vn_CmdDrawIndirect(VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride)
{
VN_CMD_ENQUEUE(vkCmdDrawIndirect, commandBuffer, buffer, offset, drawCount,
stride);
}
void
vn_CmdDrawIndexedIndirect(VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
uint32_t drawCount,
uint32_t stride)
{
VN_CMD_ENQUEUE(vkCmdDrawIndexedIndirect, commandBuffer, buffer, offset,
drawCount, stride);
}
void
vn_CmdDrawIndirectCount(VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkBuffer countBuffer,
VkDeviceSize countBufferOffset,
uint32_t maxDrawCount,
uint32_t stride)
{
VN_CMD_ENQUEUE(vkCmdDrawIndirectCount, commandBuffer, buffer, offset,
countBuffer, countBufferOffset, maxDrawCount, stride);
}
void
vn_CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset,
VkBuffer countBuffer,
VkDeviceSize countBufferOffset,
uint32_t maxDrawCount,
uint32_t stride)
{
VN_CMD_ENQUEUE(vkCmdDrawIndexedIndirectCount, commandBuffer, buffer,
offset, countBuffer, countBufferOffset, maxDrawCount,
stride);
}
void
vn_CmdDispatch(VkCommandBuffer commandBuffer,
uint32_t groupCountX,
uint32_t groupCountY,
uint32_t groupCountZ)
{
VN_CMD_ENQUEUE(vkCmdDispatch, commandBuffer, groupCountX, groupCountY,
groupCountZ);
}
void
vn_CmdDispatchIndirect(VkCommandBuffer commandBuffer,
VkBuffer buffer,
VkDeviceSize offset)
{
VN_CMD_ENQUEUE(vkCmdDispatchIndirect, commandBuffer, buffer, offset);
}
void
vn_CmdCopyBuffer(VkCommandBuffer commandBuffer,
VkBuffer srcBuffer,
VkBuffer dstBuffer,
uint32_t regionCount,
const VkBufferCopy *pRegions)
{
VN_CMD_ENQUEUE(vkCmdCopyBuffer, commandBuffer, srcBuffer, dstBuffer,
regionCount, pRegions);
}
void
vn_CmdCopyBuffer2(VkCommandBuffer commandBuffer,
const VkCopyBufferInfo2 *pCopyBufferInfo)
{
VN_CMD_ENQUEUE(vkCmdCopyBuffer2, commandBuffer, pCopyBufferInfo);
}
void
vn_CmdCopyImage(VkCommandBuffer commandBuffer,
VkImage srcImage,
VkImageLayout srcImageLayout,
VkImage dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkImageCopy *pRegions)
{
VN_CMD_ENQUEUE(vkCmdCopyImage, commandBuffer, srcImage, srcImageLayout,
dstImage, dstImageLayout, regionCount, pRegions);
}
void
vn_CmdCopyImage2(VkCommandBuffer commandBuffer,
const VkCopyImageInfo2 *pCopyImageInfo)
{
VN_CMD_ENQUEUE(vkCmdCopyImage2, commandBuffer, pCopyImageInfo);
}
void
vn_CmdBlitImage(VkCommandBuffer commandBuffer,
VkImage srcImage,
VkImageLayout srcImageLayout,
VkImage dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkImageBlit *pRegions,
VkFilter filter)
{
VN_CMD_ENQUEUE(vkCmdBlitImage, commandBuffer, srcImage, srcImageLayout,
dstImage, dstImageLayout, regionCount, pRegions, filter);
}
void
vn_CmdBlitImage2(VkCommandBuffer commandBuffer,
const VkBlitImageInfo2 *pBlitImageInfo)
{
VN_CMD_ENQUEUE(vkCmdBlitImage2, commandBuffer, pBlitImageInfo);
}
void
vn_CmdCopyBufferToImage(VkCommandBuffer commandBuffer,
VkBuffer srcBuffer,
VkImage dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkBufferImageCopy *pRegions)
{
VN_CMD_ENQUEUE(vkCmdCopyBufferToImage, commandBuffer, srcBuffer, dstImage,
dstImageLayout, regionCount, pRegions);
}
void
vn_CmdCopyBufferToImage2(
VkCommandBuffer commandBuffer,
const VkCopyBufferToImageInfo2 *pCopyBufferToImageInfo)
{
VN_CMD_ENQUEUE(vkCmdCopyBufferToImage2, commandBuffer,
pCopyBufferToImageInfo);
}
static bool
vn_needs_prime_blit(VkImage src_image, VkImageLayout src_image_layout)
{
if (src_image_layout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR &&
VN_PRESENT_SRC_INTERNAL_LAYOUT != VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) {
/* sanity check */
ASSERTED const struct vn_image *img = vn_image_from_handle(src_image);
assert(img->wsi.is_wsi && img->wsi.is_prime_blit_src);
return true;
}
return false;
}
static void
vn_transition_prime_layout(struct vn_command_buffer *cmd, VkBuffer dst_buffer)
{
const VkBufferMemoryBarrier buf_barrier = {
.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
.srcQueueFamilyIndex = cmd->pool->queue_family_index,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_FOREIGN_EXT,
.buffer = dst_buffer,
.size = VK_WHOLE_SIZE,
};
vn_cmd_encode_memory_barriers(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 1,
&buf_barrier, 0, NULL);
}
void
vn_CmdCopyImageToBuffer(VkCommandBuffer commandBuffer,
VkImage srcImage,
VkImageLayout srcImageLayout,
VkBuffer dstBuffer,
uint32_t regionCount,
const VkBufferImageCopy *pRegions)
{
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
bool prime_blit = vn_needs_prime_blit(srcImage, srcImageLayout);
if (prime_blit)
srcImageLayout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
VN_CMD_ENQUEUE(vkCmdCopyImageToBuffer, commandBuffer, srcImage,
srcImageLayout, dstBuffer, regionCount, pRegions);
if (prime_blit)
vn_transition_prime_layout(cmd, dstBuffer);
}
void
vn_CmdCopyImageToBuffer2(
VkCommandBuffer commandBuffer,
const VkCopyImageToBufferInfo2 *pCopyImageToBufferInfo)
{
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
struct VkCopyImageToBufferInfo2 copy_info = *pCopyImageToBufferInfo;
bool prime_blit =
vn_needs_prime_blit(copy_info.srcImage, copy_info.srcImageLayout);
if (prime_blit)
copy_info.srcImageLayout = VN_PRESENT_SRC_INTERNAL_LAYOUT;
VN_CMD_ENQUEUE(vkCmdCopyImageToBuffer2, commandBuffer, &copy_info);
if (prime_blit)
vn_transition_prime_layout(cmd, copy_info.dstBuffer);
}
void
vn_CmdUpdateBuffer(VkCommandBuffer commandBuffer,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
const void *pData)
{
VN_CMD_ENQUEUE(vkCmdUpdateBuffer, commandBuffer, dstBuffer, dstOffset,
dataSize, pData);
}
void
vn_CmdFillBuffer(VkCommandBuffer commandBuffer,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize size,
uint32_t data)
{
VN_CMD_ENQUEUE(vkCmdFillBuffer, commandBuffer, dstBuffer, dstOffset, size,
data);
}
void
vn_CmdClearColorImage(VkCommandBuffer commandBuffer,
VkImage image,
VkImageLayout imageLayout,
const VkClearColorValue *pColor,
uint32_t rangeCount,
const VkImageSubresourceRange *pRanges)
{
VN_CMD_ENQUEUE(vkCmdClearColorImage, commandBuffer, image, imageLayout,
pColor, rangeCount, pRanges);
}
void
vn_CmdClearDepthStencilImage(VkCommandBuffer commandBuffer,
VkImage image,
VkImageLayout imageLayout,
const VkClearDepthStencilValue *pDepthStencil,
uint32_t rangeCount,
const VkImageSubresourceRange *pRanges)
{
VN_CMD_ENQUEUE(vkCmdClearDepthStencilImage, commandBuffer, image,
imageLayout, pDepthStencil, rangeCount, pRanges);
}
void
vn_CmdClearAttachments(VkCommandBuffer commandBuffer,
uint32_t attachmentCount,
const VkClearAttachment *pAttachments,
uint32_t rectCount,
const VkClearRect *pRects)
{
VN_CMD_ENQUEUE(vkCmdClearAttachments, commandBuffer, attachmentCount,
pAttachments, rectCount, pRects);
}
void
vn_CmdResolveImage(VkCommandBuffer commandBuffer,
VkImage srcImage,
VkImageLayout srcImageLayout,
VkImage dstImage,
VkImageLayout dstImageLayout,
uint32_t regionCount,
const VkImageResolve *pRegions)
{
VN_CMD_ENQUEUE(vkCmdResolveImage, commandBuffer, srcImage, srcImageLayout,
dstImage, dstImageLayout, regionCount, pRegions);
}
void
vn_CmdResolveImage2(VkCommandBuffer commandBuffer,
const VkResolveImageInfo2 *pResolveImageInfo)
{
VN_CMD_ENQUEUE(vkCmdResolveImage2, commandBuffer, pResolveImageInfo);
}
void
vn_CmdSetEvent(VkCommandBuffer commandBuffer,
VkEvent event,
VkPipelineStageFlags stageMask)
{
VN_CMD_ENQUEUE(vkCmdSetEvent, commandBuffer, event, stageMask);
vn_event_feedback_cmd_record(commandBuffer, event, stageMask, VK_EVENT_SET,
false);
}
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);
const VkPipelineStageFlags2 src_stage_mask =
vn_dependency_info_collect_src_stage_mask(pDependencyInfo);
vn_event_feedback_cmd_record(commandBuffer, event, src_stage_mask,
VK_EVENT_SET, true);
}
void
vn_CmdResetEvent(VkCommandBuffer commandBuffer,
VkEvent event,
VkPipelineStageFlags stageMask)
{
VN_CMD_ENQUEUE(vkCmdResetEvent, commandBuffer, event, stageMask);
vn_event_feedback_cmd_record(commandBuffer, event, stageMask,
VK_EVENT_RESET, false);
}
void
vn_CmdResetEvent2(VkCommandBuffer commandBuffer,
VkEvent event,
VkPipelineStageFlags2 stageMask)
{
VN_CMD_ENQUEUE(vkCmdResetEvent2, commandBuffer, event, stageMask);
vn_event_feedback_cmd_record(commandBuffer, event, stageMask,
VK_EVENT_RESET, true);
}
void
vn_CmdWaitEvents(VkCommandBuffer commandBuffer,
uint32_t eventCount,
const VkEvent *pEvents,
VkPipelineStageFlags srcStageMask,
VkPipelineStageFlags dstStageMask,
uint32_t memoryBarrierCount,
const VkMemoryBarrier *pMemoryBarriers,
uint32_t bufferMemoryBarrierCount,
const VkBufferMemoryBarrier *pBufferMemoryBarriers,
uint32_t imageMemoryBarrierCount,
const VkImageMemoryBarrier *pImageMemoryBarriers)
{
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
uint32_t transfer_count;
pImageMemoryBarriers = vn_cmd_wait_events_fix_image_memory_barriers(
cmd, pImageMemoryBarriers, imageMemoryBarrierCount, &transfer_count);
imageMemoryBarrierCount -= transfer_count;
VN_CMD_ENQUEUE(vkCmdWaitEvents, commandBuffer, eventCount, pEvents,
srcStageMask, dstStageMask, memoryBarrierCount,
pMemoryBarriers, bufferMemoryBarrierCount,
pBufferMemoryBarriers, imageMemoryBarrierCount,
pImageMemoryBarriers);
if (transfer_count) {
pImageMemoryBarriers += imageMemoryBarrierCount;
vn_cmd_encode_memory_barriers(cmd, srcStageMask, dstStageMask, 0, NULL,
transfer_count, pImageMemoryBarriers);
}
}
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,
VkPipelineStageFlags dstStageMask,
VkDependencyFlags dependencyFlags,
uint32_t memoryBarrierCount,
const VkMemoryBarrier *pMemoryBarriers,
uint32_t bufferMemoryBarrierCount,
const VkBufferMemoryBarrier *pBufferMemoryBarriers,
uint32_t imageMemoryBarrierCount,
const VkImageMemoryBarrier *pImageMemoryBarriers)
{
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
pImageMemoryBarriers = vn_cmd_pipeline_barrier_fix_image_memory_barriers(
cmd, pImageMemoryBarriers, imageMemoryBarrierCount);
VN_CMD_ENQUEUE(vkCmdPipelineBarrier, commandBuffer, srcStageMask,
dstStageMask, dependencyFlags, memoryBarrierCount,
pMemoryBarriers, bufferMemoryBarrierCount,
pBufferMemoryBarriers, imageMemoryBarrierCount,
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,
uint32_t query,
VkQueryControlFlags flags)
{
VN_CMD_ENQUEUE(vkCmdBeginQuery, commandBuffer, queryPool, query, flags);
}
static inline uint32_t
vn_cmd_get_query_count(VkCommandBuffer cmd_handle)
{
/* Per 1.3.255 spec "If queries are used while executing a render pass
* instance that has multiview enabled, the query uses N consecutive
* query indices in the query pool (starting at query) where N is the
* number of bits set in the view mask in the subpass the query is used
* in."
*/
struct vn_command_buffer *cmd = vn_command_buffer_from_handle(cmd_handle);
return cmd->builder.in_render_pass && cmd->builder.view_mask
? util_bitcount(cmd->builder.view_mask)
: 1;
}
static void
vn_cmd_record_query(VkCommandBuffer cmd_handle,
VkQueryPool pool_handle,
uint32_t query,
uint32_t query_count,
bool copy)
{
struct vn_command_buffer *cmd = vn_command_buffer_from_handle(cmd_handle);
struct vn_query_pool *query_pool = vn_query_pool_from_handle(pool_handle);
if (unlikely(VN_PERF(NO_QUERY_FEEDBACK)))
return;
if (unlikely(!query_pool->fb_buf)) {
if (vn_query_feedback_buffer_init_once(cmd->pool->device, query_pool) !=
VK_SUCCESS) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return;
}
}
struct vn_cmd_query_record *record = vn_cmd_pool_alloc_query_record(
cmd->pool, query_pool, query, query_count, copy);
if (!record) {
cmd->state = VN_COMMAND_BUFFER_STATE_INVALID;
return;
}
list_addtail(&record->head, &cmd->builder.query_records);
}
void
vn_CmdEndQuery(VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t query)
{
VN_CMD_ENQUEUE(vkCmdEndQuery, commandBuffer, queryPool, query);
const uint32_t query_count = vn_cmd_get_query_count(commandBuffer);
vn_cmd_record_query(commandBuffer, queryPool, query, query_count, true);
}
void
vn_CmdResetQueryPool(VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount)
{
VN_CMD_ENQUEUE(vkCmdResetQueryPool, commandBuffer, queryPool, firstQuery,
queryCount);
vn_cmd_record_query(commandBuffer, queryPool, firstQuery, queryCount,
false);
}
void
vn_CmdWriteTimestamp(VkCommandBuffer commandBuffer,
VkPipelineStageFlagBits pipelineStage,
VkQueryPool queryPool,
uint32_t query)
{
VN_CMD_ENQUEUE(vkCmdWriteTimestamp, commandBuffer, pipelineStage,
queryPool, query);
const uint32_t query_count = vn_cmd_get_query_count(commandBuffer);
vn_cmd_record_query(commandBuffer, queryPool, query, query_count, true);
}
void
vn_CmdWriteTimestamp2(VkCommandBuffer commandBuffer,
VkPipelineStageFlagBits2 stage,
VkQueryPool queryPool,
uint32_t query)
{
VN_CMD_ENQUEUE(vkCmdWriteTimestamp2, commandBuffer, stage, queryPool,
query);
const uint32_t query_count = vn_cmd_get_query_count(commandBuffer);
vn_cmd_record_query(commandBuffer, queryPool, query, query_count, true);
}
void
vn_CmdCopyQueryPoolResults(VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize stride,
VkQueryResultFlags flags)
{
VN_CMD_ENQUEUE(vkCmdCopyQueryPoolResults, commandBuffer, queryPool,
firstQuery, queryCount, dstBuffer, dstOffset, stride,
flags);
}
void
vn_CmdPushConstants(VkCommandBuffer commandBuffer,
VkPipelineLayout layout,
VkShaderStageFlags stageFlags,
uint32_t offset,
uint32_t size,
const void *pValues)
{
VN_CMD_ENQUEUE(vkCmdPushConstants, commandBuffer, layout, stageFlags,
offset, size, pValues);
}
void
vn_CmdBeginRenderPass(VkCommandBuffer commandBuffer,
const VkRenderPassBeginInfo *pRenderPassBegin,
VkSubpassContents contents)
{
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
vn_cmd_begin_render_pass(
cmd, vn_render_pass_from_handle(pRenderPassBegin->renderPass),
vn_framebuffer_from_handle(pRenderPassBegin->framebuffer),
pRenderPassBegin);
VN_CMD_ENQUEUE(vkCmdBeginRenderPass, commandBuffer, pRenderPassBegin,
contents);
}
void
vn_CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents)
{
vn_cmd_next_subpass(vn_command_buffer_from_handle(commandBuffer));
VN_CMD_ENQUEUE(vkCmdNextSubpass, commandBuffer, contents);
}
void
vn_CmdEndRenderPass(VkCommandBuffer commandBuffer)
{
VN_CMD_ENQUEUE(vkCmdEndRenderPass, commandBuffer);
vn_cmd_end_render_pass(vn_command_buffer_from_handle(commandBuffer));
}
void
vn_CmdBeginRenderPass2(VkCommandBuffer commandBuffer,
const VkRenderPassBeginInfo *pRenderPassBegin,
const VkSubpassBeginInfo *pSubpassBeginInfo)
{
struct vn_command_buffer *cmd =
vn_command_buffer_from_handle(commandBuffer);
vn_cmd_begin_render_pass(
cmd, vn_render_pass_from_handle(pRenderPassBegin->renderPass),
vn_framebuffer_from_handle(pRenderPassBegin->framebuffer),
pRenderPassBegin);
VN_CMD_ENQUEUE(vkCmdBeginRenderPass2, commandBuffer, pRenderPassBegin,
pSubpassBeginInfo);
}
void
vn_CmdNextSubpass2(VkCommandBuffer commandBuffer,
const VkSubpassBeginInfo *pSubpassBeginInfo,
const VkSubpassEndInfo *pSubpassEndInfo)
{
vn_cmd_next_subpass(vn_command_buffer_from_handle(commandBuffer));
VN_CMD_ENQUEUE(vkCmdNextSubpass2, commandBuffer, pSubpassBeginInfo,
pSubpassEndInfo);
}
void
vn_CmdEndRenderPass2(VkCommandBuffer commandBuffer,
const VkSubpassEndInfo *pSubpassEndInfo)
{
VN_CMD_ENQUEUE(vkCmdEndRenderPass2, commandBuffer, pSubpassEndInfo);
vn_cmd_end_render_pass(vn_command_buffer_from_handle(commandBuffer));
}
void
vn_CmdExecuteCommands(VkCommandBuffer commandBuffer,
uint32_t commandBufferCount,
const VkCommandBuffer *pCommandBuffers)
{
VN_CMD_ENQUEUE(vkCmdExecuteCommands, commandBuffer, commandBufferCount,
pCommandBuffers);
struct vn_command_buffer *primary_cmd =
vn_command_buffer_from_handle(commandBuffer);
for (uint32_t i = 0; i < commandBufferCount; i++) {
struct vn_command_buffer *secondary_cmd =
vn_command_buffer_from_handle(pCommandBuffers[i]);
vn_cmd_merge_query_records(primary_cmd, secondary_cmd);
}
}
void
vn_CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask)
{
VN_CMD_ENQUEUE(vkCmdSetDeviceMask, commandBuffer, deviceMask);
}
void
vn_CmdDispatchBase(VkCommandBuffer commandBuffer,
uint32_t baseGroupX,
uint32_t baseGroupY,
uint32_t baseGroupZ,
uint32_t groupCountX,
uint32_t groupCountY,
uint32_t groupCountZ)
{
VN_CMD_ENQUEUE(vkCmdDispatchBase, commandBuffer, baseGroupX, baseGroupY,
baseGroupZ, groupCountX, groupCountY, groupCountZ);
}
void
vn_CmdSetLineStippleEXT(VkCommandBuffer commandBuffer,
uint32_t lineStippleFactor,
uint16_t lineStipplePattern)
{
VN_CMD_ENQUEUE(vkCmdSetLineStippleEXT, commandBuffer, lineStippleFactor,
lineStipplePattern);
}
void
vn_CmdBeginQueryIndexedEXT(VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t query,
VkQueryControlFlags flags,
uint32_t index)
{
VN_CMD_ENQUEUE(vkCmdBeginQueryIndexedEXT, commandBuffer, queryPool, query,
flags, index);
}
void
vn_CmdEndQueryIndexedEXT(VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t query,
uint32_t index)
{
VN_CMD_ENQUEUE(vkCmdEndQueryIndexedEXT, commandBuffer, queryPool, query,
index);
const uint32_t query_count = vn_cmd_get_query_count(commandBuffer);
vn_cmd_record_query(commandBuffer, queryPool, query, query_count, true);
}
void
vn_CmdBindTransformFeedbackBuffersEXT(VkCommandBuffer commandBuffer,
uint32_t firstBinding,
uint32_t bindingCount,
const VkBuffer *pBuffers,
const VkDeviceSize *pOffsets,
const VkDeviceSize *pSizes)
{
VN_CMD_ENQUEUE(vkCmdBindTransformFeedbackBuffersEXT, commandBuffer,
firstBinding, bindingCount, pBuffers, pOffsets, pSizes);
}
void
vn_CmdBeginTransformFeedbackEXT(VkCommandBuffer commandBuffer,
uint32_t firstCounterBuffer,
uint32_t counterBufferCount,
const VkBuffer *pCounterBuffers,
const VkDeviceSize *pCounterBufferOffsets)
{
VN_CMD_ENQUEUE(vkCmdBeginTransformFeedbackEXT, commandBuffer,
firstCounterBuffer, counterBufferCount, pCounterBuffers,
pCounterBufferOffsets);
}
void
vn_CmdEndTransformFeedbackEXT(VkCommandBuffer commandBuffer,
uint32_t firstCounterBuffer,
uint32_t counterBufferCount,
const VkBuffer *pCounterBuffers,
const VkDeviceSize *pCounterBufferOffsets)
{
VN_CMD_ENQUEUE(vkCmdEndTransformFeedbackEXT, commandBuffer,
firstCounterBuffer, counterBufferCount, pCounterBuffers,
pCounterBufferOffsets);
}
void
vn_CmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer,
uint32_t instanceCount,
uint32_t firstInstance,
VkBuffer counterBuffer,
VkDeviceSize counterBufferOffset,
uint32_t counterOffset,
uint32_t vertexStride)
{
VN_CMD_ENQUEUE(vkCmdDrawIndirectByteCountEXT, commandBuffer, instanceCount,
firstInstance, counterBuffer, counterBufferOffset,
counterOffset, vertexStride);
}
void
vn_CmdBindVertexBuffers2(VkCommandBuffer commandBuffer,
uint32_t firstBinding,
uint32_t bindingCount,
const VkBuffer *pBuffers,
const VkDeviceSize *pOffsets,
const VkDeviceSize *pSizes,
const VkDeviceSize *pStrides)
{
VN_CMD_ENQUEUE(vkCmdBindVertexBuffers2, commandBuffer, firstBinding,
bindingCount, pBuffers, pOffsets, pSizes, pStrides);
}
void
vn_CmdSetCullMode(VkCommandBuffer commandBuffer, VkCullModeFlags cullMode)
{
VN_CMD_ENQUEUE(vkCmdSetCullMode, commandBuffer, cullMode);
}
void
vn_CmdSetDepthBoundsTestEnable(VkCommandBuffer commandBuffer,
VkBool32 depthBoundsTestEnable)
{
VN_CMD_ENQUEUE(vkCmdSetDepthBoundsTestEnable, commandBuffer,
depthBoundsTestEnable);
}
void
vn_CmdSetDepthCompareOp(VkCommandBuffer commandBuffer,
VkCompareOp depthCompareOp)
{
VN_CMD_ENQUEUE(vkCmdSetDepthCompareOp, commandBuffer, depthCompareOp);
}
void
vn_CmdSetDepthTestEnable(VkCommandBuffer commandBuffer,
VkBool32 depthTestEnable)
{
VN_CMD_ENQUEUE(vkCmdSetDepthTestEnable, commandBuffer, depthTestEnable);
}
void
vn_CmdSetDepthWriteEnable(VkCommandBuffer commandBuffer,
VkBool32 depthWriteEnable)
{
VN_CMD_ENQUEUE(vkCmdSetDepthWriteEnable, commandBuffer, depthWriteEnable);
}
void
vn_CmdSetFrontFace(VkCommandBuffer commandBuffer, VkFrontFace frontFace)
{
VN_CMD_ENQUEUE(vkCmdSetFrontFace, commandBuffer, frontFace);
}
void
vn_CmdSetPrimitiveTopology(VkCommandBuffer commandBuffer,
VkPrimitiveTopology primitiveTopology)
{
VN_CMD_ENQUEUE(vkCmdSetPrimitiveTopology, commandBuffer,
primitiveTopology);
}
void
vn_CmdSetScissorWithCount(VkCommandBuffer commandBuffer,
uint32_t scissorCount,
const VkRect2D *pScissors)
{
VN_CMD_ENQUEUE(vkCmdSetScissorWithCount, commandBuffer, scissorCount,
pScissors);
}
void
vn_CmdSetStencilOp(VkCommandBuffer commandBuffer,
VkStencilFaceFlags faceMask,
VkStencilOp failOp,
VkStencilOp passOp,
VkStencilOp depthFailOp,
VkCompareOp compareOp)
{
VN_CMD_ENQUEUE(vkCmdSetStencilOp, commandBuffer, faceMask, failOp, passOp,
depthFailOp, compareOp);
}
void
vn_CmdSetStencilTestEnable(VkCommandBuffer commandBuffer,
VkBool32 stencilTestEnable)
{
VN_CMD_ENQUEUE(vkCmdSetStencilTestEnable, commandBuffer,
stencilTestEnable);
}
void
vn_CmdSetViewportWithCount(VkCommandBuffer commandBuffer,
uint32_t viewportCount,
const VkViewport *pViewports)
{
VN_CMD_ENQUEUE(vkCmdSetViewportWithCount, commandBuffer, viewportCount,
pViewports);
}
void
vn_CmdSetDepthBiasEnable(VkCommandBuffer commandBuffer,
VkBool32 depthBiasEnable)
{
VN_CMD_ENQUEUE(vkCmdSetDepthBiasEnable, commandBuffer, depthBiasEnable);
}
void
vn_CmdSetLogicOpEXT(VkCommandBuffer commandBuffer, VkLogicOp logicOp)
{
VN_CMD_ENQUEUE(vkCmdSetLogicOpEXT, commandBuffer, logicOp);
}
void
vn_CmdSetColorWriteEnableEXT(VkCommandBuffer commandBuffer,
uint32_t attachmentCount,
const VkBool32 *pColorWriteEnables)
{
VN_CMD_ENQUEUE(vkCmdSetColorWriteEnableEXT, commandBuffer, attachmentCount,
pColorWriteEnables);
}
void
vn_CmdSetPatchControlPointsEXT(VkCommandBuffer commandBuffer,
uint32_t patchControlPoints)
{
VN_CMD_ENQUEUE(vkCmdSetPatchControlPointsEXT, commandBuffer,
patchControlPoints);
}
void
vn_CmdSetPrimitiveRestartEnable(VkCommandBuffer commandBuffer,
VkBool32 primitiveRestartEnable)
{
VN_CMD_ENQUEUE(vkCmdSetPrimitiveRestartEnable, commandBuffer,
primitiveRestartEnable);
}
void
vn_CmdSetRasterizerDiscardEnable(VkCommandBuffer commandBuffer,
VkBool32 rasterizerDiscardEnable)
{
VN_CMD_ENQUEUE(vkCmdSetRasterizerDiscardEnable, commandBuffer,
rasterizerDiscardEnable);
}
void
vn_CmdBeginConditionalRenderingEXT(
VkCommandBuffer commandBuffer,
const VkConditionalRenderingBeginInfoEXT *pConditionalRenderingBegin)
{
VN_CMD_ENQUEUE(vkCmdBeginConditionalRenderingEXT, commandBuffer,
pConditionalRenderingBegin);
}
void
vn_CmdEndConditionalRenderingEXT(VkCommandBuffer commandBuffer)
{
VN_CMD_ENQUEUE(vkCmdEndConditionalRenderingEXT, commandBuffer);
}
void
vn_CmdDrawMultiEXT(VkCommandBuffer commandBuffer,
uint32_t drawCount,
const VkMultiDrawInfoEXT *pVertexInfo,
uint32_t instanceCount,
uint32_t firstInstance,
uint32_t stride)
{
VN_CMD_ENQUEUE(vkCmdDrawMultiEXT, commandBuffer, drawCount, pVertexInfo,
instanceCount, firstInstance, stride);
}
void
vn_CmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer,
uint32_t drawCount,
const VkMultiDrawIndexedInfoEXT *pIndexInfo,
uint32_t instanceCount,
uint32_t firstInstance,
uint32_t stride,
const int32_t *pVertexOffset)
{
VN_CMD_ENQUEUE(vkCmdDrawMultiIndexedEXT, commandBuffer, drawCount,
pIndexInfo, instanceCount, firstInstance, stride,
pVertexOffset);
}
void
vn_CmdPushDescriptorSetKHR(VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet *pDescriptorWrites)
{
const uint32_t img_info_count = vn_descriptor_set_count_write_images(
descriptorWriteCount, pDescriptorWrites);
STACK_ARRAY(VkWriteDescriptorSet, writes, descriptorWriteCount);
STACK_ARRAY(VkDescriptorImageInfo, img_infos, img_info_count);
struct vn_descriptor_set_writes local = {
.writes = writes,
.img_infos = img_infos,
};
pDescriptorWrites = vn_descriptor_set_get_writes(
descriptorWriteCount, pDescriptorWrites, layout, &local);
VN_CMD_ENQUEUE(vkCmdPushDescriptorSetKHR, commandBuffer, pipelineBindPoint,
layout, set, descriptorWriteCount, pDescriptorWrites);
STACK_ARRAY_FINISH(writes);
STACK_ARRAY_FINISH(img_infos);
}
void
vn_CmdPushDescriptorSetWithTemplateKHR(
VkCommandBuffer commandBuffer,
VkDescriptorUpdateTemplate descriptorUpdateTemplate,
VkPipelineLayout layout,
uint32_t set,
const void *pData)
{
struct vn_descriptor_update_template *templ =
vn_descriptor_update_template_from_handle(descriptorUpdateTemplate);
STACK_ARRAY(VkWriteDescriptorSet, writes, templ->entry_count);
STACK_ARRAY(VkDescriptorImageInfo, img_infos, templ->img_info_count);
STACK_ARRAY(VkDescriptorBufferInfo, buf_infos, templ->buf_info_count);
STACK_ARRAY(VkBufferView, bview_handles, templ->bview_count);
STACK_ARRAY(VkWriteDescriptorSetInlineUniformBlock, iubs,
templ->iub_count);
struct vn_descriptor_set_update update = {
.writes = writes,
.img_infos = img_infos,
.buf_infos = buf_infos,
.bview_handles = bview_handles,
.iubs = iubs,
};
vn_descriptor_set_fill_update_with_template(templ, VK_NULL_HANDLE, pData,
&update);
VN_CMD_ENQUEUE(vkCmdPushDescriptorSetKHR, commandBuffer,
templ->push.pipeline_bind_point, layout, set,
update.write_count, update.writes);
STACK_ARRAY_FINISH(writes);
STACK_ARRAY_FINISH(img_infos);
STACK_ARRAY_FINISH(buf_infos);
STACK_ARRAY_FINISH(bview_handles);
STACK_ARRAY_FINISH(iubs);
}
void
vn_CmdSetVertexInputEXT(
VkCommandBuffer commandBuffer,
uint32_t vertexBindingDescriptionCount,
const VkVertexInputBindingDescription2EXT *pVertexBindingDescriptions,
uint32_t vertexAttributeDescriptionCount,
const VkVertexInputAttributeDescription2EXT *pVertexAttributeDescriptions)
{
VN_CMD_ENQUEUE(vkCmdSetVertexInputEXT, commandBuffer,
vertexBindingDescriptionCount, pVertexBindingDescriptions,
vertexAttributeDescriptionCount,
pVertexAttributeDescriptions);
}
void
vn_CmdSetAlphaToCoverageEnableEXT(VkCommandBuffer commandBuffer,
VkBool32 alphaToCoverageEnable)
{
VN_CMD_ENQUEUE(vkCmdSetAlphaToCoverageEnableEXT, commandBuffer,
alphaToCoverageEnable);
}
void
vn_CmdSetAlphaToOneEnableEXT(VkCommandBuffer commandBuffer,
VkBool32 alphaToOneEnable)
{
VN_CMD_ENQUEUE(vkCmdSetAlphaToOneEnableEXT, commandBuffer,
alphaToOneEnable);
}
void
vn_CmdSetColorBlendAdvancedEXT(
VkCommandBuffer commandBuffer,
uint32_t firstAttachment,
uint32_t attachmentCount,
const VkColorBlendAdvancedEXT *pColorBlendAdvanced)
{
VN_CMD_ENQUEUE(vkCmdSetColorBlendAdvancedEXT, commandBuffer,
firstAttachment, attachmentCount, pColorBlendAdvanced);
}
void
vn_CmdSetColorBlendEnableEXT(VkCommandBuffer commandBuffer,
uint32_t firstAttachment,
uint32_t attachmentCount,
const VkBool32 *pColorBlendEnables)
{
VN_CMD_ENQUEUE(vkCmdSetColorBlendEnableEXT, commandBuffer, firstAttachment,
attachmentCount, pColorBlendEnables);
}
void
vn_CmdSetColorBlendEquationEXT(
VkCommandBuffer commandBuffer,
uint32_t firstAttachment,
uint32_t attachmentCount,
const VkColorBlendEquationEXT *pColorBlendEquations)
{
VN_CMD_ENQUEUE(vkCmdSetColorBlendEquationEXT, commandBuffer,
firstAttachment, attachmentCount, pColorBlendEquations);
}
void
vn_CmdSetColorWriteMaskEXT(VkCommandBuffer commandBuffer,
uint32_t firstAttachment,
uint32_t attachmentCount,
const VkColorComponentFlags *pColorWriteMasks)
{
VN_CMD_ENQUEUE(vkCmdSetColorWriteMaskEXT, commandBuffer, firstAttachment,
attachmentCount, pColorWriteMasks);
}
void
vn_CmdSetConservativeRasterizationModeEXT(
VkCommandBuffer commandBuffer,
VkConservativeRasterizationModeEXT conservativeRasterizationMode)
{
VN_CMD_ENQUEUE(vkCmdSetConservativeRasterizationModeEXT, commandBuffer,
conservativeRasterizationMode);
}
void
vn_CmdSetDepthClampEnableEXT(VkCommandBuffer commandBuffer,
VkBool32 depthClampEnable)
{
VN_CMD_ENQUEUE(vkCmdSetDepthClampEnableEXT, commandBuffer,
depthClampEnable);
}
void
vn_CmdSetDepthClipEnableEXT(VkCommandBuffer commandBuffer,
VkBool32 depthClipEnable)
{
VN_CMD_ENQUEUE(vkCmdSetDepthClipEnableEXT, commandBuffer, depthClipEnable);
}
void
vn_CmdSetDepthClipNegativeOneToOneEXT(VkCommandBuffer commandBuffer,
VkBool32 negativeOneToOne)
{
VN_CMD_ENQUEUE(vkCmdSetDepthClipNegativeOneToOneEXT, commandBuffer,
negativeOneToOne);
}
void
vn_CmdSetExtraPrimitiveOverestimationSizeEXT(
VkCommandBuffer commandBuffer, float extraPrimitiveOverestimationSize)
{
VN_CMD_ENQUEUE(vkCmdSetExtraPrimitiveOverestimationSizeEXT, commandBuffer,
extraPrimitiveOverestimationSize);
}
void
vn_CmdSetLineRasterizationModeEXT(
VkCommandBuffer commandBuffer,
VkLineRasterizationModeEXT lineRasterizationMode)
{
VN_CMD_ENQUEUE(vkCmdSetLineRasterizationModeEXT, commandBuffer,
lineRasterizationMode);
}
void
vn_CmdSetLineStippleEnableEXT(VkCommandBuffer commandBuffer,
VkBool32 stippledLineEnable)
{
VN_CMD_ENQUEUE(vkCmdSetLineStippleEnableEXT, commandBuffer,
stippledLineEnable);
}
void
vn_CmdSetLogicOpEnableEXT(VkCommandBuffer commandBuffer,
VkBool32 logicOpEnable)
{
VN_CMD_ENQUEUE(vkCmdSetLogicOpEnableEXT, commandBuffer, logicOpEnable);
}
void
vn_CmdSetPolygonModeEXT(VkCommandBuffer commandBuffer,
VkPolygonMode polygonMode)
{
VN_CMD_ENQUEUE(vkCmdSetPolygonModeEXT, commandBuffer, polygonMode);
}
void
vn_CmdSetProvokingVertexModeEXT(VkCommandBuffer commandBuffer,
VkProvokingVertexModeEXT provokingVertexMode)
{
VN_CMD_ENQUEUE(vkCmdSetProvokingVertexModeEXT, commandBuffer,
provokingVertexMode);
}
void
vn_CmdSetRasterizationSamplesEXT(VkCommandBuffer commandBuffer,
VkSampleCountFlagBits rasterizationSamples)
{
VN_CMD_ENQUEUE(vkCmdSetRasterizationSamplesEXT, commandBuffer,
rasterizationSamples);
}
void
vn_CmdSetRasterizationStreamEXT(VkCommandBuffer commandBuffer,
uint32_t rasterizationStream)
{
VN_CMD_ENQUEUE(vkCmdSetRasterizationStreamEXT, commandBuffer,
rasterizationStream);
}
void
vn_CmdSetSampleLocationsEnableEXT(VkCommandBuffer commandBuffer,
VkBool32 sampleLocationsEnable)
{
VN_CMD_ENQUEUE(vkCmdSetSampleLocationsEnableEXT, commandBuffer,
sampleLocationsEnable);
}
void
vn_CmdSetSampleMaskEXT(VkCommandBuffer commandBuffer,
VkSampleCountFlagBits samples,
const VkSampleMask *pSampleMask)
{
VN_CMD_ENQUEUE(vkCmdSetSampleMaskEXT, commandBuffer, samples, pSampleMask);
}
void
vn_CmdSetTessellationDomainOriginEXT(VkCommandBuffer commandBuffer,
VkTessellationDomainOrigin domainOrigin)
{
VN_CMD_ENQUEUE(vkCmdSetTessellationDomainOriginEXT, commandBuffer,
domainOrigin);
}
void
vn_CmdSetFragmentShadingRateKHR(
VkCommandBuffer commandBuffer,
const VkExtent2D *pFragmentSize,
const VkFragmentShadingRateCombinerOpKHR combinerOps[2])
{
VN_CMD_ENQUEUE(vkCmdSetFragmentShadingRateKHR, commandBuffer,
pFragmentSize, combinerOps);
}