diff options
author | Jason Ekstrand <[email protected]> | 2017-11-15 19:04:10 -0800 |
---|---|---|
committer | Jason Ekstrand <[email protected]> | 2017-12-04 10:04:19 -0800 |
commit | d50937f137201e1d90ce18bbea1383af7a7ebd5d (patch) | |
tree | 8a18a2bd666e4ed3e11a5e12849e0f68f5a6dbad /src/vulkan/wsi/wsi_common.c | |
parent | df4fc684920840220bb1fb92281e40157b4db618 (diff) |
vulkan/wsi: Implement prime in a completely generic way
Reviewed-by: Dave Airlie <[email protected]>
Reviewed-by: Chad Versace <[email protected]>
Diffstat (limited to 'src/vulkan/wsi/wsi_common.c')
-rw-r--r-- | src/vulkan/wsi/wsi_common.c | 341 |
1 files changed, 340 insertions, 1 deletions
diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index bb35237fb92..7cb5d894e77 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -22,6 +22,7 @@ */ #include "wsi_common_private.h" +#include "util/macros.h" void wsi_device_init(struct wsi_device *wsi, @@ -29,25 +30,363 @@ wsi_device_init(struct wsi_device *wsi, WSI_FN_GetPhysicalDeviceProcAddr proc_addr) { memset(wsi, 0, sizeof(*wsi)); + +#define WSI_GET_CB(func) \ + PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func) + WSI_GET_CB(GetPhysicalDeviceMemoryProperties); + WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties); +#undef WSI_GET_CB + + GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props); + GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL); + +#define WSI_GET_CB(func) \ + wsi->func = (PFN_vk##func)proc_addr(pdevice, "vk" #func) + WSI_GET_CB(AllocateMemory); + WSI_GET_CB(AllocateCommandBuffers); + WSI_GET_CB(BindBufferMemory); + WSI_GET_CB(BindImageMemory); + WSI_GET_CB(BeginCommandBuffer); + WSI_GET_CB(CmdCopyImageToBuffer); + WSI_GET_CB(CreateBuffer); + WSI_GET_CB(CreateCommandPool); + WSI_GET_CB(CreateImage); + WSI_GET_CB(DestroyBuffer); + WSI_GET_CB(DestroyCommandPool); + WSI_GET_CB(DestroyImage); + WSI_GET_CB(EndCommandBuffer); + WSI_GET_CB(FreeMemory); + WSI_GET_CB(FreeCommandBuffers); + WSI_GET_CB(GetBufferMemoryRequirements); + WSI_GET_CB(GetImageMemoryRequirements); + WSI_GET_CB(GetMemoryFdKHR); + WSI_GET_CB(QueueSubmit); +#undef WSI_GET_CB } VkResult wsi_swapchain_init(const struct wsi_device *wsi, struct wsi_swapchain *chain, VkDevice device, - const VkSwapchainCreateInfoKHR* pCreateInfo, + const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator) { + VkResult result; + memset(chain, 0, sizeof(*chain)); chain->wsi = wsi; chain->device = device; chain->alloc = *pAllocator; + chain->cmd_pools = + vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!chain->cmd_pools) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + for (uint32_t i = 0; i < wsi->queue_family_count; i++) { + const VkCommandPoolCreateInfo cmd_pool_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .queueFamilyIndex = i, + }; + result = wsi->CreateCommandPool(device, &cmd_pool_info, &chain->alloc, + &chain->cmd_pools[i]); + if (result != VK_SUCCESS) + goto fail; + } + return VK_SUCCESS; + +fail: + wsi_swapchain_finish(chain); + return result; } void wsi_swapchain_finish(struct wsi_swapchain *chain) { + for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) { + chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i], + &chain->alloc); + } +} + +static uint32_t +select_memory_type(const struct wsi_device *wsi, + VkMemoryPropertyFlags props, + uint32_t type_bits) +{ + for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) { + const VkMemoryType type = wsi->memory_props.memoryTypes[i]; + if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props) + return i; + } + + unreachable("No memory type found"); +} + +static uint32_t +vk_format_size(VkFormat format) +{ + switch (format) { + case VK_FORMAT_B8G8R8A8_UNORM: + case VK_FORMAT_B8G8R8A8_SRGB: + return 4; + default: + unreachable("Unknown WSI Format"); + } +} + +static inline uint32_t +align_u32(uint32_t v, uint32_t a) +{ + assert(a != 0 && a == (a & -a)); + return (v + a - 1) & ~(a - 1); +} + +#define WSI_PRIME_LINEAR_STRIDE_ALIGN 256 + +VkResult +wsi_create_prime_image(const struct wsi_swapchain *chain, + const VkSwapchainCreateInfoKHR *pCreateInfo, + struct wsi_image *image) +{ + const struct wsi_device *wsi = chain->wsi; + VkResult result; + + memset(image, 0, sizeof(*image)); + + const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat); + const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp, + WSI_PRIME_LINEAR_STRIDE_ALIGN); + + uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height; + linear_size = align_u32(linear_size, 4096); + + const VkExternalMemoryBufferCreateInfoKHR prime_buffer_external_info = { + .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR, + .pNext = NULL, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkBufferCreateInfo prime_buffer_info = { + .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, + .pNext = &prime_buffer_external_info, + .size = linear_size, + .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + result = wsi->CreateBuffer(chain->device, &prime_buffer_info, + &chain->alloc, &image->prime.buffer); + if (result != VK_SUCCESS) + goto fail; + + VkMemoryRequirements reqs; + wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs); + assert(reqs.size <= linear_size); + + const struct wsi_memory_allocate_info memory_wsi_info = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, + .pNext = NULL, + .implicit_sync = true, + }; + const VkExportMemoryAllocateInfoKHR prime_memory_export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR, + .pNext = &memory_wsi_info, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkMemoryDedicatedAllocateInfoKHR prime_memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, + .pNext = &prime_memory_export_info, + .image = VK_NULL_HANDLE, + .buffer = image->prime.buffer, + }; + const VkMemoryAllocateInfo prime_memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &prime_memory_dedicated_info, + .allocationSize = linear_size, + .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &prime_memory_info, + &chain->alloc, &image->prime.memory); + if (result != VK_SUCCESS) + goto fail; + + result = wsi->BindBufferMemory(chain->device, image->prime.buffer, + image->prime.memory, 0); + if (result != VK_SUCCESS) + goto fail; + + const VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = pCreateInfo->imageFormat, + .extent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + result = wsi->CreateImage(chain->device, &image_info, + &chain->alloc, &image->image); + if (result != VK_SUCCESS) + goto fail; + + wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); + + const VkMemoryDedicatedAllocateInfoKHR memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR, + .pNext = NULL, + .image = image->image, + .buffer = VK_NULL_HANDLE, + }; + const VkMemoryAllocateInfo memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memory_dedicated_info, + .allocationSize = reqs.size, + .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &memory_info, + &chain->alloc, &image->memory); + if (result != VK_SUCCESS) + goto fail; + + result = wsi->BindImageMemory(chain->device, image->image, + image->memory, 0); + if (result != VK_SUCCESS) + goto fail; + + image->prime.blit_cmd_buffers = + vk_zalloc(&chain->alloc, + sizeof(VkCommandBuffer) * wsi->queue_family_count, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!image->prime.blit_cmd_buffers) + goto fail; + + for (uint32_t i = 0; i < wsi->queue_family_count; i++) { + const VkCommandBufferAllocateInfo cmd_buffer_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, + .pNext = NULL, + .commandPool = chain->cmd_pools[i], + .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, + .commandBufferCount = 1, + }; + result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info, + &image->prime.blit_cmd_buffers[i]); + if (result != VK_SUCCESS) + goto fail; + + const VkCommandBufferBeginInfo begin_info = { + .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, + }; + wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info); + + struct VkBufferImageCopy buffer_image_copy = { + .bufferOffset = 0, + .bufferRowLength = linear_stride / cpp, + .bufferImageHeight = 0, + .imageSubresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = { .x = 0, .y = 0, .z = 0 }, + .imageExtent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + }; + wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i], + image->image, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, + image->prime.buffer, + 1, &buffer_image_copy); + + result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]); + if (result != VK_SUCCESS) + goto fail; + } + + const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, + .pNext = NULL, + .memory = image->prime.memory, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + int fd; + result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd); + if (result != VK_SUCCESS) + goto fail; + + image->size = linear_size; + image->row_pitch = linear_stride; + image->offset = 0; + image->fd = fd; + + return VK_SUCCESS; + +fail: + wsi_destroy_prime_image(chain, image); + + return result; +} + +void +wsi_destroy_prime_image(const struct wsi_swapchain *chain, + struct wsi_image *image) +{ + const struct wsi_device *wsi = chain->wsi; + + if (image->prime.blit_cmd_buffers) { + for (uint32_t i = 0; i < wsi->queue_family_count; i++) { + wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i], + 1, &image->prime.blit_cmd_buffers[i]); + } + vk_free(&chain->alloc, image->prime.blit_cmd_buffers); + } + + wsi->FreeMemory(chain->device, image->memory, &chain->alloc); + wsi->DestroyImage(chain->device, image->image, &chain->alloc); + wsi->FreeMemory(chain->device, image->prime.memory, &chain->alloc); + wsi->DestroyBuffer(chain->device, image->prime.buffer, &chain->alloc); +} + +VkResult +wsi_prime_image_blit_to_linear(const struct wsi_swapchain *chain, + struct wsi_image *image, + VkQueue queue, + uint32_t waitSemaphoreCount, + const VkSemaphore *pWaitSemaphores) +{ + uint32_t queue_family = chain->wsi->queue_get_family_index(queue); + + VkPipelineStageFlags stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + const VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = NULL, + .waitSemaphoreCount = waitSemaphoreCount, + .pWaitSemaphores = pWaitSemaphores, + .pWaitDstStageMask = &stage_flags, + .commandBufferCount = 1, + .pCommandBuffers = &image->prime.blit_cmd_buffers[queue_family], + .signalSemaphoreCount = 0, + .pSignalSemaphores = NULL, + }; + return chain->wsi->QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); } |