|
|
|
/*
|
|
|
|
* Copyright 2020 Google LLC
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "vkr_device.h"
|
|
|
|
|
|
|
|
#include "venus-protocol/vn_protocol_renderer_device.h"
|
|
|
|
|
|
|
|
#include "vkr_command_buffer.h"
|
|
|
|
#include "vkr_context.h"
|
|
|
|
#include "vkr_descriptor_set.h"
|
|
|
|
#include "vkr_device_memory.h"
|
|
|
|
#include "vkr_physical_device.h"
|
|
|
|
#include "vkr_queue.h"
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
mtx_init(&dev->free_sync_mutex, mtx_plain);
|
|
|
|
list_inithead(&dev->free_syncs);
|
|
|
|
|
|
|
|
list_inithead(&dev->objects);
|
|
|
|
|
|
|
|
list_add(&dev->base.track_head, &physical_dev->devices);
|
|
|
|
|
|
|
|
util_hash_table_set_u64(ctx->object_table, dev->base.id, dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vkr_device_object_destroy(struct vkr_context *ctx,
|
|
|
|
struct vkr_device *dev,
|
|
|
|
struct vkr_object *obj)
|
|
|
|
{
|
|
|
|
VkDevice device = dev->base.handle.device;
|
|
|
|
|
|
|
|
switch (obj->type) {
|
|
|
|
case VK_OBJECT_TYPE_SEMAPHORE:
|
|
|
|
vkDestroySemaphore(device, obj->handle.semaphore, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_FENCE:
|
|
|
|
vkDestroyFence(device, obj->handle.fence, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_DEVICE_MEMORY:
|
|
|
|
vkFreeMemory(device, obj->handle.device_memory, NULL);
|
|
|
|
|
|
|
|
/* remove device memory from exported or attachment list */
|
|
|
|
list_del(&((struct vkr_device_memory *)obj)->exported_head);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_BUFFER:
|
|
|
|
vkDestroyBuffer(device, obj->handle.buffer, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_IMAGE:
|
|
|
|
vkDestroyImage(device, obj->handle.image, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_EVENT:
|
|
|
|
vkDestroyEvent(device, obj->handle.event, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_QUERY_POOL:
|
|
|
|
vkDestroyQueryPool(device, obj->handle.query_pool, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_BUFFER_VIEW:
|
|
|
|
vkDestroyBufferView(device, obj->handle.buffer_view, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_IMAGE_VIEW:
|
|
|
|
vkDestroyImageView(device, obj->handle.image_view, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_SHADER_MODULE:
|
|
|
|
vkDestroyShaderModule(device, obj->handle.shader_module, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_PIPELINE_CACHE:
|
|
|
|
vkDestroyPipelineCache(device, obj->handle.pipeline_cache, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_PIPELINE_LAYOUT:
|
|
|
|
vkDestroyPipelineLayout(device, obj->handle.pipeline_layout, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_RENDER_PASS:
|
|
|
|
vkDestroyRenderPass(device, obj->handle.render_pass, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_PIPELINE:
|
|
|
|
vkDestroyPipeline(device, obj->handle.pipeline, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT:
|
|
|
|
vkDestroyDescriptorSetLayout(device, obj->handle.descriptor_set_layout, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_SAMPLER:
|
|
|
|
vkDestroySampler(device, obj->handle.sampler, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_DESCRIPTOR_POOL: {
|
|
|
|
/* Destroying VkDescriptorPool frees all VkDescriptorSet objects that were allocated
|
|
|
|
* from it.
|
|
|
|
*/
|
|
|
|
vkDestroyDescriptorPool(device, obj->handle.descriptor_pool, NULL);
|
|
|
|
|
|
|
|
struct vkr_descriptor_pool *pool = (struct vkr_descriptor_pool *)obj;
|
|
|
|
vkr_context_remove_objects(ctx, &pool->descriptor_sets);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case VK_OBJECT_TYPE_FRAMEBUFFER:
|
|
|
|
vkDestroyFramebuffer(device, obj->handle.framebuffer, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_COMMAND_POOL: {
|
|
|
|
/* Destroying VkCommandPool frees all VkCommandBuffer objects that were allocated
|
|
|
|
* from it.
|
|
|
|
*/
|
|
|
|
vkDestroyCommandPool(device, obj->handle.command_pool, NULL);
|
|
|
|
|
|
|
|
struct vkr_command_pool *pool = (struct vkr_command_pool *)obj;
|
|
|
|
vkr_context_remove_objects(ctx, &pool->command_buffers);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION:
|
|
|
|
vkDestroySamplerYcbcrConversion(device, obj->handle.sampler_ycbcr_conversion, NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE:
|
|
|
|
vkDestroyDescriptorUpdateTemplate(device, obj->handle.descriptor_update_template,
|
|
|
|
NULL);
|
|
|
|
break;
|
|
|
|
case VK_OBJECT_TYPE_INSTANCE: /* non-device objects */
|
|
|
|
case VK_OBJECT_TYPE_PHYSICAL_DEVICE: /* non-device objects */
|
|
|
|
case VK_OBJECT_TYPE_DEVICE: /* device itself */
|
|
|
|
case VK_OBJECT_TYPE_QUEUE: /* not tracked as device objects */
|
|
|
|
case VK_OBJECT_TYPE_COMMAND_BUFFER: /* pool objects */
|
|
|
|
case VK_OBJECT_TYPE_DESCRIPTOR_SET: /* pool objects */
|
|
|
|
default:
|
|
|
|
vrend_printf("Unhandled vkr_object(%p) with VkObjectType(%u)\n", obj,
|
|
|
|
(uint32_t)obj->type);
|
|
|
|
assert(false);
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
|
|
|
list_del(&obj->track_head);
|
|
|
|
|
|
|
|
util_hash_table_remove_u64(ctx->object_table, obj->id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vkr_device_destroy(struct vkr_context *ctx, struct vkr_device *dev)
|
|
|
|
{
|
|
|
|
VkDevice device = dev->base.handle.device;
|
|
|
|
VkResult ret = vkDeviceWaitIdle(device);
|
|
|
|
if (ret != VK_SUCCESS)
|
|
|
|
vrend_printf("vkDeviceWaitIdle(%p) failed(%d)", dev, (int32_t)ret);
|
|
|
|
|
|
|
|
if (!LIST_IS_EMPTY(&dev->objects)) {
|
|
|
|
vrend_printf("destroying device with valid objects");
|
|
|
|
|
|
|
|
struct vkr_object *obj, *obj_tmp;
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE (obj, obj_tmp, &dev->objects, track_head)
|
|
|
|
vkr_device_object_destroy(ctx, dev, obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
mtx_destroy(&dev->free_sync_mutex);
|
|
|
|
|
|
|
|
vkDestroyDevice(device, NULL);
|
|
|
|
|
|
|
|
list_del(&dev->base.track_head);
|
|
|
|
|
|
|
|
util_hash_table_remove_u64(ctx->object_table, dev->base.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
vkr_device_destroy(ctx, dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
vkr_context_init_device_dispatch(struct vkr_context *ctx)
|
|
|
|
{
|
|
|
|
struct vn_dispatch_context *dispatch = &ctx->dispatch;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|