From 6bbd96259ab9a92885e2c78ce8399a5fd6064078 Mon Sep 17 00:00:00 2001 From: Vivek Pandya Date: Sat, 5 Sep 2020 17:18:28 +0530 Subject: [PATCH] Making SWAPChain exntesions work. There is lots of commented code. --- src/libre-soc/vulkan/libresoc_cmd_buffer.c | 306 ++++ src/libre-soc/vulkan/libresoc_device.c | 792 +++++++++- src/libre-soc/vulkan/libresoc_extensions.py | 21 +- src/libre-soc/vulkan/libresoc_formats.c | 1355 +++++++++++++++++ src/libre-soc/vulkan/libresoc_image.c | 159 ++ src/libre-soc/vulkan/libresoc_meta_clear.c | 36 + .../vulkan/libresoc_pipeline_cache.c | 646 ++++++++ src/libre-soc/vulkan/libresoc_private.h | 285 +++- src/libre-soc/vulkan/libresoc_wsi.c | 351 +++++ src/libre-soc/vulkan/libresoc_wsi_x11.c | 105 ++ src/libre-soc/vulkan/meson.build | 69 +- 11 files changed, 4012 insertions(+), 113 deletions(-) create mode 100644 src/libre-soc/vulkan/libresoc_cmd_buffer.c create mode 100644 src/libre-soc/vulkan/libresoc_formats.c create mode 100644 src/libre-soc/vulkan/libresoc_image.c create mode 100644 src/libre-soc/vulkan/libresoc_meta_clear.c create mode 100644 src/libre-soc/vulkan/libresoc_pipeline_cache.c create mode 100644 src/libre-soc/vulkan/libresoc_wsi.c create mode 100644 src/libre-soc/vulkan/libresoc_wsi_x11.c diff --git a/src/libre-soc/vulkan/libresoc_cmd_buffer.c b/src/libre-soc/vulkan/libresoc_cmd_buffer.c new file mode 100644 index 00000000000..a865f5bd816 --- /dev/null +++ b/src/libre-soc/vulkan/libresoc_cmd_buffer.c @@ -0,0 +1,306 @@ + +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * based in part on anv driver which is: + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "libresoc_private.h" + +void libresoc_FreeCommandBuffers( + VkDevice device, + VkCommandPool commandPool, + uint32_t commandBufferCount, + const VkCommandBuffer *pCommandBuffers) +{ + //TODO: stub +} + +VkResult libresoc_CreateCommandPool( + VkDevice _device, + const VkCommandPoolCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkCommandPool* pCmdPool) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + struct libresoc_cmd_pool *pool; + + pool = vk_alloc2(&device->vk.alloc, pAllocator, sizeof(*pool), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (pool == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + vk_object_base_init(&device->vk, &pool->base, + VK_OBJECT_TYPE_COMMAND_POOL); + + if (pAllocator) + pool->alloc = *pAllocator; + else + pool->alloc = device->vk.alloc; + + list_inithead(&pool->cmd_buffers); + list_inithead(&pool->free_cmd_buffers); + + pool->queue_family_index = pCreateInfo->queueFamilyIndex; + + *pCmdPool = libresoc_cmd_pool_to_handle(pool); + + return VK_SUCCESS; + +} + +void libresoc_DestroyCommandPool( + VkDevice _device, + VkCommandPool commandPool, + const VkAllocationCallbacks* pAllocator) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + LIBRESOC_FROM_HANDLE(libresoc_cmd_pool, pool, commandPool); + + if (!pool) + return; + + // list_for_each_entry_safe(struct libresoc_cmd_buffer, cmd_buffer, + // &pool->cmd_buffers, pool_link) { + // libresoc_destroy_cmd_buffer(cmd_buffer); + // } + + // list_for_each_entry_safe(struct libresoc_cmd_buffer, cmd_buffer, + // &pool->free_cmd_buffers, pool_link) { + // libresoc_destroy_cmd_buffer(cmd_buffer); + // } + + vk_object_base_finish(&pool->base); + vk_free2(&device->vk.alloc, pAllocator, pool); +} + +static VkResult libresoc_create_cmd_buffer( + struct libresoc_device * device, + struct libresoc_cmd_pool * pool, + VkCommandBufferLevel level, + VkCommandBuffer* pCommandBuffer) +{ + struct libresoc_cmd_buffer *cmd_buffer; + unsigned ring; + cmd_buffer = vk_zalloc(&pool->alloc, sizeof(*cmd_buffer), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (cmd_buffer == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + vk_object_base_init(&device->vk, &cmd_buffer->base, + VK_OBJECT_TYPE_COMMAND_BUFFER); + + cmd_buffer->device = device; + cmd_buffer->pool = pool; + cmd_buffer->level = level; + + list_addtail(&cmd_buffer->pool_link, &pool->cmd_buffers); + cmd_buffer->queue_family_index = pool->queue_family_index; + + // ring = libresoc_queue_family_to_ring(cmd_buffer->queue_family_index); + + // cmd_buffer->cs = device->ws->cs_create(device->ws, ring); + // if (!cmd_buffer->cs) { + // libresoc_destroy_cmd_buffer(cmd_buffer); + // return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + // } + + *pCommandBuffer = libresoc_cmd_buffer_to_handle(cmd_buffer); + + list_inithead(&cmd_buffer->upload.list); + + return VK_SUCCESS; +} + +VkResult libresoc_AllocateCommandBuffers( + VkDevice _device, + const VkCommandBufferAllocateInfo *pAllocateInfo, + VkCommandBuffer *pCommandBuffers) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + LIBRESOC_FROM_HANDLE(libresoc_cmd_pool, pool, pAllocateInfo->commandPool); + + VkResult result = VK_SUCCESS; + uint32_t i; + + for (i = 0; i < pAllocateInfo->commandBufferCount; i++) { + + if (!list_is_empty(&pool->free_cmd_buffers)) { + struct libresoc_cmd_buffer *cmd_buffer = list_first_entry(&pool->free_cmd_buffers, struct libresoc_cmd_buffer, pool_link); + + list_del(&cmd_buffer->pool_link); + list_addtail(&cmd_buffer->pool_link, &pool->cmd_buffers); + + //result = libresoc_reset_cmd_buffer(cmd_buffer); + cmd_buffer->level = pAllocateInfo->level; + + pCommandBuffers[i] = libresoc_cmd_buffer_to_handle(cmd_buffer); + } else { + result = libresoc_create_cmd_buffer(device, pool, pAllocateInfo->level, + &pCommandBuffers[i]); + } + if (result != VK_SUCCESS) + break; + } + + // if (result != VK_SUCCESS) { + // libresoc_FreeCommandBuffers(_device, pAllocateInfo->commandPool, + // i, pCommandBuffers); + + // /* From the Vulkan 1.0.66 spec: + // * + // * "vkAllocateCommandBuffers can be used to create multiple + // * command buffers. If the creation of any of those command + // * buffers fails, the implementation must destroy all + // * successfully created command buffer objects from this + // * command, set all entries of the pCommandBuffers array to + // * NULL and return the error." + // */ + // memset(pCommandBuffers, 0, + // sizeof(*pCommandBuffers) * pAllocateInfo->commandBufferCount); + // } + + return result; +} + +VkResult libresoc_BeginCommandBuffer( + VkCommandBuffer commandBuffer, + const VkCommandBufferBeginInfo *pBeginInfo) +{ + LIBRESOC_FROM_HANDLE(libresoc_cmd_buffer, cmd_buffer, commandBuffer); + VkResult result = VK_SUCCESS; + + + // memset(&cmd_buffer->state, 0, sizeof(cmd_buffer->state)); + // cmd_buffer->state.last_primitive_reset_en = -1; + // cmd_buffer->state.last_index_type = -1; + // cmd_buffer->state.last_num_instances = -1; + // cmd_buffer->state.last_vertex_offset = -1; + // cmd_buffer->state.last_first_instance = -1; + // cmd_buffer->state.predication_type = -1; + // cmd_buffer->state.last_sx_ps_downconvert = -1; + // cmd_buffer->state.last_sx_blend_opt_epsilon = -1; + // cmd_buffer->state.last_sx_blend_opt_control = -1; + cmd_buffer->usage_flags = pBeginInfo->flags; + + // if (cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_SECONDARY && + // (pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT)) { + // assert(pBeginInfo->pInheritanceInfo); + // cmd_buffer->state.framebuffer = libresoc_framebuffer_from_handle(pBeginInfo->pInheritanceInfo->framebuffer); + // cmd_buffer->state.pass = libresoc_render_pass_from_handle(pBeginInfo->pInheritanceInfo->renderPass); + + // struct libresoc_subpass *subpass = + // &cmd_buffer->state.pass->subpasses[pBeginInfo->pInheritanceInfo->subpass]; + + // if (cmd_buffer->state.framebuffer) { + // result = libresoc_cmd_state_setup_attachments(cmd_buffer, cmd_buffer->state.pass, NULL); + // if (result != VK_SUCCESS) + // return result; + // } + + // cmd_buffer->state.inherited_pipeline_statistics = + // pBeginInfo->pInheritanceInfo->pipelineStatistics; + + // libresoc_cmd_buffer_set_subpass(cmd_buffer, subpass); + // } + + // if (unlikely(cmd_buffer->device->trace_bo)) + // libresoc_cmd_buffer_trace_emit(cmd_buffer); + +// libresoc_describe_begin_cmd_buffer(cmd_buffer); + + //cmd_buffer->status = LIBRESOC_CMD_BUFFER_STATUS_RECORDING; + + return result; +} + +void libresoc_CmdPipelineBarrier( + VkCommandBuffer commandBuffer, + VkPipelineStageFlags srcStageMask, + VkPipelineStageFlags destStageMask, + VkBool32 byRegion, + uint32_t memoryBarrierCount, + const VkMemoryBarrier* pMemoryBarriers, + uint32_t bufferMemoryBarrierCount, + const VkBufferMemoryBarrier* pBufferMemoryBarriers, + uint32_t imageMemoryBarrierCount, + const VkImageMemoryBarrier* pImageMemoryBarriers) +{ + // LIBRESOC_FROM_HANDLE(libresoc_cmd_buffer, cmd_buffer, commandBuffer); + // struct libresoc_barrier_info info; + + // info.reason = RGP_BARRIER_EXTERNAL_CMD_PIPELINE_BARRIER; + // info.eventCount = 0; + // info.pEvents = NULL; + // info.srcStageMask = srcStageMask; + // info.dstStageMask = destStageMask; + + // libresoc_barrier(cmd_buffer, memoryBarrierCount, pMemoryBarriers, + // bufferMemoryBarrierCount, pBufferMemoryBarriers, + // imageMemoryBarrierCount, pImageMemoryBarriers, &info); +} + +VkResult libresoc_EndCommandBuffer( + VkCommandBuffer commandBuffer) +{ + + LIBRESOC_FROM_HANDLE(libresoc_cmd_buffer, cmd_buffer, commandBuffer); + + // if (cmd_buffer->queue_family_index != LIBRESOC_QUEUE_TRANSFER) { + // if (cmd_buffer->device->physical_device->rad_info.chip_class == GFX6) + // cmd_buffer->state.flush_bits |= LIBRESOC_CMD_FLAG_CS_PARTIAL_FLUSH | LIBRESOC_CMD_FLAG_PS_PARTIAL_FLUSH | LIBRESOC_CMD_FLAG_WB_L2; + + // /* Make sure to sync all pending active queries at the end of + // * command buffer. + // */ + // cmd_buffer->state.flush_bits |= cmd_buffer->active_query_flush_bits; + + // /* Since NGG streamout uses GDS, we need to make GDS idle when + // * we leave the IB, otherwise another process might overwrite + // * it while our shaders are busy. + // */ + // if (cmd_buffer->gds_needed) + // cmd_buffer->state.flush_bits |= LIBRESOC_CMD_FLAG_PS_PARTIAL_FLUSH; + + // si_emit_cache_flush(cmd_buffer); + // } + + // /* Make sure CP DMA is idle at the end of IBs because the kernel + // * doesn't wait for it. + // */ + // si_cp_dma_wait_for_idle(cmd_buffer); + + // libresoc_describe_end_cmd_buffer(cmd_buffer); + + // vk_free(&cmd_buffer->pool->alloc, cmd_buffer->state.attachments); + // vk_free(&cmd_buffer->pool->alloc, cmd_buffer->state.subpass_sample_locs); + + // VkResult result = cmd_buffer->device->ws->cs_finalize(cmd_buffer->cs); + // if (result != VK_SUCCESS) + // return vk_error(cmd_buffer->device->instance, result); + + // cmd_buffer->status = LIBRESOC_CMD_BUFFER_STATUS_EXECUTABLE; + + return cmd_buffer->record_result; +} diff --git a/src/libre-soc/vulkan/libresoc_device.c b/src/libre-soc/vulkan/libresoc_device.c index 229fd172a0d..92a901657e9 100644 --- a/src/libre-soc/vulkan/libresoc_device.c +++ b/src/libre-soc/vulkan/libresoc_device.c @@ -29,10 +29,279 @@ #include #include "util/debug.h" +#include "util/driconf.h" #include "libresoc_private.h" #include "vk_util.h" #include "vk_alloc.h" +struct libresoc_deferred_queue_submission { + struct libresoc_queue *queue; + VkCommandBuffer *cmd_buffers; + uint32_t cmd_buffer_count; + + /* Sparse bindings that happen on a queue. */ + VkSparseBufferMemoryBindInfo *buffer_binds; + uint32_t buffer_bind_count; + VkSparseImageOpaqueMemoryBindInfo *image_opaque_binds; + uint32_t image_opaque_bind_count; + + bool flush_caches; + VkShaderStageFlags wait_dst_stage_mask; + struct libresoc_semaphore_part **wait_semaphores; + uint32_t wait_semaphore_count; + struct libresoc_semaphore_part **signal_semaphores; + uint32_t signal_semaphore_count; + VkFence fence; + + uint64_t *wait_values; + uint64_t *signal_values; + + struct libresoc_semaphore_part *temporary_semaphore_parts; + uint32_t temporary_semaphore_part_count; + + struct list_head queue_pending_list; + uint32_t submission_wait_count; + struct libresoc_timeline_waiter *wait_nodes; + + struct list_head processing_list; +}; + +struct libresoc_queue_submission { + const VkCommandBuffer *cmd_buffers; + uint32_t cmd_buffer_count; + + /* Sparse bindings that happen on a queue. */ + const VkSparseBufferMemoryBindInfo *buffer_binds; + uint32_t buffer_bind_count; + const VkSparseImageOpaqueMemoryBindInfo *image_opaque_binds; + uint32_t image_opaque_bind_count; + + bool flush_caches; + VkPipelineStageFlags wait_dst_stage_mask; + const VkSemaphore *wait_semaphores; + uint32_t wait_semaphore_count; + const VkSemaphore *signal_semaphores; + uint32_t signal_semaphore_count; + VkFence fence; + + const uint64_t *wait_values; + uint32_t wait_value_count; + const uint64_t *signal_values; + uint32_t signal_value_count; +}; + +void +libresoc_free_memory(struct libresoc_device *device, + const VkAllocationCallbacks* pAllocator, + struct libresoc_device_memory *mem) +{ + if (mem == NULL) + return; + + vk_object_base_finish(&mem->base); + vk_free2(&device->vk.alloc, pAllocator, mem); +} + +static VkResult libresoc_alloc_memory(struct libresoc_device *device, + const VkMemoryAllocateInfo* pAllocateInfo, + const VkAllocationCallbacks* pAllocator, + VkDeviceMemory* pMem) +{ + struct libresoc_device_memory *mem; + VkResult result; + uint32_t flags = 0; + + assert(pAllocateInfo->sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO); + + const VkImportMemoryFdInfoKHR *import_info = + vk_find_struct_const(pAllocateInfo->pNext, IMPORT_MEMORY_FD_INFO_KHR); + const VkMemoryDedicatedAllocateInfo *dedicate_info = + vk_find_struct_const(pAllocateInfo->pNext, MEMORY_DEDICATED_ALLOCATE_INFO); + const VkExportMemoryAllocateInfo *export_info = + vk_find_struct_const(pAllocateInfo->pNext, EXPORT_MEMORY_ALLOCATE_INFO); + const VkImportMemoryHostPointerInfoEXT *host_ptr_info = + vk_find_struct_const(pAllocateInfo->pNext, IMPORT_MEMORY_HOST_POINTER_INFO_EXT); + + const struct wsi_memory_allocate_info *wsi_info = + vk_find_struct_const(pAllocateInfo->pNext, WSI_MEMORY_ALLOCATE_INFO_MESA); + + + mem = vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*mem), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (mem == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + vk_object_base_init(&device->vk, &mem->base, + VK_OBJECT_TYPE_DEVICE_MEMORY); + + if (dedicate_info) { + mem->image = libresoc_image_from_handle(dedicate_info->image); + //mem->buffer = libresoc_buffer_from_handle(dedicate_info->buffer); + } else { + mem->image = NULL; + //mem->buffer = NULL; + } + + // float priority_float = 0.5; + // const struct VkMemoryPriorityAllocateInfoEXT *priority_ext = + // vk_find_struct_const(pAllocateInfo->pNext, + // MEMORY_PRIORITY_ALLOCATE_INFO_EXT); + // if (priority_ext) + // priority_float = priority_ext->priority; + + // unsigned priority = MIN2(LIBRESOC_BO_PRIORITY_APPLICATION_MAX - 1, + // (int)(priority_float * LIBRESOC_BO_PRIORITY_APPLICATION_MAX)); + + mem->user_ptr = NULL; + //mem->bo = NULL; + + + if (import_info) { + assert(import_info->handleType == + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT || + import_info->handleType == + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT); + // mem->bo = device->ws->buffer_from_fd(device->ws, import_info->fd, + // priority, NULL); + // if (!mem->bo) { + // result = VK_ERROR_INVALID_EXTERNAL_HANDLE; + // goto fail; + // } else { + // close(import_info->fd); + // } + + // if (mem->image && mem->image->plane_count == 1 && + // !vk_format_is_depth_or_stencil(mem->image->vk_format)) { + // struct radeon_bo_metadata metadata; + // device->ws->buffer_get_metadata(mem->bo, &metadata); + + // struct libresoc_image_create_info create_info = { + // .no_metadata_planes = true, + // .bo_metadata = &metadata + // }; + + // /* This gives a basic ability to import radeonsi images + // * that don't have DCC. This is not guaranteed by any + // * spec and can be removed after we support modifiers. */ + // result = libresoc_image_create_layout(device, create_info, mem->image); + // if (result != VK_SUCCESS) { + // device->ws->buffer_destroy(mem->bo); + // goto fail; + // } + // } + } else if (host_ptr_info) { + // assert(host_ptr_info->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT); + // mem->bo = device->ws->buffer_from_ptr(device->ws, host_ptr_info->pHostPointer, + // pAllocateInfo->allocationSize, + // priority); + // if (!mem->bo) { + // result = VK_ERROR_INVALID_EXTERNAL_HANDLE; + // goto fail; + // } else { + // mem->user_ptr = host_ptr_info->pHostPointer; + // } + } else { + uint64_t alloc_size = align_u64(pAllocateInfo->allocationSize, 4096); + uint32_t heap_index; + + heap_index = device->physical_device->memory_properties.memoryTypes[pAllocateInfo->memoryTypeIndex].heapIndex; + // domain = device->physical_device->memory_domains[pAllocateInfo->memoryTypeIndex]; + // flags |= device->physical_device->memory_flags[pAllocateInfo->memoryTypeIndex]; + + // if (!dedicate_info && !import_info && (!export_info || !export_info->handleTypes)) { + // flags |= RADEON_FLAG_NO_INTERPROCESS_SHARING; + // if (device->use_global_bo_list) { + // flags |= RADEON_FLAG_PREFER_LOCAL_BO; + // } + // } + + if (device->overallocation_disallowed) { + uint64_t total_size = + device->physical_device->memory_properties.memoryHeaps[heap_index].size; + + mtx_lock(&device->overallocation_mutex); + if (device->allocated_memory_size[heap_index] + alloc_size > total_size) { + mtx_unlock(&device->overallocation_mutex); + result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + goto fail; + } + device->allocated_memory_size[heap_index] += alloc_size; + mtx_unlock(&device->overallocation_mutex); + } + + // mem->bo = device->ws->buffer_create(device->ws, alloc_size, device->physical_device->rad_info.max_alignment, + // domain, flags, priority); + + // if (!mem->bo) { + // if (device->overallocation_disallowed) { + // mtx_lock(&device->overallocation_mutex); + // device->allocated_memory_size[heap_index] -= alloc_size; + // mtx_unlock(&device->overallocation_mutex); + // } + // result = VK_ERROR_OUT_OF_DEVICE_MEMORY; + // goto fail; + // } + + mem->heap_index = heap_index; + mem->alloc_size = alloc_size; + } + + // if (!wsi_info) { + // result = libresoc_bo_list_add(device, mem->bo); + // if (result != VK_SUCCESS) + // goto fail; + // } + + *pMem = libresoc_device_memory_to_handle(mem); + + return VK_SUCCESS; + +fail: + libresoc_free_memory(device, pAllocator,mem); + + return result; +} + +VkResult libresoc_AllocateMemory( + VkDevice _device, + const VkMemoryAllocateInfo* pAllocateInfo, + const VkAllocationCallbacks* pAllocator, + VkDeviceMemory* pMem) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + return libresoc_alloc_memory(device, pAllocateInfo, pAllocator, pMem); +} + +void libresoc_FreeMemory( + VkDevice _device, + VkDeviceMemory _mem, + const VkAllocationCallbacks* pAllocator) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + LIBRESOC_FROM_HANDLE(libresoc_device_memory, mem, _mem); + + libresoc_free_memory(device, pAllocator, mem); +} +static VkResult +libresoc_create_pthread_cond(pthread_cond_t *cond) +{ + pthread_condattr_t condattr; + if (pthread_condattr_init(&condattr)) { + return VK_ERROR_INITIALIZATION_FAILED; + } + + if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) { + pthread_condattr_destroy(&condattr); + return VK_ERROR_INITIALIZATION_FAILED; + } + if (pthread_cond_init(cond, &condattr)) { + pthread_condattr_destroy(&condattr); + return VK_ERROR_INITIALIZATION_FAILED; + } + pthread_condattr_destroy(&condattr); + return VK_SUCCESS; +} + VkResult libresoc_EnumerateInstanceExtensionProperties(const char *pLayerName, uint32_t *pPropertyCount, @@ -119,6 +388,33 @@ libresoc_get_debug_option_name(int id) assert(id < ARRAY_SIZE(libresoc_debug_options) - 1); return libresoc_debug_options[id].string; } + +static const char libresoc_dri_options_xml[] = +DRI_CONF_BEGIN + DRI_CONF_SECTION_PERFORMANCE + DRI_CONF_ADAPTIVE_SYNC("true") + DRI_CONF_VK_X11_OVERRIDE_MIN_IMAGE_COUNT(0) + DRI_CONF_VK_X11_STRICT_IMAGE_COUNT("false") + DRI_CONF_VK_X11_ENSURE_MIN_IMAGE_COUNT("false") + DRI_CONF_SECTION_END + + DRI_CONF_SECTION_DEBUG + DRI_CONF_VK_WSI_FORCE_BGRA8_UNORM_FIRST("false") + DRI_CONF_SECTION_END +DRI_CONF_END; + +static void libresoc_init_dri_options(struct libresoc_instance *instance) +{ + driParseOptionInfo(&instance->available_dri_options, libresoc_dri_options_xml); + driParseConfigFiles(&instance->dri_options, + &instance->available_dri_options, + 0, "libresoc", NULL, + instance->app_info.app_name, + instance->app_info.app_version, + instance->engineName, + instance->engineVersion); +} + VkResult libresoc_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, @@ -208,6 +504,7 @@ libresoc_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, } instance->physical_devices_enumerated = false; list_inithead(&instance->physical_devices); + libresoc_init_dri_options(instance); *pInstance = libresoc_instance_to_handle(instance); return VK_SUCCESS; @@ -223,11 +520,57 @@ libresoc_DestroyInstance(VkInstance _instance, /* FIXME: stub */ } +static void +libresoc_physical_device_init_mem_types(struct libresoc_physical_device *device) +{ + uint64_t visible_vram_size = 65536; //TODO: some dummy value + uint64_t vram_size = 65536; //TODO: some dummy value + int vram_index = -1, visible_vram_index = -1; + device->memory_properties.memoryHeapCount = 0; + if (vram_size > 0) { + vram_index = device->memory_properties.memoryHeapCount++; + device->memory_properties.memoryHeaps[vram_index] = (VkMemoryHeap) { + .size = vram_size, + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }; + } + + if (visible_vram_size) { + visible_vram_index = device->memory_properties.memoryHeapCount++; + device->memory_properties.memoryHeaps[visible_vram_index] = (VkMemoryHeap) { + .size = visible_vram_size, + .flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT, + }; + } + unsigned type_count = 0; + + if (vram_index >= 0 || visible_vram_index >= 0) { + device->memory_properties.memoryTypes[type_count++] = (VkMemoryType) { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + .heapIndex = vram_index >= 0 ? vram_index : visible_vram_index, + }; + } + + if (visible_vram_index >= 0) { + device->memory_properties.memoryTypes[type_count++] = (VkMemoryType) { + .propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + .heapIndex = visible_vram_index, + }; + } + + device->memory_properties.memoryTypeCount = type_count; + + +} static VkResult libresoc_physical_device_try_create(struct libresoc_instance *instance, struct libresoc_physical_device **device_out) { VkResult result; + int fd = -1; + int master_fd = -1; struct libresoc_physical_device *device = vk_zalloc2(&instance->alloc, NULL, sizeof(*device), 8, @@ -240,10 +583,20 @@ libresoc_physical_device_try_create(struct libresoc_instance *instance, device->_loader_data.loaderMagic = ICD_LOADER_MAGIC; device->instance = instance; + device->master_fd = master_fd; + device->local_fd = fd; + libresoc_physical_device_init_mem_types(device); + + libresoc_physical_device_get_supported_extensions(device, + &device->supported_extensions); + result = libresoc_init_wsi(device); + if (result != VK_SUCCESS) { + return result; + } snprintf(device->name, sizeof(device->name), "LIBRE-SOC DEVICE"); *device_out = device; - +//TODO: incase of failures need to deallocate and cleanup various allocation properly. return VK_SUCCESS; } @@ -502,7 +855,7 @@ libresoc_GetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, .apiVersion = libresoc_physical_device_api_version(pdevice), .driverVersion = vk_get_driver_version(), .vendorID = 1, //TODO: some dummy value - .deviceID = 1, //TODO: dome dummay value + .deviceID = 1, //TODO: dome dummy value .deviceType = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, .limits = limits, .sparseProperties = {0}, @@ -574,36 +927,39 @@ libresoc_GetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, if (getenv("LIBRESOC_TRACE")) { fprintf(stderr, "GetPhysicalDEviceMemoryProperties called. \n"); } - /* FIXME: stub */ -} + LIBRESOC_FROM_HANDLE(libresoc_physical_device, physical_device, physicalDevice); -void -libresoc_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties) { - - if (getenv("LIBRESOC_TRACE")) { - fprintf(stderr, "GetPhysicalDeviceFormatProperties called. \n"); - } + *pMemoryProperties = physical_device->memory_properties; /* FIXME: stub */ } -VkResult - libresoc_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties) -{ - if (getenv("LIBRESOC_TRACE")) { - fprintf(stderr, "GetPhysicalDEviceImageFormatProperties called. \n"); - } - - /* FIXME: stub */ - return VK_SUCCESS; -} - void - libresoc_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties) - { - if (getenv("LIBRESOC_TRACE")) { - fprintf(stderr, "GetPhysicalDeviceSparseImageFormatProperties called. \n"); - } - /* FIXME: stub */ - } +//void +//libresoc_GetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties) { +// +// if (getenv("LIBRESOC_TRACE")) { +// fprintf(stderr, "GetPhysicalDeviceFormatProperties called. \n"); +// } +// /* FIXME: stub */ +//} + +//VkResult +// libresoc_GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties) +//{ +// if (getenv("LIBRESOC_TRACE")) { +// fprintf(stderr, "GetPhysicalDEviceImageFormatProperties called. \n"); +// } +// +// /* FIXME: stub */ +// return VK_SUCCESS; +//} +// void +// libresoc_GetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t* pPropertyCount, VkSparseImageFormatProperties* pProperties) +// { +// if (getenv("LIBRESOC_TRACE")) { +// fprintf(stderr, "GetPhysicalDeviceSparseImageFormatProperties called. \n"); +// } +// /* FIXME: stub */ +// } PFN_vkVoidFunction libresoc_GetInstanceProcAddr(VkInstance _instance, const char *pName) @@ -773,27 +1129,6 @@ libresoc_device_init_dispatch(struct libresoc_device *device) } } -/* -static VkResult -libresoc_create_pthread_cond(pthread_cond_t *cond) -{ - pthread_condattr_t condattr; - if (pthread_condattr_init(&condattr)) { - return VK_ERROR_INITIALIZATION_FAILED; - } - - if (pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) { - pthread_condattr_destroy(&condattr); - return VK_ERROR_INITIALIZATION_FAILED; - } - if (pthread_cond_init(cond, &condattr)) { - pthread_condattr_destroy(&condattr); - return VK_ERROR_INITIALIZATION_FAILED; - } - pthread_condattr_destroy(&condattr); - return VK_SUCCESS; -} -*/ static VkResult check_physical_device_features(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceFeatures *features) @@ -831,6 +1166,16 @@ libresoc_queue_init(struct libresoc_device *device, struct libresoc_queue *queue queue->queue_family_index = queue_family_index; queue->queue_idx = idx; queue->flags = flags; + list_inithead(&queue->pending_submissions); + pthread_mutex_init(&queue->pending_mutex, NULL); + + pthread_mutex_init(&queue->thread_mutex, NULL); + //queue->thread_submission = NULL; + queue->thread_running = queue->thread_exit = false; + VkResult result = libresoc_create_pthread_cond(&queue->thread_cond); + if (result != VK_SUCCESS) + return vk_error(device->instance, result); + return VK_SUCCESS; } @@ -1033,3 +1378,352 @@ VkResult libresoc_DeviceWaitIdle( } return VK_SUCCESS; } + +void libresoc_GetPhysicalDeviceProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceProperties2 *pProperties) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, pdevice, physicalDevice); + libresoc_GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties); + //TODO: add more stuffs when required +} + +void libresoc_GetPhysicalDeviceFeatures2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceFeatures2 *pFeatures) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, pdevice, physicalDevice); + libresoc_GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features); +} + +void libresoc_GetPhysicalDeviceQueueFamilyProperties2( + VkPhysicalDevice physicalDevice, + uint32_t* pCount, + VkQueueFamilyProperties2 *pQueueFamilyProperties) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, pdevice, physicalDevice); + if (!pQueueFamilyProperties) { + libresoc_get_physical_device_queue_family_properties(pdevice, pCount, NULL); + return; + } + VkQueueFamilyProperties *properties[] = { + &pQueueFamilyProperties[0].queueFamilyProperties, + &pQueueFamilyProperties[1].queueFamilyProperties, + &pQueueFamilyProperties[2].queueFamilyProperties, + }; + libresoc_get_physical_device_queue_family_properties(pdevice, pCount, properties); + assert(*pCount <= 3); +} + +static void +libresoc_get_memory_budget_properties(VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryBudgetPropertiesEXT *memoryBudget) +{ +//TODO: stub +} + +void libresoc_GetPhysicalDeviceMemoryProperties2( + VkPhysicalDevice physicalDevice, + VkPhysicalDeviceMemoryProperties2 *pMemoryProperties) +{ + libresoc_GetPhysicalDeviceMemoryProperties(physicalDevice, + &pMemoryProperties->memoryProperties); + + VkPhysicalDeviceMemoryBudgetPropertiesEXT *memory_budget = + vk_find_struct(pMemoryProperties->pNext, + PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT); + if (memory_budget) + libresoc_get_memory_budget_properties(physicalDevice, memory_budget); +} + +VkResult libresoc_CreateSemaphore( + VkDevice _device, + const VkSemaphoreCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSemaphore* pSemaphore) +{ + //TODO: minimal things as of now, add more complex code as required + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + struct libresoc_semaphore *sem = vk_alloc2(&device->vk.alloc, pAllocator, + sizeof(*sem), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!sem) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + vk_object_base_init(&device->vk, &sem->base, + VK_OBJECT_TYPE_SEMAPHORE); + + *pSemaphore = libresoc_semaphore_to_handle(sem); + return VK_SUCCESS; +} + +void libresoc_GetImageMemoryRequirements( + VkDevice _device, + VkImage _image, + VkMemoryRequirements* pMemoryRequirements) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + LIBRESOC_FROM_HANDLE(libresoc_image, image, _image); + + pMemoryRequirements->memoryTypeBits = (1u << device->physical_device->memory_properties.memoryTypeCount) - 1; + + pMemoryRequirements->size = image->size; + pMemoryRequirements->alignment = image->alignment; +} + +void libresoc_GetImageMemoryRequirements2( + VkDevice device, + const VkImageMemoryRequirementsInfo2 *pInfo, + VkMemoryRequirements2 *pMemoryRequirements) +{ + libresoc_GetImageMemoryRequirements(device, pInfo->image, + &pMemoryRequirements->memoryRequirements); +} + +VkResult libresoc_BindImageMemory2(VkDevice device, + uint32_t bindInfoCount, + const VkBindImageMemoryInfo *pBindInfos) +{ + for (uint32_t i = 0; i < bindInfoCount; ++i) { + LIBRESOC_FROM_HANDLE(libresoc_device_memory, mem, pBindInfos[i].memory); + LIBRESOC_FROM_HANDLE(libresoc_image, image, pBindInfos[i].image); + + if (mem) { + // image->bo = mem->bo; + // image->offset = pBindInfos[i].memoryOffset; + } else { + // image->bo = NULL; + // image->offset = 0; + } + } + return VK_SUCCESS; +} + + +VkResult libresoc_BindImageMemory( + VkDevice device, + VkImage image, + VkDeviceMemory memory, + VkDeviceSize memoryOffset) +{ + const VkBindImageMemoryInfo info = { + .sType = VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO, + .image = image, + .memory = memory, + .memoryOffset = memoryOffset + }; + + return libresoc_BindImageMemory2(device, 1, &info); +} + +static VkResult libresoc_queue_submit(struct libresoc_queue *queue, + const struct libresoc_queue_submission *submission) +{ + return VK_SUCCESS; + // struct libresoc_deferred_queue_submission *deferred = NULL; + + // VkResult result = libresoc_create_deferred_submission(queue, submission, &deferred); + // if (result != VK_SUCCESS) + // return result; + + // struct list_head processing_list; + // list_inithead(&processing_list); + + // result = libresoc_queue_enqueue_submission(deferred, &processing_list); + // if (result != VK_SUCCESS) { + // /* If anything is in the list we leak. */ + // assert(list_is_empty(&processing_list)); + // return result; + // } + // return libresoc_process_submissions(&processing_list); +} + +/* Signals fence as soon as all the work currently put on queue is done. */ +static VkResult libresoc_signal_fence(struct libresoc_queue *queue, + VkFence fence) +{ + return libresoc_queue_submit(queue, &(struct libresoc_queue_submission) { + .fence = fence + }); +} + +static bool libresoc_submit_has_effects(const VkSubmitInfo *info) +{ + return info->commandBufferCount || + info->waitSemaphoreCount || + info->signalSemaphoreCount; +} + +VkResult libresoc_QueueSubmit( + VkQueue _queue, + uint32_t submitCount, + const VkSubmitInfo* pSubmits, + VkFence fence) +{ + LIBRESOC_FROM_HANDLE(libresoc_queue, queue, _queue); + VkResult result; + uint32_t fence_idx = 0; + bool flushed_caches = false; + + if (fence != VK_NULL_HANDLE) { + for (uint32_t i = 0; i < submitCount; ++i) + if (libresoc_submit_has_effects(pSubmits + i)) + fence_idx = i; + } else + fence_idx = UINT32_MAX; + + for (uint32_t i = 0; i < submitCount; i++) { + if (!libresoc_submit_has_effects(pSubmits + i) && fence_idx != i) + continue; + + VkPipelineStageFlags wait_dst_stage_mask = 0; + for (unsigned j = 0; j < pSubmits[i].waitSemaphoreCount; ++j) { + wait_dst_stage_mask |= pSubmits[i].pWaitDstStageMask[j]; + } + + const VkTimelineSemaphoreSubmitInfo *timeline_info = + vk_find_struct_const(pSubmits[i].pNext, TIMELINE_SEMAPHORE_SUBMIT_INFO); + + result = libresoc_queue_submit(queue, &(struct libresoc_queue_submission) { + .cmd_buffers = pSubmits[i].pCommandBuffers, + .cmd_buffer_count = pSubmits[i].commandBufferCount, + .wait_dst_stage_mask = wait_dst_stage_mask, + .flush_caches = !flushed_caches, + .wait_semaphores = pSubmits[i].pWaitSemaphores, + .wait_semaphore_count = pSubmits[i].waitSemaphoreCount, + .signal_semaphores = pSubmits[i].pSignalSemaphores, + .signal_semaphore_count = pSubmits[i].signalSemaphoreCount, + .fence = i == fence_idx ? fence : VK_NULL_HANDLE, + .wait_values = timeline_info ? timeline_info->pWaitSemaphoreValues : NULL, + .wait_value_count = timeline_info && timeline_info->pWaitSemaphoreValues ? timeline_info->waitSemaphoreValueCount : 0, + .signal_values = timeline_info ? timeline_info->pSignalSemaphoreValues : NULL, + .signal_value_count = timeline_info && timeline_info->pSignalSemaphoreValues ? timeline_info->signalSemaphoreValueCount : 0, + }); + if (result != VK_SUCCESS) + return result; + + flushed_caches = true; + } + + if (fence != VK_NULL_HANDLE && !submitCount) { + result = libresoc_signal_fence(queue, fence); + if (result != VK_SUCCESS) + return result; + } + + return VK_SUCCESS; +} + +VkResult libresoc_CreateFence( + VkDevice _device, + const VkFenceCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkFence* pFence) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + const VkExportFenceCreateInfo *export = + vk_find_struct_const(pCreateInfo->pNext, EXPORT_FENCE_CREATE_INFO); + VkExternalFenceHandleTypeFlags handleTypes = + export ? export->handleTypes : 0; + struct libresoc_fence *fence; + + fence = vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*fence), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!fence) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + vk_object_base_init(&device->vk, &fence->base, VK_OBJECT_TYPE_FENCE); + + // if (device->always_use_syncobj || handleTypes) { + // fence->permanent.kind = LIBRESOC_FENCE_SYNCOBJ; + + // bool create_signaled = false; + // if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) + // create_signaled = true; + + // int ret = device->ws->create_syncobj(device->ws, create_signaled, + // &fence->permanent.syncobj); + // if (ret) { + // libresoc_destroy_fence(device, pAllocator, fence); + // return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + // } + // } else { + // fence->permanent.kind = LIBRESOC_FENCE_WINSYS; + + // fence->permanent.fence = device->ws->create_fence(); + // if (!fence->permanent.fence) { + // vk_free2(&device->vk.alloc, pAllocator, fence); + // libresoc_destroy_fence(device, pAllocator, fence); + // return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + // } + // if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) + // device->ws->signal_fence(fence->permanent.fence); + // } + + *pFence = libresoc_fence_to_handle(fence); + + return VK_SUCCESS; +} + +VkResult libresoc_MapMemory( + VkDevice _device, + VkDeviceMemory _memory, + VkDeviceSize offset, + VkDeviceSize size, + VkMemoryMapFlags flags, + void** ppData) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + LIBRESOC_FROM_HANDLE(libresoc_device_memory, mem, _memory); + + if (mem == NULL) { + *ppData = NULL; + return VK_SUCCESS; + } + + if (mem->user_ptr) + *ppData = mem->user_ptr; + // else + // *ppData = device->ws->buffer_map(mem->bo); + + if (*ppData) { + *ppData += offset; + return VK_SUCCESS; + } + + return vk_error(device->instance, VK_ERROR_MEMORY_MAP_FAILED); +} + +void libresoc_UnmapMemory( + VkDevice _device, + VkDeviceMemory _memory) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + LIBRESOC_FROM_HANDLE(libresoc_device_memory, mem, _memory); + + if (mem == NULL) + return; + + // if (mem->user_ptr == NULL) + // device->ws->buffer_unmap(mem->bo); +} + +VkResult libresoc_WaitForFences( + VkDevice _device, + uint32_t fenceCount, + const VkFence* pFences, + VkBool32 waitAll, + uint64_t timeout) +{ + //TODO: stub + return VK_SUCCESS; +} + +VkResult libresoc_ResetFences(VkDevice _device, + uint32_t fenceCount, + const VkFence *pFences) +{ + + //TODO: stub + return VK_SUCCESS; +} diff --git a/src/libre-soc/vulkan/libresoc_extensions.py b/src/libre-soc/vulkan/libresoc_extensions.py index 3d83d41ed4c..17e5265e461 100644 --- a/src/libre-soc/vulkan/libresoc_extensions.py +++ b/src/libre-soc/vulkan/libresoc_extensions.py @@ -53,16 +53,29 @@ API_PATCH_VERSION = 102 # available. API_VERSIONS = [ ApiVersion('1.0', True), + ApiVersion('1.1', False), - # FIXME: for now we only support 1.0. We maintain this support from anv just in case in - # the future we support more that one version supported. - # ApiVersion('1.1', ), ] MAX_API_VERSION = None # Computed later EXTENSIONS = [ - #FIXME: for now we don't support additional extensions beyond 1.0. Revisit later + #Extension('VK_KHR_display', 23, 'VK_USE_PLATFORM_DISPLAY_KHR'), + #Extension('VK_KHR_external_memory', 1, True), + #TODO: enabling following extension creates compilation problem + #Extension('VK_KHR_external_memory_capabilities', 1, True), + #Extension('VK_KHR_external_memory_fd', 1, True), + Extension('VK_KHR_get_physical_device_properties2', 1, True), + #Extension('VK_KHR_get_surface_capabilities2', 1, 'LIBRESOC_HAS_SURFACE'), + Extension('VK_KHR_surface', 25, 'LIBRESOC_HAS_SURFACE'), + Extension('VK_KHR_swapchain', 68, 'LIBRESOC_HAS_SURFACE'), + # Extension('VK_KHR_wayland_surface', 6, 'VK_USE_PLATFORM_WAYLAND_KHR'), + Extension('VK_KHR_xcb_surface', 6, 'VK_USE_PLATFORM_XCB_KHR'), + Extension('VK_KHR_xlib_surface', 6, 'VK_USE_PLATFORM_XLIB_KHR'), + # Extension('VK_EXT_debug_report', 9, True), + # Extension('VK_EXT_external_memory_dma_buf', 1, True), + # Extension('VK_EXT_image_drm_format_modifier', 1, False), + ] # Sort the extension list the way we expect: KHR, then EXT, then vendors diff --git a/src/libre-soc/vulkan/libresoc_formats.c b/src/libre-soc/vulkan/libresoc_formats.c new file mode 100644 index 00000000000..4c55016395b --- /dev/null +++ b/src/libre-soc/vulkan/libresoc_formats.c @@ -0,0 +1,1355 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "libresoc_private.h" + +#include "vk_format.h" + +#include "vk_util.h" + +#include "util/u_half.h" +#include "util/format_srgb.h" +#include "util/format_r11g11b10f.h" + +//uint32_t libresoc_translate_buffer_dataformat(const struct vk_format_description *desc, +// int first_non_void) +//{ +// unsigned type; +// int i; +// +// assert(desc->layout != VK_FORMAT_LAYOUT_MULTIPLANE); +// +// if (desc->format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) +// return V_008F0C_BUF_DATA_FORMAT_10_11_11; +// +// if (first_non_void < 0) +// return V_008F0C_BUF_DATA_FORMAT_INVALID; +// type = desc->channel[first_non_void].type; +// +// if (type == VK_FORMAT_TYPE_FIXED) +// return V_008F0C_BUF_DATA_FORMAT_INVALID; +// if (desc->nr_channels == 4 && +// desc->channel[0].size == 10 && +// desc->channel[1].size == 10 && +// desc->channel[2].size == 10 && +// desc->channel[3].size == 2) +// return V_008F0C_BUF_DATA_FORMAT_2_10_10_10; +// +// /* See whether the components are of the same size. */ +// for (i = 0; i < desc->nr_channels; i++) { +// if (desc->channel[first_non_void].size != desc->channel[i].size) +// return V_008F0C_BUF_DATA_FORMAT_INVALID; +// } +// +// switch (desc->channel[first_non_void].size) { +// case 8: +// switch (desc->nr_channels) { +// case 1: +// return V_008F0C_BUF_DATA_FORMAT_8; +// case 2: +// return V_008F0C_BUF_DATA_FORMAT_8_8; +// case 4: +// return V_008F0C_BUF_DATA_FORMAT_8_8_8_8; +// } +// break; +// case 16: +// switch (desc->nr_channels) { +// case 1: +// return V_008F0C_BUF_DATA_FORMAT_16; +// case 2: +// return V_008F0C_BUF_DATA_FORMAT_16_16; +// case 4: +// return V_008F0C_BUF_DATA_FORMAT_16_16_16_16; +// } +// break; +// case 32: +// /* From the Southern Islands ISA documentation about MTBUF: +// * 'Memory reads of data in memory that is 32 or 64 bits do not +// * undergo any format conversion.' +// */ +// if (type != VK_FORMAT_TYPE_FLOAT && +// !desc->channel[first_non_void].pure_integer) +// return V_008F0C_BUF_DATA_FORMAT_INVALID; +// +// switch (desc->nr_channels) { +// case 1: +// return V_008F0C_BUF_DATA_FORMAT_32; +// case 2: +// return V_008F0C_BUF_DATA_FORMAT_32_32; +// case 3: +// return V_008F0C_BUF_DATA_FORMAT_32_32_32; +// case 4: +// return V_008F0C_BUF_DATA_FORMAT_32_32_32_32; +// } +// break; +// } +// +// return V_008F0C_BUF_DATA_FORMAT_INVALID; +//} + +//uint32_t libresoc_translate_buffer_numformat(const struct vk_format_description *desc, +// int first_non_void) +//{ +// assert(desc->layout != VK_FORMAT_LAYOUT_MULTIPLANE); +// +// if (desc->format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) +// return V_008F0C_BUF_NUM_FORMAT_FLOAT; +// +// if (first_non_void < 0) +// return ~0; +// +// switch (desc->channel[first_non_void].type) { +// case VK_FORMAT_TYPE_SIGNED: +// if (desc->channel[first_non_void].normalized) +// return V_008F0C_BUF_NUM_FORMAT_SNORM; +// else if (desc->channel[first_non_void].pure_integer) +// return V_008F0C_BUF_NUM_FORMAT_SINT; +// else +// return V_008F0C_BUF_NUM_FORMAT_SSCALED; +// break; +// case VK_FORMAT_TYPE_UNSIGNED: +// if (desc->channel[first_non_void].normalized) +// return V_008F0C_BUF_NUM_FORMAT_UNORM; +// else if (desc->channel[first_non_void].pure_integer) +// return V_008F0C_BUF_NUM_FORMAT_UINT; +// else +// return V_008F0C_BUF_NUM_FORMAT_USCALED; +// break; +// case VK_FORMAT_TYPE_FLOAT: +// default: +// return V_008F0C_BUF_NUM_FORMAT_FLOAT; +// } +//} + +//uint32_t libresoc_translate_tex_dataformat(VkFormat format, +// const struct vk_format_description *desc, +// int first_non_void) +//{ +// bool uniform = true; +// int i; +// +// assert(vk_format_get_plane_count(format) == 1); +// +// if (!desc) +// return ~0; +// /* Colorspace (return non-RGB formats directly). */ +// switch (desc->colorspace) { +// /* Depth stencil formats */ +// case VK_FORMAT_COLORSPACE_ZS: +// switch (format) { +// case VK_FORMAT_D16_UNORM: +// return V_008F14_IMG_DATA_FORMAT_16; +// case VK_FORMAT_D24_UNORM_S8_UINT: +// case VK_FORMAT_X8_D24_UNORM_PACK32: +// return V_008F14_IMG_DATA_FORMAT_8_24; +// case VK_FORMAT_S8_UINT: +// return V_008F14_IMG_DATA_FORMAT_8; +// case VK_FORMAT_D32_SFLOAT: +// return V_008F14_IMG_DATA_FORMAT_32; +// case VK_FORMAT_D32_SFLOAT_S8_UINT: +// return V_008F14_IMG_DATA_FORMAT_X24_8_32; +// default: +// goto out_unknown; +// } +// +// case VK_FORMAT_COLORSPACE_YUV: +// goto out_unknown; /* TODO */ +// +// case VK_FORMAT_COLORSPACE_SRGB: +// if (desc->nr_channels != 4 && desc->nr_channels != 1) +// goto out_unknown; +// break; +// +// default: +// break; +// } +// +// if (desc->layout == VK_FORMAT_LAYOUT_SUBSAMPLED) { +// switch(format) { +// /* Don't ask me why this looks inverted. PAL does the same. */ +// case VK_FORMAT_G8B8G8R8_422_UNORM: +// return V_008F14_IMG_DATA_FORMAT_BG_RG; +// case VK_FORMAT_B8G8R8G8_422_UNORM: +// return V_008F14_IMG_DATA_FORMAT_GB_GR; +// default: +// goto out_unknown; +// } +// } +// +// if (desc->layout == VK_FORMAT_LAYOUT_RGTC) { +// switch(format) { +// case VK_FORMAT_BC4_UNORM_BLOCK: +// case VK_FORMAT_BC4_SNORM_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_BC4; +// case VK_FORMAT_BC5_UNORM_BLOCK: +// case VK_FORMAT_BC5_SNORM_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_BC5; +// default: +// break; +// } +// } +// +// if (desc->layout == VK_FORMAT_LAYOUT_S3TC) { +// switch(format) { +// case VK_FORMAT_BC1_RGB_UNORM_BLOCK: +// case VK_FORMAT_BC1_RGB_SRGB_BLOCK: +// case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: +// case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_BC1; +// case VK_FORMAT_BC2_UNORM_BLOCK: +// case VK_FORMAT_BC2_SRGB_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_BC2; +// case VK_FORMAT_BC3_UNORM_BLOCK: +// case VK_FORMAT_BC3_SRGB_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_BC3; +// default: +// break; +// } +// } +// +// if (desc->layout == VK_FORMAT_LAYOUT_BPTC) { +// switch(format) { +// case VK_FORMAT_BC6H_UFLOAT_BLOCK: +// case VK_FORMAT_BC6H_SFLOAT_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_BC6; +// case VK_FORMAT_BC7_UNORM_BLOCK: +// case VK_FORMAT_BC7_SRGB_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_BC7; +// default: +// break; +// } +// } +// +// if (desc->layout == VK_FORMAT_LAYOUT_ETC) { +// switch (format) { +// case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: +// case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_ETC2_RGB; +// case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: +// case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_ETC2_RGBA1; +// case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: +// case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_ETC2_RGBA; +// case VK_FORMAT_EAC_R11_UNORM_BLOCK: +// case VK_FORMAT_EAC_R11_SNORM_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_ETC2_R; +// case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: +// case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: +// return V_008F14_IMG_DATA_FORMAT_ETC2_RG; +// default: +// break; +// } +// } +// +// if (format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) { +// return V_008F14_IMG_DATA_FORMAT_5_9_9_9; +// } else if (format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) { +// return V_008F14_IMG_DATA_FORMAT_10_11_11; +// } +// +// /* R8G8Bx_SNORM - TODO CxV8U8 */ +// +// /* hw cannot support mixed formats (except depth/stencil, since only +// * depth is read).*/ +// if (desc->is_mixed && desc->colorspace != VK_FORMAT_COLORSPACE_ZS) +// goto out_unknown; +// +// /* See whether the components are of the same size. */ +// for (i = 1; i < desc->nr_channels; i++) { +// uniform = uniform && desc->channel[0].size == desc->channel[i].size; +// } +// +// /* Non-uniform formats. */ +// if (!uniform) { +// switch(desc->nr_channels) { +// case 3: +// if (desc->channel[0].size == 5 && +// desc->channel[1].size == 6 && +// desc->channel[2].size == 5) { +// return V_008F14_IMG_DATA_FORMAT_5_6_5; +// } +// goto out_unknown; +// case 4: +// if (desc->channel[0].size == 5 && +// desc->channel[1].size == 5 && +// desc->channel[2].size == 5 && +// desc->channel[3].size == 1) { +// return V_008F14_IMG_DATA_FORMAT_1_5_5_5; +// } +// if (desc->channel[0].size == 1 && +// desc->channel[1].size == 5 && +// desc->channel[2].size == 5 && +// desc->channel[3].size == 5) { +// return V_008F14_IMG_DATA_FORMAT_5_5_5_1; +// } +// if (desc->channel[0].size == 10 && +// desc->channel[1].size == 10 && +// desc->channel[2].size == 10 && +// desc->channel[3].size == 2) { +// /* Closed VK driver does this also no 2/10/10/10 snorm */ +// if (desc->channel[0].type == VK_FORMAT_TYPE_SIGNED && +// desc->channel[0].normalized) +// goto out_unknown; +// return V_008F14_IMG_DATA_FORMAT_2_10_10_10; +// } +// goto out_unknown; +// } +// goto out_unknown; +// } +// +// if (first_non_void < 0 || first_non_void > 3) +// goto out_unknown; +// +// /* uniform formats */ +// switch (desc->channel[first_non_void].size) { +// case 4: +// switch (desc->nr_channels) { +//#if 0 /* Not supported for render targets */ +// case 2: +// return V_008F14_IMG_DATA_FORMAT_4_4; +//#endif +// case 4: +// return V_008F14_IMG_DATA_FORMAT_4_4_4_4; +// } +// break; +// case 8: +// switch (desc->nr_channels) { +// case 1: +// return V_008F14_IMG_DATA_FORMAT_8; +// case 2: +// return V_008F14_IMG_DATA_FORMAT_8_8; +// case 4: +// return V_008F14_IMG_DATA_FORMAT_8_8_8_8; +// } +// break; +// case 16: +// switch (desc->nr_channels) { +// case 1: +// return V_008F14_IMG_DATA_FORMAT_16; +// case 2: +// return V_008F14_IMG_DATA_FORMAT_16_16; +// case 4: +// return V_008F14_IMG_DATA_FORMAT_16_16_16_16; +// } +// break; +// case 32: +// switch (desc->nr_channels) { +// case 1: +// return V_008F14_IMG_DATA_FORMAT_32; +// case 2: +// return V_008F14_IMG_DATA_FORMAT_32_32; +// case 3: +// return V_008F14_IMG_DATA_FORMAT_32_32_32; +// case 4: +// return V_008F14_IMG_DATA_FORMAT_32_32_32_32; +// } +// } +// +//out_unknown: +// /* R600_ERR("Unable to handle texformat %d %s\n", format, vk_format_name(format)); */ +// return ~0; +//} + +//uint32_t libresoc_translate_tex_numformat(VkFormat format, +// const struct vk_format_description *desc, +// int first_non_void) +//{ +// assert(vk_format_get_plane_count(format) == 1); +// +// switch (format) { +// case VK_FORMAT_D24_UNORM_S8_UINT: +// return V_008F14_IMG_NUM_FORMAT_UNORM; +// default: +// if (first_non_void < 0) { +// if (vk_format_is_compressed(format)) { +// switch (format) { +// case VK_FORMAT_BC1_RGB_SRGB_BLOCK: +// case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: +// case VK_FORMAT_BC2_SRGB_BLOCK: +// case VK_FORMAT_BC3_SRGB_BLOCK: +// case VK_FORMAT_BC7_SRGB_BLOCK: +// case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: +// case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: +// case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: +// return V_008F14_IMG_NUM_FORMAT_SRGB; +// case VK_FORMAT_BC4_SNORM_BLOCK: +// case VK_FORMAT_BC5_SNORM_BLOCK: +// case VK_FORMAT_BC6H_SFLOAT_BLOCK: +// case VK_FORMAT_EAC_R11_SNORM_BLOCK: +// case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: +// return V_008F14_IMG_NUM_FORMAT_SNORM; +// default: +// return V_008F14_IMG_NUM_FORMAT_UNORM; +// } +// } else if (desc->layout == VK_FORMAT_LAYOUT_SUBSAMPLED) { +// return V_008F14_IMG_NUM_FORMAT_UNORM; +// } else { +// return V_008F14_IMG_NUM_FORMAT_FLOAT; +// } +// } else if (desc->colorspace == VK_FORMAT_COLORSPACE_SRGB) { +// return V_008F14_IMG_NUM_FORMAT_SRGB; +// } else { +// switch (desc->channel[first_non_void].type) { +// case VK_FORMAT_TYPE_FLOAT: +// return V_008F14_IMG_NUM_FORMAT_FLOAT; +// case VK_FORMAT_TYPE_SIGNED: +// if (desc->channel[first_non_void].normalized) +// return V_008F14_IMG_NUM_FORMAT_SNORM; +// else if (desc->channel[first_non_void].pure_integer) +// return V_008F14_IMG_NUM_FORMAT_SINT; +// else +// return V_008F14_IMG_NUM_FORMAT_SSCALED; +// case VK_FORMAT_TYPE_UNSIGNED: +// if (desc->channel[first_non_void].normalized) +// return V_008F14_IMG_NUM_FORMAT_UNORM; +// else if (desc->channel[first_non_void].pure_integer) +// return V_008F14_IMG_NUM_FORMAT_UINT; +// else +// return V_008F14_IMG_NUM_FORMAT_USCALED; +// default: +// return V_008F14_IMG_NUM_FORMAT_UNORM; +// } +// } +// } +//} + +//uint32_t libresoc_translate_color_numformat(VkFormat format, +// const struct vk_format_description *desc, +// int first_non_void) +//{ +// unsigned ntype; +// +// assert(vk_format_get_plane_count(format) == 1); +// +// if (first_non_void == -1 || desc->channel[first_non_void].type == VK_FORMAT_TYPE_FLOAT) +// ntype = V_028C70_NUMBER_FLOAT; +// else { +// ntype = V_028C70_NUMBER_UNORM; +// if (desc->colorspace == VK_FORMAT_COLORSPACE_SRGB) +// ntype = V_028C70_NUMBER_SRGB; +// else if (desc->channel[first_non_void].type == VK_FORMAT_TYPE_SIGNED) { +// if (desc->channel[first_non_void].pure_integer) { +// ntype = V_028C70_NUMBER_SINT; +// } else if (desc->channel[first_non_void].normalized) { +// ntype = V_028C70_NUMBER_SNORM; +// } else +// ntype = ~0u; +// } else if (desc->channel[first_non_void].type == VK_FORMAT_TYPE_UNSIGNED) { +// if (desc->channel[first_non_void].pure_integer) { +// ntype = V_028C70_NUMBER_UINT; +// } else if (desc->channel[first_non_void].normalized) { +// ntype = V_028C70_NUMBER_UNORM; +// } else +// ntype = ~0u; +// } +// } +// return ntype; +//} + +static bool libresoc_is_sampler_format_supported(VkFormat format, bool *linear_sampling) +{ + const struct vk_format_description *desc = vk_format_description(format); + uint32_t num_format; + if (!desc || format == VK_FORMAT_UNDEFINED) + return false; + + //TODO: stub, enables everything + return true; +} + + +static bool libresoc_is_storage_image_format_supported(struct libresoc_physical_device *physical_device, + VkFormat format) +{ + const struct vk_format_description *desc = vk_format_description(format); + unsigned data_format, num_format; + if (!desc || format == VK_FORMAT_UNDEFINED) + return false; + //TODO: stub, enables everything + return true; +} + +bool libresoc_is_buffer_format_supported(VkFormat format, bool *scaled) +{ + const struct vk_format_description *desc = vk_format_description(format); + unsigned data_format, num_format; + if (!desc || format == VK_FORMAT_UNDEFINED) + return false; + + //TODO: stub, enables everything + return true; +} + +bool libresoc_is_colorbuffer_format_supported(VkFormat format, bool *blendable) +{ + //TODO: stub, enables everything + return true; +} + +static bool libresoc_is_zs_format_supported(VkFormat format) +{ + //TODO: stub, enables everything + return true; +} + +static bool libresoc_is_filter_minmax_format_supported(VkFormat format) +{ + /* From the Vulkan spec 1.1.71: + * + * "The following formats must support the + * VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT feature with + * VK_IMAGE_TILING_OPTIMAL, if they support + * VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT." + */ + /* TODO: enable more formats. */ + switch (format) { + case VK_FORMAT_R8_UNORM: + case VK_FORMAT_R8_SNORM: + case VK_FORMAT_R16_UNORM: + case VK_FORMAT_R16_SNORM: + case VK_FORMAT_R16_SFLOAT: + case VK_FORMAT_R32_SFLOAT: + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return true; + default: + return false; + } +} + +bool +libresoc_device_supports_etc(struct libresoc_physical_device *physical_device) +{ + //TODO: stub, enables everything + return true; +} + +static void +libresoc_physical_device_get_format_properties(struct libresoc_physical_device *physical_device, + VkFormat format, + VkFormatProperties *out_properties) +{ + VkFormatFeatureFlags linear = 0, tiled = 0, buffer = 0; + const struct vk_format_description *desc = vk_format_description(format); + bool blendable; + bool scaled = false; + /* TODO: implement some software emulation of SUBSAMPLED formats. */ + if (!desc || desc->layout == VK_FORMAT_LAYOUT_SUBSAMPLED) { + out_properties->linearTilingFeatures = linear; + out_properties->optimalTilingFeatures = tiled; + out_properties->bufferFeatures = buffer; + return; + } + + if (desc->layout == VK_FORMAT_LAYOUT_ETC && + !libresoc_device_supports_etc(physical_device)) { + out_properties->linearTilingFeatures = linear; + out_properties->optimalTilingFeatures = tiled; + out_properties->bufferFeatures = buffer; + return; + } + + if (desc->layout == VK_FORMAT_LAYOUT_MULTIPLANE || + desc->layout == VK_FORMAT_LAYOUT_SUBSAMPLED) { + uint32_t tiling = VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | + VK_FORMAT_FEATURE_TRANSFER_DST_BIT | + VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT | + VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT; + + /* The subsampled formats have no support for linear filters. */ + if (desc->layout != VK_FORMAT_LAYOUT_SUBSAMPLED) { + tiling |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT; + } + + /* Fails for unknown reasons with linear tiling & subsampled formats. */ + out_properties->linearTilingFeatures = desc->layout == VK_FORMAT_LAYOUT_SUBSAMPLED ? 0 : tiling; + out_properties->optimalTilingFeatures = tiling; + out_properties->bufferFeatures = 0; + return; + } + + if (libresoc_is_storage_image_format_supported(physical_device, format)) { + tiled |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; + linear |= VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT; + } + + if (libresoc_is_buffer_format_supported(format, &scaled)) { + buffer |= VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT; + if (!scaled) + buffer |= VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT | + VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT; + } + + if (vk_format_is_depth_or_stencil(format)) { + if (libresoc_is_zs_format_supported(format)) { + tiled |= VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT; + tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT; + tiled |= VK_FORMAT_FEATURE_BLIT_SRC_BIT | + VK_FORMAT_FEATURE_BLIT_DST_BIT; + tiled |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | + VK_FORMAT_FEATURE_TRANSFER_DST_BIT; + + if (libresoc_is_filter_minmax_format_supported(format)) + tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT; + + /* Don't support blitting surfaces with depth/stencil. */ + if (vk_format_is_depth(format) && vk_format_is_stencil(format)) + tiled &= ~VK_FORMAT_FEATURE_BLIT_DST_BIT; + + /* Don't support linear depth surfaces */ + linear = 0; + } + } else { + bool linear_sampling; + if (libresoc_is_sampler_format_supported(format, &linear_sampling)) { + linear |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_BLIT_SRC_BIT; + tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | + VK_FORMAT_FEATURE_BLIT_SRC_BIT; + + if (libresoc_is_filter_minmax_format_supported(format)) + tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT; + + if (linear_sampling) { + linear |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; + tiled |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; + } + + /* Don't support blitting for R32G32B32 formats. */ + if (format == VK_FORMAT_R32G32B32_SFLOAT || + format == VK_FORMAT_R32G32B32_UINT || + format == VK_FORMAT_R32G32B32_SINT) { + linear &= ~VK_FORMAT_FEATURE_BLIT_SRC_BIT; + } + } + if (libresoc_is_colorbuffer_format_supported(format, &blendable)) { + linear |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; + tiled |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | VK_FORMAT_FEATURE_BLIT_DST_BIT; + if (blendable) { + linear |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; + tiled |= VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT; + } + } + if (tiled && !scaled) { + tiled |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | + VK_FORMAT_FEATURE_TRANSFER_DST_BIT; + } + + /* Tiled formatting does not support NPOT pixel sizes */ + if (!util_is_power_of_two_or_zero(vk_format_get_blocksize(format))) + tiled = 0; + } + + if (linear && !scaled) { + linear |= VK_FORMAT_FEATURE_TRANSFER_SRC_BIT | + VK_FORMAT_FEATURE_TRANSFER_DST_BIT; + } + + if (format == VK_FORMAT_R32_UINT || + format == VK_FORMAT_R32_SINT || + format == VK_FORMAT_R32_SFLOAT) { + buffer |= VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT; + linear |= VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT; + tiled |= VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT; + } + + + out_properties->linearTilingFeatures = linear; + out_properties->optimalTilingFeatures = tiled; + out_properties->bufferFeatures = buffer; +} + +//uint32_t libresoc_translate_colorformat(VkFormat format) +//{ +// const struct vk_format_description *desc = vk_format_description(format); +// +//#define HAS_SIZE(x,y,z,w) \ +// (desc->channel[0].size == (x) && desc->channel[1].size == (y) && \ +// desc->channel[2].size == (z) && desc->channel[3].size == (w)) +// +// if (format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) /* isn't plain */ +// return V_028C70_COLOR_10_11_11; +// +// if (desc->layout != VK_FORMAT_LAYOUT_PLAIN) +// return V_028C70_COLOR_INVALID; +// +// /* hw cannot support mixed formats (except depth/stencil, since +// * stencil is not written to). */ +// if (desc->is_mixed && desc->colorspace != VK_FORMAT_COLORSPACE_ZS) +// return V_028C70_COLOR_INVALID; +// +// switch (desc->nr_channels) { +// case 1: +// switch (desc->channel[0].size) { +// case 8: +// return V_028C70_COLOR_8; +// case 16: +// return V_028C70_COLOR_16; +// case 32: +// return V_028C70_COLOR_32; +// } +// break; +// case 2: +// if (desc->channel[0].size == desc->channel[1].size) { +// switch (desc->channel[0].size) { +// case 8: +// return V_028C70_COLOR_8_8; +// case 16: +// return V_028C70_COLOR_16_16; +// case 32: +// return V_028C70_COLOR_32_32; +// } +// } else if (HAS_SIZE(8,24,0,0)) { +// return V_028C70_COLOR_24_8; +// } else if (HAS_SIZE(24,8,0,0)) { +// return V_028C70_COLOR_8_24; +// } +// break; +// case 3: +// if (HAS_SIZE(5,6,5,0)) { +// return V_028C70_COLOR_5_6_5; +// } else if (HAS_SIZE(32,8,24,0)) { +// return V_028C70_COLOR_X24_8_32_FLOAT; +// } +// break; +// case 4: +// if (desc->channel[0].size == desc->channel[1].size && +// desc->channel[0].size == desc->channel[2].size && +// desc->channel[0].size == desc->channel[3].size) { +// switch (desc->channel[0].size) { +// case 4: +// return V_028C70_COLOR_4_4_4_4; +// case 8: +// return V_028C70_COLOR_8_8_8_8; +// case 16: +// return V_028C70_COLOR_16_16_16_16; +// case 32: +// return V_028C70_COLOR_32_32_32_32; +// } +// } else if (HAS_SIZE(5,5,5,1)) { +// return V_028C70_COLOR_1_5_5_5; +// } else if (HAS_SIZE(1,5,5,5)) { +// return V_028C70_COLOR_5_5_5_1; +// } else if (HAS_SIZE(10,10,10,2)) { +// return V_028C70_COLOR_2_10_10_10; +// } +// break; +// } +// return V_028C70_COLOR_INVALID; +//} + +//uint32_t libresoc_colorformat_endian_swap(uint32_t colorformat) +//{ +// if (0/*SI_BIG_ENDIAN*/) { +// switch(colorformat) { +// /* 8-bit buffers. */ +// case V_028C70_COLOR_8: +// return V_028C70_ENDIAN_NONE; +// +// /* 16-bit buffers. */ +// case V_028C70_COLOR_5_6_5: +// case V_028C70_COLOR_1_5_5_5: +// case V_028C70_COLOR_4_4_4_4: +// case V_028C70_COLOR_16: +// case V_028C70_COLOR_8_8: +// return V_028C70_ENDIAN_8IN16; +// +// /* 32-bit buffers. */ +// case V_028C70_COLOR_8_8_8_8: +// case V_028C70_COLOR_2_10_10_10: +// case V_028C70_COLOR_8_24: +// case V_028C70_COLOR_24_8: +// case V_028C70_COLOR_16_16: +// return V_028C70_ENDIAN_8IN32; +// +// /* 64-bit buffers. */ +// case V_028C70_COLOR_16_16_16_16: +// return V_028C70_ENDIAN_8IN16; +// +// case V_028C70_COLOR_32_32: +// return V_028C70_ENDIAN_8IN32; +// +// /* 128-bit buffers. */ +// case V_028C70_COLOR_32_32_32_32: +// return V_028C70_ENDIAN_8IN32; +// default: +// return V_028C70_ENDIAN_NONE; /* Unsupported. */ +// } +// } else { +// return V_028C70_ENDIAN_NONE; +// } +//} + +//uint32_t libresoc_translate_dbformat(VkFormat format) +//{ +// switch (format) { +// case VK_FORMAT_D16_UNORM: +// case VK_FORMAT_D16_UNORM_S8_UINT: +// return V_028040_Z_16; +// case VK_FORMAT_D32_SFLOAT: +// case VK_FORMAT_D32_SFLOAT_S8_UINT: +// return V_028040_Z_32_FLOAT; +// default: +// return V_028040_Z_INVALID; +// } +//} + +//unsigned libresoc_translate_colorswap(VkFormat format, bool do_endian_swap) +//{ +// const struct vk_format_description *desc = vk_format_description(format); +// +//#define HAS_SWIZZLE(chan,swz) (desc->swizzle[chan] == VK_SWIZZLE_##swz) +// +// if (format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) +// return V_028C70_SWAP_STD; +// +// if (desc->layout != VK_FORMAT_LAYOUT_PLAIN) +// return ~0U; +// +// switch (desc->nr_channels) { +// case 1: +// if (HAS_SWIZZLE(0,X)) +// return V_028C70_SWAP_STD; /* X___ */ +// else if (HAS_SWIZZLE(3,X)) +// return V_028C70_SWAP_ALT_REV; /* ___X */ +// break; +// case 2: +// if ((HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,Y)) || +// (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(1,NONE)) || +// (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,Y))) +// return V_028C70_SWAP_STD; /* XY__ */ +// else if ((HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,X)) || +// (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(1,NONE)) || +// (HAS_SWIZZLE(0,NONE) && HAS_SWIZZLE(1,X))) +// /* YX__ */ +// return (do_endian_swap ? V_028C70_SWAP_STD : V_028C70_SWAP_STD_REV); +// else if (HAS_SWIZZLE(0,X) && HAS_SWIZZLE(3,Y)) +// return V_028C70_SWAP_ALT; /* X__Y */ +// else if (HAS_SWIZZLE(0,Y) && HAS_SWIZZLE(3,X)) +// return V_028C70_SWAP_ALT_REV; /* Y__X */ +// break; +// case 3: +// if (HAS_SWIZZLE(0,X)) +// return (do_endian_swap ? V_028C70_SWAP_STD_REV : V_028C70_SWAP_STD); +// else if (HAS_SWIZZLE(0,Z)) +// return V_028C70_SWAP_STD_REV; /* ZYX */ +// break; +// case 4: +// /* check the middle channels, the 1st and 4th channel can be NONE */ +// if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,Z)) { +// return V_028C70_SWAP_STD; /* XYZW */ +// } else if (HAS_SWIZZLE(1,Z) && HAS_SWIZZLE(2,Y)) { +// return V_028C70_SWAP_STD_REV; /* WZYX */ +// } else if (HAS_SWIZZLE(1,Y) && HAS_SWIZZLE(2,X)) { +// return V_028C70_SWAP_ALT; /* ZYXW */ +// } else if (HAS_SWIZZLE(1,Z) && HAS_SWIZZLE(2,W)) { +// /* YZWX */ +// if (desc->is_array) +// return V_028C70_SWAP_ALT_REV; +// else +// return (do_endian_swap ? V_028C70_SWAP_ALT : V_028C70_SWAP_ALT_REV); +// } +// break; +// } +// return ~0U; +//} + +//bool libresoc_format_pack_clear_color(VkFormat format, +// uint32_t clear_vals[2], +// VkClearColorValue *value) +//{ +// const struct vk_format_description *desc = vk_format_description(format); +// +// if (format == VK_FORMAT_B10G11R11_UFLOAT_PACK32) { +// clear_vals[0] = float3_to_r11g11b10f(value->float32); +// clear_vals[1] = 0; +// return true; +// } +// +// if (desc->layout != VK_FORMAT_LAYOUT_PLAIN) { +// fprintf(stderr, "failed to fast clear for non-plain format %d\n", format); +// return false; +// } +// +// if (!util_is_power_of_two_or_zero(desc->block.bits)) { +// fprintf(stderr, "failed to fast clear for NPOT format %d\n", format); +// return false; +// } +// +// if (desc->block.bits > 64) { +// /* +// * We have a 128 bits format, check if the first 3 components are the same. +// * Every elements has to be 32 bits since we don't support 64-bit formats, +// * and we can skip swizzling checks as alpha always comes last for these and +// * we do not care about the rest as they have to be the same. +// */ +// if (desc->channel[0].type == VK_FORMAT_TYPE_FLOAT) { +// if (value->float32[0] != value->float32[1] || +// value->float32[0] != value->float32[2]) +// return false; +// } else { +// if (value->uint32[0] != value->uint32[1] || +// value->uint32[0] != value->uint32[2]) +// return false; +// } +// clear_vals[0] = value->uint32[0]; +// clear_vals[1] = value->uint32[3]; +// return true; +// } +// uint64_t clear_val = 0; +// +// for (unsigned c = 0; c < 4; ++c) { +// if (desc->swizzle[c] >= 4) +// continue; +// +// const struct vk_format_channel_description *channel = &desc->channel[desc->swizzle[c]]; +// assert(channel->size); +// +// uint64_t v = 0; +// if (channel->pure_integer) { +// v = value->uint32[c] & ((1ULL << channel->size) - 1); +// } else if (channel->normalized) { +// if (channel->type == VK_FORMAT_TYPE_UNSIGNED && +// desc->swizzle[c] < 3 && +// desc->colorspace == VK_FORMAT_COLORSPACE_SRGB) { +// assert(channel->size == 8); +// +// v = util_format_linear_float_to_srgb_8unorm(value->float32[c]); +// } else { +// float f = MIN2(value->float32[c], 1.0f); +// +// if (channel->type == VK_FORMAT_TYPE_UNSIGNED) { +// f = MAX2(f, 0.0f) * ((1ULL << channel->size) - 1); +// } else { +// f = MAX2(f, -1.0f) * ((1ULL << (channel->size - 1)) - 1); +// } +// +// /* The hardware rounds before conversion. */ +// if (f > 0) +// f += 0.5f; +// else +// f -= 0.5f; +// +// v = (uint64_t)f; +// } +// } else if (channel->type == VK_FORMAT_TYPE_FLOAT) { +// if (channel->size == 32) { +// memcpy(&v, &value->float32[c], 4); +// } else if(channel->size == 16) { +// v = util_float_to_half_rtz(value->float32[c]); +// } else { +// fprintf(stderr, "failed to fast clear for unhandled float size in format %d\n", format); +// return false; +// } +// } else { +// fprintf(stderr, "failed to fast clear for unhandled component type in format %d\n", format); +// return false; +// } +// clear_val |= (v & ((1ULL << channel->size) - 1)) << channel->shift; +// } +// +// clear_vals[0] = clear_val; +// clear_vals[1] = clear_val >> 32; +// +// return true; +//} + +void libresoc_GetPhysicalDeviceFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkFormatProperties* pFormatProperties) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, physical_device, physicalDevice); + + libresoc_physical_device_get_format_properties(physical_device, + format, + pFormatProperties); +} + +//void libresoc_GetPhysicalDeviceFormatProperties2( +// VkPhysicalDevice physicalDevice, +// VkFormat format, +// VkFormatProperties2* pFormatProperties) +//{ +// LIBRESOC_FROM_HANDLE(libresoc_physical_device, physical_device, physicalDevice); +// +// libresoc_physical_device_get_format_properties(physical_device, +// format, +// &pFormatProperties->formatProperties); +//} + +static VkResult libresoc_get_image_format_properties(struct libresoc_physical_device *physical_device, + const VkPhysicalDeviceImageFormatInfo2 *info, + VkFormat format, + VkImageFormatProperties *pImageFormatProperties) + +{ + VkFormatProperties format_props; + VkFormatFeatureFlags format_feature_flags; + VkExtent3D maxExtent; + uint32_t maxMipLevels; + uint32_t maxArraySize; + VkSampleCountFlags sampleCounts = VK_SAMPLE_COUNT_1_BIT; + const struct vk_format_description *desc = vk_format_description(format); + + libresoc_physical_device_get_format_properties(physical_device, format, + &format_props); + if (info->tiling == VK_IMAGE_TILING_LINEAR) { + format_feature_flags = format_props.linearTilingFeatures; + } else if (info->tiling == VK_IMAGE_TILING_OPTIMAL) { + format_feature_flags = format_props.optimalTilingFeatures; + } else { + unreachable("bad VkImageTiling"); + } + + if (format_feature_flags == 0) + goto unsupported; + + if (info->type != VK_IMAGE_TYPE_2D && vk_format_is_depth_or_stencil(format)) + goto unsupported; + + switch (info->type) { + default: + unreachable("bad vkimage type\n"); + case VK_IMAGE_TYPE_1D: + maxExtent.width = 16384; + maxExtent.height = 1; + maxExtent.depth = 1; + maxMipLevels = 15; /* log2(maxWidth) + 1 */ + maxArraySize = 2048; + break; + case VK_IMAGE_TYPE_2D: + maxExtent.width = 16384; + maxExtent.height = 16384; + maxExtent.depth = 1; + maxMipLevels = 15; /* log2(maxWidth) + 1 */ + maxArraySize = 2048; + break; + case VK_IMAGE_TYPE_3D: + maxExtent.width = 2048; + maxExtent.height = 2048; + maxExtent.depth = 2048; + maxMipLevels = util_logbase2(maxExtent.width) + 1; + maxArraySize = 1; + break; + } + + if (desc->layout == VK_FORMAT_LAYOUT_SUBSAMPLED) { + /* Might be able to support but the entire format support is + * messy, so taking the lazy way out. */ + maxArraySize = 1; + } + + if (info->tiling == VK_IMAGE_TILING_OPTIMAL && + info->type == VK_IMAGE_TYPE_2D && + (format_feature_flags & (VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT | + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) && + !(info->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) { + sampleCounts |= VK_SAMPLE_COUNT_2_BIT | VK_SAMPLE_COUNT_4_BIT | VK_SAMPLE_COUNT_8_BIT; + } + + if (info->tiling == VK_IMAGE_TILING_LINEAR && + (format == VK_FORMAT_R32G32B32_SFLOAT || + format == VK_FORMAT_R32G32B32_SINT || + format == VK_FORMAT_R32G32B32_UINT)) { + /* R32G32B32 is a weird format and the driver currently only + * supports the barely minimum. + * TODO: Implement more if we really need to. + */ + maxArraySize = 1; + maxMipLevels = 1; + } + + + + *pImageFormatProperties = (VkImageFormatProperties) { + .maxExtent = maxExtent, + .maxMipLevels = maxMipLevels, + .maxArrayLayers = maxArraySize, + .sampleCounts = sampleCounts, + + /* FINISHME: Accurately calculate + * VkImageFormatProperties::maxResourceSize. + */ + .maxResourceSize = UINT32_MAX, + }; + + return VK_SUCCESS; +//TODO: for now we support everything +unsupported: + *pImageFormatProperties = (VkImageFormatProperties) { + .maxExtent = { 0, 0, 0 }, + .maxMipLevels = 0, + .maxArrayLayers = 0, + .sampleCounts = 0, + .maxResourceSize = 0, + }; + + return VK_ERROR_FORMAT_NOT_SUPPORTED; +} + +VkResult libresoc_GetPhysicalDeviceImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + VkImageTiling tiling, + VkImageUsageFlags usage, + VkImageCreateFlags createFlags, + VkImageFormatProperties* pImageFormatProperties) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, physical_device, physicalDevice); + + const VkPhysicalDeviceImageFormatInfo2 info = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .pNext = NULL, + .format = format, + .type = type, + .tiling = tiling, + .usage = usage, + .flags = createFlags, + }; + + return libresoc_get_image_format_properties(physical_device, &info, format, + pImageFormatProperties); +} + +static void +get_external_image_format_properties(struct libresoc_physical_device *physical_device, + const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, + VkExternalMemoryHandleTypeFlagBits handleType, + VkExternalMemoryProperties *external_properties, + VkImageFormatProperties *format_properties) +{ + VkExternalMemoryFeatureFlagBits flags = 0; + VkExternalMemoryHandleTypeFlags export_flags = 0; + VkExternalMemoryHandleTypeFlags compat_flags = 0; + + if (pImageFormatInfo->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) + return; + + switch (handleType) { + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: + switch (pImageFormatInfo->type) { + case VK_IMAGE_TYPE_2D: + flags = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT|VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; + if (pImageFormatInfo->tiling != VK_IMAGE_TILING_LINEAR) + flags |= VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT; + + compat_flags = export_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | + VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; + break; + default: + break; + } + break; + case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: + flags = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; + compat_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; + break; + default: + break; + } + + *external_properties = (VkExternalMemoryProperties) { + .externalMemoryFeatures = flags, + .exportFromImportedHandleTypes = export_flags, + .compatibleHandleTypes = compat_flags, + }; +} + +//VkResult libresoc_GetPhysicalDeviceImageFormatProperties2( +// VkPhysicalDevice physicalDevice, +// const VkPhysicalDeviceImageFormatInfo2 *base_info, +// VkImageFormatProperties2 *base_props) +//{ +// LIBRESOC_FROM_HANDLE(libresoc_physical_device, physical_device, physicalDevice); +// const VkPhysicalDeviceExternalImageFormatInfo *external_info = NULL; +// VkExternalImageFormatProperties *external_props = NULL; +// struct VkAndroidHardwareBufferUsageANDROID *android_usage = NULL; +// VkSamplerYcbcrConversionImageFormatProperties *ycbcr_props = NULL; +// VkTextureLODGatherFormatPropertiesAMD *texture_lod_props = NULL; +// VkResult result; +// VkFormat format = libresoc_select_android_external_format(base_info->pNext, base_info->format); +// +// result = libresoc_get_image_format_properties(physical_device, base_info, format, +// &base_props->imageFormatProperties); +// if (result != VK_SUCCESS) +// return result; +// +// /* Extract input structs */ +// vk_foreach_struct_const(s, base_info->pNext) { +// switch (s->sType) { +// case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO: +// external_info = (const void *) s; +// break; +// default: +// break; +// } +// } +// +// /* Extract output structs */ +// vk_foreach_struct(s, base_props->pNext) { +// switch (s->sType) { +// case VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES: +// external_props = (void *) s; +// break; +// case VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES: +// ycbcr_props = (void *) s; +// break; +// case VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID: +// android_usage = (void *) s; +// break; +// case VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD: +// texture_lod_props = (void *) s; +// break; +// default: +// break; +// } +// } +// +// bool ahb_supported = physical_device->supported_extensions.ANDROID_external_memory_android_hardware_buffer; +// if (android_usage && ahb_supported) { +//#if LIBRESOC_SUPPORT_ANDROID_HARDWARE_BUFFER +// android_usage->androidHardwareBufferUsage = +// libresoc_ahb_usage_from_vk_usage(base_info->flags, +// base_info->usage); +//#endif +// } +// +// /* From the Vulkan 1.0.97 spec: +// * +// * If handleType is 0, vkGetPhysicalDeviceImageFormatProperties2 will +// * behave as if VkPhysicalDeviceExternalImageFormatInfo was not +// * present and VkExternalImageFormatProperties will be ignored. +// */ +// if (external_info && external_info->handleType != 0) { +// get_external_image_format_properties(physical_device, base_info, external_info->handleType, +// &external_props->externalMemoryProperties, +// &base_props->imageFormatProperties); +// if (!external_props->externalMemoryProperties.externalMemoryFeatures) { +// /* From the Vulkan 1.0.97 spec: +// * +// * If handleType is not compatible with the [parameters] specified +// * in VkPhysicalDeviceImageFormatInfo2, then +// * vkGetPhysicalDeviceImageFormatProperties2 returns +// * VK_ERROR_FORMAT_NOT_SUPPORTED. +// */ +// result = vk_errorf(physical_device->instance, VK_ERROR_FORMAT_NOT_SUPPORTED, +// "unsupported VkExternalMemoryTypeFlagBitsKHR 0x%x", +// external_info->handleType); +// goto fail; +// } +// } +// +// if (ycbcr_props) { +// ycbcr_props->combinedImageSamplerDescriptorCount = vk_format_get_plane_count(format); +// } +// +// if (texture_lod_props) { +// if (physical_device->rad_info.chip_class >= GFX9) { +// texture_lod_props->supportsTextureGatherLODBiasAMD = true; +// } else { +// texture_lod_props->supportsTextureGatherLODBiasAMD = !vk_format_is_int(format); +// } +// } +// +// return VK_SUCCESS; +// +//fail: +// if (result == VK_ERROR_FORMAT_NOT_SUPPORTED) { +// /* From the Vulkan 1.0.97 spec: +// * +// * If the combination of parameters to +// * vkGetPhysicalDeviceImageFormatProperties2 is not supported by +// * the implementation for use in vkCreateImage, then all members of +// * imageFormatProperties will be filled with zero. +// */ +// base_props->imageFormatProperties = (VkImageFormatProperties) {0}; +// } +// +// return result; +//} + +void libresoc_GetPhysicalDeviceSparseImageFormatProperties( + VkPhysicalDevice physicalDevice, + VkFormat format, + VkImageType type, + uint32_t samples, + VkImageUsageFlags usage, + VkImageTiling tiling, + uint32_t* pNumProperties, + VkSparseImageFormatProperties* pProperties) +{ + /* Sparse images are not yet supported. */ + *pNumProperties = 0; +} + +//void libresoc_GetPhysicalDeviceSparseImageFormatProperties2( +// VkPhysicalDevice physicalDevice, +// const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, +// uint32_t *pPropertyCount, +// VkSparseImageFormatProperties2 *pProperties) +//{ +// /* Sparse images are not yet supported. */ +// *pPropertyCount = 0; +//} + + +//void libresoc_GetPhysicalDeviceExternalBufferProperties( +// VkPhysicalDevice physicalDevice, +// const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, +// VkExternalBufferProperties *pExternalBufferProperties) +//{ +// VkExternalMemoryFeatureFlagBits flags = 0; +// VkExternalMemoryHandleTypeFlags export_flags = 0; +// VkExternalMemoryHandleTypeFlags compat_flags = 0; +// switch(pExternalBufferInfo->handleType) { +// case VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT: +// case VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT: +// flags = VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT | +// VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; +// compat_flags = export_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT | +// VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; +// break; +// case VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT: +// flags = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT; +// compat_flags = VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT; +// break; +// default: +// break; +// } +// pExternalBufferProperties->externalMemoryProperties = (VkExternalMemoryProperties) { +// .externalMemoryFeatures = flags, +// .exportFromImportedHandleTypes = export_flags, +// .compatibleHandleTypes = compat_flags, +// }; +//} + diff --git a/src/libre-soc/vulkan/libresoc_image.c b/src/libre-soc/vulkan/libresoc_image.c new file mode 100644 index 00000000000..46b9acb200e --- /dev/null +++ b/src/libre-soc/vulkan/libresoc_image.c @@ -0,0 +1,159 @@ + +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * based in part on anv driver which is: + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "vk_util.h" +#include "libresoc_private.h" + + +VkResult +libresoc_image_create(VkDevice _device, + const struct libresoc_image_create_info *create_info, + const VkAllocationCallbacks* alloc, + VkImage *pImage) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + const VkImageCreateInfo *pCreateInfo = create_info->vk_info; + struct libresoc_image *image = NULL; + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO); + + // const unsigned plane_count = vk_format_get_plane_count(format); + // const size_t image_struct_size = sizeof(*image) + sizeof(struct libresoc_image_plane) * plane_count; + + const size_t image_struct_size = sizeof(*image); + // libresoc_assert(pCreateInfo->mipLevels > 0); + // libresoc_assert(pCreateInfo->arrayLayers > 0); + // libresoc_assert(pCreateInfo->samples > 0); + // libresoc_assert(pCreateInfo->extent.width > 0); + // libresoc_assert(pCreateInfo->extent.height > 0); + // libresoc_assert(pCreateInfo->extent.depth > 0); + + image = vk_zalloc2(&device->vk.alloc, alloc, image_struct_size, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!image) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + vk_object_base_init(&device->vk, &image->base, VK_OBJECT_TYPE_IMAGE); + + image->type = pCreateInfo->imageType; + // image->info.width = pCreateInfo->extent.width; + // image->info.height = pCreateInfo->extent.height; + // image->info.depth = pCreateInfo->extent.depth; + // image->info.samples = pCreateInfo->samples; + // image->info.storage_samples = pCreateInfo->samples; + // image->info.array_size = pCreateInfo->arrayLayers; + // image->info.levels = pCreateInfo->mipLevels; + // image->info.num_channels = vk_format_get_nr_components(format); + + //image->vk_format = format; + image->tiling = pCreateInfo->tiling; + image->usage = pCreateInfo->usage; + image->flags = pCreateInfo->flags; + //image->plane_count = plane_count; + + image->exclusive = pCreateInfo->sharingMode == VK_SHARING_MODE_EXCLUSIVE; + // if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT) { + // for (uint32_t i = 0; i < pCreateInfo->queueFamilyIndexCount; ++i) + // if (pCreateInfo->pQueueFamilyIndices[i] == VK_QUEUE_FAMILY_EXTERNAL || + // pCreateInfo->pQueueFamilyIndices[i] == VK_QUEUE_FAMILY_FOREIGN_EXT) + // image->queue_family_mask |= (1u << LIBRESOC_MAX_QUEUE_FAMILIES) - 1u; + // else + // image->queue_family_mask |= 1u << pCreateInfo->pQueueFamilyIndices[i]; + // } + + // const VkExternalMemoryImageCreateInfo *external_info = + // vk_find_struct_const(pCreateInfo->pNext, + // EXTERNAL_MEMORY_IMAGE_CREATE_INFO) ; + + // image->shareable = external_info; + // if (!vk_format_is_depth_or_stencil(format) && !image->shareable) { + // image->info.surf_index = &device->image_mrt_offset_counter; + // } + + // for (unsigned plane = 0; plane < image->plane_count; ++plane) { + // image->planes[plane].surface.flags = + // libresoc_get_surface_flags(device, image, plane, pCreateInfo, format); + // } + + // bool delay_layout = external_info && + // (external_info->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID); + + // if (delay_layout) { + // *pImage = libresoc_image_to_handle(image); + // assert (!(image->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT)); + // return VK_SUCCESS; + // } + + // ASSERTED VkResult result = libresoc_image_create_layout(device, *create_info, image); + // assert(result == VK_SUCCESS); + + // if (image->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) { + // image->alignment = MAX2(image->alignment, 4096); + // image->size = align64(image->size, image->alignment); + // image->offset = 0; + + // image->bo = device->ws->buffer_create(device->ws, image->size, image->alignment, + // 0, RADEON_FLAG_VIRTUAL, LIBRESOC_BO_PRIORITY_VIRTUAL); + // if (!image->bo) { + // libresoc_destroy_image(device, alloc, image); + // return vk_error(device->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY); + // } + // } + + *pImage = libresoc_image_to_handle(image); + + return VK_SUCCESS; +} + + +VkResult +libresoc_CreateImage(VkDevice device, + const VkImageCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkImage *pImage) +{ + + const struct wsi_image_create_info *wsi_info = + vk_find_struct_const(pCreateInfo->pNext, WSI_IMAGE_CREATE_INFO_MESA); + bool scanout = wsi_info && wsi_info->scanout; + + return libresoc_image_create(device, + &(struct libresoc_image_create_info) { + .vk_info = pCreateInfo, + .scanout = scanout, + }, + pAllocator, + pImage); +} +void libresoc_GetImageSubresourceLayout( + VkDevice _device, + VkImage _image, + const VkImageSubresource* pSubresource, + VkSubresourceLayout* pLayout) +{ +//TODO: stub +} diff --git a/src/libre-soc/vulkan/libresoc_meta_clear.c b/src/libre-soc/vulkan/libresoc_meta_clear.c new file mode 100644 index 00000000000..a0a0f41cbf4 --- /dev/null +++ b/src/libre-soc/vulkan/libresoc_meta_clear.c @@ -0,0 +1,36 @@ + +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "libresoc_private.h" + +void libresoc_CmdClearColorImage( + VkCommandBuffer commandBuffer, + VkImage image_h, + VkImageLayout imageLayout, + const VkClearColorValue* pColor, + uint32_t rangeCount, + const VkImageSubresourceRange* pRanges) +{ +//TODO: stub +} diff --git a/src/libre-soc/vulkan/libresoc_pipeline_cache.c b/src/libre-soc/vulkan/libresoc_pipeline_cache.c new file mode 100644 index 00000000000..e00dde678f3 --- /dev/null +++ b/src/libre-soc/vulkan/libresoc_pipeline_cache.c @@ -0,0 +1,646 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "util/mesa-sha1.h" +#include "util/debug.h" +#include "util/disk_cache.h" +#include "util/u_atomic.h" +#include "libresoc_debug.h" +#include "libresoc_private.h" +//#include "libresoc_shader.h" +#include "vulkan/util/vk_util.h" + +//#include "ac_nir_to_llvm.h" + +struct cache_entry { + union { + unsigned char sha1[20]; + uint32_t sha1_dw[5]; + }; + uint32_t binary_sizes[MESA_SHADER_STAGES]; + struct libresoc_shader_variant *variants[MESA_SHADER_STAGES]; + char code[0]; +}; + +static void +libresoc_pipeline_cache_lock(struct libresoc_pipeline_cache *cache) +{ + if (cache->flags & VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT) + return; + + pthread_mutex_lock(&cache->mutex); +} + +static void +libresoc_pipeline_cache_unlock(struct libresoc_pipeline_cache *cache) +{ + if (cache->flags & VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT) + return; + + pthread_mutex_unlock(&cache->mutex); +} + +void +libresoc_pipeline_cache_init(struct libresoc_pipeline_cache *cache, + struct libresoc_device *device) +{ + cache->device = device; + pthread_mutex_init(&cache->mutex, NULL); + cache->flags = 0; + + cache->modified = false; + cache->kernel_count = 0; + cache->total_size = 0; + cache->table_size = 1024; + const size_t byte_size = cache->table_size * sizeof(cache->hash_table[0]); + cache->hash_table = malloc(byte_size); + + /* We don't consider allocation failure fatal, we just start with a 0-sized + * cache. Disable caching when we want to keep shader debug info, since + * we don't get the debug info on cached shaders. */ + if (cache->hash_table == NULL || + (device->instance->debug_flags & LIBRESOC_DEBUG_NO_CACHE)) + cache->table_size = 0; + else + memset(cache->hash_table, 0, byte_size); +} + +void +libresoc_pipeline_cache_finish(struct libresoc_pipeline_cache *cache) +{ + for (unsigned i = 0; i < cache->table_size; ++i) + if (cache->hash_table[i]) { + for(int j = 0; j < MESA_SHADER_STAGES; ++j) { + // TODO: uncomment following lines + //if (cache->hash_table[i]->variants[j]) + // libresoc_shader_variant_destroy(cache->device, + // cache->hash_table[i]->variants[j]); + } + vk_free(&cache->alloc, cache->hash_table[i]); + } + pthread_mutex_destroy(&cache->mutex); + free(cache->hash_table); +} + +static uint32_t +entry_size(struct cache_entry *entry) +{ + size_t ret = sizeof(*entry); + for (int i = 0; i < MESA_SHADER_STAGES; ++i) + if (entry->binary_sizes[i]) + ret += entry->binary_sizes[i]; + return ret; +} + +/* +void +libresoc_hash_shaders(unsigned char *hash, + const VkPipelineShaderStageCreateInfo **stages, + const struct libresoc_pipeline_layout *layout, + const struct libresoc_pipeline_key *key, + uint32_t flags) +{ + struct mesa_sha1 ctx; + + _mesa_sha1_init(&ctx); + if (key) + _mesa_sha1_update(&ctx, key, sizeof(*key)); + if (layout) + _mesa_sha1_update(&ctx, layout->sha1, sizeof(layout->sha1)); + + for (int i = 0; i < MESA_SHADER_STAGES; ++i) { + if (stages[i]) { + LIBRESOC_FROM_HANDLE(libresoc_shader_module, module, stages[i]->module); + const VkSpecializationInfo *spec_info = stages[i]->pSpecializationInfo; + + _mesa_sha1_update(&ctx, module->sha1, sizeof(module->sha1)); + _mesa_sha1_update(&ctx, stages[i]->pName, strlen(stages[i]->pName)); + if (spec_info) { + _mesa_sha1_update(&ctx, spec_info->pMapEntries, + spec_info->mapEntryCount * sizeof spec_info->pMapEntries[0]); + _mesa_sha1_update(&ctx, spec_info->pData, spec_info->dataSize); + } + } + } + _mesa_sha1_update(&ctx, &flags, 4); + _mesa_sha1_final(&ctx, hash); +}*/ + + +static struct cache_entry * +libresoc_pipeline_cache_search_unlocked(struct libresoc_pipeline_cache *cache, + const unsigned char *sha1) +{ + const uint32_t mask = cache->table_size - 1; + const uint32_t start = (*(uint32_t *) sha1); + + if (cache->table_size == 0) + return NULL; + + for (uint32_t i = 0; i < cache->table_size; i++) { + const uint32_t index = (start + i) & mask; + struct cache_entry *entry = cache->hash_table[index]; + + if (!entry) + return NULL; + + if (memcmp(entry->sha1, sha1, sizeof(entry->sha1)) == 0) { + return entry; + } + } + + unreachable("hash table should never be full"); +} + +static struct cache_entry * +libresoc_pipeline_cache_search(struct libresoc_pipeline_cache *cache, + const unsigned char *sha1) +{ + struct cache_entry *entry; + + libresoc_pipeline_cache_lock(cache); + + entry = libresoc_pipeline_cache_search_unlocked(cache, sha1); + + libresoc_pipeline_cache_unlock(cache); + + return entry; +} + +static void +libresoc_pipeline_cache_set_entry(struct libresoc_pipeline_cache *cache, + struct cache_entry *entry) +{ + const uint32_t mask = cache->table_size - 1; + const uint32_t start = entry->sha1_dw[0]; + + /* We'll always be able to insert when we get here. */ + assert(cache->kernel_count < cache->table_size / 2); + + for (uint32_t i = 0; i < cache->table_size; i++) { + const uint32_t index = (start + i) & mask; + if (!cache->hash_table[index]) { + cache->hash_table[index] = entry; + break; + } + } + + cache->total_size += entry_size(entry); + cache->kernel_count++; +} + + +static VkResult +libresoc_pipeline_cache_grow(struct libresoc_pipeline_cache *cache) +{ + const uint32_t table_size = cache->table_size * 2; + const uint32_t old_table_size = cache->table_size; + const size_t byte_size = table_size * sizeof(cache->hash_table[0]); + struct cache_entry **table; + struct cache_entry **old_table = cache->hash_table; + + table = malloc(byte_size); + if (table == NULL) + return vk_error(cache->device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + cache->hash_table = table; + cache->table_size = table_size; + cache->kernel_count = 0; + cache->total_size = 0; + + memset(cache->hash_table, 0, byte_size); + for (uint32_t i = 0; i < old_table_size; i++) { + struct cache_entry *entry = old_table[i]; + if (!entry) + continue; + + libresoc_pipeline_cache_set_entry(cache, entry); + } + + free(old_table); + + return VK_SUCCESS; +} + +static void +libresoc_pipeline_cache_add_entry(struct libresoc_pipeline_cache *cache, + struct cache_entry *entry) +{ + if (cache->kernel_count == cache->table_size / 2) + libresoc_pipeline_cache_grow(cache); + + /* Failing to grow that hash table isn't fatal, but may mean we don't + * have enough space to add this new kernel. Only add it if there's room. + */ + if (cache->kernel_count < cache->table_size / 2) + libresoc_pipeline_cache_set_entry(cache, entry); +} + +static bool +libresoc_is_cache_disabled(struct libresoc_device *device) +{ + /* Pipeline caches can be disabled with LIBRESOC_DEBUG=nocache, with + * MESA_GLSL_CACHE_DISABLE=1, and when VK_AMD_shader_info is requested. + */ + return (device->instance->debug_flags & LIBRESOC_DEBUG_NO_CACHE); +} + +/* +bool +libresoc_create_shader_variants_from_pipeline_cache(struct libresoc_device *device, + struct libresoc_pipeline_cache *cache, + const unsigned char *sha1, + struct libresoc_shader_variant **variants, + bool *found_in_application_cache) +{ + struct cache_entry *entry; + + if (!cache) { + cache = device->mem_cache; + *found_in_application_cache = false; + } + + libresoc_pipeline_cache_lock(cache); + + entry = libresoc_pipeline_cache_search_unlocked(cache, sha1); + + if (!entry) { + *found_in_application_cache = false; + +*/ /* Don't cache when we want debug info, since this isn't + * present in the cache. + */ +/* if (libresoc_is_cache_disabled(device) || !device->physical_device->disk_cache) { + libresoc_pipeline_cache_unlock(cache); + return false; + } + + uint8_t disk_sha1[20]; + disk_cache_compute_key(device->physical_device->disk_cache, + sha1, 20, disk_sha1); + + entry = (struct cache_entry *) + disk_cache_get(device->physical_device->disk_cache, + disk_sha1, NULL); + if (!entry) { + libresoc_pipeline_cache_unlock(cache); + return false; + } else { + size_t size = entry_size(entry); + struct cache_entry *new_entry = vk_alloc(&cache->alloc, size, 8, + VK_SYSTEM_ALLOCATION_SCOPE_CACHE); + if (!new_entry) { + free(entry); + libresoc_pipeline_cache_unlock(cache); + return false; + } + + memcpy(new_entry, entry, entry_size(entry)); + free(entry); + entry = new_entry; + + if (!(device->instance->debug_flags & LIBRESOC_DEBUG_NO_MEMORY_CACHE) || + cache != device->mem_cache) + libresoc_pipeline_cache_add_entry(cache, new_entry); + } + } + + char *p = entry->code; + for(int i = 0; i < MESA_SHADER_STAGES; ++i) { + if (!entry->variants[i] && entry->binary_sizes[i]) { + struct libresoc_shader_binary *binary = calloc(1, entry->binary_sizes[i]); + memcpy(binary, p, entry->binary_sizes[i]); + p += entry->binary_sizes[i]; + + entry->variants[i] = libresoc_shader_variant_create(device, binary, false); + free(binary); + } else if (entry->binary_sizes[i]) { + p += entry->binary_sizes[i]; + } + + } + + memcpy(variants, entry->variants, sizeof(entry->variants)); + + if (device->instance->debug_flags & LIBRESOC_DEBUG_NO_MEMORY_CACHE && + cache == device->mem_cache) + vk_free(&cache->alloc, entry); + else { + for (int i = 0; i < MESA_SHADER_STAGES; ++i) + if (entry->variants[i]) + p_atomic_inc(&entry->variants[i]->ref_count); + } + + libresoc_pipeline_cache_unlock(cache); + return true; +}*/ + +/* +void +libresoc_pipeline_cache_insert_shaders(struct libresoc_device *device, + struct libresoc_pipeline_cache *cache, + const unsigned char *sha1, + struct libresoc_shader_variant **variants, + struct libresoc_shader_binary *const *binaries) +{ + if (!cache) + cache = device->mem_cache; + + libresoc_pipeline_cache_lock(cache); + struct cache_entry *entry = libresoc_pipeline_cache_search_unlocked(cache, sha1); + if (entry) { + for (int i = 0; i < MESA_SHADER_STAGES; ++i) { + if (entry->variants[i]) { + libresoc_shader_variant_destroy(cache->device, variants[i]); + variants[i] = entry->variants[i]; + } else { + entry->variants[i] = variants[i]; + } + if (variants[i]) + p_atomic_inc(&variants[i]->ref_count); + } + libresoc_pipeline_cache_unlock(cache); + return; + } + +*/ /* Don't cache when we want debug info, since this isn't + * present in the cache. + */ +/* if (libresoc_is_cache_disabled(device)) { + libresoc_pipeline_cache_unlock(cache); + return; + } + + size_t size = sizeof(*entry); + for (int i = 0; i < MESA_SHADER_STAGES; ++i) + if (variants[i]) + size += binaries[i]->total_size; + + + entry = vk_alloc(&cache->alloc, size, 8, + VK_SYSTEM_ALLOCATION_SCOPE_CACHE); + if (!entry) { + libresoc_pipeline_cache_unlock(cache); + return; + } + + memset(entry, 0, sizeof(*entry)); + memcpy(entry->sha1, sha1, 20); + + char* p = entry->code; + + for (int i = 0; i < MESA_SHADER_STAGES; ++i) { + if (!variants[i]) + continue; + + entry->binary_sizes[i] = binaries[i]->total_size; + + memcpy(p, binaries[i], binaries[i]->total_size); + p += binaries[i]->total_size; + } + +*/ /* Always add cache items to disk. This will allow collection of + * compiled shaders by third parties such as steam, even if the app + * implements its own pipeline cache. + */ +/* if (device->physical_device->disk_cache) { + uint8_t disk_sha1[20]; + disk_cache_compute_key(device->physical_device->disk_cache, sha1, 20, + disk_sha1); + + disk_cache_put(device->physical_device->disk_cache, disk_sha1, + entry, entry_size(entry), NULL); + } + + if (device->instance->debug_flags & LIBRESOC_DEBUG_NO_MEMORY_CACHE && + cache == device->mem_cache) { + vk_free2(&cache->alloc, NULL, entry); + libresoc_pipeline_cache_unlock(cache); + return; + } + +*/ /* We delay setting the variant so we have reproducible disk cache + * items. + */ +/* for (int i = 0; i < MESA_SHADER_STAGES; ++i) { + if (!variants[i]) + continue; + + entry->variants[i] = variants[i]; + p_atomic_inc(&variants[i]->ref_count); + } + + libresoc_pipeline_cache_add_entry(cache, entry); + + cache->modified = true; + libresoc_pipeline_cache_unlock(cache); + return; +}*/ + +bool +libresoc_pipeline_cache_load(struct libresoc_pipeline_cache *cache, + const void *data, size_t size) +{ + struct libresoc_device *device = cache->device; + struct vk_pipeline_cache_header header; + + if (size < sizeof(header)) + return false; + memcpy(&header, data, sizeof(header)); + if (header.header_size < sizeof(header)) + return false; + if (header.header_version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE) + return false; + if (header.vendor_id != 1) //TODO: just dummy value + return false; + if (header.device_id != 1) //TODO: just dummy value + return false; + if (memcmp(header.uuid, device->physical_device->cache_uuid, VK_UUID_SIZE) != 0) + return false; + + char *end = (void *) data + size; + char *p = (void *) data + header.header_size; + + while (end - p >= sizeof(struct cache_entry)) { + struct cache_entry *entry = (struct cache_entry*)p; + struct cache_entry *dest_entry; + size_t size = entry_size(entry); + if(end - p < size) + break; + + dest_entry = vk_alloc(&cache->alloc, size, + 8, VK_SYSTEM_ALLOCATION_SCOPE_CACHE); + if (dest_entry) { + memcpy(dest_entry, entry, size); + for (int i = 0; i < MESA_SHADER_STAGES; ++i) + dest_entry->variants[i] = NULL; + libresoc_pipeline_cache_add_entry(cache, dest_entry); + } + p += size; + } + + return true; +} + +VkResult libresoc_CreatePipelineCache( + VkDevice _device, + const VkPipelineCacheCreateInfo* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkPipelineCache* pPipelineCache) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + struct libresoc_pipeline_cache *cache; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO); + assert(pCreateInfo->flags == 0); + + cache = vk_alloc2(&device->vk.alloc, pAllocator, + sizeof(*cache), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (cache == NULL) + return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY); + + vk_object_base_init(&device->vk, &cache->base, + VK_OBJECT_TYPE_PIPELINE_CACHE); + + if (pAllocator) + cache->alloc = *pAllocator; + else + cache->alloc = device->vk.alloc; + + libresoc_pipeline_cache_init(cache, device); + cache->flags = pCreateInfo->flags; + + /*if (pCreateInfo->initialDataSize > 0) { + libresoc_pipeline_cache_load(cache, + pCreateInfo->pInitialData, + pCreateInfo->initialDataSize); + }*/ + + *pPipelineCache = libresoc_pipeline_cache_to_handle(cache); + + return VK_SUCCESS; +} + +void libresoc_DestroyPipelineCache( + VkDevice _device, + VkPipelineCache _cache, + const VkAllocationCallbacks* pAllocator) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + LIBRESOC_FROM_HANDLE(libresoc_pipeline_cache, cache, _cache); + + if (!cache) + return; + libresoc_pipeline_cache_finish(cache); + + vk_object_base_finish(&cache->base); + vk_free2(&device->vk.alloc, pAllocator, cache); +} + +VkResult libresoc_GetPipelineCacheData( + VkDevice _device, + VkPipelineCache _cache, + size_t* pDataSize, + void* pData) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + LIBRESOC_FROM_HANDLE(libresoc_pipeline_cache, cache, _cache); + struct vk_pipeline_cache_header *header; + VkResult result = VK_SUCCESS; + + libresoc_pipeline_cache_lock(cache); + + const size_t size = sizeof(*header) + cache->total_size; + if (pData == NULL) { + libresoc_pipeline_cache_unlock(cache); + *pDataSize = size; + return VK_SUCCESS; + } + if (*pDataSize < sizeof(*header)) { + libresoc_pipeline_cache_unlock(cache); + *pDataSize = 0; + return VK_INCOMPLETE; + } + void *p = pData, *end = pData + *pDataSize; + header = p; + header->header_size = sizeof(*header); + header->header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE; + header->vendor_id = 1; //TODO: some dummy value + header->device_id = 1; //TODO: some dummy value + memcpy(header->uuid, device->physical_device->cache_uuid, VK_UUID_SIZE); + p += header->header_size; + + struct cache_entry *entry; + for (uint32_t i = 0; i < cache->table_size; i++) { + if (!cache->hash_table[i]) + continue; + entry = cache->hash_table[i]; + const uint32_t size = entry_size(entry); + if (end < p + size) { + result = VK_INCOMPLETE; + break; + } + + memcpy(p, entry, size); + for(int j = 0; j < MESA_SHADER_STAGES; ++j) + ((struct cache_entry*)p)->variants[j] = NULL; + p += size; + } + *pDataSize = p - pData; + + libresoc_pipeline_cache_unlock(cache); + return result; +} + +static void +libresoc_pipeline_cache_merge(struct libresoc_pipeline_cache *dst, + struct libresoc_pipeline_cache *src) +{ + for (uint32_t i = 0; i < src->table_size; i++) { + struct cache_entry *entry = src->hash_table[i]; + if (!entry || libresoc_pipeline_cache_search(dst, entry->sha1)) + continue; + + libresoc_pipeline_cache_add_entry(dst, entry); + + src->hash_table[i] = NULL; + } +} + +VkResult libresoc_MergePipelineCaches( + VkDevice _device, + VkPipelineCache destCache, + uint32_t srcCacheCount, + const VkPipelineCache* pSrcCaches) +{ + LIBRESOC_FROM_HANDLE(libresoc_pipeline_cache, dst, destCache); + + for (uint32_t i = 0; i < srcCacheCount; i++) { + LIBRESOC_FROM_HANDLE(libresoc_pipeline_cache, src, pSrcCaches[i]); + + libresoc_pipeline_cache_merge(dst, src); + } + + return VK_SUCCESS; +} diff --git a/src/libre-soc/vulkan/libresoc_private.h b/src/libre-soc/vulkan/libresoc_private.h index 60f12937448..0c2d1e5eea2 100644 --- a/src/libre-soc/vulkan/libresoc_private.h +++ b/src/libre-soc/vulkan/libresoc_private.h @@ -46,7 +46,136 @@ #include "libresoc_constants.h" #include "libresoc_debug.h" +#include "wsi_common.h" #define LIBRESOC_MAX_QUEUE_FAMILIES 1 + +static inline uint32_t +align_u32(uint32_t v, uint32_t a) +{ + assert(a != 0 && a == (a & -a)); + return (v + a - 1) & ~(a - 1); +} + +static inline uint32_t +align_u32_npot(uint32_t v, uint32_t a) +{ + return (v + a - 1) / a * a; +} + +static inline uint64_t +align_u64(uint64_t v, uint64_t a) +{ + assert(a != 0 && a == (a & -a)); + return (v + a - 1) & ~(a - 1); +} + +static inline int32_t +align_i32(int32_t v, int32_t a) +{ + assert(a != 0 && a == (a & -a)); + return (v + a - 1) & ~(a - 1); +} + +/** Alignment must be a power of 2. */ +static inline bool +libresoc_is_aligned(uintmax_t n, uintmax_t a) +{ + assert(a == (a & -a)); + return (n & (a - 1)) == 0; +} + +static inline uint32_t +round_up_u32(uint32_t v, uint32_t a) +{ + return (v + a - 1) / a; +} + +static inline uint64_t +round_up_u64(uint64_t v, uint64_t a) +{ + return (v + a - 1) / a; +} + +static inline uint32_t +libresoc_minify(uint32_t n, uint32_t levels) +{ + if (unlikely(n == 0)) + return 0; + else + return MAX2(n >> levels, 1); +} +static inline float +libresoc_clamp_f(float f, float min, float max) +{ + assert(min < max); + + if (f > max) + return max; + else if (f < min) + return min; + else + return f; +} + +static inline bool +libresoc_clear_mask(uint32_t *inout_mask, uint32_t clear_mask) +{ + if (*inout_mask & clear_mask) { + *inout_mask &= ~clear_mask; + return true; + } else { + return false; + } +} + +struct libresoc_fence { + struct vk_object_base base; +}; + +struct libresoc_image_create_info { + const VkImageCreateInfo *vk_info; + bool scanout; + bool no_metadata_planes; +}; + +struct libresoc_image { + struct vk_object_base base; + VkImageType type; + /* The original VkFormat provided by the client. This may not match any + * of the actual surface formats. + */ + VkFormat vk_format; + VkImageAspectFlags aspects; + VkImageUsageFlags usage; /**< Superset of VkImageCreateInfo::usage. */ + VkImageTiling tiling; /** VkImageCreateInfo::tiling */ + VkImageCreateFlags flags; /** VkImageCreateInfo::flags */ + + VkDeviceSize size; + uint32_t alignment; + + unsigned queue_family_mask; + bool exclusive; + bool shareable; + +}; + +VkResult libresoc_image_create(VkDevice _device, + const struct libresoc_image_create_info *info, + const VkAllocationCallbacks* alloc, + VkImage *pImage); + +struct libresoc_cmd_pool { + struct vk_object_base base; + VkAllocationCallbacks alloc; + struct list_head cmd_buffers; + struct list_head free_cmd_buffers; + uint32_t queue_family_index; +}; + +struct libresoc_semaphore { + struct vk_object_base base; +}; + struct libresoc_instance; struct libresoc_device; struct cache_entry; @@ -92,6 +221,10 @@ libresoc_pipeline_cache_insert_shaders(struct libresoc_device *device, const unsigned char *sha1, struct libresoc_shader_variant **variants, struct libresoc_shader_binary *const *binaries); + +VkResult libresoc_init_wsi(struct libresoc_physical_device *physical_device); +void libresoc_finish_wsi(struct libresoc_physical_device *physical_device); + struct libresoc_device { struct vk_device vk; @@ -112,6 +245,10 @@ struct libresoc_device { /* Condition variable for legacy timelines, to notify waiters when a * new point gets submitted. */ pthread_cond_t timeline_cond; + /* Overallocation. */ + bool overallocation_disallowed; + uint64_t allocated_memory_size[VK_MAX_MEMORY_HEAPS]; + mtx_t overallocation_mutex; /* FIXME: stub */ }; @@ -121,7 +258,7 @@ struct libresoc_physical_device { struct list_head link; struct libresoc_instance *instance; - + struct wsi_device wsi_device; struct libresoc_device_extension_table supported_extensions; struct libresoc_physical_device_dispatch_table dispatch; @@ -129,6 +266,9 @@ struct libresoc_physical_device { uint8_t driver_uuid[VK_UUID_SIZE]; uint8_t device_uuid[VK_UUID_SIZE]; uint8_t cache_uuid[VK_UUID_SIZE]; + int local_fd; + int master_fd; + VkPhysicalDeviceMemoryProperties memory_properties; /* FIXME: stub */ }; @@ -160,9 +300,12 @@ struct libresoc_instance { int physical_device_count; struct list_head physical_devices; + struct driOptionCache dri_options; + struct driOptionCache available_dri_options; struct vk_debug_report_instance debug_report_callbacks; }; +struct libresoc_deferred_queue_submission; struct libresoc_queue { VK_LOADER_DATA _loader_data; @@ -174,16 +317,83 @@ struct libresoc_queue { struct list_head pending_submissions; pthread_mutex_t pending_mutex; + pthread_mutex_t thread_mutex; + pthread_cond_t thread_cond; + //struct libresoc_deferred_queue_submission *thread_submission; + pthread_t submission_thread; + bool thread_exit; + bool thread_running; /* FIXME: stub */ }; +struct libresoc_cmd_buffer_upload { + uint8_t *map; + unsigned offset; + uint64_t size; + struct list_head list; +}; + +enum libresoc_cmd_buffer_status { + LIBRESOC_CMD_BUFFER_STATUS_INVALID, + LIBRESOC_CMD_BUFFER_STATUS_INITIAL, + LIBRESOC_CMD_BUFFER_STATUS_RECORDING, + LIBRESOC_CMD_BUFFER_STATUS_EXECUTABLE, + LIBRESOC_CMD_BUFFER_STATUS_PENDING, +}; + struct libresoc_cmd_buffer { + struct vk_object_base base; - struct libresoc_device *device; + struct libresoc_device * device; + + struct libresoc_cmd_pool * pool; + struct list_head pool_link; + + VkCommandBufferUsageFlags usage_flags; + VkCommandBufferLevel level; + enum libresoc_cmd_buffer_status status; + //struct radeon_cmdbuf *cs; + // struct libresoc_cmd_state state; + // struct libresoc_vertex_binding vertex_bindings[MAX_VBS]; + // struct libresoc_streamout_binding streamout_bindings[MAX_SO_BUFFERS]; + uint32_t queue_family_index; + + uint8_t push_constants[MAX_PUSH_CONSTANTS_SIZE]; + VkShaderStageFlags push_constant_stages; + // struct libresoc_descriptor_set meta_push_descriptors; + + // struct libresoc_descriptor_state descriptors[MAX_BIND_POINTS]; + + struct libresoc_cmd_buffer_upload upload; + + uint32_t scratch_size_per_wave_needed; + uint32_t scratch_waves_wanted; + uint32_t compute_scratch_size_per_wave_needed; + uint32_t compute_scratch_waves_wanted; + uint32_t esgs_ring_size_needed; + uint32_t gsvs_ring_size_needed; + bool tess_rings_needed; + bool sample_positions_needed; + + VkResult record_result; - /* FIXME: stub */ }; +struct libresoc_device_memory { + struct vk_object_base base; + /* for dedicated allocations */ + struct libresoc_image *image; + //struct libresoc_buffer *buffer; + uint32_t heap_index; + uint64_t alloc_size; + void * map; + void * user_ptr; +}; + +void libresoc_free_memory(struct libresoc_device *device, + const VkAllocationCallbacks* pAllocator, + struct libresoc_device_memory *mem); + uint32_t libresoc_physical_device_api_version(struct libresoc_physical_device *dev); int libresoc_get_instance_entrypoint_index(const char *name); @@ -210,6 +420,65 @@ void *libresoc_lookup_entrypoint(const char *name); const char * libresoc_get_debug_option_name(int id); +struct libresoc_binning_settings { + unsigned context_states_per_bin; /* allowed range: [1, 6] */ + unsigned persistent_states_per_bin; /* allowed range: [1, 32] */ + unsigned fpovs_per_batch; /* allowed range: [0, 255], 0 = unlimited */ +}; + +struct libresoc_binning_settings +libresoc_get_binning_settings(const struct libresoc_physical_device *pdev); + +struct vk_format_description; +uint32_t libresoc_translate_buffer_dataformat(const struct vk_format_description *desc, + int first_non_void); +uint32_t libresoc_translate_buffer_numformat(const struct vk_format_description *desc, + int first_non_void); +bool libresoc_is_buffer_format_supported(VkFormat format, bool *scaled); +uint32_t libresoc_translate_colorformat(VkFormat format); +uint32_t libresoc_translate_color_numformat(VkFormat format, + const struct vk_format_description *desc, + int first_non_void); +uint32_t libresoc_colorformat_endian_swap(uint32_t colorformat); +unsigned libresoc_translate_colorswap(VkFormat format, bool do_endian_swap); +uint32_t libresoc_translate_dbformat(VkFormat format); +uint32_t libresoc_translate_tex_dataformat(VkFormat format, + const struct vk_format_description *desc, + int first_non_void); +uint32_t libresoc_translate_tex_numformat(VkFormat format, + const struct vk_format_description *desc, + int first_non_void); +bool libresoc_format_pack_clear_color(VkFormat format, + uint32_t clear_vals[2], + VkClearColorValue *value); +bool libresoc_is_colorbuffer_format_supported(VkFormat format, bool *blendable); +bool libresoc_dcc_formats_compatible(VkFormat format1, + VkFormat format2); +bool libresoc_device_supports_etc(struct libresoc_physical_device *physical_device); + + +/* Whether the image has a htile that is known consistent with the contents of + * the image and is allowed to be in compressed form. + * + * If this is false reads that don't use the htile should be able to return + * correct results. + */ +bool libresoc_layout_is_htile_compressed(const struct libresoc_image *image, + VkImageLayout layout, + bool in_render_loop, + unsigned queue_mask); + +bool libresoc_layout_can_fast_clear(const struct libresoc_image *image, + VkImageLayout layout, + bool in_render_loop, + unsigned queue_mask); + +bool libresoc_layout_dcc_compressed(const struct libresoc_device *device, + const struct libresoc_image *image, + VkImageLayout layout, + bool in_render_loop, + unsigned queue_mask); + #define libresoc_printflike(a, b) __attribute__((__format__(__printf__, a, b))) VkResult __vk_errorf(struct libresoc_instance *instance, VkResult error, @@ -259,18 +528,18 @@ LIBRESOC_DEFINE_HANDLE_CASTS(libresoc_instance, VkInstance) LIBRESOC_DEFINE_HANDLE_CASTS(libresoc_physical_device, VkPhysicalDevice) LIBRESOC_DEFINE_HANDLE_CASTS(libresoc_queue, VkQueue) -//LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_cmd_pool, VkCommandPool) +LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_cmd_pool, VkCommandPool) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_buffer, VkBuffer) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_buffer_view, VkBufferView) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_descriptor_pool, VkDescriptorPool) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_descriptor_set, VkDescriptorSet) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_descriptor_set_layout, VkDescriptorSetLayout) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_descriptor_update_template, VkDescriptorUpdateTemplate) -//LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_device_memory, VkDeviceMemory) -//LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_fence, VkFence) +LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_device_memory, VkDeviceMemory) +LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_fence, VkFence) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_event, VkEvent) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_framebuffer, VkFramebuffer) -//LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_image, VkImage) +LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_image, VkImage) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_image_view, VkImageView); LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_pipeline_cache, VkPipelineCache) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_pipeline, VkPipeline) @@ -280,6 +549,6 @@ LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_pipeline_cache, VkPipelineCache) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_sampler, VkSampler) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_sampler_ycbcr_conversion, VkSamplerYcbcrConversion) //LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_shader_module, VkShaderModule) -//LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_semaphore, VkSemaphore) +LIBRESOC_DEFINE_NONDISP_HANDLE_CASTS(libresoc_semaphore, VkSemaphore) #endif /* LIBRESOC_PRIVATE_H */ diff --git a/src/libre-soc/vulkan/libresoc_wsi.c b/src/libre-soc/vulkan/libresoc_wsi.c new file mode 100644 index 00000000000..2cd0fa1f74e --- /dev/null +++ b/src/libre-soc/vulkan/libresoc_wsi.c @@ -0,0 +1,351 @@ +/* + * Copyright © 2016 Red Hat + * based on intel anv code: + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "libresoc_private.h" +//#include "libresoc_meta.h" +#include "wsi_common.h" +#include "vk_util.h" +#include "util/macros.h" + +static PFN_vkVoidFunction +libresoc_wsi_proc_addr(VkPhysicalDevice physicalDevice, const char *pName) +{ + return libresoc_lookup_entrypoint(pName); +} + +static void +libresoc_wsi_set_memory_ownership(VkDevice _device, + VkDeviceMemory _mem, + VkBool32 ownership) +{ + //TODO: enable when required + //LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + //LIBRESOC_FROM_HANDLE(libresoc_device_memory, mem, _mem); + + //if (ownership) + // libresoc_bo_list_add(device, mem->bo); + //else + // libresoc_bo_list_remove(device, mem->bo); +} + +VkResult +libresoc_init_wsi(struct libresoc_physical_device *physical_device) +{ + //TODO: stub + //return VK_SUCCESS; + VkResult result = wsi_device_init(&physical_device->wsi_device, + libresoc_physical_device_to_handle(physical_device), + libresoc_wsi_proc_addr, + &physical_device->instance->alloc, + physical_device->master_fd, + &physical_device->instance->dri_options, + true); //TODO: for now this is sw_device + if (result != VK_SUCCESS) + return result; + + physical_device->wsi_device.set_memory_ownership = libresoc_wsi_set_memory_ownership; + return VK_SUCCESS; +} + +void +libresoc_finish_wsi(struct libresoc_physical_device *physical_device) +{ + wsi_device_finish(&physical_device->wsi_device, + &physical_device->instance->alloc); +} + +void libresoc_DestroySurfaceKHR( + VkInstance _instance, + VkSurfaceKHR _surface, + const VkAllocationCallbacks* pAllocator) +{ + LIBRESOC_FROM_HANDLE(libresoc_instance, instance, _instance); + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + + vk_free2(&instance->alloc, pAllocator, surface); +} + +VkResult libresoc_GetPhysicalDeviceSurfaceSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + VkSurfaceKHR surface, + VkBool32* pSupported) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + + return wsi_common_get_surface_support(&device->wsi_device, + queueFamilyIndex, + surface, + pSupported); +} + +VkResult libresoc_GetPhysicalDeviceSurfaceCapabilitiesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + + return wsi_common_get_surface_capabilities(&device->wsi_device, + surface, + pSurfaceCapabilities); +} + +// VkResult libresoc_GetPhysicalDeviceSurfaceCapabilities2KHR( +// VkPhysicalDevice physicalDevice, +// const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, +// VkSurfaceCapabilities2KHR* pSurfaceCapabilities) +// { +// LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + +// return wsi_common_get_surface_capabilities2(&device->wsi_device, +// pSurfaceInfo, +// pSurfaceCapabilities); +// } + +// VkResult libresoc_GetPhysicalDeviceSurfaceCapabilities2EXT( +// VkPhysicalDevice physicalDevice, +// VkSurfaceKHR surface, +// VkSurfaceCapabilities2EXT* pSurfaceCapabilities) +// { +// LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + +// return wsi_common_get_surface_capabilities2ext(&device->wsi_device, +// surface, +// pSurfaceCapabilities); +// } + +VkResult libresoc_GetPhysicalDeviceSurfaceFormatsKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormatKHR* pSurfaceFormats) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + + return wsi_common_get_surface_formats(&device->wsi_device, + surface, + pSurfaceFormatCount, + pSurfaceFormats); +} + +// VkResult libresoc_GetPhysicalDeviceSurfaceFormats2KHR( +// VkPhysicalDevice physicalDevice, +// const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo, +// uint32_t* pSurfaceFormatCount, +// VkSurfaceFormat2KHR* pSurfaceFormats) +// { +// LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + +// return wsi_common_get_surface_formats2(&device->wsi_device, +// pSurfaceInfo, +// pSurfaceFormatCount, +// pSurfaceFormats); +// } + +VkResult libresoc_GetPhysicalDeviceSurfacePresentModesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + + return wsi_common_get_surface_present_modes(&device->wsi_device, + surface, + pPresentModeCount, + pPresentModes); +} + +VkResult libresoc_CreateSwapchainKHR( + VkDevice _device, + const VkSwapchainCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSwapchainKHR* pSwapchain) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + const VkAllocationCallbacks *alloc; + if (pAllocator) + alloc = pAllocator; + else + alloc = &device->vk.alloc; + + return wsi_common_create_swapchain(&device->physical_device->wsi_device, + libresoc_device_to_handle(device), + pCreateInfo, + alloc, + pSwapchain); +} + +void libresoc_DestroySwapchainKHR( + VkDevice _device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks* pAllocator) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + const VkAllocationCallbacks *alloc; + + if (pAllocator) + alloc = pAllocator; + else + alloc = &device->vk.alloc; + + wsi_common_destroy_swapchain(_device, swapchain, alloc); +} + +VkResult libresoc_GetSwapchainImagesKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint32_t* pSwapchainImageCount, + VkImage* pSwapchainImages) +{ + return wsi_common_get_images(swapchain, + pSwapchainImageCount, + pSwapchainImages); +} + +VkResult libresoc_AcquireNextImageKHR( + VkDevice device, + VkSwapchainKHR swapchain, + uint64_t timeout, + VkSemaphore semaphore, + VkFence fence, + uint32_t* pImageIndex) +{ + VkAcquireNextImageInfoKHR acquire_info = { + .sType = VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR, + .swapchain = swapchain, + .timeout = timeout, + .semaphore = semaphore, + .fence = fence, + .deviceMask = 0, + }; + + return libresoc_AcquireNextImage2KHR(device, &acquire_info, pImageIndex); +} + +VkResult libresoc_AcquireNextImage2KHR( + VkDevice _device, + const VkAcquireNextImageInfoKHR* pAcquireInfo, + uint32_t* pImageIndex) +{ + LIBRESOC_FROM_HANDLE(libresoc_device, device, _device); + struct libresoc_physical_device *pdevice = device->physical_device; + //LIBRESOC_FROM_HANDLE(libresoc_fence, fence, pAcquireInfo->fence); + //LIBRESOC_FROM_HANDLE(libresoc_semaphore, semaphore, pAcquireInfo->semaphore); + + VkResult result = wsi_common_acquire_next_image2(&pdevice->wsi_device, + _device, + pAcquireInfo, + pImageIndex); + //TODO: enable if required + // if (result == VK_SUCCESS || result == VK_SUBOPTIMAL_KHR) { + // if (fence) { + // struct libresoc_fence_part *part = + // fence->temporary.kind != LIBRESOC_FENCE_NONE ? + // &fence->temporary : &fence->permanent; + + // switch (part->kind) { + // case LIBRESOC_FENCE_NONE: + // break; + // case LIBRESOC_FENCE_WINSYS: + // device->ws->signal_fence(part->fence); + // break; + // case LIBRESOC_FENCE_SYNCOBJ: + // device->ws->signal_syncobj(device->ws, part->syncobj, 0); + // break; + // default: + // unreachable("Invalid WSI fence type"); + // } + // } + // if (semaphore) { + // struct libresoc_semaphore_part *part = + // semaphore->temporary.kind != LIBRESOC_SEMAPHORE_NONE ? + // &semaphore->temporary : &semaphore->permanent; + + // switch (part->kind) { + // case LIBRESOC_SEMAPHORE_NONE: + // case LIBRESOC_SEMAPHORE_WINSYS: + // /* Do not need to do anything. */ + // break; + // case LIBRESOC_SEMAPHORE_TIMELINE: + // case LIBRESOC_SEMAPHORE_TIMELINE_SYNCOBJ: + // unreachable("WSI only allows binary semaphores."); + // case LIBRESOC_SEMAPHORE_SYNCOBJ: + // device->ws->signal_syncobj(device->ws, part->syncobj, 0); + // break; + // } + // } + // } + return result; +} + +VkResult libresoc_QueuePresentKHR( + VkQueue _queue, + const VkPresentInfoKHR* pPresentInfo) +{ + LIBRESOC_FROM_HANDLE(libresoc_queue, queue, _queue); + return wsi_common_queue_present(&queue->device->physical_device->wsi_device, + libresoc_device_to_handle(queue->device), + _queue, + queue->queue_family_index, + pPresentInfo); +} + + +VkResult libresoc_GetDeviceGroupPresentCapabilitiesKHR( + VkDevice device, + VkDeviceGroupPresentCapabilitiesKHR* pCapabilities) +{ + memset(pCapabilities->presentMask, 0, + sizeof(pCapabilities->presentMask)); + pCapabilities->presentMask[0] = 0x1; + pCapabilities->modes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR; + + return VK_SUCCESS; +} + +VkResult libresoc_GetDeviceGroupSurfacePresentModesKHR( + VkDevice device, + VkSurfaceKHR surface, + VkDeviceGroupPresentModeFlagsKHR* pModes) +{ + *pModes = VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR; + + return VK_SUCCESS; +} + +VkResult libresoc_GetPhysicalDevicePresentRectanglesKHR( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR surface, + uint32_t* pRectCount, + VkRect2D* pRects) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + + return wsi_common_get_present_rectangles(&device->wsi_device, + surface, + pRectCount, pRects); +} diff --git a/src/libre-soc/vulkan/libresoc_wsi_x11.c b/src/libre-soc/vulkan/libresoc_wsi_x11.c new file mode 100644 index 00000000000..9185dac7e65 --- /dev/null +++ b/src/libre-soc/vulkan/libresoc_wsi_x11.c @@ -0,0 +1,105 @@ +/* + * Copyright © 2016 Red Hat. + * Copyright © 2016 Bas Nieuwenhuizen + * + * based mostly on anv driver which is: + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#include "wsi_common_x11.h" +#include "libresoc_private.h" + + +VkBool32 libresoc_GetPhysicalDeviceXcbPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + xcb_connection_t* connection, + xcb_visualid_t visual_id) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + + return true; + //TODO: for now always allow +/* return wsi_get_physical_device_xcb_presentation_support( + &device->wsi_device, + queueFamilyIndex, + connection, visual_id);*/ +} + +VkBool32 libresoc_GetPhysicalDeviceXlibPresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + Display* dpy, + VisualID visualID) +{ + LIBRESOC_FROM_HANDLE(libresoc_physical_device, device, physicalDevice); + + return true; + //TODO: for now always allow +/* return wsi_get_physical_device_xcb_presentation_support( + &device->wsi_device, + queueFamilyIndex, + XGetXCBConnection(dpy), visualID);*/ +} + +VkResult libresoc_CreateXcbSurfaceKHR( + VkInstance _instance, + const VkXcbSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface) +{ + LIBRESOC_FROM_HANDLE(libresoc_instance, instance, _instance); + const VkAllocationCallbacks *alloc; + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR); + + if (pAllocator) + alloc = pAllocator; + else + alloc = &instance->alloc; + + return wsi_create_xcb_surface(alloc, pCreateInfo, pSurface); +} + +VkResult libresoc_CreateXlibSurfaceKHR( + VkInstance _instance, + const VkXlibSurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface) +{ + LIBRESOC_FROM_HANDLE(libresoc_instance, instance, _instance); + const VkAllocationCallbacks *alloc; + + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR); + + if (pAllocator) + alloc = pAllocator; + else + alloc = &instance->alloc; + + return wsi_create_xlib_surface(alloc, pCreateInfo, pSurface); +} diff --git a/src/libre-soc/vulkan/meson.build b/src/libre-soc/vulkan/meson.build index 1c4e84314c8..d5e6f9baaeb 100644 --- a/src/libre-soc/vulkan/meson.build +++ b/src/libre-soc/vulkan/meson.build @@ -51,26 +51,6 @@ libresoc_entrypoints = custom_target( ], depend_files : files('libresoc_extensions.py'), ) -#libresoc_entrypoints = custom_target( -# 'libresoc_entrypoints.[ch]', -# input : ['libresoc_entrypoints_gen.py', vk_api_xml], -# output : ['libresoc_entrypoints.h', 'libresoc_entrypoints.c'], -# command : [ -# prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--outdir', -# meson.current_build_dir() -# ], -# depend_files : files('libresoc_extensions.py'), -#) -# -#libresoc_extensions_c = custom_target( -# 'libresoc_extensions.c', -# input : ['libresoc_extensions.py', vk_api_xml], -# output : ['libresoc_extensions.c', 'libresoc_extensions.h'], -# command : [ -# prog_python, '@INPUT0@', '--xml', '@INPUT1@', '--out-c', '@OUTPUT0@', -# '--out-h', '@OUTPUT1@' -# ], -#) libresoc_vk_format_table_c = custom_target( 'libresoc_vk_format_table.c', @@ -83,59 +63,44 @@ libresoc_vk_format_table_c = custom_target( liblibresoc_files = files( 'libresoc_device.c', + 'libresoc_meta_clear.c', + 'libresoc_image.c', + 'libresoc_cmd_buffer.c', + 'libresoc_formats.c', 'libresoc_pipeline.c', 'libresoc_pipeline_cache.c', 'libresoc_util.c', + 'libresoc_wsi.c', + 'libresoc_private.h', + 'vk_format.h', ) libresoc_deps = [] libresoc_flags = [] - libresoc_flags += '-DVK_USE_PLATFORM_DISPLAY_KHR' +libresoc_flags += '-DVK_USE_PLATFORM_XLIB_KHR' +libresoc_flags += '-DVK_USE_PLATFORM_XCB_KHR' if with_platform_x11 - #libresoc_deps += dep_xcb_dri3 - #libresoc_flags += [ - # '-DVK_USE_PLATFORM_XCB_KHR', - # '-DVK_USE_PLATFORM_XLIB_KHR', - #] - #liblibresoc_files += files('libresoc_wsi_x11.c') -endif - -if with_platform_wayland - #libresoc_deps += dep_wayland_client - #libresoc_flags += '-DVK_USE_PLATFORM_WAYLAND_KHR' - #liblibresoc_files += files('libresoc_wsi_wayland.c') -endif - -if system_has_kms_drm and not with_platform_android - #libresoc_flags += '-DVK_USE_PLATFORM_DISPLAY_KHR' - #liblibresoc_files += files('libresoc_wsi_display.c') -endif - -if with_xlib_lease - #libresoc_deps += [dep_xcb_xrandr, dep_xlib_xrandr] - #libresoc_flags += '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT' -endif - -if with_platform_android - #libresoc_deps += dep_android - #libresoc_flags += [ - # '-DVK_USE_PLATFORM_ANDROID_KHR' - #] + libresoc_deps += dep_xcb_dri3 + libresoc_flags += [ + '-DVK_USE_PLATFORM_XCB_KHR', + '-DVK_USE_PLATFORM_XLIB_KHR', + ] + liblibresoc_files += files('libresoc_wsi_x11.c') endif libvulkan_libresoc = shared_library( 'vulkan_libresoc', [liblibresoc_files, libresoc_entrypoints, libresoc_extensions_c, libresoc_extensions_h, libresoc_vk_format_table_c, sha1_h], include_directories : [ - inc_include, inc_src, inc_mapi, inc_mesa, inc_compiler, inc_util, inc_vulkan_wsi, #inc_gallium, inc_gallium_aux, inc_amd, inc_amd_common, inc_amd_common_llvm, + inc_include, inc_src, inc_mapi, inc_mesa, inc_compiler, inc_util, inc_vulkan_wsi, inc_gallium_aux, inc_gallium, #inc_amd, inc_amd_common, inc_amd_common_llvm, ], link_with : [ libvulkan_wsi, #libamd_common, libamd_common_llvm, libamdgpu_addrlib, ], dependencies : [idep_vulkan_util, libresoc_deps,idep_xmlconfig, dep_libdrm, dep_llvm, dep_thread, dep_elf, dep_dl, dep_m,dep_valgrind, idep_mesautil, idep_nir, - # libresoc_deps, idep_aco, dep_libdrm_amdgpu, + libresoc_deps, #idep_aco, dep_libdrm_amdgpu, # idep_amdgfxregs_h, ], c_args : [no_override_init_args, libresoc_flags], -- 2.30.2