| /* |
| * Copyright 2020 Google LLC |
| * SPDX-License-Identifier: MIT |
| */ |
| |
| #include "vkr_renderer.h" |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #include "c11/threads.h" |
| #include "pipe/p_state.h" |
| #include "util/u_double_list.h" |
| #include "util/u_hash_table.h" |
| #include "util/u_math.h" |
| #include "util/u_memory.h" |
| #include "util/u_pointer.h" |
| |
| #include "venus-protocol/vn_protocol_renderer.h" |
| #include "virgl_context.h" |
| #include "virgl_protocol.h" /* for transfer_mode */ |
| #include "virgl_resource.h" |
| #include "virgl_util.h" |
| #include "virglrenderer.h" |
| #include "virglrenderer_hw.h" |
| #include "vkr_cs.h" |
| #include "vkr_object.h" |
| #include "vkr_ring.h" |
| #include "vrend_debug.h" |
| #include "vrend_iov.h" |
| |
| /* |
| * TODO what extensions do we need from the host driver? |
| * |
| * We don't check vkGetPhysicalDeviceExternalBufferProperties, etc. yet. Even |
| * if we did, silently adding external memory info to vkCreateBuffer or |
| * vkCreateImage could change the results of vkGetBufferMemoryRequirements or |
| * vkGetImageMemoryRequirements and confuse the guest. |
| */ |
| #define FORCE_ENABLE_DMABUF |
| |
| /* |
| * TODO Most of the functions are generated. Some of them are then |
| * hand-edited. Find a better/cleaner way to reduce manual works. |
| */ |
| #define CREATE_OBJECT(obj, vkr_type, vk_obj, vk_cmd, vk_arg) \ |
| struct vkr_ ## vkr_type *obj = calloc(1, sizeof(*obj)); \ |
| if (!obj) { \ |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; \ |
| return; \ |
| } \ |
| obj->base.type = VK_OBJECT_TYPE_ ## vk_obj; \ |
| obj->base.id = vkr_cs_handle_load_id( \ |
| (const void **)args->vk_arg, obj->base.type); \ |
| \ |
| vn_replace_ ## vk_cmd ## _args_handle(args); \ |
| args->ret = vk_cmd(args->device, args->pCreateInfo, NULL, \ |
| &obj->base.handle.vkr_type); \ |
| if (args->ret != VK_SUCCESS) { \ |
| free(obj); \ |
| return; \ |
| } \ |
| (void)obj |
| |
| #define DESTROY_OBJECT(obj, vkr_type, vk_obj, vk_cmd, vk_arg) \ |
| struct vkr_ ## vkr_type *obj = \ |
| (struct vkr_ ## vkr_type *)(uintptr_t)args->vk_arg; \ |
| if (!obj || obj->base.type != VK_OBJECT_TYPE_ ## vk_obj) { \ |
| if (obj) \ |
| vkr_cs_decoder_set_fatal(&ctx->decoder); \ |
| return; \ |
| } \ |
| \ |
| vn_replace_ ## vk_cmd ## _args_handle(args); \ |
| vk_cmd(args->device, args->vk_arg, NULL) |
| |
| struct vkr_physical_device; |
| |
| struct vkr_instance { |
| struct vkr_object base; |
| |
| uint32_t api_version; |
| PFN_vkGetMemoryFdKHR get_memory_fd; |
| PFN_vkGetFenceFdKHR get_fence_fd; |
| |
| uint32_t physical_device_count; |
| VkPhysicalDevice *physical_device_handles; |
| struct vkr_physical_device **physical_devices; |
| }; |
| |
| struct vkr_physical_device { |
| struct vkr_object base; |
| |
| VkPhysicalDeviceProperties properties; |
| uint32_t api_version; |
| |
| VkExtensionProperties *extensions; |
| uint32_t extension_count; |
| |
| VkPhysicalDeviceMemoryProperties memory_properties; |
| |
| bool KHR_external_memory_fd; |
| bool EXT_external_memory_dma_buf; |
| |
| bool KHR_external_fence_fd; |
| }; |
| |
| struct vkr_queue_sync { |
| VkFence fence; |
| |
| uint32_t flags; |
| void *fence_cookie; |
| |
| struct list_head head; |
| }; |
| |
| struct vkr_device { |
| struct vkr_object base; |
| |
| struct vkr_physical_device *physical_device; |
| |
| /* Vulkan 1.2 */ |
| PFN_vkGetSemaphoreCounterValue GetSemaphoreCounterValue; |
| PFN_vkWaitSemaphores WaitSemaphores; |
| PFN_vkSignalSemaphore SignalSemaphore; |
| PFN_vkGetDeviceMemoryOpaqueCaptureAddress GetDeviceMemoryOpaqueCaptureAddress; |
| PFN_vkGetBufferOpaqueCaptureAddress GetBufferOpaqueCaptureAddress; |
| PFN_vkGetBufferDeviceAddress GetBufferDeviceAddress; |
| PFN_vkResetQueryPool ResetQueryPool; |
| PFN_vkCreateRenderPass2 CreateRenderPass2; |
| PFN_vkCmdBeginRenderPass2 CmdBeginRenderPass2; |
| PFN_vkCmdNextSubpass2 CmdNextSubpass2; |
| PFN_vkCmdEndRenderPass2 CmdEndRenderPass2; |
| PFN_vkCmdDrawIndirectCount CmdDrawIndirectCount; |
| PFN_vkCmdDrawIndexedIndirectCount CmdDrawIndexedIndirectCount; |
| |
| PFN_vkCmdBindTransformFeedbackBuffersEXT cmd_bind_transform_feedback_buffers; |
| PFN_vkCmdBeginTransformFeedbackEXT cmd_begin_transform_feedback; |
| PFN_vkCmdEndTransformFeedbackEXT cmd_end_transform_feedback; |
| PFN_vkCmdBeginQueryIndexedEXT cmd_begin_query_indexed; |
| PFN_vkCmdEndQueryIndexedEXT cmd_end_query_indexed; |
| PFN_vkCmdDrawIndirectByteCountEXT cmd_draw_indirect_byte_count; |
| |
| PFN_vkGetImageDrmFormatModifierPropertiesEXT get_image_drm_format_modifier_properties; |
| |
| PFN_vkGetMemoryFdPropertiesKHR get_memory_fd_properties; |
| |
| struct list_head queues; |
| |
| struct list_head free_syncs; |
| }; |
| |
| struct vkr_queue { |
| struct vkr_object base; |
| |
| struct vkr_device *device; |
| |
| uint32_t family; |
| uint32_t index; |
| |
| bool has_thread; |
| int eventfd; |
| thrd_t thread; |
| mtx_t mutex; |
| cnd_t cond; |
| bool join; |
| struct list_head pending_syncs; |
| struct list_head signaled_syncs; |
| |
| struct list_head head; |
| struct list_head busy_head; |
| }; |
| |
| struct vkr_device_memory { |
| struct vkr_object base; |
| |
| VkDevice device; |
| uint32_t property_flags; |
| uint32_t valid_fd_types; |
| |
| bool exported; |
| uint32_t exported_res_id; |
| struct list_head head; |
| }; |
| |
| struct vkr_fence { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_semaphore { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_buffer { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_buffer_view { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_image { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_image_view { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_sampler { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_sampler_ycbcr_conversion { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_descriptor_set_layout { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_descriptor_pool { |
| struct vkr_object base; |
| |
| struct list_head descriptor_sets; |
| }; |
| |
| struct vkr_descriptor_set { |
| struct vkr_object base; |
| |
| struct list_head head; |
| }; |
| |
| struct vkr_descriptor_update_template { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_render_pass { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_framebuffer { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_event { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_query_pool { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_shader_module { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_pipeline_layout { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_pipeline_cache { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_pipeline { |
| struct vkr_object base; |
| }; |
| |
| struct vkr_command_pool { |
| struct vkr_object base; |
| |
| struct list_head command_buffers; |
| }; |
| |
| struct vkr_command_buffer { |
| struct vkr_object base; |
| |
| struct vkr_device *device; |
| |
| struct list_head head; |
| }; |
| |
| /* |
| * When a virgl_resource is attached in vkr_context_attach_resource, a |
| * vkr_resource_attachment is created. A vkr_resource_attachment is valid |
| * until the resource it tracks is detached. |
| * |
| * To support transfers to resources not backed by coherent dma-bufs, we |
| * associate a vkr_resource_attachment with a (list of) vkr_device_memory. |
| * This way, we can find a vkr_device_memory from a vkr_resource_attachment |
| * and do transfers using VkDeviceMemory. |
| */ |
| struct vkr_resource_attachment { |
| struct virgl_resource *resource; |
| struct list_head memories; |
| }; |
| |
| struct vkr_context { |
| struct virgl_context base; |
| |
| char *debug_name; |
| |
| mtx_t mutex; |
| |
| struct list_head rings; |
| struct util_hash_table_u64 *object_table; |
| struct util_hash_table *resource_table; |
| struct list_head newly_exported_memories; |
| |
| struct vkr_cs_encoder encoder; |
| struct vkr_cs_decoder decoder; |
| struct vn_dispatch_context dispatch; |
| |
| int fence_eventfd; |
| struct list_head busy_queues; |
| |
| struct vkr_instance *instance; |
| }; |
| |
| static uint32_t vkr_renderer_flags; |
| |
| struct object_array { |
| uint32_t count; |
| void **objects; |
| void *handle_storage; |
| |
| /* true if the ownership of the objects has been transferred (to |
| * vkr_context::object_table) |
| */ |
| bool objects_stolen; |
| }; |
| |
| static void |
| object_array_fini(struct object_array *arr) |
| { |
| if (!arr->objects_stolen) { |
| for (uint32_t i = 0; i < arr->count; i++) |
| free(arr->objects[i]); |
| } |
| |
| free(arr->objects); |
| free(arr->handle_storage); |
| } |
| |
| static bool |
| object_array_init(struct object_array *arr, |
| uint32_t count, |
| VkObjectType obj_type, |
| size_t obj_size, |
| size_t handle_size, |
| const void *handles) |
| { |
| arr->count = count; |
| |
| arr->objects = malloc(sizeof(*arr->objects) * count); |
| if (!arr->objects) |
| return false; |
| |
| arr->handle_storage = malloc(handle_size * count); |
| if (!arr->handle_storage) { |
| free(arr->objects); |
| return false; |
| } |
| |
| arr->objects_stolen = false; |
| for (uint32_t i = 0; i < count; i++) { |
| struct vkr_object *obj = calloc(1, obj_size); |
| if (!obj) { |
| arr->count = i; |
| object_array_fini(arr); |
| return false; |
| } |
| |
| obj->type = obj_type; |
| obj->id = vkr_cs_handle_load_id( |
| (const void **)((char *)handles + handle_size * i), obj->type); |
| |
| arr->objects[i] = obj; |
| } |
| |
| return arr; |
| } |
| |
| static void |
| vkr_dispatch_vkSetReplyCommandStreamMESA(struct vn_dispatch_context *dispatch, struct vn_command_vkSetReplyCommandStreamMESA *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_resource_attachment *att; |
| |
| att = util_hash_table_get(ctx->resource_table, |
| uintptr_to_pointer(args->pStream->resourceId)); |
| if (!att) |
| return; |
| |
| vkr_cs_encoder_set_stream(&ctx->encoder, |
| att->resource->iov, |
| att->resource->iov_count, |
| args->pStream->offset, |
| args->pStream->size); |
| } |
| |
| static void |
| vkr_dispatch_vkSeekReplyCommandStreamMESA(struct vn_dispatch_context *dispatch, struct vn_command_vkSeekReplyCommandStreamMESA *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| vkr_cs_encoder_seek_stream(&ctx->encoder, args->position); |
| } |
| |
| static void * |
| copy_command_stream(struct vkr_context *ctx, |
| const VkCommandStreamDescriptionMESA *stream) |
| { |
| struct vkr_resource_attachment *att; |
| struct virgl_resource *res; |
| |
| att = util_hash_table_get(ctx->resource_table, |
| uintptr_to_pointer(stream->resourceId)); |
| if (!att) |
| return NULL; |
| res = att->resource; |
| |
| /* seek to offset */ |
| size_t iov_offset = stream->offset; |
| const struct iovec *iov = NULL; |
| for (int i = 0; i < res->iov_count; i++) { |
| if (iov_offset < res->iov[i].iov_len) { |
| iov = &res->iov[i]; |
| break; |
| } |
| iov_offset -= res->iov[i].iov_len; |
| } |
| if (!iov) |
| return NULL; |
| |
| /* XXX until the decoder supports scatter-gather and is robust enough, |
| * always make a copy in case the caller modifies the commands while we |
| * parse |
| */ |
| uint8_t *data = malloc(stream->size); |
| if (!data) |
| return NULL; |
| |
| uint32_t copied = 0; |
| while (true) { |
| const size_t s = MIN2(stream->size - copied, iov->iov_len - iov_offset); |
| memcpy(data + copied, (const uint8_t *)iov->iov_base + iov_offset, s); |
| |
| copied += s; |
| if (copied == stream->size) { |
| break; |
| } else if (iov == &res->iov[res->iov_count - 1]) { |
| free(data); |
| return NULL; |
| } |
| |
| iov++; |
| iov_offset = 0; |
| } |
| |
| return data; |
| } |
| |
| static void |
| vkr_dispatch_vkExecuteCommandStreamsMESA(struct vn_dispatch_context *dispatch, struct vn_command_vkExecuteCommandStreamsMESA *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| /* note that nested vkExecuteCommandStreamsMESA is not allowed */ |
| if (!vkr_cs_decoder_push_state(&ctx->decoder)) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| for (uint32_t i = 0; i < args->streamCount; i++) { |
| const VkCommandStreamDescriptionMESA *stream = &args->pStreams[i]; |
| |
| if (args->pReplyPositions) |
| vkr_cs_encoder_seek_stream(&ctx->encoder, args->pReplyPositions[i]); |
| |
| if (!stream->size) |
| continue; |
| |
| void *data = copy_command_stream(ctx, stream); |
| if (!data) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| break; |
| } |
| |
| vkr_cs_decoder_set_stream(&ctx->decoder, data, stream->size); |
| while (vkr_cs_decoder_has_command(&ctx->decoder)) { |
| vn_dispatch_command(&ctx->dispatch); |
| if (vkr_cs_decoder_get_fatal(&ctx->decoder)) |
| break; |
| } |
| |
| free(data); |
| |
| if (vkr_cs_decoder_get_fatal(&ctx->decoder)) |
| break; |
| } |
| |
| vkr_cs_decoder_pop_state(&ctx->decoder); |
| } |
| |
| static struct vkr_ring * |
| lookup_ring(struct vkr_context *ctx, uint64_t ring_id) |
| { |
| struct vkr_ring *ring; |
| LIST_FOR_EACH_ENTRY(ring, &ctx->rings, head) { |
| if (ring->id == ring_id) |
| return ring; |
| } |
| return NULL; |
| } |
| |
| static void |
| vkr_dispatch_vkCreateRingMESA(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateRingMESA *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| const VkRingCreateInfoMESA *info = args->pCreateInfo; |
| const struct vkr_resource_attachment *att; |
| uint8_t *shared; |
| size_t size; |
| struct vkr_ring *ring; |
| |
| att = util_hash_table_get(ctx->resource_table, |
| uintptr_to_pointer(info->resourceId)); |
| if (!att) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| /* TODO support scatter-gather or require logically contiguous resources */ |
| if (att->resource->iov_count != 1) { |
| vrend_printf("vkr: no scatter-gather support for ring buffers (TODO)"); |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| shared = att->resource->iov[0].iov_base; |
| size = att->resource->iov[0].iov_len; |
| if (info->offset > size || info->size > size - info->offset) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| shared += info->offset; |
| size = info->size; |
| if (info->headOffset > size || |
| info->tailOffset > size || |
| info->statusOffset > size || |
| info->bufferOffset > size || |
| info->extraOffset > size) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| if (sizeof(uint32_t) > size - info->headOffset || |
| sizeof(uint32_t) > size - info->tailOffset || |
| sizeof(uint32_t) > size - info->statusOffset || |
| info->bufferSize > size - info->bufferOffset || |
| info->extraSize > size - info->extraOffset) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| if (!info->bufferSize || !util_is_power_of_two(info->bufferSize)) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| const struct vkr_ring_layout layout = { |
| .head_offset = info->headOffset, |
| .tail_offset = info->tailOffset, |
| .status_offset = info->statusOffset, |
| .buffer_offset = info->bufferOffset, |
| .buffer_size = info->bufferSize, |
| .extra_offset = info->extraOffset, |
| .extra_size = info->extraSize, |
| }; |
| |
| ring = vkr_ring_create(&layout, shared, &ctx->base, info->idleTimeout); |
| if (!ring) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| ring->id = args->ring; |
| list_addtail(&ring->head, &ctx->rings); |
| |
| vkr_ring_start(ring); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyRingMESA(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyRingMESA *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_ring *ring = lookup_ring(ctx, args->ring); |
| if (!ring || !vkr_ring_stop(ring)) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| list_del(&ring->head); |
| vkr_ring_destroy(ring); |
| } |
| |
| static void |
| vkr_dispatch_vkNotifyRingMESA(struct vn_dispatch_context *dispatch, struct vn_command_vkNotifyRingMESA *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_ring *ring = lookup_ring(ctx, args->ring); |
| if (!ring) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vkr_ring_notify(ring); |
| } |
| |
| static void |
| vkr_dispatch_vkWriteRingExtraMESA(struct vn_dispatch_context *dispatch, struct vn_command_vkWriteRingExtraMESA *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_ring *ring = lookup_ring(ctx, args->ring); |
| if (!ring) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| if (!vkr_ring_write_extra(ring, args->offset, args->value)) |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| } |
| |
| static void |
| vkr_dispatch_vkEnumerateInstanceVersion(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkEnumerateInstanceVersion *args) |
| { |
| vn_replace_vkEnumerateInstanceVersion_args_handle(args); |
| args->ret = vkEnumerateInstanceVersion(args->pApiVersion); |
| } |
| |
| static void |
| vkr_dispatch_vkEnumerateInstanceExtensionProperties(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkEnumerateInstanceExtensionProperties *args) |
| { |
| VkExtensionProperties private_extensions[] = { |
| { |
| .extensionName = "VK_EXT_command_serialization", |
| }, |
| { |
| .extensionName = "VK_MESA_venus_protocol", |
| }, |
| }; |
| |
| if (!args->pProperties) { |
| *args->pPropertyCount = ARRAY_SIZE(private_extensions); |
| args->ret = VK_SUCCESS; |
| return; |
| } |
| |
| for (uint32_t i = 0; i < ARRAY_SIZE(private_extensions); i++) { |
| VkExtensionProperties *props = &private_extensions[i]; |
| props->specVersion = vn_info_extension_spec_version(props->extensionName); |
| } |
| |
| const uint32_t count = |
| MIN2(*args->pPropertyCount, ARRAY_SIZE(private_extensions)); |
| memcpy(args->pProperties, private_extensions, sizeof(*args->pProperties) * count); |
| *args->pPropertyCount = count; |
| args->ret = count == ARRAY_SIZE(private_extensions) ? VK_SUCCESS : VK_INCOMPLETE; |
| } |
| |
| static void |
| vkr_dispatch_vkCreateInstance(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateInstance *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| if (ctx->instance) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| if (args->pCreateInfo->enabledExtensionCount) { |
| args->ret = VK_ERROR_EXTENSION_NOT_PRESENT; |
| return; |
| } |
| |
| struct vkr_instance *instance = calloc(1, sizeof(*instance)); |
| if (!instance) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| return; |
| } |
| |
| uint32_t instance_version; |
| args->ret = vkEnumerateInstanceVersion(&instance_version); |
| if (args->ret != VK_SUCCESS) { |
| free(instance); |
| return; |
| } |
| |
| /* require Vulkan 1.1 */ |
| if (instance_version < VK_API_VERSION_1_1) { |
| args->ret = VK_ERROR_INITIALIZATION_FAILED; |
| return; |
| } |
| |
| VkApplicationInfo app_info = { |
| .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, |
| .apiVersion = VK_API_VERSION_1_1, |
| }; |
| if (args->pCreateInfo->pApplicationInfo) { |
| app_info = *args->pCreateInfo->pApplicationInfo; |
| if (app_info.apiVersion < VK_API_VERSION_1_1) |
| app_info.apiVersion = VK_API_VERSION_1_1; |
| } |
| ((VkInstanceCreateInfo *)args->pCreateInfo)->pApplicationInfo = &app_info; |
| |
| instance->base.type = VK_OBJECT_TYPE_INSTANCE; |
| instance->base.id = vkr_cs_handle_load_id((const void **)args->pInstance, |
| instance->base.type); |
| instance->api_version = app_info.apiVersion; |
| |
| vn_replace_vkCreateInstance_args_handle(args); |
| args->ret = vkCreateInstance(args->pCreateInfo, NULL, &instance->base.handle.instance); |
| if (args->ret != VK_SUCCESS) { |
| free(instance); |
| return; |
| } |
| |
| instance->get_memory_fd = (PFN_vkGetMemoryFdKHR) |
| vkGetInstanceProcAddr(instance->base.handle.instance, "vkGetMemoryFdKHR"); |
| instance->get_fence_fd = (PFN_vkGetFenceFdKHR) |
| vkGetInstanceProcAddr(instance->base.handle.instance, "vkGetFenceFdKHR"); |
| |
| util_hash_table_set_u64(ctx->object_table, instance->base.id, instance); |
| |
| ctx->instance = instance; |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyInstance(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyInstance *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_instance *instance = (struct vkr_instance *)args->instance; |
| |
| if (ctx->instance != instance) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkDestroyInstance_args_handle(args); |
| vkDestroyInstance(args->instance, NULL); |
| |
| /* TODO cleanup all objects instead? */ |
| for (uint32_t i = 0; i < instance->physical_device_count; i++) { |
| struct vkr_physical_device *physical_dev = instance->physical_devices[i]; |
| if (!physical_dev) |
| break; |
| free(physical_dev->extensions); |
| util_hash_table_remove_u64(ctx->object_table, physical_dev->base.id); |
| } |
| free(instance->physical_device_handles); |
| free(instance->physical_devices); |
| |
| util_hash_table_remove_u64(ctx->object_table, instance->base.id); |
| |
| ctx->instance = NULL; |
| } |
| |
| static VkResult |
| vkr_instance_enumerate_physical_devices(struct vkr_instance *instance) |
| { |
| if (instance->physical_device_count) |
| return VK_SUCCESS; |
| |
| uint32_t count; |
| VkResult result = vkEnumeratePhysicalDevices(instance->base.handle.instance, &count, NULL); |
| if (result != VK_SUCCESS) |
| return result; |
| |
| VkPhysicalDevice *handles = calloc(count, sizeof(*handles)); |
| struct vkr_physical_device **physical_devs = calloc(count, sizeof(*physical_devs)); |
| if (!handles || !physical_devs) { |
| free(physical_devs); |
| free(handles); |
| return VK_ERROR_OUT_OF_HOST_MEMORY; |
| } |
| |
| result = vkEnumeratePhysicalDevices(instance->base.handle.instance, &count, handles); |
| if (result != VK_SUCCESS) { |
| free(physical_devs); |
| free(handles); |
| return result; |
| } |
| |
| instance->physical_device_count = count; |
| instance->physical_device_handles = handles; |
| instance->physical_devices = physical_devs; |
| |
| return VK_SUCCESS; |
| } |
| |
| static struct vkr_physical_device * |
| vkr_instance_lookup_physical_device(struct vkr_instance *instance, VkPhysicalDevice handle) |
| { |
| for (uint32_t i = 0; i < instance->physical_device_count; i++) { |
| /* XXX this assumes VkPhysicalDevice handles are unique */ |
| if (instance->physical_device_handles[i] == handle) |
| return instance->physical_devices[i]; |
| } |
| return NULL; |
| } |
| |
| static void |
| vkr_physical_device_init_memory_properties(struct vkr_physical_device *physical_dev) |
| { |
| VkPhysicalDevice handle = physical_dev->base.handle.physical_device; |
| vkGetPhysicalDeviceMemoryProperties(handle, &physical_dev->memory_properties); |
| } |
| |
| static void |
| vkr_physical_device_init_extensions(struct vkr_physical_device *physical_dev) |
| { |
| VkPhysicalDevice handle = physical_dev->base.handle.physical_device; |
| |
| VkExtensionProperties *exts; |
| uint32_t count; |
| VkResult result = vkEnumerateDeviceExtensionProperties(handle, NULL, &count, NULL); |
| if (result != VK_SUCCESS) |
| return; |
| |
| exts = malloc(sizeof(*exts) * count); |
| if (!exts) |
| return; |
| |
| result = vkEnumerateDeviceExtensionProperties(handle, NULL, &count, exts); |
| if (result != VK_SUCCESS) { |
| free(exts); |
| return; |
| } |
| |
| uint32_t advertised_count = 0; |
| for (uint32_t i = 0; i < count; i++) { |
| VkExtensionProperties *props = &exts[i]; |
| |
| if (!strcmp(props->extensionName, "VK_KHR_external_memory_fd")) |
| physical_dev->KHR_external_memory_fd = true; |
| else if (!strcmp(props->extensionName, "VK_EXT_external_memory_dma_buf")) |
| physical_dev->EXT_external_memory_dma_buf = true; |
| else if (!strcmp(props->extensionName, "VK_KHR_external_fence_fd")) |
| physical_dev->KHR_external_fence_fd = true; |
| |
| const uint32_t spec_ver = vn_info_extension_spec_version(props->extensionName); |
| if (spec_ver) { |
| if (props->specVersion > spec_ver) |
| props->specVersion = spec_ver; |
| exts[advertised_count++] = exts[i]; |
| } |
| } |
| |
| physical_dev->extensions = exts; |
| physical_dev->extension_count = advertised_count; |
| } |
| |
| static void |
| vkr_physical_device_init_properties(struct vkr_physical_device *physical_dev) |
| { |
| VkPhysicalDevice handle = physical_dev->base.handle.physical_device; |
| vkGetPhysicalDeviceProperties(handle, &physical_dev->properties); |
| |
| VkPhysicalDeviceProperties *props = &physical_dev->properties; |
| props->driverVersion = 0; |
| props->vendorID = 0; |
| props->deviceID = 0; |
| props->deviceType = VK_PHYSICAL_DEVICE_TYPE_OTHER; |
| memset(props->deviceName, 0, sizeof(props->deviceName)); |
| |
| /* TODO lie about props->pipelineCacheUUID and patch cache header */ |
| } |
| |
| static void |
| vkr_dispatch_vkEnumeratePhysicalDevices(struct vn_dispatch_context *dispatch, struct vn_command_vkEnumeratePhysicalDevices *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_instance *instance = (struct vkr_instance *)args->instance; |
| if (instance != ctx->instance) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| args->ret = vkr_instance_enumerate_physical_devices(instance); |
| if (args->ret != VK_SUCCESS) |
| return; |
| |
| uint32_t count = instance->physical_device_count; |
| if (!args->pPhysicalDevices) { |
| *args->pPhysicalDeviceCount = count; |
| args->ret = VK_SUCCESS; |
| return; |
| } |
| |
| if (count > *args->pPhysicalDeviceCount) { |
| count = *args->pPhysicalDeviceCount; |
| args->ret = VK_INCOMPLETE; |
| } else { |
| *args->pPhysicalDeviceCount = count; |
| args->ret = VK_SUCCESS; |
| } |
| |
| uint32_t i; |
| for (i = 0; i < count; i++) { |
| struct vkr_physical_device *physical_dev = instance->physical_devices[i]; |
| const vkr_object_id id = vkr_cs_handle_load_id( |
| (const void **)&args->pPhysicalDevices[i], |
| VK_OBJECT_TYPE_PHYSICAL_DEVICE); |
| |
| if (physical_dev) { |
| if (physical_dev->base.id != id) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| break; |
| } |
| continue; |
| } |
| |
| physical_dev = calloc(1, sizeof(*physical_dev)); |
| if (!physical_dev) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| break; |
| } |
| |
| physical_dev->base.type = VK_OBJECT_TYPE_PHYSICAL_DEVICE; |
| physical_dev->base.id = id; |
| physical_dev->base.handle.physical_device = instance->physical_device_handles[i]; |
| |
| vkr_physical_device_init_properties(physical_dev); |
| physical_dev->api_version = MIN2(physical_dev->properties.apiVersion, |
| instance->api_version); |
| vkr_physical_device_init_extensions(physical_dev); |
| vkr_physical_device_init_memory_properties(physical_dev); |
| |
| instance->physical_devices[i] = physical_dev; |
| |
| util_hash_table_set_u64(ctx->object_table, physical_dev->base.id, physical_dev); |
| } |
| /* remove all physical devices on errors */ |
| if (i < count) { |
| for (i = 0; i < instance->physical_device_count; i++) { |
| struct vkr_physical_device *physical_dev = instance->physical_devices[i]; |
| if (!physical_dev) |
| break; |
| free(physical_dev->extensions); |
| util_hash_table_remove_u64(ctx->object_table, physical_dev->base.id); |
| instance->physical_devices[i] = NULL; |
| } |
| } |
| } |
| |
| static void |
| vkr_dispatch_vkEnumeratePhysicalDeviceGroups(struct vn_dispatch_context *dispatch, struct vn_command_vkEnumeratePhysicalDeviceGroups *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_instance *instance = (struct vkr_instance *)args->instance; |
| if (instance != ctx->instance) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| args->ret = vkr_instance_enumerate_physical_devices(instance); |
| if (args->ret != VK_SUCCESS) |
| return; |
| |
| VkPhysicalDeviceGroupProperties *orig_props = args->pPhysicalDeviceGroupProperties; |
| if (orig_props) { |
| args->pPhysicalDeviceGroupProperties = |
| malloc(sizeof(*orig_props) * *args->pPhysicalDeviceGroupCount); |
| if (!args->pPhysicalDeviceGroupProperties) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| return; |
| } |
| } |
| |
| vn_replace_vkEnumeratePhysicalDeviceGroups_args_handle(args); |
| args->ret = vkEnumeratePhysicalDeviceGroups(args->instance, args->pPhysicalDeviceGroupCount, args->pPhysicalDeviceGroupProperties); |
| if (args->ret != VK_SUCCESS) |
| return; |
| |
| if (!orig_props) |
| return; |
| |
| /* XXX this assumes vkEnumeratePhysicalDevices is called first */ |
| /* replace VkPhysicalDevice handles by object ids */ |
| for (uint32_t i = 0; i < *args->pPhysicalDeviceGroupCount; i++) { |
| const VkPhysicalDeviceGroupProperties *props = &args->pPhysicalDeviceGroupProperties[i]; |
| VkPhysicalDeviceGroupProperties *out = &orig_props[i]; |
| |
| out->physicalDeviceCount = props->physicalDeviceCount; |
| out->subsetAllocation = props->subsetAllocation; |
| for (uint32_t j = 0; j < props->physicalDeviceCount; j++) { |
| const struct vkr_physical_device *physical_dev = |
| vkr_instance_lookup_physical_device(instance, props->physicalDevices[j]); |
| vkr_cs_handle_store_id((void **)&out->physicalDevices[j], physical_dev->base.id, |
| VK_OBJECT_TYPE_PHYSICAL_DEVICE); |
| } |
| } |
| |
| free(args->pPhysicalDeviceGroupProperties); |
| args->pPhysicalDeviceGroupProperties = orig_props; |
| } |
| |
| static void |
| vkr_dispatch_vkEnumerateDeviceExtensionProperties(struct vn_dispatch_context *dispatch, struct vn_command_vkEnumerateDeviceExtensionProperties *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_physical_device *physical_dev = (struct vkr_physical_device *)args->physicalDevice; |
| if (!physical_dev || physical_dev->base.type != VK_OBJECT_TYPE_PHYSICAL_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| if (args->pLayerName) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| if (!args->pProperties) { |
| *args->pPropertyCount = physical_dev->extension_count; |
| args->ret = VK_SUCCESS; |
| return; |
| } |
| |
| uint32_t count = physical_dev->extension_count; |
| if (count > *args->pPropertyCount) { |
| count = *args->pPropertyCount; |
| args->ret = VK_INCOMPLETE; |
| } else { |
| *args->pPropertyCount = count; |
| args->ret = VK_SUCCESS; |
| } |
| |
| memcpy(args->pProperties, physical_dev->extensions, sizeof(*args->pProperties) * count); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceFeatures(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceFeatures *args) |
| { |
| vn_replace_vkGetPhysicalDeviceFeatures_args_handle(args); |
| vkGetPhysicalDeviceFeatures(args->physicalDevice, args->pFeatures); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceProperties(struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceProperties *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_physical_device *physical_dev = (struct vkr_physical_device *)args->physicalDevice; |
| if (!physical_dev || physical_dev->base.type != VK_OBJECT_TYPE_PHYSICAL_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| *args->pProperties = physical_dev->properties; |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceQueueFamilyProperties(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceQueueFamilyProperties *args) |
| { |
| vn_replace_vkGetPhysicalDeviceQueueFamilyProperties_args_handle(args); |
| vkGetPhysicalDeviceQueueFamilyProperties(args->physicalDevice, args->pQueueFamilyPropertyCount, args->pQueueFamilyProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceMemoryProperties(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceMemoryProperties *args) |
| { |
| /* TODO lie about this */ |
| vn_replace_vkGetPhysicalDeviceMemoryProperties_args_handle(args); |
| vkGetPhysicalDeviceMemoryProperties(args->physicalDevice, args->pMemoryProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceFormatProperties(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceFormatProperties *args) |
| { |
| vn_replace_vkGetPhysicalDeviceFormatProperties_args_handle(args); |
| vkGetPhysicalDeviceFormatProperties(args->physicalDevice, args->format, args->pFormatProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceImageFormatProperties(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceImageFormatProperties *args) |
| { |
| vn_replace_vkGetPhysicalDeviceImageFormatProperties_args_handle(args); |
| args->ret = vkGetPhysicalDeviceImageFormatProperties(args->physicalDevice, args->format, args->type, args->tiling, args->usage, args->flags, args->pImageFormatProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceSparseImageFormatProperties(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceSparseImageFormatProperties *args) |
| { |
| vn_replace_vkGetPhysicalDeviceSparseImageFormatProperties_args_handle(args); |
| vkGetPhysicalDeviceSparseImageFormatProperties(args->physicalDevice, args->format, args->type, args->samples, args->usage, args->tiling, args->pPropertyCount, args->pProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceFeatures2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceFeatures2 *args) |
| { |
| vn_replace_vkGetPhysicalDeviceFeatures2_args_handle(args); |
| vkGetPhysicalDeviceFeatures2(args->physicalDevice, args->pFeatures); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceProperties2(struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceProperties2 *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_physical_device *physical_dev = (struct vkr_physical_device *)args->physicalDevice; |
| if (!physical_dev || physical_dev->base.type != VK_OBJECT_TYPE_PHYSICAL_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkGetPhysicalDeviceProperties2_args_handle(args); |
| vkGetPhysicalDeviceProperties2(args->physicalDevice, args->pProperties); |
| |
| union { |
| VkBaseOutStructure *pnext; |
| VkPhysicalDeviceProperties2 *props; |
| VkPhysicalDeviceVulkan11Properties *vk11; |
| VkPhysicalDeviceVulkan12Properties *vk12; |
| VkPhysicalDeviceIDProperties *id; |
| VkPhysicalDeviceDriverProperties *driver; |
| } u; |
| |
| u.pnext = (VkBaseOutStructure *)args->pProperties; |
| while (u.pnext) { |
| switch (u.pnext->sType) { |
| case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2: |
| u.props->properties = physical_dev->properties; |
| break; |
| case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES: |
| memset(u.vk11->deviceUUID, 0, sizeof(u.vk11->deviceUUID)); |
| memset(u.vk11->driverUUID, 0, sizeof(u.vk11->driverUUID)); |
| memset(u.vk11->deviceLUID, 0, sizeof(u.vk11->deviceLUID)); |
| u.vk11->deviceNodeMask = 0; |
| u.vk11->deviceLUIDValid = false; |
| break; |
| case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_PROPERTIES: |
| u.vk12->driverID = 0; |
| memset(u.vk12->driverName, 0, sizeof(u.vk12->driverName)); |
| memset(u.vk12->driverInfo, 0, sizeof(u.vk12->driverInfo)); |
| memset(&u.vk12->conformanceVersion, 0, sizeof(u.vk12->conformanceVersion)); |
| break; |
| case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES: |
| memset(u.id->deviceUUID, 0, sizeof(u.id->deviceUUID)); |
| memset(u.id->driverUUID, 0, sizeof(u.id->driverUUID)); |
| memset(u.id->deviceLUID, 0, sizeof(u.id->deviceLUID)); |
| u.id->deviceNodeMask = 0; |
| u.id->deviceLUIDValid = false; |
| break; |
| case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES: |
| u.driver->driverID = 0; |
| memset(u.driver->driverName, 0, sizeof(u.driver->driverName)); |
| memset(u.driver->driverInfo, 0, sizeof(u.driver->driverInfo)); |
| memset(&u.driver->conformanceVersion, 0, sizeof(u.driver->conformanceVersion)); |
| break; |
| default: |
| break; |
| } |
| |
| u.pnext = u.pnext->pNext; |
| } |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceQueueFamilyProperties2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceQueueFamilyProperties2 *args) |
| { |
| vn_replace_vkGetPhysicalDeviceQueueFamilyProperties2_args_handle(args); |
| vkGetPhysicalDeviceQueueFamilyProperties2(args->physicalDevice, args->pQueueFamilyPropertyCount, args->pQueueFamilyProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceMemoryProperties2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceMemoryProperties2 *args) |
| { |
| /* TODO lie about this */ |
| vn_replace_vkGetPhysicalDeviceMemoryProperties2_args_handle(args); |
| vkGetPhysicalDeviceMemoryProperties2(args->physicalDevice, args->pMemoryProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceFormatProperties2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceFormatProperties2 *args) |
| { |
| vn_replace_vkGetPhysicalDeviceFormatProperties2_args_handle(args); |
| vkGetPhysicalDeviceFormatProperties2(args->physicalDevice, args->format, args->pFormatProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceImageFormatProperties2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceImageFormatProperties2 *args) |
| { |
| vn_replace_vkGetPhysicalDeviceImageFormatProperties2_args_handle(args); |
| args->ret = vkGetPhysicalDeviceImageFormatProperties2(args->physicalDevice, args->pImageFormatInfo, args->pImageFormatProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPhysicalDeviceSparseImageFormatProperties2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPhysicalDeviceSparseImageFormatProperties2 *args) |
| { |
| vn_replace_vkGetPhysicalDeviceSparseImageFormatProperties2_args_handle(args); |
| vkGetPhysicalDeviceSparseImageFormatProperties2(args->physicalDevice, args->pFormatInfo, args->pPropertyCount, args->pProperties); |
| } |
| |
| static void |
| vkr_queue_retire_syncs(struct vkr_queue *queue, |
| struct list_head *retired_syncs, |
| bool *queue_empty) |
| { |
| struct vkr_device *dev = queue->device; |
| struct vkr_queue_sync *sync, *tmp; |
| |
| list_inithead(retired_syncs); |
| |
| if (queue->has_thread) { |
| mtx_lock(&queue->mutex); |
| |
| LIST_FOR_EACH_ENTRY_SAFE(sync, tmp, &queue->signaled_syncs, head) { |
| if (sync->head.next == &queue->signaled_syncs || |
| !(sync->flags & VIRGL_RENDERER_FENCE_FLAG_MERGEABLE)) |
| list_addtail(&sync->head, retired_syncs); |
| else |
| list_addtail(&sync->head, &dev->free_syncs); |
| } |
| list_inithead(&queue->signaled_syncs); |
| |
| *queue_empty = LIST_IS_EMPTY(&queue->pending_syncs); |
| |
| mtx_unlock(&queue->mutex); |
| } else { |
| LIST_FOR_EACH_ENTRY_SAFE(sync, tmp, &queue->pending_syncs, head) { |
| VkResult result = vkGetFenceStatus(dev->base.handle.device, sync->fence); |
| if (result == VK_NOT_READY) |
| break; |
| |
| list_del(&sync->head); |
| if (sync->head.next == &queue->pending_syncs || |
| !(sync->flags & VIRGL_RENDERER_FENCE_FLAG_MERGEABLE)) |
| list_addtail(&sync->head, retired_syncs); |
| else |
| list_addtail(&sync->head, &dev->free_syncs); |
| } |
| |
| *queue_empty = LIST_IS_EMPTY(&queue->pending_syncs); |
| } |
| } |
| |
| static int |
| vkr_queue_thread(void *arg) |
| { |
| struct vkr_queue *queue = arg; |
| struct vkr_device *dev = queue->device; |
| const uint64_t ns_per_sec = 1000000000llu; |
| |
| mtx_lock(&queue->mutex); |
| while (true) { |
| while (LIST_IS_EMPTY(&queue->pending_syncs) && !queue->join) |
| cnd_wait(&queue->cond, &queue->mutex); |
| |
| if (queue->join) |
| break; |
| |
| struct vkr_queue_sync *sync = |
| LIST_ENTRY(struct vkr_queue_sync, queue->pending_syncs.next, head); |
| |
| mtx_unlock(&queue->mutex); |
| |
| VkResult result = vkWaitForFences(dev->base.handle.device, 1, &sync->fence, |
| false, ns_per_sec * 3); |
| |
| mtx_lock(&queue->mutex); |
| |
| if (result != VK_TIMEOUT) { |
| list_del(&sync->head); |
| list_addtail(&sync->head, &queue->signaled_syncs); |
| write_eventfd(queue->eventfd, 1); |
| } |
| } |
| mtx_unlock(&queue->mutex); |
| |
| return 0; |
| } |
| |
| static void |
| vkr_queue_destroy(struct vkr_context *ctx, |
| struct vkr_queue *queue) |
| { |
| struct vkr_queue_sync *sync, *tmp; |
| |
| if (queue->has_thread) { |
| mtx_lock(&queue->mutex); |
| queue->join = true; |
| mtx_unlock(&queue->mutex); |
| |
| cnd_signal(&queue->cond); |
| thrd_join(queue->thread, NULL); |
| |
| LIST_FOR_EACH_ENTRY_SAFE(sync, tmp, &queue->signaled_syncs, head) |
| list_addtail(&sync->head, &queue->device->free_syncs); |
| } else { |
| assert(LIST_IS_EMPTY(&queue->signaled_syncs)); |
| } |
| |
| LIST_FOR_EACH_ENTRY_SAFE(sync, tmp, &queue->pending_syncs, head) |
| list_addtail(&sync->head, &queue->device->free_syncs); |
| |
| mtx_destroy(&queue->mutex); |
| cnd_destroy(&queue->cond); |
| |
| list_del(&queue->head); |
| list_del(&queue->busy_head); |
| |
| util_hash_table_remove_u64(ctx->object_table, queue->base.id); |
| } |
| |
| static struct vkr_queue * |
| vkr_queue_create(struct vkr_context *ctx, |
| struct vkr_device *dev, |
| vkr_object_id id, |
| VkQueue handle, |
| uint32_t family, |
| uint32_t index) |
| { |
| struct vkr_queue *queue; |
| int ret; |
| |
| LIST_FOR_EACH_ENTRY(queue, &dev->queues, head) { |
| if (queue->family == family && queue->index == index) |
| return queue; |
| } |
| |
| queue = calloc(1, sizeof(*queue)); |
| if (!queue) |
| return NULL; |
| |
| queue->base.type = VK_OBJECT_TYPE_QUEUE; |
| queue->base.id = id; |
| queue->base.handle.queue = handle; |
| |
| queue->device = dev; |
| queue->family = family; |
| queue->index = index; |
| |
| list_inithead(&queue->pending_syncs); |
| list_inithead(&queue->signaled_syncs); |
| |
| ret = mtx_init(&queue->mutex, mtx_plain); |
| if (ret != thrd_success) { |
| free(queue); |
| return NULL; |
| } |
| ret = cnd_init(&queue->cond); |
| if (ret != thrd_success) { |
| mtx_destroy(&queue->mutex); |
| free(queue); |
| return NULL; |
| } |
| |
| if (ctx->fence_eventfd >= 0) { |
| ret = thrd_create(&queue->thread, vkr_queue_thread, queue); |
| if (ret != thrd_success) { |
| mtx_destroy(&queue->mutex); |
| cnd_destroy(&queue->cond); |
| free(queue); |
| return NULL; |
| } |
| queue->has_thread = true; |
| queue->eventfd = ctx->fence_eventfd; |
| } |
| |
| list_addtail(&queue->head, &dev->queues); |
| list_inithead(&queue->busy_head); |
| |
| util_hash_table_set_u64(ctx->object_table, queue->base.id, queue); |
| |
| return queue; |
| } |
| |
| static void |
| vkr_dispatch_vkCreateDevice(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateDevice *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_physical_device *physical_dev = (struct vkr_physical_device *)args->physicalDevice; |
| if (!physical_dev || physical_dev->base.type != VK_OBJECT_TYPE_PHYSICAL_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| /* append extensions for our own use */ |
| const char **exts = NULL; |
| uint32_t ext_count = args->pCreateInfo->enabledExtensionCount; |
| ext_count += physical_dev->KHR_external_memory_fd; |
| ext_count += physical_dev->EXT_external_memory_dma_buf; |
| ext_count += physical_dev->KHR_external_fence_fd; |
| if (ext_count > args->pCreateInfo->enabledExtensionCount) { |
| exts = malloc(sizeof(*exts) * ext_count); |
| if (!exts) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| return; |
| } |
| for (uint32_t i = 0; i < args->pCreateInfo->enabledExtensionCount; i++) |
| exts[i] = args->pCreateInfo->ppEnabledExtensionNames[i]; |
| |
| ext_count = args->pCreateInfo->enabledExtensionCount; |
| if (physical_dev->KHR_external_memory_fd) |
| exts[ext_count++] = "VK_KHR_external_memory_fd"; |
| if (physical_dev->EXT_external_memory_dma_buf) |
| exts[ext_count++] = "VK_EXT_external_memory_dma_buf"; |
| if (physical_dev->KHR_external_fence_fd) |
| exts[ext_count++] = "VK_KHR_external_fence_fd"; |
| |
| ((VkDeviceCreateInfo *)args->pCreateInfo)->ppEnabledExtensionNames = exts; |
| ((VkDeviceCreateInfo *)args->pCreateInfo)->enabledExtensionCount = ext_count; |
| } |
| |
| struct vkr_device *dev = calloc(1, sizeof(*dev)); |
| if (!dev) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| free(exts); |
| return; |
| } |
| |
| dev->base.type = VK_OBJECT_TYPE_DEVICE; |
| dev->base.id = vkr_cs_handle_load_id((const void **)args->pDevice, dev->base.type); |
| |
| vn_replace_vkCreateDevice_args_handle(args); |
| args->ret = vkCreateDevice(args->physicalDevice, args->pCreateInfo, NULL, &dev->base.handle.device); |
| if (args->ret != VK_SUCCESS) { |
| free(exts); |
| free(dev); |
| return; |
| } |
| |
| free(exts); |
| |
| dev->physical_device = physical_dev; |
| |
| VkDevice handle = dev->base.handle.device; |
| if (physical_dev->api_version >= VK_API_VERSION_1_2) { |
| dev->GetSemaphoreCounterValue = (PFN_vkGetSemaphoreCounterValue) |
| vkGetDeviceProcAddr(handle, "vkGetSemaphoreCounterValue"); |
| dev->WaitSemaphores = (PFN_vkWaitSemaphores) |
| vkGetDeviceProcAddr(handle, "vkWaitSemaphores"); |
| dev->SignalSemaphore = (PFN_vkSignalSemaphore) |
| vkGetDeviceProcAddr(handle, "vkSignalSemaphore"); |
| dev->GetDeviceMemoryOpaqueCaptureAddress = (PFN_vkGetDeviceMemoryOpaqueCaptureAddress) |
| vkGetDeviceProcAddr(handle, "vkGetDeviceMemoryOpaqueCaptureAddress"); |
| dev->GetBufferOpaqueCaptureAddress = (PFN_vkGetBufferOpaqueCaptureAddress) |
| vkGetDeviceProcAddr(handle, "vkGetBufferOpaqueCaptureAddress"); |
| dev->GetBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress) |
| vkGetDeviceProcAddr(handle, "vkGetBufferDeviceAddress"); |
| dev->ResetQueryPool = (PFN_vkResetQueryPool) |
| vkGetDeviceProcAddr(handle, "vkResetQueryPool"); |
| dev->CreateRenderPass2 = (PFN_vkCreateRenderPass2) |
| vkGetDeviceProcAddr(handle, "vkCreateRenderPass2"); |
| dev->CmdBeginRenderPass2 = (PFN_vkCmdBeginRenderPass2) |
| vkGetDeviceProcAddr(handle, "vkCmdBeginRenderPass2"); |
| dev->CmdNextSubpass2 = (PFN_vkCmdNextSubpass2) |
| vkGetDeviceProcAddr(handle, "vkCmdNextSubpass2"); |
| dev->CmdEndRenderPass2 = (PFN_vkCmdEndRenderPass2) |
| vkGetDeviceProcAddr(handle, "vkCmdEndRenderPass2"); |
| dev->CmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount) |
| vkGetDeviceProcAddr(handle, "vkCmdDrawIndirectCount"); |
| dev->CmdDrawIndexedIndirectCount = (PFN_vkCmdDrawIndexedIndirectCount) |
| vkGetDeviceProcAddr(handle, "vkCmdDrawIndexedIndirectCount"); |
| } else { |
| dev->GetSemaphoreCounterValue = (PFN_vkGetSemaphoreCounterValue) |
| vkGetDeviceProcAddr(handle, "vkGetSemaphoreCounterValueKHR"); |
| dev->WaitSemaphores = (PFN_vkWaitSemaphores) |
| vkGetDeviceProcAddr(handle, "vkWaitSemaphoresKHR"); |
| dev->SignalSemaphore = (PFN_vkSignalSemaphore) |
| vkGetDeviceProcAddr(handle, "vkSignalSemaphoreKHR"); |
| dev->GetDeviceMemoryOpaqueCaptureAddress = (PFN_vkGetDeviceMemoryOpaqueCaptureAddress) |
| vkGetDeviceProcAddr(handle, "vkGetDeviceMemoryOpaqueCaptureAddressKHR"); |
| dev->GetBufferOpaqueCaptureAddress = (PFN_vkGetBufferOpaqueCaptureAddress) |
| vkGetDeviceProcAddr(handle, "vkGetBufferOpaqueCaptureAddressKHR"); |
| dev->GetBufferDeviceAddress = (PFN_vkGetBufferDeviceAddress) |
| vkGetDeviceProcAddr(handle, "vkGetBufferDeviceAddressKHR"); |
| dev->ResetQueryPool = (PFN_vkResetQueryPool) |
| vkGetDeviceProcAddr(handle, "vkResetQueryPoolEXT"); |
| dev->CreateRenderPass2 = (PFN_vkCreateRenderPass2) |
| vkGetDeviceProcAddr(handle, "vkCreateRenderPass2KHR"); |
| dev->CmdBeginRenderPass2 = (PFN_vkCmdBeginRenderPass2) |
| vkGetDeviceProcAddr(handle, "vkCmdBeginRenderPass2KHR"); |
| dev->CmdNextSubpass2 = (PFN_vkCmdNextSubpass2) |
| vkGetDeviceProcAddr(handle, "vkCmdNextSubpass2KHR"); |
| dev->CmdEndRenderPass2 = (PFN_vkCmdEndRenderPass2) |
| vkGetDeviceProcAddr(handle, "vkCmdEndRenderPass2KHR"); |
| dev->CmdDrawIndirectCount = (PFN_vkCmdDrawIndirectCount) |
| vkGetDeviceProcAddr(handle, "vkCmdDrawIndirectCountKHR"); |
| dev->CmdDrawIndexedIndirectCount = (PFN_vkCmdDrawIndexedIndirectCount) |
| vkGetDeviceProcAddr(handle, "vkCmdDrawIndexedIndirectCountKHR"); |
| } |
| |
| dev->cmd_bind_transform_feedback_buffers = (PFN_vkCmdBindTransformFeedbackBuffersEXT) |
| vkGetDeviceProcAddr(handle, "vkCmdBindTransformFeedbackBuffersEXT"); |
| dev->cmd_begin_transform_feedback = (PFN_vkCmdBeginTransformFeedbackEXT) |
| vkGetDeviceProcAddr(handle, "vkCmdBeginTransformFeedbackEXT"); |
| dev->cmd_end_transform_feedback = (PFN_vkCmdEndTransformFeedbackEXT) |
| vkGetDeviceProcAddr(handle, "vkCmdEndTransformFeedbackEXT"); |
| dev->cmd_begin_query_indexed = (PFN_vkCmdBeginQueryIndexedEXT) |
| vkGetDeviceProcAddr(handle, "vkCmdBeginQueryIndexedEXT"); |
| dev->cmd_end_query_indexed = (PFN_vkCmdEndQueryIndexedEXT) |
| vkGetDeviceProcAddr(handle, "vkCmdEndQueryIndexedEXT"); |
| dev->cmd_draw_indirect_byte_count = (PFN_vkCmdDrawIndirectByteCountEXT) |
| vkGetDeviceProcAddr(handle, "vkCmdDrawIndirectByteCountEXT"); |
| |
| dev->get_image_drm_format_modifier_properties = (PFN_vkGetImageDrmFormatModifierPropertiesEXT) |
| vkGetDeviceProcAddr(handle, "vkGetImageDrmFormatModifierPropertiesEXT"); |
| |
| dev->get_memory_fd_properties = (PFN_vkGetMemoryFdPropertiesKHR) |
| vkGetDeviceProcAddr(handle, "vkGetMemoryFdPropertiesKHR"); |
| |
| list_inithead(&dev->queues); |
| list_inithead(&dev->free_syncs); |
| |
| util_hash_table_set_u64(ctx->object_table, dev->base.id, dev); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyDevice(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyDevice *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| if (dev) |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| /* TODO cleanup all objects here? */ |
| struct vkr_queue *queue, *queue_tmp; |
| LIST_FOR_EACH_ENTRY_SAFE(queue, queue_tmp, &dev->queues, head) |
| vkr_queue_destroy(ctx, queue); |
| |
| struct vkr_queue_sync *sync, *sync_tmp; |
| LIST_FOR_EACH_ENTRY_SAFE(sync, sync_tmp, &dev->free_syncs, head) { |
| vkDestroyFence(dev->base.handle.device, sync->fence, NULL); |
| free(sync); |
| } |
| |
| vn_replace_vkDestroyDevice_args_handle(args); |
| vkDestroyDevice(args->device, NULL); |
| |
| util_hash_table_remove_u64(ctx->object_table, dev->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkGetDeviceGroupPeerMemoryFeatures(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetDeviceGroupPeerMemoryFeatures *args) |
| { |
| vn_replace_vkGetDeviceGroupPeerMemoryFeatures_args_handle(args); |
| vkGetDeviceGroupPeerMemoryFeatures(args->device, args->heapIndex, args->localDeviceIndex, args->remoteDeviceIndex, args->pPeerMemoryFeatures); |
| } |
| |
| static void |
| vkr_dispatch_vkDeviceWaitIdle(struct vn_dispatch_context *dispatch, UNUSED struct vn_command_vkDeviceWaitIdle *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| /* no blocking call */ |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| } |
| |
| static void |
| vkr_dispatch_vkGetDeviceQueue(struct vn_dispatch_context *dispatch, struct vn_command_vkGetDeviceQueue *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| const vkr_object_id id = |
| vkr_cs_handle_load_id((const void **)args->pQueue, VK_OBJECT_TYPE_QUEUE); |
| |
| VkQueue handle; |
| vn_replace_vkGetDeviceQueue_args_handle(args); |
| vkGetDeviceQueue(args->device, args->queueFamilyIndex, args->queueIndex, &handle); |
| |
| struct vkr_queue *queue = vkr_queue_create(ctx, dev, id, handle, |
| args->queueFamilyIndex, args->queueIndex); |
| /* TODO create queues with device and deal with failures there */ |
| if (!queue) |
| vrend_printf("failed to create queue\n"); |
| } |
| |
| static void |
| vkr_dispatch_vkGetDeviceQueue2(struct vn_dispatch_context *dispatch, struct vn_command_vkGetDeviceQueue2 *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| const vkr_object_id id = |
| vkr_cs_handle_load_id((const void **)args->pQueue, VK_OBJECT_TYPE_QUEUE); |
| |
| VkQueue handle; |
| vn_replace_vkGetDeviceQueue2_args_handle(args); |
| vkGetDeviceQueue2(args->device, args->pQueueInfo, &handle); |
| |
| /* TODO deal with errors */ |
| vkr_queue_create(ctx, dev, id, handle, args->pQueueInfo->queueFamilyIndex, |
| args->pQueueInfo->queueIndex); |
| } |
| |
| static void |
| vkr_dispatch_vkQueueSubmit(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkQueueSubmit *args) |
| { |
| vn_replace_vkQueueSubmit_args_handle(args); |
| args->ret = vkQueueSubmit(args->queue, args->submitCount, args->pSubmits, args->fence); |
| } |
| |
| static void |
| vkr_dispatch_vkQueueBindSparse(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkQueueBindSparse *args) |
| { |
| vn_replace_vkQueueBindSparse_args_handle(args); |
| args->ret = vkQueueBindSparse(args->queue, args->bindInfoCount, args->pBindInfo, args->fence); |
| } |
| |
| static void |
| vkr_dispatch_vkQueueWaitIdle(struct vn_dispatch_context *dispatch, UNUSED struct vn_command_vkQueueWaitIdle *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| /* no blocking call */ |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| } |
| |
| static bool |
| vkr_get_fd_handle_type_from_virgl_fd_type(struct vkr_physical_device *dev, enum virgl_resource_fd_type fd_type, VkExternalMemoryHandleTypeFlagBits *out_handle_type) |
| { |
| assert(dev); |
| assert(out_handle_type); |
| |
| switch (fd_type) { |
| case VIRGL_RESOURCE_FD_DMABUF: |
| if (!dev->EXT_external_memory_dma_buf) |
| return false; |
| *out_handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; |
| break; |
| case VIRGL_RESOURCE_FD_OPAQUE: |
| if (!dev->KHR_external_memory_fd) |
| return false; |
| *out_handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; |
| break; |
| default: |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static void |
| vkr_dispatch_vkAllocateMemory(struct vn_dispatch_context *dispatch, struct vn_command_vkAllocateMemory *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| #ifdef FORCE_ENABLE_DMABUF |
| const VkExportMemoryAllocateInfo export_info = { |
| .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, |
| .pNext = args->pAllocateInfo->pNext, |
| .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, |
| }; |
| if (dev->physical_device->EXT_external_memory_dma_buf) |
| ((VkMemoryAllocateInfo *)args->pAllocateInfo)->pNext = &export_info; |
| #endif |
| |
| /* translate VkImportMemoryResourceInfoMESA into VkImportMemoryFdInfoKHR */ |
| VkImportMemoryResourceInfoMESA *import_resource_info = NULL; |
| VkImportMemoryFdInfoKHR import_fd_info = { |
| .sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, |
| .fd = -1, |
| }; |
| VkBaseInStructure *pprev = (VkBaseInStructure *)args->pAllocateInfo; |
| while (pprev->pNext) { |
| if (pprev->pNext->sType == VK_STRUCTURE_TYPE_IMPORT_MEMORY_RESOURCE_INFO_MESA) { |
| import_resource_info = (VkImportMemoryResourceInfoMESA *)pprev->pNext; |
| import_fd_info.pNext = pprev->pNext->pNext; |
| pprev->pNext = (const struct VkBaseInStructure *)&import_fd_info; |
| break; |
| } |
| pprev = (VkBaseInStructure *)pprev->pNext; |
| } |
| if (import_resource_info) { |
| uint32_t res_id = import_resource_info->resourceId; |
| struct vkr_resource_attachment *att = util_hash_table_get(ctx->resource_table, uintptr_to_pointer(res_id)); |
| if (!att || !att->resource) { |
| args->ret = VK_ERROR_INVALID_EXTERNAL_HANDLE; |
| return; |
| } |
| |
| enum virgl_resource_fd_type fd_type = virgl_resource_export_fd(att->resource, &import_fd_info.fd); |
| if (!vkr_get_fd_handle_type_from_virgl_fd_type(dev->physical_device, fd_type, &import_fd_info.handleType)) { |
| close(import_fd_info.fd); |
| args->ret = VK_ERROR_INVALID_EXTERNAL_HANDLE; |
| return; |
| } |
| } |
| |
| struct vkr_device_memory *mem = calloc(1, sizeof(*mem)); |
| if (!mem) { |
| if (import_resource_info) |
| close(import_fd_info.fd); |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| return; |
| } |
| |
| mem->base.type = VK_OBJECT_TYPE_DEVICE_MEMORY; |
| mem->base.id = vkr_cs_handle_load_id((const void **)args->pMemory, mem->base.type); |
| |
| vn_replace_vkAllocateMemory_args_handle(args); |
| args->ret = vkAllocateMemory(args->device, args->pAllocateInfo, NULL, &mem->base.handle.device_memory); |
| if (args->ret != VK_SUCCESS) { |
| if (import_resource_info) |
| close(import_fd_info.fd); |
| free(mem); |
| return; |
| } |
| |
| const VkPhysicalDeviceMemoryProperties *mem_props = &dev->physical_device->memory_properties; |
| const uint32_t mt_index = args->pAllocateInfo->memoryTypeIndex; |
| const uint32_t property_flags = mem_props->memoryTypes[mt_index].propertyFlags; |
| |
| /* get valid fd types */ |
| uint32_t valid_fd_types = 0; |
| const VkBaseInStructure *pnext = args->pAllocateInfo->pNext; |
| while (pnext) { |
| if (pnext->sType == VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO) { |
| const VkExportMemoryAllocateInfo *export = (const void *)pnext; |
| |
| if (export->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) |
| valid_fd_types |= 1 << VIRGL_RESOURCE_FD_OPAQUE; |
| if (export->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) |
| valid_fd_types |= 1 << VIRGL_RESOURCE_FD_DMABUF; |
| |
| break; |
| } |
| pnext = pnext->pNext; |
| } |
| |
| mem->device = args->device; |
| mem->property_flags = property_flags; |
| mem->valid_fd_types = valid_fd_types; |
| list_inithead(&mem->head); |
| |
| util_hash_table_set_u64(ctx->object_table, mem->base.id, mem); |
| } |
| |
| static void |
| vkr_dispatch_vkFreeMemory(struct vn_dispatch_context *dispatch, struct vn_command_vkFreeMemory *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_device_memory *mem = (struct vkr_device_memory *)(uintptr_t)args->memory; |
| if (!mem || mem->base.type != VK_OBJECT_TYPE_DEVICE_MEMORY) { |
| if (mem) |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkFreeMemory_args_handle(args); |
| vkFreeMemory(args->device, args->memory, NULL); |
| |
| list_del(&mem->head); |
| |
| util_hash_table_remove_u64(ctx->object_table, mem->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkGetDeviceMemoryCommitment(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetDeviceMemoryCommitment *args) |
| { |
| vn_replace_vkGetDeviceMemoryCommitment_args_handle(args); |
| vkGetDeviceMemoryCommitment(args->device, args->memory, args->pCommittedMemoryInBytes); |
| } |
| |
| static void |
| vkr_dispatch_vkGetDeviceMemoryOpaqueCaptureAddress(struct vn_dispatch_context *dispatch, struct vn_command_vkGetDeviceMemoryOpaqueCaptureAddress *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkGetDeviceMemoryOpaqueCaptureAddress_args_handle(args); |
| args->ret = dev->GetDeviceMemoryOpaqueCaptureAddress(args->device, args->pInfo); |
| } |
| |
| static void |
| vkr_dispatch_vkGetBufferMemoryRequirements(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetBufferMemoryRequirements *args) |
| { |
| vn_replace_vkGetBufferMemoryRequirements_args_handle(args); |
| vkGetBufferMemoryRequirements(args->device, args->buffer, args->pMemoryRequirements); |
| } |
| |
| static void |
| vkr_dispatch_vkGetBufferMemoryRequirements2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetBufferMemoryRequirements2 *args) |
| { |
| vn_replace_vkGetBufferMemoryRequirements2_args_handle(args); |
| vkGetBufferMemoryRequirements2(args->device, args->pInfo, args->pMemoryRequirements); |
| } |
| |
| static void |
| vkr_dispatch_vkBindBufferMemory(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkBindBufferMemory *args) |
| { |
| vn_replace_vkBindBufferMemory_args_handle(args); |
| args->ret = vkBindBufferMemory(args->device, args->buffer, args->memory, args->memoryOffset); |
| } |
| |
| static void |
| vkr_dispatch_vkBindBufferMemory2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkBindBufferMemory2 *args) |
| { |
| vn_replace_vkBindBufferMemory2_args_handle(args); |
| args->ret = vkBindBufferMemory2(args->device, args->bindInfoCount, args->pBindInfos); |
| } |
| |
| static void |
| vkr_dispatch_vkGetBufferOpaqueCaptureAddress(struct vn_dispatch_context *dispatch, struct vn_command_vkGetBufferOpaqueCaptureAddress *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkGetBufferOpaqueCaptureAddress_args_handle(args); |
| args->ret = dev->GetBufferOpaqueCaptureAddress(args->device, args->pInfo); |
| } |
| |
| static void |
| vkr_dispatch_vkGetBufferDeviceAddress(struct vn_dispatch_context *dispatch, struct vn_command_vkGetBufferDeviceAddress *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkGetBufferDeviceAddress_args_handle(args); |
| args->ret = dev->GetBufferDeviceAddress(args->device, args->pInfo); |
| } |
| |
| static void |
| vkr_dispatch_vkGetImageMemoryRequirements(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetImageMemoryRequirements *args) |
| { |
| vn_replace_vkGetImageMemoryRequirements_args_handle(args); |
| vkGetImageMemoryRequirements(args->device, args->image, args->pMemoryRequirements); |
| } |
| |
| static void |
| vkr_dispatch_vkGetImageMemoryRequirements2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetImageMemoryRequirements2 *args) |
| { |
| vn_replace_vkGetImageMemoryRequirements2_args_handle(args); |
| vkGetImageMemoryRequirements2(args->device, args->pInfo, args->pMemoryRequirements); |
| } |
| |
| static void |
| vkr_dispatch_vkGetImageSparseMemoryRequirements(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetImageSparseMemoryRequirements *args) |
| { |
| vn_replace_vkGetImageSparseMemoryRequirements_args_handle(args); |
| vkGetImageSparseMemoryRequirements(args->device, args->image, args->pSparseMemoryRequirementCount, args->pSparseMemoryRequirements); |
| } |
| |
| static void |
| vkr_dispatch_vkGetImageSparseMemoryRequirements2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetImageSparseMemoryRequirements2 *args) |
| { |
| vn_replace_vkGetImageSparseMemoryRequirements2_args_handle(args); |
| vkGetImageSparseMemoryRequirements2(args->device, args->pInfo, args->pSparseMemoryRequirementCount, args->pSparseMemoryRequirements); |
| } |
| |
| static void |
| vkr_dispatch_vkBindImageMemory(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkBindImageMemory *args) |
| { |
| vn_replace_vkBindImageMemory_args_handle(args); |
| args->ret = vkBindImageMemory(args->device, args->image, args->memory, args->memoryOffset); |
| } |
| |
| static void |
| vkr_dispatch_vkBindImageMemory2(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkBindImageMemory2 *args) |
| { |
| vn_replace_vkBindImageMemory2_args_handle(args); |
| args->ret = vkBindImageMemory2(args->device, args->bindInfoCount, args->pBindInfos); |
| } |
| |
| static void |
| vkr_dispatch_vkGetImageSubresourceLayout(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetImageSubresourceLayout *args) |
| { |
| vn_replace_vkGetImageSubresourceLayout_args_handle(args); |
| vkGetImageSubresourceLayout(args->device, args->image, args->pSubresource, args->pLayout); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateFence(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateFence *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(fence, fence, FENCE, vkCreateFence, pFence); |
| |
| util_hash_table_set_u64(ctx->object_table, fence->base.id, fence); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyFence(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyFence *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(fence, fence, FENCE, vkDestroyFence, fence); |
| |
| util_hash_table_remove_u64(ctx->object_table, fence->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkResetFences(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkResetFences *args) |
| { |
| vn_replace_vkResetFences_args_handle(args); |
| args->ret = vkResetFences(args->device, args->fenceCount, args->pFences); |
| } |
| |
| static void |
| vkr_dispatch_vkGetFenceStatus(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetFenceStatus *args) |
| { |
| vn_replace_vkGetFenceStatus_args_handle(args); |
| args->ret = vkGetFenceStatus(args->device, args->fence); |
| } |
| |
| static void |
| vkr_dispatch_vkWaitForFences(struct vn_dispatch_context *dispatch, struct vn_command_vkWaitForFences *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| /* Being single-threaded, we cannot afford potential blocking calls. It |
| * also leads to GPU lost when the wait never returns and can only be |
| * unblocked by a following command (e.g., vkCmdWaitEvents that is |
| * unblocked by a following vkSetEvent). |
| */ |
| if (args->timeout) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkWaitForFences_args_handle(args); |
| args->ret = vkWaitForFences(args->device, args->fenceCount, args->pFences, args->waitAll, args->timeout); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateSemaphore(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateSemaphore *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(sem, semaphore, SEMAPHORE, vkCreateSemaphore, pSemaphore); |
| |
| util_hash_table_set_u64(ctx->object_table, sem->base.id, sem); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroySemaphore(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroySemaphore *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(sem, semaphore, SEMAPHORE, vkDestroySemaphore, semaphore); |
| |
| util_hash_table_remove_u64(ctx->object_table, sem->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkGetSemaphoreCounterValue(struct vn_dispatch_context *dispatch, struct vn_command_vkGetSemaphoreCounterValue *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkGetSemaphoreCounterValue_args_handle(args); |
| args->ret = dev->GetSemaphoreCounterValue(args->device, args->semaphore, args->pValue); |
| } |
| |
| static void |
| vkr_dispatch_vkWaitSemaphores(struct vn_dispatch_context *dispatch, struct vn_command_vkWaitSemaphores *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| /* no blocking call */ |
| if (args->timeout) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkWaitSemaphores_args_handle(args); |
| args->ret = dev->WaitSemaphores(args->device, args->pWaitInfo, args->timeout); |
| } |
| |
| static void |
| vkr_dispatch_vkSignalSemaphore(struct vn_dispatch_context *dispatch, struct vn_command_vkSignalSemaphore *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkSignalSemaphore_args_handle(args); |
| args->ret = dev->SignalSemaphore(args->device, args->pSignalInfo); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateBuffer(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateBuffer *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| #ifdef FORCE_ENABLE_DMABUF |
| const VkExternalMemoryBufferCreateInfo external_info = { |
| .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO, |
| .pNext = args->pCreateInfo->pNext, |
| .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, |
| }; |
| if (dev->physical_device->EXT_external_memory_dma_buf) |
| ((VkBufferCreateInfo *)args->pCreateInfo)->pNext = &external_info; |
| #endif |
| |
| CREATE_OBJECT(buf, buffer, BUFFER, vkCreateBuffer, pBuffer); |
| |
| util_hash_table_set_u64(ctx->object_table, buf->base.id, buf); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyBuffer(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyBuffer *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(buf, buffer, BUFFER, vkDestroyBuffer, buffer); |
| |
| util_hash_table_remove_u64(ctx->object_table, buf->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateBufferView(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateBufferView *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(view, buffer_view, BUFFER_VIEW, vkCreateBufferView, pView); |
| |
| util_hash_table_set_u64(ctx->object_table, view->base.id, view); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyBufferView(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyBufferView *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(view, buffer_view, BUFFER_VIEW, vkDestroyBufferView, bufferView); |
| |
| util_hash_table_remove_u64(ctx->object_table, view->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateImage(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateImage *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| #ifdef FORCE_ENABLE_DMABUF |
| const VkExternalMemoryImageCreateInfo external_info = { |
| .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, |
| .pNext = args->pCreateInfo->pNext, |
| .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, |
| }; |
| if (dev->physical_device->EXT_external_memory_dma_buf) |
| ((VkImageCreateInfo *)args->pCreateInfo)->pNext = &external_info; |
| #endif |
| |
| CREATE_OBJECT(img, image, IMAGE, vkCreateImage, pImage); |
| |
| util_hash_table_set_u64(ctx->object_table, img->base.id, img); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyImage(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyImage *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(img, image, IMAGE, vkDestroyImage, image); |
| |
| util_hash_table_remove_u64(ctx->object_table, img->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateImageView(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateImageView *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(view, image_view, IMAGE_VIEW, vkCreateImageView, pView); |
| |
| util_hash_table_set_u64(ctx->object_table, view->base.id, view); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyImageView(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyImageView *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(view, image_view, IMAGE_VIEW, vkDestroyImageView, imageView); |
| |
| util_hash_table_remove_u64(ctx->object_table, view->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateSampler(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateSampler *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(sampler, sampler, SAMPLER, vkCreateSampler, pSampler); |
| |
| util_hash_table_set_u64(ctx->object_table, sampler->base.id, sampler); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroySampler(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroySampler *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(sampler, sampler, SAMPLER, vkDestroySampler, sampler); |
| |
| util_hash_table_remove_u64(ctx->object_table, sampler->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateSamplerYcbcrConversion(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateSamplerYcbcrConversion *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(conv, sampler_ycbcr_conversion, SAMPLER_YCBCR_CONVERSION, vkCreateSamplerYcbcrConversion, pYcbcrConversion); |
| |
| util_hash_table_set_u64(ctx->object_table, conv->base.id, conv); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroySamplerYcbcrConversion(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroySamplerYcbcrConversion *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(conv, sampler_ycbcr_conversion, SAMPLER_YCBCR_CONVERSION, vkDestroySamplerYcbcrConversion, ycbcrConversion); |
| |
| util_hash_table_remove_u64(ctx->object_table, conv->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkGetDescriptorSetLayoutSupport(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetDescriptorSetLayoutSupport *args) |
| { |
| vn_replace_vkGetDescriptorSetLayoutSupport_args_handle(args); |
| vkGetDescriptorSetLayoutSupport(args->device, args->pCreateInfo, args->pSupport); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateDescriptorSetLayout(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateDescriptorSetLayout *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(layout, descriptor_set_layout, DESCRIPTOR_SET_LAYOUT, vkCreateDescriptorSetLayout, pSetLayout); |
| |
| util_hash_table_set_u64(ctx->object_table, layout->base.id, layout); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyDescriptorSetLayout(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyDescriptorSetLayout *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(layout, descriptor_set_layout, DESCRIPTOR_SET_LAYOUT, vkDestroyDescriptorSetLayout, descriptorSetLayout); |
| |
| util_hash_table_remove_u64(ctx->object_table, layout->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateDescriptorPool(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateDescriptorPool *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(pool, descriptor_pool, DESCRIPTOR_POOL, vkCreateDescriptorPool, pDescriptorPool); |
| |
| list_inithead(&pool->descriptor_sets); |
| |
| util_hash_table_set_u64(ctx->object_table, pool->base.id, pool); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyDescriptorPool(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyDescriptorPool *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(pool, descriptor_pool, DESCRIPTOR_POOL, vkDestroyDescriptorPool, descriptorPool); |
| |
| struct vkr_descriptor_set *set, *tmp; |
| LIST_FOR_EACH_ENTRY_SAFE(set, tmp, &pool->descriptor_sets, head) |
| util_hash_table_remove_u64(ctx->object_table, set->base.id); |
| |
| util_hash_table_remove_u64(ctx->object_table, pool->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkResetDescriptorPool(struct vn_dispatch_context *dispatch, struct vn_command_vkResetDescriptorPool *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_descriptor_pool *pool = (struct vkr_descriptor_pool *)(uintptr_t)args->descriptorPool; |
| if (!pool || pool->base.type != VK_OBJECT_TYPE_DESCRIPTOR_POOL) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkResetDescriptorPool_args_handle(args); |
| args->ret = vkResetDescriptorPool(args->device, args->descriptorPool, args->flags); |
| |
| struct vkr_descriptor_set *set, *tmp; |
| LIST_FOR_EACH_ENTRY_SAFE(set, tmp, &pool->descriptor_sets, head) |
| util_hash_table_remove_u64(ctx->object_table, set->base.id); |
| list_inithead(&pool->descriptor_sets); |
| } |
| |
| static void |
| vkr_dispatch_vkAllocateDescriptorSets(struct vn_dispatch_context *dispatch, struct vn_command_vkAllocateDescriptorSets *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_descriptor_pool *pool = (struct vkr_descriptor_pool *)(uintptr_t)args->pAllocateInfo->descriptorPool; |
| if (!pool || pool->base.type != VK_OBJECT_TYPE_DESCRIPTOR_POOL) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| struct object_array arr; |
| if (!object_array_init(&arr, |
| args->pAllocateInfo->descriptorSetCount, |
| VK_OBJECT_TYPE_DESCRIPTOR_SET, |
| sizeof(struct vkr_descriptor_set), |
| sizeof(VkDescriptorSet), |
| args->pDescriptorSets)) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| return; |
| } |
| |
| vn_replace_vkAllocateDescriptorSets_args_handle(args); |
| args->ret = vkAllocateDescriptorSets(args->device, args->pAllocateInfo, arr.handle_storage); |
| if (args->ret != VK_SUCCESS) { |
| object_array_fini(&arr); |
| return; |
| } |
| |
| for (uint32_t i = 0; i < arr.count; i++) { |
| struct vkr_descriptor_set *set = arr.objects[i]; |
| |
| set->base.handle.descriptor_set = ((VkDescriptorSet *)arr.handle_storage)[i]; |
| list_add(&set->head, &pool->descriptor_sets); |
| |
| util_hash_table_set_u64(ctx->object_table, set->base.id, set); |
| } |
| |
| arr.objects_stolen = true; |
| object_array_fini(&arr); |
| } |
| |
| static void |
| vkr_dispatch_vkFreeDescriptorSets(struct vn_dispatch_context *dispatch, struct vn_command_vkFreeDescriptorSets *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct list_head free_sets; |
| |
| list_inithead(&free_sets); |
| for (uint32_t i = 0; i < args->descriptorSetCount; i++) { |
| struct vkr_descriptor_set *set = (struct vkr_descriptor_set *)(uintptr_t)args->pDescriptorSets[i]; |
| if (!set) |
| continue; |
| if (set->base.type != VK_OBJECT_TYPE_DESCRIPTOR_SET) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| list_del(&set->head); |
| list_addtail(&set->head, &free_sets); |
| } |
| |
| vn_replace_vkFreeDescriptorSets_args_handle(args); |
| args->ret = vkFreeDescriptorSets(args->device, args->descriptorPool, args->descriptorSetCount, args->pDescriptorSets); |
| |
| struct vkr_descriptor_set *set, *tmp; |
| LIST_FOR_EACH_ENTRY_SAFE(set, tmp, &free_sets, head) |
| util_hash_table_remove_u64(ctx->object_table, set->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkUpdateDescriptorSets(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkUpdateDescriptorSets *args) |
| { |
| vn_replace_vkUpdateDescriptorSets_args_handle(args); |
| vkUpdateDescriptorSets(args->device, args->descriptorWriteCount, args->pDescriptorWrites, args->descriptorCopyCount, args->pDescriptorCopies); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateDescriptorUpdateTemplate(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateDescriptorUpdateTemplate *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(templ, descriptor_update_template, DESCRIPTOR_UPDATE_TEMPLATE, vkCreateDescriptorUpdateTemplate, pDescriptorUpdateTemplate); |
| |
| util_hash_table_set_u64(ctx->object_table, templ->base.id, templ); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyDescriptorUpdateTemplate(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyDescriptorUpdateTemplate *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(templ, descriptor_update_template, DESCRIPTOR_UPDATE_TEMPLATE, vkDestroyDescriptorUpdateTemplate, descriptorUpdateTemplate); |
| |
| util_hash_table_remove_u64(ctx->object_table, templ->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateRenderPass(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateRenderPass *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(pass, render_pass, RENDER_PASS, vkCreateRenderPass, pRenderPass); |
| |
| util_hash_table_set_u64(ctx->object_table, pass->base.id, pass); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateRenderPass2(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateRenderPass2 *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| struct vkr_render_pass *pass = calloc(1, sizeof(*pass)); |
| if (!pass) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| return; |
| } |
| pass->base.type = VK_OBJECT_TYPE_RENDER_PASS; |
| pass->base.id = vkr_cs_handle_load_id((const void **)args->pRenderPass, pass->base.type); |
| |
| vn_replace_vkCreateRenderPass2_args_handle(args); |
| args->ret = dev->CreateRenderPass2(args->device, args->pCreateInfo, |
| NULL, &pass->base.handle.render_pass); |
| if (args->ret != VK_SUCCESS) { |
| free(pass); |
| return; |
| } |
| |
| util_hash_table_set_u64(ctx->object_table, pass->base.id, pass); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyRenderPass(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyRenderPass *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(pass, render_pass, RENDER_PASS, vkDestroyRenderPass, renderPass); |
| |
| util_hash_table_remove_u64(ctx->object_table, pass->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkGetRenderAreaGranularity(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetRenderAreaGranularity *args) |
| { |
| vn_replace_vkGetRenderAreaGranularity_args_handle(args); |
| vkGetRenderAreaGranularity(args->device, args->renderPass, args->pGranularity); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateFramebuffer(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateFramebuffer *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(fb, framebuffer, FRAMEBUFFER, vkCreateFramebuffer, pFramebuffer); |
| |
| util_hash_table_set_u64(ctx->object_table, fb->base.id, fb); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyFramebuffer(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyFramebuffer *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(fb, framebuffer, FRAMEBUFFER, vkDestroyFramebuffer, framebuffer); |
| |
| util_hash_table_remove_u64(ctx->object_table, fb->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateEvent(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateEvent *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(ev, event, EVENT, vkCreateEvent, pEvent); |
| |
| util_hash_table_set_u64(ctx->object_table, ev->base.id, ev); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyEvent(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyEvent *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(ev, event, EVENT, vkDestroyEvent, event); |
| |
| util_hash_table_remove_u64(ctx->object_table, ev->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkGetEventStatus(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetEventStatus *args) |
| { |
| vn_replace_vkGetEventStatus_args_handle(args); |
| args->ret = vkGetEventStatus(args->device, args->event); |
| } |
| |
| static void |
| vkr_dispatch_vkSetEvent(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkSetEvent *args) |
| { |
| vn_replace_vkSetEvent_args_handle(args); |
| args->ret = vkSetEvent(args->device, args->event); |
| } |
| |
| static void |
| vkr_dispatch_vkResetEvent(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkResetEvent *args) |
| { |
| vn_replace_vkResetEvent_args_handle(args); |
| args->ret = vkResetEvent(args->device, args->event); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateQueryPool(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateQueryPool *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(pool, query_pool, QUERY_POOL, vkCreateQueryPool, pQueryPool); |
| |
| util_hash_table_set_u64(ctx->object_table, pool->base.id, pool); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyQueryPool(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyQueryPool *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(pool, query_pool, QUERY_POOL, vkDestroyQueryPool, queryPool); |
| |
| util_hash_table_remove_u64(ctx->object_table, pool->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkGetQueryPoolResults(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetQueryPoolResults *args) |
| { |
| vn_replace_vkGetQueryPoolResults_args_handle(args); |
| args->ret = vkGetQueryPoolResults(args->device, args->queryPool, args->firstQuery, args->queryCount, args->dataSize, args->pData, args->stride, args->flags); |
| } |
| |
| static void |
| vkr_dispatch_vkResetQueryPool(struct vn_dispatch_context *dispatch, struct vn_command_vkResetQueryPool *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkResetQueryPool_args_handle(args); |
| dev->ResetQueryPool(args->device, args->queryPool, args->firstQuery, args->queryCount); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateShaderModule(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateShaderModule *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(mod, shader_module, SHADER_MODULE, vkCreateShaderModule, pShaderModule); |
| |
| util_hash_table_set_u64(ctx->object_table, mod->base.id, mod); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyShaderModule(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyShaderModule *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(mod, shader_module, SHADER_MODULE, vkDestroyShaderModule, shaderModule); |
| |
| util_hash_table_remove_u64(ctx->object_table, mod->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreatePipelineLayout(struct vn_dispatch_context *dispatch, struct vn_command_vkCreatePipelineLayout *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(layout, pipeline_layout, PIPELINE_LAYOUT, vkCreatePipelineLayout, pPipelineLayout); |
| |
| util_hash_table_set_u64(ctx->object_table, layout->base.id, layout); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyPipelineLayout(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyPipelineLayout *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(layout, pipeline_layout, PIPELINE_LAYOUT, vkDestroyPipelineLayout, pipelineLayout); |
| |
| util_hash_table_remove_u64(ctx->object_table, layout->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreatePipelineCache(struct vn_dispatch_context *dispatch, struct vn_command_vkCreatePipelineCache *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(cache, pipeline_cache, PIPELINE_CACHE, vkCreatePipelineCache, pPipelineCache); |
| |
| util_hash_table_set_u64(ctx->object_table, cache->base.id, cache); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyPipelineCache(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyPipelineCache *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(cache, pipeline_cache, PIPELINE_CACHE, vkDestroyPipelineCache, pipelineCache); |
| |
| util_hash_table_remove_u64(ctx->object_table, cache->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkGetPipelineCacheData(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkGetPipelineCacheData *args) |
| { |
| vn_replace_vkGetPipelineCacheData_args_handle(args); |
| args->ret = vkGetPipelineCacheData(args->device, args->pipelineCache, args->pDataSize, args->pData); |
| } |
| |
| static void |
| vkr_dispatch_vkMergePipelineCaches(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkMergePipelineCaches *args) |
| { |
| vn_replace_vkMergePipelineCaches_args_handle(args); |
| args->ret = vkMergePipelineCaches(args->device, args->dstCache, args->srcCacheCount, args->pSrcCaches); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateGraphicsPipelines(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateGraphicsPipelines *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct object_array arr; |
| if (!object_array_init(&arr, |
| args->createInfoCount, |
| VK_OBJECT_TYPE_PIPELINE, |
| sizeof(struct vkr_pipeline), |
| sizeof(VkPipeline), |
| args->pPipelines)) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| return; |
| } |
| |
| vn_replace_vkCreateGraphicsPipelines_args_handle(args); |
| args->ret = vkCreateGraphicsPipelines(args->device, args->pipelineCache, args->createInfoCount, args->pCreateInfos, NULL, arr.handle_storage); |
| if (args->ret != VK_SUCCESS) { |
| object_array_fini(&arr); |
| return; |
| } |
| |
| for (uint32_t i = 0; i < arr.count; i++) { |
| struct vkr_pipeline *pipeline = arr.objects[i]; |
| |
| pipeline->base.handle.pipeline = ((VkPipeline *)arr.handle_storage)[i]; |
| |
| util_hash_table_set_u64(ctx->object_table, pipeline->base.id, pipeline); |
| } |
| |
| arr.objects_stolen = true; |
| object_array_fini(&arr); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateComputePipelines(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateComputePipelines *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct object_array arr; |
| if (!object_array_init(&arr, |
| args->createInfoCount, |
| VK_OBJECT_TYPE_PIPELINE, |
| sizeof(struct vkr_pipeline), |
| sizeof(VkPipeline), |
| args->pPipelines)) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| return; |
| } |
| |
| vn_replace_vkCreateComputePipelines_args_handle(args); |
| args->ret = vkCreateComputePipelines(args->device, args->pipelineCache, args->createInfoCount, args->pCreateInfos, NULL, arr.handle_storage); |
| if (args->ret != VK_SUCCESS) { |
| object_array_fini(&arr); |
| return; |
| } |
| |
| for (uint32_t i = 0; i < arr.count; i++) { |
| struct vkr_pipeline *pipeline = arr.objects[i]; |
| |
| pipeline->base.handle.pipeline = ((VkPipeline *)arr.handle_storage)[i]; |
| |
| util_hash_table_set_u64(ctx->object_table, pipeline->base.id, pipeline); |
| } |
| |
| arr.objects_stolen = true; |
| object_array_fini(&arr); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyPipeline(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyPipeline *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(pipeline, pipeline, PIPELINE, vkDestroyPipeline, pipeline); |
| |
| util_hash_table_remove_u64(ctx->object_table, pipeline->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkCreateCommandPool(struct vn_dispatch_context *dispatch, struct vn_command_vkCreateCommandPool *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| CREATE_OBJECT(pool, command_pool, COMMAND_POOL, vkCreateCommandPool, pCommandPool); |
| |
| list_inithead(&pool->command_buffers); |
| |
| util_hash_table_set_u64(ctx->object_table, pool->base.id, pool); |
| } |
| |
| static void |
| vkr_dispatch_vkDestroyCommandPool(struct vn_dispatch_context *dispatch, struct vn_command_vkDestroyCommandPool *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| DESTROY_OBJECT(pool, command_pool, COMMAND_POOL, vkDestroyCommandPool, commandPool); |
| |
| struct vkr_command_buffer *cmd, *tmp; |
| LIST_FOR_EACH_ENTRY_SAFE(cmd, tmp, &pool->command_buffers, head) |
| util_hash_table_remove_u64(ctx->object_table, cmd->base.id); |
| |
| util_hash_table_remove_u64(ctx->object_table, pool->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkResetCommandPool(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkResetCommandPool *args) |
| { |
| vn_replace_vkResetCommandPool_args_handle(args); |
| args->ret = vkResetCommandPool(args->device, args->commandPool, args->flags); |
| } |
| |
| static void |
| vkr_dispatch_vkTrimCommandPool(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkTrimCommandPool *args) |
| { |
| vn_replace_vkTrimCommandPool_args_handle(args); |
| vkTrimCommandPool(args->device, args->commandPool, args->flags); |
| } |
| |
| static void |
| vkr_dispatch_vkAllocateCommandBuffers(struct vn_dispatch_context *dispatch, struct vn_command_vkAllocateCommandBuffers *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| struct vkr_command_pool *pool = (struct vkr_command_pool *)(uintptr_t)args->pAllocateInfo->commandPool; |
| if (!pool || pool->base.type != VK_OBJECT_TYPE_COMMAND_POOL) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| struct object_array arr; |
| if (!object_array_init(&arr, |
| args->pAllocateInfo->commandBufferCount, |
| VK_OBJECT_TYPE_COMMAND_BUFFER, |
| sizeof(struct vkr_command_buffer), |
| sizeof(VkCommandBuffer), |
| args->pCommandBuffers)) { |
| args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; |
| return; |
| } |
| |
| vn_replace_vkAllocateCommandBuffers_args_handle(args); |
| args->ret = vkAllocateCommandBuffers(args->device, args->pAllocateInfo, arr.handle_storage); |
| if (args->ret != VK_SUCCESS) { |
| object_array_fini(&arr); |
| return; |
| } |
| |
| for (uint32_t i = 0; i < arr.count; i++) { |
| struct vkr_command_buffer *cmd = arr.objects[i]; |
| |
| cmd->base.handle.command_buffer = ((VkCommandBuffer *)arr.handle_storage)[i]; |
| cmd->device = dev; |
| list_add(&cmd->head, &pool->command_buffers); |
| |
| util_hash_table_set_u64(ctx->object_table, cmd->base.id, cmd); |
| } |
| |
| arr.objects_stolen = true; |
| object_array_fini(&arr); |
| } |
| |
| static void |
| vkr_dispatch_vkFreeCommandBuffers(struct vn_dispatch_context *dispatch, struct vn_command_vkFreeCommandBuffers *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct list_head free_cmds; |
| |
| list_inithead(&free_cmds); |
| for (uint32_t i = 0; i < args->commandBufferCount; i++) { |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->pCommandBuffers[i]; |
| if (!cmd) |
| continue; |
| if (cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| list_del(&cmd->head); |
| list_addtail(&cmd->head, &free_cmds); |
| } |
| |
| vn_replace_vkFreeCommandBuffers_args_handle(args); |
| vkFreeCommandBuffers(args->device, args->commandPool, args->commandBufferCount, args->pCommandBuffers); |
| |
| struct vkr_command_buffer *cmd, *tmp; |
| LIST_FOR_EACH_ENTRY_SAFE(cmd, tmp, &free_cmds, head) |
| util_hash_table_remove_u64(ctx->object_table, cmd->base.id); |
| } |
| |
| static void |
| vkr_dispatch_vkResetCommandBuffer(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkResetCommandBuffer *args) |
| { |
| vn_replace_vkResetCommandBuffer_args_handle(args); |
| args->ret = vkResetCommandBuffer(args->commandBuffer, args->flags); |
| } |
| |
| static void |
| vkr_dispatch_vkBeginCommandBuffer(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkBeginCommandBuffer *args) |
| { |
| vn_replace_vkBeginCommandBuffer_args_handle(args); |
| args->ret = vkBeginCommandBuffer(args->commandBuffer, args->pBeginInfo); |
| } |
| |
| static void |
| vkr_dispatch_vkEndCommandBuffer(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkEndCommandBuffer *args) |
| { |
| vn_replace_vkEndCommandBuffer_args_handle(args); |
| args->ret = vkEndCommandBuffer(args->commandBuffer); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBindPipeline(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBindPipeline *args) |
| { |
| vn_replace_vkCmdBindPipeline_args_handle(args); |
| vkCmdBindPipeline(args->commandBuffer, args->pipelineBindPoint, args->pipeline); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetViewport(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetViewport *args) |
| { |
| vn_replace_vkCmdSetViewport_args_handle(args); |
| vkCmdSetViewport(args->commandBuffer, args->firstViewport, args->viewportCount, args->pViewports); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetScissor(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetScissor *args) |
| { |
| vn_replace_vkCmdSetScissor_args_handle(args); |
| vkCmdSetScissor(args->commandBuffer, args->firstScissor, args->scissorCount, args->pScissors); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetLineWidth(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetLineWidth *args) |
| { |
| vn_replace_vkCmdSetLineWidth_args_handle(args); |
| vkCmdSetLineWidth(args->commandBuffer, args->lineWidth); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetDepthBias(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetDepthBias *args) |
| { |
| vn_replace_vkCmdSetDepthBias_args_handle(args); |
| vkCmdSetDepthBias(args->commandBuffer, args->depthBiasConstantFactor, args->depthBiasClamp, args->depthBiasSlopeFactor); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetBlendConstants(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetBlendConstants *args) |
| { |
| vn_replace_vkCmdSetBlendConstants_args_handle(args); |
| vkCmdSetBlendConstants(args->commandBuffer, args->blendConstants); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetDepthBounds(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetDepthBounds *args) |
| { |
| vn_replace_vkCmdSetDepthBounds_args_handle(args); |
| vkCmdSetDepthBounds(args->commandBuffer, args->minDepthBounds, args->maxDepthBounds); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetStencilCompareMask(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetStencilCompareMask *args) |
| { |
| vn_replace_vkCmdSetStencilCompareMask_args_handle(args); |
| vkCmdSetStencilCompareMask(args->commandBuffer, args->faceMask, args->compareMask); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetStencilWriteMask(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetStencilWriteMask *args) |
| { |
| vn_replace_vkCmdSetStencilWriteMask_args_handle(args); |
| vkCmdSetStencilWriteMask(args->commandBuffer, args->faceMask, args->writeMask); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetStencilReference(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetStencilReference *args) |
| { |
| vn_replace_vkCmdSetStencilReference_args_handle(args); |
| vkCmdSetStencilReference(args->commandBuffer, args->faceMask, args->reference); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBindDescriptorSets(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBindDescriptorSets *args) |
| { |
| vn_replace_vkCmdBindDescriptorSets_args_handle(args); |
| vkCmdBindDescriptorSets(args->commandBuffer, args->pipelineBindPoint, args->layout, args->firstSet, args->descriptorSetCount, args->pDescriptorSets, args->dynamicOffsetCount, args->pDynamicOffsets); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBindIndexBuffer(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBindIndexBuffer *args) |
| { |
| vn_replace_vkCmdBindIndexBuffer_args_handle(args); |
| vkCmdBindIndexBuffer(args->commandBuffer, args->buffer, args->offset, args->indexType); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBindVertexBuffers(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBindVertexBuffers *args) |
| { |
| vn_replace_vkCmdBindVertexBuffers_args_handle(args); |
| vkCmdBindVertexBuffers(args->commandBuffer, args->firstBinding, args->bindingCount, args->pBuffers, args->pOffsets); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDraw(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDraw *args) |
| { |
| vn_replace_vkCmdDraw_args_handle(args); |
| vkCmdDraw(args->commandBuffer, args->vertexCount, args->instanceCount, args->firstVertex, args->firstInstance); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDrawIndexed(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDrawIndexed *args) |
| { |
| vn_replace_vkCmdDrawIndexed_args_handle(args); |
| vkCmdDrawIndexed(args->commandBuffer, args->indexCount, args->instanceCount, args->firstIndex, args->vertexOffset, args->firstInstance); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDrawIndirect(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDrawIndirect *args) |
| { |
| vn_replace_vkCmdDrawIndirect_args_handle(args); |
| vkCmdDrawIndirect(args->commandBuffer, args->buffer, args->offset, args->drawCount, args->stride); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDrawIndexedIndirect(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDrawIndexedIndirect *args) |
| { |
| vn_replace_vkCmdDrawIndexedIndirect_args_handle(args); |
| vkCmdDrawIndexedIndirect(args->commandBuffer, args->buffer, args->offset, args->drawCount, args->stride); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDispatch(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDispatch *args) |
| { |
| vn_replace_vkCmdDispatch_args_handle(args); |
| vkCmdDispatch(args->commandBuffer, args->groupCountX, args->groupCountY, args->groupCountZ); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDispatchIndirect(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDispatchIndirect *args) |
| { |
| vn_replace_vkCmdDispatchIndirect_args_handle(args); |
| vkCmdDispatchIndirect(args->commandBuffer, args->buffer, args->offset); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdCopyBuffer(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdCopyBuffer *args) |
| { |
| vn_replace_vkCmdCopyBuffer_args_handle(args); |
| vkCmdCopyBuffer(args->commandBuffer, args->srcBuffer, args->dstBuffer, args->regionCount, args->pRegions); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdCopyImage(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdCopyImage *args) |
| { |
| vn_replace_vkCmdCopyImage_args_handle(args); |
| vkCmdCopyImage(args->commandBuffer, args->srcImage, args->srcImageLayout, args->dstImage, args->dstImageLayout, args->regionCount, args->pRegions); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBlitImage(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBlitImage *args) |
| { |
| vn_replace_vkCmdBlitImage_args_handle(args); |
| vkCmdBlitImage(args->commandBuffer, args->srcImage, args->srcImageLayout, args->dstImage, args->dstImageLayout, args->regionCount, args->pRegions, args->filter); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdCopyBufferToImage(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdCopyBufferToImage *args) |
| { |
| vn_replace_vkCmdCopyBufferToImage_args_handle(args); |
| vkCmdCopyBufferToImage(args->commandBuffer, args->srcBuffer, args->dstImage, args->dstImageLayout, args->regionCount, args->pRegions); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdCopyImageToBuffer(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdCopyImageToBuffer *args) |
| { |
| vn_replace_vkCmdCopyImageToBuffer_args_handle(args); |
| vkCmdCopyImageToBuffer(args->commandBuffer, args->srcImage, args->srcImageLayout, args->dstBuffer, args->regionCount, args->pRegions); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdUpdateBuffer(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdUpdateBuffer *args) |
| { |
| vn_replace_vkCmdUpdateBuffer_args_handle(args); |
| vkCmdUpdateBuffer(args->commandBuffer, args->dstBuffer, args->dstOffset, args->dataSize, args->pData); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdFillBuffer(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdFillBuffer *args) |
| { |
| vn_replace_vkCmdFillBuffer_args_handle(args); |
| vkCmdFillBuffer(args->commandBuffer, args->dstBuffer, args->dstOffset, args->size, args->data); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdClearColorImage(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdClearColorImage *args) |
| { |
| vn_replace_vkCmdClearColorImage_args_handle(args); |
| vkCmdClearColorImage(args->commandBuffer, args->image, args->imageLayout, args->pColor, args->rangeCount, args->pRanges); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdClearDepthStencilImage(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdClearDepthStencilImage *args) |
| { |
| vn_replace_vkCmdClearDepthStencilImage_args_handle(args); |
| vkCmdClearDepthStencilImage(args->commandBuffer, args->image, args->imageLayout, args->pDepthStencil, args->rangeCount, args->pRanges); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdClearAttachments(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdClearAttachments *args) |
| { |
| vn_replace_vkCmdClearAttachments_args_handle(args); |
| vkCmdClearAttachments(args->commandBuffer, args->attachmentCount, args->pAttachments, args->rectCount, args->pRects); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdResolveImage(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdResolveImage *args) |
| { |
| vn_replace_vkCmdResolveImage_args_handle(args); |
| vkCmdResolveImage(args->commandBuffer, args->srcImage, args->srcImageLayout, args->dstImage, args->dstImageLayout, args->regionCount, args->pRegions); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetEvent(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetEvent *args) |
| { |
| vn_replace_vkCmdSetEvent_args_handle(args); |
| vkCmdSetEvent(args->commandBuffer, args->event, args->stageMask); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdResetEvent(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdResetEvent *args) |
| { |
| vn_replace_vkCmdResetEvent_args_handle(args); |
| vkCmdResetEvent(args->commandBuffer, args->event, args->stageMask); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdWaitEvents(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdWaitEvents *args) |
| { |
| vn_replace_vkCmdWaitEvents_args_handle(args); |
| vkCmdWaitEvents(args->commandBuffer, args->eventCount, args->pEvents, args->srcStageMask, args->dstStageMask, args->memoryBarrierCount, args->pMemoryBarriers, args->bufferMemoryBarrierCount, args->pBufferMemoryBarriers, args->imageMemoryBarrierCount, args->pImageMemoryBarriers); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdPipelineBarrier(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdPipelineBarrier *args) |
| { |
| vn_replace_vkCmdPipelineBarrier_args_handle(args); |
| vkCmdPipelineBarrier(args->commandBuffer, args->srcStageMask, args->dstStageMask, args->dependencyFlags, args->memoryBarrierCount, args->pMemoryBarriers, args->bufferMemoryBarrierCount, args->pBufferMemoryBarriers, args->imageMemoryBarrierCount, args->pImageMemoryBarriers); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBeginQuery(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBeginQuery *args) |
| { |
| vn_replace_vkCmdBeginQuery_args_handle(args); |
| vkCmdBeginQuery(args->commandBuffer, args->queryPool, args->query, args->flags); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdEndQuery(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdEndQuery *args) |
| { |
| vn_replace_vkCmdEndQuery_args_handle(args); |
| vkCmdEndQuery(args->commandBuffer, args->queryPool, args->query); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdResetQueryPool(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdResetQueryPool *args) |
| { |
| vn_replace_vkCmdResetQueryPool_args_handle(args); |
| vkCmdResetQueryPool(args->commandBuffer, args->queryPool, args->firstQuery, args->queryCount); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdWriteTimestamp(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdWriteTimestamp *args) |
| { |
| vn_replace_vkCmdWriteTimestamp_args_handle(args); |
| vkCmdWriteTimestamp(args->commandBuffer, args->pipelineStage, args->queryPool, args->query); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdCopyQueryPoolResults(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdCopyQueryPoolResults *args) |
| { |
| vn_replace_vkCmdCopyQueryPoolResults_args_handle(args); |
| vkCmdCopyQueryPoolResults(args->commandBuffer, args->queryPool, args->firstQuery, args->queryCount, args->dstBuffer, args->dstOffset, args->stride, args->flags); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdPushConstants(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdPushConstants *args) |
| { |
| vn_replace_vkCmdPushConstants_args_handle(args); |
| vkCmdPushConstants(args->commandBuffer, args->layout, args->stageFlags, args->offset, args->size, args->pValues); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBeginRenderPass(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBeginRenderPass *args) |
| { |
| vn_replace_vkCmdBeginRenderPass_args_handle(args); |
| vkCmdBeginRenderPass(args->commandBuffer, args->pRenderPassBegin, args->contents); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdNextSubpass(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdNextSubpass *args) |
| { |
| vn_replace_vkCmdNextSubpass_args_handle(args); |
| vkCmdNextSubpass(args->commandBuffer, args->contents); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdEndRenderPass(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdEndRenderPass *args) |
| { |
| vn_replace_vkCmdEndRenderPass_args_handle(args); |
| vkCmdEndRenderPass(args->commandBuffer); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdExecuteCommands(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdExecuteCommands *args) |
| { |
| vn_replace_vkCmdExecuteCommands_args_handle(args); |
| vkCmdExecuteCommands(args->commandBuffer, args->commandBufferCount, args->pCommandBuffers); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdSetDeviceMask(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdSetDeviceMask *args) |
| { |
| vn_replace_vkCmdSetDeviceMask_args_handle(args); |
| vkCmdSetDeviceMask(args->commandBuffer, args->deviceMask); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDispatchBase(UNUSED struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDispatchBase *args) |
| { |
| vn_replace_vkCmdDispatchBase_args_handle(args); |
| vkCmdDispatchBase(args->commandBuffer, args->baseGroupX, args->baseGroupY, args->baseGroupZ, args->groupCountX, args->groupCountY, args->groupCountZ); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBeginRenderPass2(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBeginRenderPass2 *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdBeginRenderPass2_args_handle(args); |
| cmd->device->CmdBeginRenderPass2(args->commandBuffer, args->pRenderPassBegin, args->pSubpassBeginInfo); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdNextSubpass2(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdNextSubpass2 *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdNextSubpass2_args_handle(args); |
| cmd->device->CmdNextSubpass2(args->commandBuffer, args->pSubpassBeginInfo, args->pSubpassEndInfo); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdEndRenderPass2(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdEndRenderPass2 *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdEndRenderPass2_args_handle(args); |
| cmd->device->CmdEndRenderPass2(args->commandBuffer, args->pSubpassEndInfo); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDrawIndirectCount(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDrawIndirectCount *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdDrawIndirectCount_args_handle(args); |
| cmd->device->CmdDrawIndirectCount(args->commandBuffer, args->buffer, args->offset, args->countBuffer, args->countBufferOffset, args->maxDrawCount, args->stride); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDrawIndexedIndirectCount(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDrawIndexedIndirectCount *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdDrawIndexedIndirectCount_args_handle(args); |
| cmd->device->CmdDrawIndexedIndirectCount(args->commandBuffer, args->buffer, args->offset, args->countBuffer, args->countBufferOffset, args->maxDrawCount, args->stride); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBindTransformFeedbackBuffersEXT(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBindTransformFeedbackBuffersEXT *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdBindTransformFeedbackBuffersEXT_args_handle(args); |
| cmd->device->cmd_bind_transform_feedback_buffers(args->commandBuffer, args->firstBinding, args->bindingCount, args->pBuffers, args->pOffsets, args->pSizes); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBeginTransformFeedbackEXT(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBeginTransformFeedbackEXT *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdBeginTransformFeedbackEXT_args_handle(args); |
| cmd->device->cmd_begin_transform_feedback(args->commandBuffer, args->firstCounterBuffer, args->counterBufferCount, args->pCounterBuffers, args->pCounterBufferOffsets); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdEndTransformFeedbackEXT(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdEndTransformFeedbackEXT *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdEndTransformFeedbackEXT_args_handle(args); |
| cmd->device->cmd_end_transform_feedback(args->commandBuffer, args->firstCounterBuffer, args->counterBufferCount, args->pCounterBuffers, args->pCounterBufferOffsets); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdBeginQueryIndexedEXT(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdBeginQueryIndexedEXT *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdBeginQueryIndexedEXT_args_handle(args); |
| cmd->device->cmd_begin_query_indexed(args->commandBuffer, args->queryPool, args->query, args->flags, args->index); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdEndQueryIndexedEXT(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdEndQueryIndexedEXT *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdEndQueryIndexedEXT_args_handle(args); |
| cmd->device->cmd_end_query_indexed(args->commandBuffer, args->queryPool, args->query, args->index); |
| } |
| |
| static void |
| vkr_dispatch_vkCmdDrawIndirectByteCountEXT(struct vn_dispatch_context *dispatch, struct vn_command_vkCmdDrawIndirectByteCountEXT *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_command_buffer *cmd = (struct vkr_command_buffer *)args->commandBuffer; |
| if (!cmd || cmd->base.type != VK_OBJECT_TYPE_COMMAND_BUFFER) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkCmdDrawIndirectByteCountEXT_args_handle(args); |
| cmd->device->cmd_draw_indirect_byte_count(args->commandBuffer, args->instanceCount, args->firstInstance, args->counterBuffer, args->counterBufferOffset, args->counterOffset, args->vertexStride); |
| } |
| |
| static void |
| vkr_dispatch_vkGetImageDrmFormatModifierPropertiesEXT(struct vn_dispatch_context *dispatch, struct vn_command_vkGetImageDrmFormatModifierPropertiesEXT *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| vn_replace_vkGetImageDrmFormatModifierPropertiesEXT_args_handle(args); |
| args->ret = dev->get_image_drm_format_modifier_properties(args->device, args->image, args->pProperties); |
| } |
| |
| static void |
| vkr_dispatch_vkGetMemoryResourcePropertiesMESA(struct vn_dispatch_context *dispatch, struct vn_command_vkGetMemoryResourcePropertiesMESA *args) |
| { |
| struct vkr_context *ctx = dispatch->data; |
| struct vkr_device *dev = (struct vkr_device *)args->device; |
| if (!dev || dev->base.type != VK_OBJECT_TYPE_DEVICE) { |
| vkr_cs_decoder_set_fatal(&ctx->decoder); |
| return; |
| } |
| |
| struct vkr_resource_attachment *att = util_hash_table_get(ctx->resource_table, uintptr_to_pointer(args->resourceId)); |
| if (!att || !att->resource) { |
| args->ret = VK_ERROR_INVALID_EXTERNAL_HANDLE; |
| return; |
| } |
| |
| int fd = -1; |
| enum virgl_resource_fd_type fd_type = virgl_resource_export_fd(att->resource, &fd); |
| VkExternalMemoryHandleTypeFlagBits handle_type; |
| if (!vkr_get_fd_handle_type_from_virgl_fd_type(dev->physical_device, fd_type, &handle_type)) { |
| close(fd); |
| args->ret = VK_ERROR_INVALID_EXTERNAL_HANDLE; |
| return; |
| } |
| |
| VkMemoryFdPropertiesKHR memory_fd_properties = { |
| .sType = VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR, |
| .pNext = NULL, |
| .memoryTypeBits = 0, |
| }; |
| vn_replace_vkGetMemoryResourcePropertiesMESA_args_handle(args); |
| args->ret = dev->get_memory_fd_properties(args->device, handle_type, fd, &memory_fd_properties); |
| args->pMemoryResourceProperties->memoryTypeBits = memory_fd_properties.memoryTypeBits; |
| close(fd); |
| } |
| |
| static void |
| vkr_dispatch_debug_log(UNUSED struct vn_dispatch_context *dispatch, const char *msg) |
| { |
| vrend_printf("vkr: %s\n", msg); |
| } |
| |
| static void |
| vkr_context_init_dispatch(struct vkr_context *ctx) |
| { |
| struct vn_dispatch_context *dispatch = &ctx->dispatch; |
| |
| dispatch->data = ctx; |
| dispatch->debug_log = vkr_dispatch_debug_log; |
| |
| dispatch->encoder = (struct vn_cs_encoder *)&ctx->encoder; |
| dispatch->decoder = (struct vn_cs_decoder *)&ctx->decoder; |
| |
| dispatch->dispatch_vkSetReplyCommandStreamMESA = vkr_dispatch_vkSetReplyCommandStreamMESA; |
| dispatch->dispatch_vkSeekReplyCommandStreamMESA = vkr_dispatch_vkSeekReplyCommandStreamMESA; |
| dispatch->dispatch_vkExecuteCommandStreamsMESA = vkr_dispatch_vkExecuteCommandStreamsMESA; |
| dispatch->dispatch_vkCreateRingMESA = vkr_dispatch_vkCreateRingMESA; |
| dispatch->dispatch_vkDestroyRingMESA = vkr_dispatch_vkDestroyRingMESA; |
| dispatch->dispatch_vkNotifyRingMESA = vkr_dispatch_vkNotifyRingMESA; |
| dispatch->dispatch_vkWriteRingExtraMESA = vkr_dispatch_vkWriteRingExtraMESA; |
| |
| dispatch->dispatch_vkEnumerateInstanceVersion = vkr_dispatch_vkEnumerateInstanceVersion; |
| dispatch->dispatch_vkEnumerateInstanceExtensionProperties = vkr_dispatch_vkEnumerateInstanceExtensionProperties; |
| /* we don't advertise layers (and should never) */ |
| dispatch->dispatch_vkEnumerateInstanceLayerProperties = NULL; |
| dispatch->dispatch_vkCreateInstance = vkr_dispatch_vkCreateInstance; |
| dispatch->dispatch_vkDestroyInstance = vkr_dispatch_vkDestroyInstance; |
| dispatch->dispatch_vkGetInstanceProcAddr = NULL; |
| |
| dispatch->dispatch_vkEnumeratePhysicalDevices = vkr_dispatch_vkEnumeratePhysicalDevices; |
| dispatch->dispatch_vkEnumeratePhysicalDeviceGroups = vkr_dispatch_vkEnumeratePhysicalDeviceGroups; |
| dispatch->dispatch_vkGetPhysicalDeviceFeatures = vkr_dispatch_vkGetPhysicalDeviceFeatures; |
| dispatch->dispatch_vkGetPhysicalDeviceProperties = vkr_dispatch_vkGetPhysicalDeviceProperties; |
| dispatch->dispatch_vkGetPhysicalDeviceQueueFamilyProperties = vkr_dispatch_vkGetPhysicalDeviceQueueFamilyProperties; |
| dispatch->dispatch_vkGetPhysicalDeviceMemoryProperties = vkr_dispatch_vkGetPhysicalDeviceMemoryProperties; |
| dispatch->dispatch_vkGetPhysicalDeviceFormatProperties = vkr_dispatch_vkGetPhysicalDeviceFormatProperties; |
| dispatch->dispatch_vkGetPhysicalDeviceImageFormatProperties = vkr_dispatch_vkGetPhysicalDeviceImageFormatProperties; |
| dispatch->dispatch_vkGetPhysicalDeviceSparseImageFormatProperties = vkr_dispatch_vkGetPhysicalDeviceSparseImageFormatProperties; |
| dispatch->dispatch_vkGetPhysicalDeviceFeatures2 = vkr_dispatch_vkGetPhysicalDeviceFeatures2; |
| dispatch->dispatch_vkGetPhysicalDeviceProperties2 = vkr_dispatch_vkGetPhysicalDeviceProperties2; |
| dispatch->dispatch_vkGetPhysicalDeviceQueueFamilyProperties2 = vkr_dispatch_vkGetPhysicalDeviceQueueFamilyProperties2; |
| dispatch->dispatch_vkGetPhysicalDeviceMemoryProperties2 = vkr_dispatch_vkGetPhysicalDeviceMemoryProperties2; |
| dispatch->dispatch_vkGetPhysicalDeviceFormatProperties2 = vkr_dispatch_vkGetPhysicalDeviceFormatProperties2; |
| dispatch->dispatch_vkGetPhysicalDeviceImageFormatProperties2 = vkr_dispatch_vkGetPhysicalDeviceImageFormatProperties2; |
| dispatch->dispatch_vkGetPhysicalDeviceSparseImageFormatProperties2 = vkr_dispatch_vkGetPhysicalDeviceSparseImageFormatProperties2; |
| dispatch->dispatch_vkGetPhysicalDeviceExternalBufferProperties = NULL; |
| dispatch->dispatch_vkGetPhysicalDeviceExternalSemaphoreProperties = NULL; |
| dispatch->dispatch_vkGetPhysicalDeviceExternalFenceProperties = NULL; |
| |
| dispatch->dispatch_vkEnumerateDeviceExtensionProperties = vkr_dispatch_vkEnumerateDeviceExtensionProperties; |
| dispatch->dispatch_vkEnumerateDeviceLayerProperties = NULL; |
| dispatch->dispatch_vkCreateDevice = vkr_dispatch_vkCreateDevice; |
| dispatch->dispatch_vkDestroyDevice = vkr_dispatch_vkDestroyDevice; |
| dispatch->dispatch_vkGetDeviceProcAddr = NULL; |
| dispatch->dispatch_vkGetDeviceGroupPeerMemoryFeatures = vkr_dispatch_vkGetDeviceGroupPeerMemoryFeatures; |
| dispatch->dispatch_vkDeviceWaitIdle = vkr_dispatch_vkDeviceWaitIdle; |
| |
| dispatch->dispatch_vkGetDeviceQueue = vkr_dispatch_vkGetDeviceQueue; |
| dispatch->dispatch_vkGetDeviceQueue2 = vkr_dispatch_vkGetDeviceQueue2; |
| dispatch->dispatch_vkQueueSubmit = vkr_dispatch_vkQueueSubmit; |
| dispatch->dispatch_vkQueueBindSparse = vkr_dispatch_vkQueueBindSparse; |
| dispatch->dispatch_vkQueueWaitIdle = vkr_dispatch_vkQueueWaitIdle; |
| |
| dispatch->dispatch_vkCreateFence = vkr_dispatch_vkCreateFence; |
| dispatch->dispatch_vkDestroyFence = vkr_dispatch_vkDestroyFence; |
| dispatch->dispatch_vkResetFences = vkr_dispatch_vkResetFences; |
| dispatch->dispatch_vkGetFenceStatus = vkr_dispatch_vkGetFenceStatus; |
| dispatch->dispatch_vkWaitForFences = vkr_dispatch_vkWaitForFences; |
| |
| dispatch->dispatch_vkCreateSemaphore = vkr_dispatch_vkCreateSemaphore; |
| dispatch->dispatch_vkDestroySemaphore = vkr_dispatch_vkDestroySemaphore; |
| dispatch->dispatch_vkGetSemaphoreCounterValue = vkr_dispatch_vkGetSemaphoreCounterValue; |
| dispatch->dispatch_vkWaitSemaphores = vkr_dispatch_vkWaitSemaphores; |
| dispatch->dispatch_vkSignalSemaphore = vkr_dispatch_vkSignalSemaphore; |
| |
| dispatch->dispatch_vkAllocateMemory = vkr_dispatch_vkAllocateMemory; |
| dispatch->dispatch_vkFreeMemory = vkr_dispatch_vkFreeMemory; |
| dispatch->dispatch_vkMapMemory = NULL; |
| dispatch->dispatch_vkUnmapMemory = NULL; |
| dispatch->dispatch_vkFlushMappedMemoryRanges = NULL; |
| dispatch->dispatch_vkInvalidateMappedMemoryRanges = NULL; |
| dispatch->dispatch_vkGetDeviceMemoryCommitment = vkr_dispatch_vkGetDeviceMemoryCommitment; |
| dispatch->dispatch_vkGetDeviceMemoryOpaqueCaptureAddress = vkr_dispatch_vkGetDeviceMemoryOpaqueCaptureAddress; |
| |
| dispatch->dispatch_vkCreateBuffer = vkr_dispatch_vkCreateBuffer; |
| dispatch->dispatch_vkDestroyBuffer = vkr_dispatch_vkDestroyBuffer; |
| dispatch->dispatch_vkGetBufferMemoryRequirements = vkr_dispatch_vkGetBufferMemoryRequirements; |
| dispatch->dispatch_vkGetBufferMemoryRequirements2 = vkr_dispatch_vkGetBufferMemoryRequirements2; |
| dispatch->dispatch_vkBindBufferMemory = vkr_dispatch_vkBindBufferMemory; |
| dispatch->dispatch_vkBindBufferMemory2 = vkr_dispatch_vkBindBufferMemory2; |
| dispatch->dispatch_vkGetBufferOpaqueCaptureAddress = vkr_dispatch_vkGetBufferOpaqueCaptureAddress; |
| dispatch->dispatch_vkGetBufferDeviceAddress = vkr_dispatch_vkGetBufferDeviceAddress; |
| |
| dispatch->dispatch_vkCreateBufferView = vkr_dispatch_vkCreateBufferView; |
| dispatch->dispatch_vkDestroyBufferView = vkr_dispatch_vkDestroyBufferView; |
| |
| dispatch->dispatch_vkCreateImage = vkr_dispatch_vkCreateImage; |
| dispatch->dispatch_vkDestroyImage = vkr_dispatch_vkDestroyImage; |
| dispatch->dispatch_vkGetImageMemoryRequirements = vkr_dispatch_vkGetImageMemoryRequirements; |
| dispatch->dispatch_vkGetImageMemoryRequirements2 = vkr_dispatch_vkGetImageMemoryRequirements2; |
| dispatch->dispatch_vkGetImageSparseMemoryRequirements = vkr_dispatch_vkGetImageSparseMemoryRequirements; |
| dispatch->dispatch_vkGetImageSparseMemoryRequirements2 = vkr_dispatch_vkGetImageSparseMemoryRequirements2; |
| dispatch->dispatch_vkBindImageMemory = vkr_dispatch_vkBindImageMemory; |
| dispatch->dispatch_vkBindImageMemory2 = vkr_dispatch_vkBindImageMemory2; |
| dispatch->dispatch_vkGetImageSubresourceLayout = vkr_dispatch_vkGetImageSubresourceLayout; |
| |
| dispatch->dispatch_vkCreateImageView = vkr_dispatch_vkCreateImageView; |
| dispatch->dispatch_vkDestroyImageView = vkr_dispatch_vkDestroyImageView; |
| |
| dispatch->dispatch_vkCreateSampler = vkr_dispatch_vkCreateSampler; |
| dispatch->dispatch_vkDestroySampler = vkr_dispatch_vkDestroySampler; |
| |
| dispatch->dispatch_vkCreateSamplerYcbcrConversion = vkr_dispatch_vkCreateSamplerYcbcrConversion; |
| dispatch->dispatch_vkDestroySamplerYcbcrConversion = vkr_dispatch_vkDestroySamplerYcbcrConversion; |
| |
| dispatch->dispatch_vkGetDescriptorSetLayoutSupport = vkr_dispatch_vkGetDescriptorSetLayoutSupport; |
| dispatch->dispatch_vkCreateDescriptorSetLayout = vkr_dispatch_vkCreateDescriptorSetLayout; |
| dispatch->dispatch_vkDestroyDescriptorSetLayout = vkr_dispatch_vkDestroyDescriptorSetLayout; |
| |
| dispatch->dispatch_vkCreateDescriptorPool = vkr_dispatch_vkCreateDescriptorPool; |
| dispatch->dispatch_vkDestroyDescriptorPool = vkr_dispatch_vkDestroyDescriptorPool; |
| dispatch->dispatch_vkResetDescriptorPool = vkr_dispatch_vkResetDescriptorPool; |
| |
| dispatch->dispatch_vkAllocateDescriptorSets = vkr_dispatch_vkAllocateDescriptorSets; |
| dispatch->dispatch_vkFreeDescriptorSets = vkr_dispatch_vkFreeDescriptorSets; |
| dispatch->dispatch_vkUpdateDescriptorSets = vkr_dispatch_vkUpdateDescriptorSets; |
| |
| dispatch->dispatch_vkCreateDescriptorUpdateTemplate = vkr_dispatch_vkCreateDescriptorUpdateTemplate; |
| dispatch->dispatch_vkDestroyDescriptorUpdateTemplate = vkr_dispatch_vkDestroyDescriptorUpdateTemplate; |
| dispatch->dispatch_vkUpdateDescriptorSetWithTemplate = NULL; |
| |
| dispatch->dispatch_vkCreateRenderPass = vkr_dispatch_vkCreateRenderPass; |
| dispatch->dispatch_vkCreateRenderPass2 = vkr_dispatch_vkCreateRenderPass2; |
| dispatch->dispatch_vkDestroyRenderPass = vkr_dispatch_vkDestroyRenderPass; |
| dispatch->dispatch_vkGetRenderAreaGranularity = vkr_dispatch_vkGetRenderAreaGranularity; |
| |
| dispatch->dispatch_vkCreateFramebuffer = vkr_dispatch_vkCreateFramebuffer; |
| dispatch->dispatch_vkDestroyFramebuffer = vkr_dispatch_vkDestroyFramebuffer; |
| |
| dispatch->dispatch_vkCreateEvent = vkr_dispatch_vkCreateEvent; |
| dispatch->dispatch_vkDestroyEvent = vkr_dispatch_vkDestroyEvent; |
| dispatch->dispatch_vkGetEventStatus = vkr_dispatch_vkGetEventStatus; |
| dispatch->dispatch_vkSetEvent = vkr_dispatch_vkSetEvent; |
| dispatch->dispatch_vkResetEvent = vkr_dispatch_vkResetEvent; |
| |
| dispatch->dispatch_vkCreateQueryPool = vkr_dispatch_vkCreateQueryPool; |
| dispatch->dispatch_vkDestroyQueryPool = vkr_dispatch_vkDestroyQueryPool; |
| dispatch->dispatch_vkGetQueryPoolResults = vkr_dispatch_vkGetQueryPoolResults; |
| dispatch->dispatch_vkResetQueryPool = vkr_dispatch_vkResetQueryPool; |
| |
| dispatch->dispatch_vkCreateShaderModule = vkr_dispatch_vkCreateShaderModule; |
| dispatch->dispatch_vkDestroyShaderModule = vkr_dispatch_vkDestroyShaderModule; |
| |
| dispatch->dispatch_vkCreatePipelineLayout = vkr_dispatch_vkCreatePipelineLayout; |
| dispatch->dispatch_vkDestroyPipelineLayout = vkr_dispatch_vkDestroyPipelineLayout; |
| |
| dispatch->dispatch_vkCreatePipelineCache = vkr_dispatch_vkCreatePipelineCache; |
| dispatch->dispatch_vkDestroyPipelineCache = vkr_dispatch_vkDestroyPipelineCache; |
| dispatch->dispatch_vkGetPipelineCacheData = vkr_dispatch_vkGetPipelineCacheData; |
| dispatch->dispatch_vkMergePipelineCaches = vkr_dispatch_vkMergePipelineCaches; |
| |
| dispatch->dispatch_vkCreateGraphicsPipelines = vkr_dispatch_vkCreateGraphicsPipelines; |
| dispatch->dispatch_vkCreateComputePipelines = vkr_dispatch_vkCreateComputePipelines; |
| dispatch->dispatch_vkDestroyPipeline = vkr_dispatch_vkDestroyPipeline; |
| |
| dispatch->dispatch_vkCreateCommandPool = vkr_dispatch_vkCreateCommandPool; |
| dispatch->dispatch_vkDestroyCommandPool = vkr_dispatch_vkDestroyCommandPool; |
| dispatch->dispatch_vkResetCommandPool = vkr_dispatch_vkResetCommandPool; |
| dispatch->dispatch_vkTrimCommandPool = vkr_dispatch_vkTrimCommandPool; |
| |
| dispatch->dispatch_vkAllocateCommandBuffers = vkr_dispatch_vkAllocateCommandBuffers; |
| dispatch->dispatch_vkFreeCommandBuffers = vkr_dispatch_vkFreeCommandBuffers; |
| dispatch->dispatch_vkResetCommandBuffer = vkr_dispatch_vkResetCommandBuffer; |
| dispatch->dispatch_vkBeginCommandBuffer = vkr_dispatch_vkBeginCommandBuffer; |
| dispatch->dispatch_vkEndCommandBuffer = vkr_dispatch_vkEndCommandBuffer; |
| |
| dispatch->dispatch_vkCmdBindPipeline = vkr_dispatch_vkCmdBindPipeline; |
| dispatch->dispatch_vkCmdSetViewport = vkr_dispatch_vkCmdSetViewport; |
| dispatch->dispatch_vkCmdSetScissor = vkr_dispatch_vkCmdSetScissor; |
| dispatch->dispatch_vkCmdSetLineWidth = vkr_dispatch_vkCmdSetLineWidth; |
| dispatch->dispatch_vkCmdSetDepthBias = vkr_dispatch_vkCmdSetDepthBias; |
| dispatch->dispatch_vkCmdSetBlendConstants = vkr_dispatch_vkCmdSetBlendConstants; |
| dispatch->dispatch_vkCmdSetDepthBounds = vkr_dispatch_vkCmdSetDepthBounds; |
| dispatch->dispatch_vkCmdSetStencilCompareMask = vkr_dispatch_vkCmdSetStencilCompareMask; |
| dispatch->dispatch_vkCmdSetStencilWriteMask = vkr_dispatch_vkCmdSetStencilWriteMask; |
| dispatch->dispatch_vkCmdSetStencilReference = vkr_dispatch_vkCmdSetStencilReference; |
| dispatch->dispatch_vkCmdBindDescriptorSets = vkr_dispatch_vkCmdBindDescriptorSets; |
| dispatch->dispatch_vkCmdBindIndexBuffer = vkr_dispatch_vkCmdBindIndexBuffer; |
| dispatch->dispatch_vkCmdBindVertexBuffers = vkr_dispatch_vkCmdBindVertexBuffers; |
| dispatch->dispatch_vkCmdDraw = vkr_dispatch_vkCmdDraw; |
| dispatch->dispatch_vkCmdDrawIndexed = vkr_dispatch_vkCmdDrawIndexed; |
| dispatch->dispatch_vkCmdDrawIndirect = vkr_dispatch_vkCmdDrawIndirect; |
| dispatch->dispatch_vkCmdDrawIndexedIndirect = vkr_dispatch_vkCmdDrawIndexedIndirect; |
| dispatch->dispatch_vkCmdDispatch = vkr_dispatch_vkCmdDispatch; |
| dispatch->dispatch_vkCmdDispatchIndirect = vkr_dispatch_vkCmdDispatchIndirect; |
| dispatch->dispatch_vkCmdCopyBuffer = vkr_dispatch_vkCmdCopyBuffer; |
| dispatch->dispatch_vkCmdCopyImage = vkr_dispatch_vkCmdCopyImage; |
| dispatch->dispatch_vkCmdBlitImage = vkr_dispatch_vkCmdBlitImage; |
| dispatch->dispatch_vkCmdCopyBufferToImage = vkr_dispatch_vkCmdCopyBufferToImage; |
| dispatch->dispatch_vkCmdCopyImageToBuffer = vkr_dispatch_vkCmdCopyImageToBuffer; |
| dispatch->dispatch_vkCmdUpdateBuffer = vkr_dispatch_vkCmdUpdateBuffer; |
| dispatch->dispatch_vkCmdFillBuffer = vkr_dispatch_vkCmdFillBuffer; |
| dispatch->dispatch_vkCmdClearColorImage = vkr_dispatch_vkCmdClearColorImage; |
| dispatch->dispatch_vkCmdClearDepthStencilImage = vkr_dispatch_vkCmdClearDepthStencilImage; |
| dispatch->dispatch_vkCmdClearAttachments = vkr_dispatch_vkCmdClearAttachments; |
| dispatch->dispatch_vkCmdResolveImage = vkr_dispatch_vkCmdResolveImage; |
| dispatch->dispatch_vkCmdSetEvent = vkr_dispatch_vkCmdSetEvent; |
| dispatch->dispatch_vkCmdResetEvent = vkr_dispatch_vkCmdResetEvent; |
| dispatch->dispatch_vkCmdWaitEvents = vkr_dispatch_vkCmdWaitEvents; |
| dispatch->dispatch_vkCmdPipelineBarrier = vkr_dispatch_vkCmdPipelineBarrier; |
| dispatch->dispatch_vkCmdBeginQuery = vkr_dispatch_vkCmdBeginQuery; |
| dispatch->dispatch_vkCmdEndQuery = vkr_dispatch_vkCmdEndQuery; |
| dispatch->dispatch_vkCmdResetQueryPool = vkr_dispatch_vkCmdResetQueryPool; |
| dispatch->dispatch_vkCmdWriteTimestamp = vkr_dispatch_vkCmdWriteTimestamp; |
| dispatch->dispatch_vkCmdCopyQueryPoolResults = vkr_dispatch_vkCmdCopyQueryPoolResults; |
| dispatch->dispatch_vkCmdPushConstants = vkr_dispatch_vkCmdPushConstants; |
| dispatch->dispatch_vkCmdBeginRenderPass = vkr_dispatch_vkCmdBeginRenderPass; |
| dispatch->dispatch_vkCmdNextSubpass = vkr_dispatch_vkCmdNextSubpass; |
| dispatch->dispatch_vkCmdEndRenderPass = vkr_dispatch_vkCmdEndRenderPass; |
| dispatch->dispatch_vkCmdExecuteCommands = vkr_dispatch_vkCmdExecuteCommands; |
| dispatch->dispatch_vkCmdSetDeviceMask = vkr_dispatch_vkCmdSetDeviceMask; |
| dispatch->dispatch_vkCmdDispatchBase = vkr_dispatch_vkCmdDispatchBase; |
| dispatch->dispatch_vkCmdBeginRenderPass2 = vkr_dispatch_vkCmdBeginRenderPass2; |
| dispatch->dispatch_vkCmdNextSubpass2 = vkr_dispatch_vkCmdNextSubpass2; |
| dispatch->dispatch_vkCmdEndRenderPass2 = vkr_dispatch_vkCmdEndRenderPass2; |
| dispatch->dispatch_vkCmdDrawIndirectCount = vkr_dispatch_vkCmdDrawIndirectCount; |
| dispatch->dispatch_vkCmdDrawIndexedIndirectCount = vkr_dispatch_vkCmdDrawIndexedIndirectCount; |
| |
| dispatch->dispatch_vkCmdBindTransformFeedbackBuffersEXT = vkr_dispatch_vkCmdBindTransformFeedbackBuffersEXT; |
| dispatch->dispatch_vkCmdBeginTransformFeedbackEXT = vkr_dispatch_vkCmdBeginTransformFeedbackEXT; |
| dispatch->dispatch_vkCmdEndTransformFeedbackEXT = vkr_dispatch_vkCmdEndTransformFeedbackEXT; |
| dispatch->dispatch_vkCmdBeginQueryIndexedEXT = vkr_dispatch_vkCmdBeginQueryIndexedEXT; |
| dispatch->dispatch_vkCmdEndQueryIndexedEXT = vkr_dispatch_vkCmdEndQueryIndexedEXT; |
| dispatch->dispatch_vkCmdDrawIndirectByteCountEXT = vkr_dispatch_vkCmdDrawIndirectByteCountEXT; |
| |
| dispatch->dispatch_vkGetImageDrmFormatModifierPropertiesEXT = vkr_dispatch_vkGetImageDrmFormatModifierPropertiesEXT; |
| |
| dispatch->dispatch_vkGetMemoryResourcePropertiesMESA = vkr_dispatch_vkGetMemoryResourcePropertiesMESA; |
| } |
| |
| static int |
| vkr_context_submit_fence_locked(struct virgl_context *base, |
| uint32_t flags, |
| uint64_t queue_id, |
| void *fence_cookie) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| struct vkr_queue *queue; |
| VkResult result; |
| |
| queue = util_hash_table_get_u64(ctx->object_table, queue_id); |
| if (!queue) |
| return -EINVAL; |
| struct vkr_device *dev = queue->device; |
| |
| struct vkr_queue_sync *sync; |
| if (LIST_IS_EMPTY(&dev->free_syncs)) { |
| sync = malloc(sizeof(*sync)); |
| if (!sync) |
| return -ENOMEM; |
| |
| const struct VkFenceCreateInfo create_info = { |
| .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, |
| }; |
| result = vkCreateFence(dev->base.handle.device, &create_info, NULL, &sync->fence); |
| if (result != VK_SUCCESS) { |
| free(sync); |
| return -ENOMEM; |
| } |
| } else { |
| sync = LIST_ENTRY(struct vkr_queue_sync, dev->free_syncs.next, head); |
| list_del(&sync->head); |
| vkResetFences(dev->base.handle.device, 1, &sync->fence); |
| } |
| |
| result = vkQueueSubmit(queue->base.handle.queue, 0, NULL, sync->fence); |
| if (result != VK_SUCCESS) { |
| list_add(&sync->head, &dev->free_syncs); |
| return -1; |
| } |
| |
| sync->flags = flags; |
| sync->fence_cookie = fence_cookie; |
| |
| if (queue->has_thread) { |
| mtx_lock(&queue->mutex); |
| list_addtail(&sync->head, &queue->pending_syncs); |
| mtx_unlock(&queue->mutex); |
| cnd_signal(&queue->cond); |
| } else { |
| list_addtail(&sync->head, &queue->pending_syncs); |
| } |
| |
| if (LIST_IS_EMPTY(&queue->busy_head)) |
| list_addtail(&queue->busy_head, &ctx->busy_queues); |
| |
| return 0; |
| } |
| |
| static int |
| vkr_context_submit_fence(struct virgl_context *base, |
| uint32_t flags, |
| uint64_t queue_id, |
| void *fence_cookie) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| int ret; |
| |
| mtx_lock(&ctx->mutex); |
| ret = vkr_context_submit_fence_locked(base, flags, queue_id, fence_cookie); |
| mtx_unlock(&ctx->mutex); |
| return ret; |
| } |
| |
| static void |
| vkr_context_retire_fences_locked(UNUSED struct virgl_context *base) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| struct vkr_queue_sync *sync, *sync_tmp; |
| struct vkr_queue *queue, *queue_tmp; |
| |
| /* flush first and once because the per-queue sync threads might write to |
| * it any time |
| */ |
| if (ctx->fence_eventfd >= 0) |
| flush_eventfd(ctx->fence_eventfd); |
| |
| LIST_FOR_EACH_ENTRY_SAFE(queue, queue_tmp, &ctx->busy_queues, busy_head) { |
| struct vkr_device *dev = queue->device; |
| struct list_head retired_syncs; |
| bool queue_empty; |
| |
| vkr_queue_retire_syncs(queue, &retired_syncs, &queue_empty); |
| |
| LIST_FOR_EACH_ENTRY_SAFE(sync, sync_tmp, &retired_syncs, head) { |
| ctx->base.fence_retire(&ctx->base, |
| queue->base.id, |
| sync->fence_cookie); |
| list_addtail(&sync->head, &dev->free_syncs); |
| } |
| |
| if (queue_empty) |
| list_delinit(&queue->busy_head); |
| } |
| } |
| |
| static void |
| vkr_context_retire_fences(struct virgl_context *base) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| mtx_lock(&ctx->mutex); |
| vkr_context_retire_fences_locked(base); |
| mtx_unlock(&ctx->mutex); |
| } |
| |
| static int vkr_context_get_fencing_fd(struct virgl_context *base) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| return ctx->fence_eventfd; |
| } |
| |
| static int vkr_context_submit_cmd(struct virgl_context *base, |
| const void *buffer, |
| size_t size) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| int ret = 0; |
| |
| mtx_lock(&ctx->mutex); |
| |
| vkr_cs_decoder_set_stream(&ctx->decoder, buffer, size); |
| |
| while (vkr_cs_decoder_has_command(&ctx->decoder)) { |
| vn_dispatch_command(&ctx->dispatch); |
| /* TODO consider the client malicious and disconnect it */ |
| if (vkr_cs_decoder_get_fatal(&ctx->decoder)) { |
| ret = EINVAL; |
| break; |
| } |
| } |
| |
| vkr_cs_decoder_reset(&ctx->decoder); |
| |
| mtx_unlock(&ctx->mutex); |
| |
| return ret; |
| } |
| |
| static int vkr_context_get_blob_locked(struct virgl_context *base, |
| uint64_t blob_id, |
| uint32_t flags, |
| struct virgl_context_blob *blob) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| struct vkr_device_memory *mem; |
| enum virgl_resource_fd_type fd_type = VIRGL_RESOURCE_FD_INVALID; |
| |
| mem = util_hash_table_get_u64(ctx->object_table, blob_id); |
| if (!mem || mem->base.type != VK_OBJECT_TYPE_DEVICE_MEMORY) |
| return EINVAL; |
| |
| /* a memory can only be exported once; we don't want two resources to point |
| * to the same storage. |
| */ |
| if (mem->exported) |
| return EINVAL; |
| |
| if (!mem->valid_fd_types) |
| return EINVAL; |
| |
| if (flags & VIRGL_RENDERER_BLOB_FLAG_USE_MAPPABLE) { |
| const bool host_visible = |
| mem->property_flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; |
| if (!host_visible) |
| return EINVAL; |
| } |
| |
| if (flags & VIRGL_RENDERER_BLOB_FLAG_USE_CROSS_DEVICE) { |
| if (!(mem->valid_fd_types & (1 << VIRGL_RESOURCE_FD_DMABUF))) |
| return EINVAL; |
| |
| fd_type = VIRGL_RESOURCE_FD_DMABUF; |
| } |
| |
| if (fd_type == VIRGL_RESOURCE_FD_INVALID) { |
| /* prefer dmabuf for easier mapping? prefer opaque for performance? */ |
| if (mem->valid_fd_types & (1 << VIRGL_RESOURCE_FD_DMABUF)) |
| fd_type = VIRGL_RESOURCE_FD_DMABUF; |
| else if (mem->valid_fd_types & (1 << VIRGL_RESOURCE_FD_OPAQUE)) |
| fd_type = VIRGL_RESOURCE_FD_OPAQUE; |
| } |
| |
| int fd = -1; |
| if (fd_type != VIRGL_RESOURCE_FD_INVALID) { |
| VkExternalMemoryHandleTypeFlagBits handle_type; |
| switch (fd_type) { |
| case VIRGL_RESOURCE_FD_DMABUF: |
| handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; |
| break; |
| case VIRGL_RESOURCE_FD_OPAQUE: |
| handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; |
| break; |
| default: |
| return EINVAL; |
| } |
| |
| VkResult result = ctx->instance->get_memory_fd(mem->device, |
| &(VkMemoryGetFdInfoKHR){ |
| .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, |
| .memory = mem->base.handle.device_memory, |
| .handleType = handle_type, |
| }, &fd); |
| if (result != VK_SUCCESS) |
| return EINVAL; |
| } |
| |
| blob->type = fd_type; |
| blob->u.fd = fd; |
| |
| if (flags & VIRGL_RENDERER_BLOB_FLAG_USE_MAPPABLE) { |
| const bool host_coherent = |
| mem->property_flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; |
| const bool host_cached = |
| mem->property_flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT; |
| |
| /* XXX guessed */ |
| if (host_coherent) { |
| blob->map_info = host_cached ? |
| VIRGL_RENDERER_MAP_CACHE_CACHED : VIRGL_RENDERER_MAP_CACHE_WC; |
| } else { |
| blob->map_info = VIRGL_RENDERER_MAP_CACHE_WC; |
| } |
| } else { |
| blob->map_info = VIRGL_RENDERER_MAP_CACHE_NONE; |
| } |
| |
| blob->renderer_data = mem; |
| |
| return 0; |
| } |
| |
| static int vkr_context_get_blob(struct virgl_context *base, |
| uint64_t blob_id, |
| uint32_t flags, |
| struct virgl_context_blob *blob) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| int ret; |
| |
| mtx_lock(&ctx->mutex); |
| ret = vkr_context_get_blob_locked(base, blob_id, flags, blob); |
| /* XXX unlock in vkr_context_get_blob_done on success */ |
| if (ret) |
| mtx_unlock(&ctx->mutex); |
| |
| return ret; |
| } |
| |
| static void vkr_context_get_blob_done(struct virgl_context *base, |
| uint32_t res_id, |
| struct virgl_context_blob *blob) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| struct vkr_device_memory *mem = blob->renderer_data; |
| |
| mem->exported = true; |
| mem->exported_res_id = res_id; |
| list_add(&mem->head, &ctx->newly_exported_memories); |
| |
| /* XXX locked in vkr_context_get_blob */ |
| mtx_unlock(&ctx->mutex); |
| } |
| |
| static int vkr_context_transfer_3d_locked(struct virgl_context *base, |
| struct virgl_resource *res, |
| const struct vrend_transfer_info *info, |
| int transfer_mode) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| struct vkr_resource_attachment *att; |
| const struct iovec *iov; |
| int iov_count; |
| |
| if (info->level || info->stride || info->layer_stride) |
| return EINVAL; |
| |
| if (info->iovec) { |
| iov = info->iovec; |
| iov_count = info->iovec_cnt; |
| } else { |
| iov = res->iov; |
| iov_count = res->iov_count; |
| } |
| |
| if (!iov || !iov_count) |
| return 0; |
| |
| att = util_hash_table_get(ctx->resource_table, |
| uintptr_to_pointer(res->res_id)); |
| if (!att) |
| return EINVAL; |
| |
| assert(att->resource == res); |
| |
| /* TODO transfer via dmabuf (and find a solution to coherency issues) */ |
| if (LIST_IS_EMPTY(&att->memories)) { |
| vrend_printf("unable to transfer without VkDeviceMemory (TODO)"); |
| return EINVAL; |
| } |
| |
| struct vkr_device_memory *mem = |
| LIST_ENTRY(struct vkr_device_memory, att->memories.next, head); |
| const VkMappedMemoryRange range = { |
| .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, |
| .memory = mem->base.handle.device_memory, |
| .offset = info->box->x, |
| .size = info->box->width, |
| }; |
| |
| void *ptr; |
| VkResult result = vkMapMemory(mem->device, range.memory, |
| range.offset, range.size, 0, &ptr); |
| if (result != VK_SUCCESS) |
| return EINVAL; |
| |
| if (transfer_mode == VIRGL_TRANSFER_TO_HOST) { |
| vrend_read_from_iovec(iov, iov_count, range.offset, ptr, range.size); |
| vkFlushMappedMemoryRanges(mem->device, 1, &range); |
| } else { |
| vkInvalidateMappedMemoryRanges(mem->device, 1, &range); |
| vrend_write_to_iovec(iov, iov_count, range.offset, ptr, range.size); |
| } |
| |
| vkUnmapMemory(mem->device, range.memory); |
| |
| return 0; |
| } |
| |
| static int vkr_context_transfer_3d(struct virgl_context *base, |
| struct virgl_resource *res, |
| const struct vrend_transfer_info *info, |
| int transfer_mode) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| int ret; |
| |
| mtx_lock(&ctx->mutex); |
| ret = vkr_context_transfer_3d_locked(base, res, info, transfer_mode); |
| mtx_unlock(&ctx->mutex); |
| |
| return ret; |
| } |
| |
| static void vkr_context_attach_resource_locked(struct virgl_context *base, |
| struct virgl_resource *res) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| struct vkr_resource_attachment *att; |
| |
| att = util_hash_table_get(ctx->resource_table, |
| uintptr_to_pointer(res->res_id)); |
| if (att) { |
| assert(att->resource == res); |
| return; |
| } |
| |
| att = calloc(1, sizeof(*att)); |
| if (!att) |
| return; |
| |
| /* TODO When in multi-process mode, we cannot share a virgl_resource as-is |
| * to another process. The resource must have a valid fd, and only the fd |
| * and the iov can be sent the other process. |
| * |
| * For vrend-to-vkr sharing, we can get the fd from pipe_resource. |
| */ |
| |
| att->resource = res; |
| list_inithead(&att->memories); |
| |
| /* associate a memory with the resource, if any */ |
| struct vkr_device_memory *mem; |
| LIST_FOR_EACH_ENTRY(mem, &ctx->newly_exported_memories, head) { |
| if (mem->exported_res_id == res->res_id) { |
| list_del(&mem->head); |
| list_addtail(&mem->head, &att->memories); |
| break; |
| } |
| } |
| |
| util_hash_table_set(ctx->resource_table, |
| uintptr_to_pointer(res->res_id), |
| att); |
| } |
| |
| static void vkr_context_attach_resource(struct virgl_context *base, |
| struct virgl_resource *res) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| mtx_lock(&ctx->mutex); |
| vkr_context_attach_resource_locked(base, res); |
| mtx_unlock(&ctx->mutex); |
| } |
| |
| static void vkr_context_detach_resource(struct virgl_context *base, |
| struct virgl_resource *res) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| |
| mtx_lock(&ctx->mutex); |
| util_hash_table_remove(ctx->resource_table, |
| uintptr_to_pointer(res->res_id)); |
| mtx_unlock(&ctx->mutex); |
| } |
| |
| static void vkr_context_destroy(struct virgl_context *base) |
| { |
| struct vkr_context *ctx = (struct vkr_context *)base; |
| |
| struct vkr_ring *ring, *ring_tmp; |
| LIST_FOR_EACH_ENTRY_SAFE(ring, ring_tmp, &ctx->rings, head) { |
| vkr_ring_stop(ring); |
| vkr_ring_destroy(ring); |
| } |
| |
| /* TODO properly destroy all Vulkan objects */ |
| util_hash_table_destroy(ctx->resource_table); |
| util_hash_table_destroy_u64(ctx->object_table); |
| |
| if (ctx->fence_eventfd >= 0) |
| close(ctx->fence_eventfd); |
| |
| vkr_cs_decoder_fini(&ctx->decoder); |
| |
| mtx_destroy(&ctx->mutex); |
| free(ctx->debug_name); |
| free(ctx); |
| } |
| |
| static void |
| vkr_context_init_base(struct vkr_context *ctx) |
| { |
| ctx->base.destroy = vkr_context_destroy; |
| ctx->base.attach_resource = vkr_context_attach_resource; |
| ctx->base.detach_resource = vkr_context_detach_resource; |
| ctx->base.transfer_3d = vkr_context_transfer_3d; |
| ctx->base.get_blob = vkr_context_get_blob; |
| ctx->base.get_blob_done = vkr_context_get_blob_done; |
| ctx->base.submit_cmd = vkr_context_submit_cmd; |
| |
| ctx->base.get_fencing_fd = vkr_context_get_fencing_fd; |
| ctx->base.retire_fences =vkr_context_retire_fences; |
| ctx->base.submit_fence = vkr_context_submit_fence; |
| } |
| |
| static void |
| destroy_func_object(void *val) |
| { |
| struct vkr_object *obj = val; |
| free(obj); |
| } |
| |
| static void |
| destroy_func_resource(void *val) |
| { |
| struct vkr_resource_attachment *att = val; |
| struct vkr_device_memory *mem, *tmp; |
| |
| LIST_FOR_EACH_ENTRY_SAFE(mem, tmp, &att->memories, head) |
| list_delinit(&mem->head); |
| |
| free(att); |
| } |
| |
| struct virgl_context * |
| vkr_context_create(size_t debug_len, const char *debug_name) |
| { |
| struct vkr_context *ctx; |
| |
| /* TODO inject a proxy context when multi-process */ |
| |
| ctx = calloc(1, sizeof(*ctx)); |
| if (!ctx) |
| return NULL; |
| |
| ctx->debug_name = malloc(debug_len + 1); |
| if (!ctx->debug_name) { |
| free(ctx); |
| return NULL; |
| } |
| |
| memcpy(ctx->debug_name, debug_name, debug_len); |
| ctx->debug_name[debug_len] = '\0'; |
| |
| if (mtx_init(&ctx->mutex, mtx_plain) != thrd_success) { |
| free(ctx->debug_name); |
| free(ctx); |
| return NULL; |
| } |
| |
| list_inithead(&ctx->rings); |
| |
| ctx->object_table = |
| util_hash_table_create_u64(destroy_func_object); |
| ctx->resource_table = |
| util_hash_table_create(hash_func_u32, |
| compare_func, |
| destroy_func_resource); |
| if (!ctx->object_table || !ctx->resource_table) |
| goto fail; |
| |
| list_inithead(&ctx->newly_exported_memories); |
| |
| vkr_cs_decoder_init(&ctx->decoder, ctx->object_table); |
| vkr_cs_encoder_init(&ctx->encoder, &ctx->decoder.fatal_error); |
| |
| vkr_context_init_base(ctx); |
| vkr_context_init_dispatch(ctx); |
| |
| if (vkr_renderer_flags & VKR_RENDERER_THREAD_SYNC) { |
| ctx->fence_eventfd = create_eventfd(0); |
| if (ctx->fence_eventfd < 0) |
| goto fail; |
| } else { |
| ctx->fence_eventfd = -1; |
| } |
| |
| list_inithead(&ctx->busy_queues); |
| |
| return &ctx->base; |
| |
| fail: |
| if (ctx->object_table) |
| util_hash_table_destroy_u64(ctx->object_table); |
| if (ctx->resource_table) |
| util_hash_table_destroy(ctx->resource_table); |
| mtx_destroy(&ctx->mutex); |
| free(ctx->debug_name); |
| free(ctx); |
| return NULL; |
| } |
| |
| size_t |
| vkr_get_capset(void *capset) |
| { |
| struct virgl_renderer_capset_venus *c = capset; |
| if (c) { |
| memset(c, 0, sizeof(*c)); |
| c->wire_format_version = vn_info_wire_format_version(); |
| c->vk_xml_version = vn_info_vk_xml_version(); |
| c->vk_ext_command_serialization_spec_version = vn_info_extension_spec_version("VK_EXT_command_serialization"); |
| c->vk_mesa_venus_protocol_spec_version = vn_info_extension_spec_version("VK_MESA_venus_protocol"); |
| } |
| |
| return sizeof(*c); |
| } |
| |
| int |
| vkr_renderer_init(uint32_t flags) |
| { |
| /* TODO VKR_RENDERER_MULTI_PROCESS hint */ |
| |
| vkr_renderer_flags = flags; |
| |
| return 0; |
| } |
| |
| void |
| vkr_renderer_fini(void) |
| { |
| vkr_renderer_flags = 0; |
| } |
| |
| void |
| vkr_renderer_reset(void) |
| { |
| } |