/* * Copyright 2020 Google LLC * SPDX-License-Identifier: MIT */ #include "vkr_renderer.h" #include #include #include #include #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 "vrend_debug.h" #include "vrend_iov.h" #include "vkr_cs.h" #include "vkr_object.h" #include "vkr_ring.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->enabledLayerCount) { args->ret = VK_ERROR_LAYER_NOT_PRESENT; return; } if (args->pCreateInfo->enabledExtensionCount) { args->ret = VK_ERROR_EXTENSION_NOT_PRESENT; return; } uint32_t instance_version; args->ret = vkEnumerateInstanceVersion(&instance_version); if (args->ret != VK_SUCCESS) return; /* require Vulkan 1.1 */ if (instance_version < VK_API_VERSION_1_1) { args->ret = VK_ERROR_INITIALIZATION_FAILED; return; } VkInstanceCreateInfo *create_info = (VkInstanceCreateInfo *)args->pCreateInfo; /* patch apiVersion */ VkApplicationInfo app_info = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .apiVersion = VK_API_VERSION_1_1, }; if (create_info->pApplicationInfo) { app_info = *create_info->pApplicationInfo; if (app_info.apiVersion < VK_API_VERSION_1_1) app_info.apiVersion = VK_API_VERSION_1_1; } create_info->pApplicationInfo = &app_info; struct vkr_instance *instance = calloc(1, sizeof(*instance)); if (!instance) { args->ret = VK_ERROR_OUT_OF_HOST_MEMORY; return; } 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(create_info, 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) { }