X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fvulkan%2Fwsi%2Fwsi_common.c;h=edba13a13de1a9493ecb56aa7fe302ab00307942;hb=a55dae6ea2cdf37d0ddd06d5f3b34ac1faf3848c;hp=b86bb90cec695e07aa0315214dbd9ed517fb0284;hpb=e12688f365258f6f719983528a2af9b6ca4e25c5;p=mesa.git diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index b86bb90cec6..edba13a13de 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -22,15 +22,24 @@ */ #include "wsi_common_private.h" +#include "drm_fourcc.h" #include "util/macros.h" +#include "vk_util.h" -void +#include + +VkResult wsi_device_init(struct wsi_device *wsi, VkPhysicalDevice pdevice, - WSI_FN_GetPhysicalDeviceProcAddr proc_addr) + WSI_FN_GetPhysicalDeviceProcAddr proc_addr, + const VkAllocationCallbacks *alloc) { + VkResult result; + memset(wsi, 0, sizeof(*wsi)); + wsi->pdevice = pdevice; + #define WSI_GET_CB(func) \ PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func) WSI_GET_CB(GetPhysicalDeviceMemoryProperties); @@ -50,9 +59,11 @@ wsi_device_init(struct wsi_device *wsi, WSI_GET_CB(CmdCopyImageToBuffer); WSI_GET_CB(CreateBuffer); WSI_GET_CB(CreateCommandPool); + WSI_GET_CB(CreateFence); WSI_GET_CB(CreateImage); WSI_GET_CB(DestroyBuffer); WSI_GET_CB(DestroyCommandPool); + WSI_GET_CB(DestroyFence); WSI_GET_CB(DestroyImage); WSI_GET_CB(EndCommandBuffer); WSI_GET_CB(FreeMemory); @@ -61,8 +72,42 @@ wsi_device_init(struct wsi_device *wsi, WSI_GET_CB(GetImageMemoryRequirements); WSI_GET_CB(GetImageSubresourceLayout); WSI_GET_CB(GetMemoryFdKHR); + WSI_GET_CB(GetPhysicalDeviceFormatProperties); + WSI_GET_CB(GetPhysicalDeviceFormatProperties2KHR); + WSI_GET_CB(ResetFences); WSI_GET_CB(QueueSubmit); + WSI_GET_CB(WaitForFences); #undef WSI_GET_CB + +#ifdef VK_USE_PLATFORM_XCB_KHR + result = wsi_x11_init_wsi(wsi, alloc); + if (result != VK_SUCCESS) + return result; +#endif + +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + result = wsi_wl_init_wsi(wsi, alloc, pdevice); + if (result != VK_SUCCESS) { +#ifdef VK_USE_PLATFORM_XCB_KHR + wsi_x11_finish_wsi(wsi, alloc); +#endif + return result; + } +#endif + + return VK_SUCCESS; +} + +void +wsi_device_finish(struct wsi_device *wsi, + const VkAllocationCallbacks *alloc) +{ +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + wsi_wl_finish_wsi(wsi, alloc); +#endif +#ifdef VK_USE_PLATFORM_XCB_KHR + wsi_x11_finish_wsi(wsi, alloc); +#endif } VkResult @@ -79,6 +124,7 @@ wsi_swapchain_init(const struct wsi_device *wsi, chain->wsi = wsi; chain->device = device; chain->alloc = *pAllocator; + chain->use_prime_blit = false; chain->cmd_pools = vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8, @@ -109,10 +155,14 @@ fail: void wsi_swapchain_finish(struct wsi_swapchain *chain) { + for (unsigned i = 0; i < ARRAY_SIZE(chain->fences); i++) + chain->wsi->DestroyFence(chain->device, chain->fences[i], &chain->alloc); + for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) { chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i], &chain->alloc); } + vk_free(&chain->alloc, chain->cmd_pools); } static uint32_t @@ -151,18 +201,103 @@ align_u32(uint32_t v, uint32_t a) VkResult wsi_create_native_image(const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, + uint32_t num_modifier_lists, + const uint32_t *num_modifiers, + const uint64_t *const *modifiers, struct wsi_image *image) { const struct wsi_device *wsi = chain->wsi; VkResult result; memset(image, 0, sizeof(*image)); + for (int i = 0; i < ARRAY_SIZE(image->fds); i++) + image->fds[i] = -1; - const struct wsi_image_create_info image_wsi_info = { + struct wsi_image_create_info image_wsi_info = { .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA, .pNext = NULL, - .scanout = true, }; + + uint32_t image_modifier_count = 0, modifier_prop_count = 0; + struct wsi_format_modifier_properties *modifier_props = NULL; + uint64_t *image_modifiers = NULL; + if (num_modifier_lists == 0) { + /* If we don't have modifiers, fall back to the legacy "scanout" flag */ + image_wsi_info.scanout = true; + } else { + /* The winsys can't request modifiers if we don't support them. */ + assert(wsi->supports_modifiers); + struct wsi_format_modifier_properties_list modifier_props_list = { + .sType = VK_STRUCTURE_TYPE_WSI_FORMAT_MODIFIER_PROPERTIES_LIST_MESA, + .pNext = NULL, + }; + VkFormatProperties2KHR format_props = { + .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR, + .pNext = &modifier_props_list, + }; + wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, + pCreateInfo->imageFormat, + &format_props); + assert(modifier_props_list.modifier_count > 0); + modifier_props = vk_alloc(&chain->alloc, + sizeof(*modifier_props) * + modifier_props_list.modifier_count, + 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!modifier_props) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + modifier_props_list.modifier_properties = modifier_props; + wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice, + pCreateInfo->imageFormat, + &format_props); + modifier_prop_count = modifier_props_list.modifier_count; + + uint32_t max_modifier_count = 0; + for (uint32_t l = 0; l < num_modifier_lists; l++) + max_modifier_count = MAX2(max_modifier_count, num_modifiers[l]); + + image_modifiers = vk_alloc(&chain->alloc, + sizeof(*image_modifiers) * + max_modifier_count, + 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!image_modifiers) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + image_modifier_count = 0; + for (uint32_t l = 0; l < num_modifier_lists; l++) { + /* Walk the modifier lists and construct a list of supported + * modifiers. + */ + for (uint32_t i = 0; i < num_modifiers[l]; i++) { + for (uint32_t j = 0; j < modifier_prop_count; j++) { + if (modifier_props[j].modifier == modifiers[l][i]) + image_modifiers[image_modifier_count++] = modifiers[l][i]; + } + } + + /* We only want to take the modifiers from the first list */ + if (image_modifier_count > 0) + break; + } + + if (image_modifier_count > 0) { + image_wsi_info.modifier_count = image_modifier_count; + image_wsi_info.modifiers = image_modifiers; + } else { + /* TODO: Add a proper error here */ + assert(!"Failed to find a supported modifier! This should never " + "happen because LINEAR should always be available"); + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + } + const VkImageCreateInfo image_info = { .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, .pNext = &image_wsi_info, @@ -192,15 +327,6 @@ wsi_create_native_image(const struct wsi_swapchain *chain, VkMemoryRequirements reqs; wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); - VkSubresourceLayout image_layout; - const VkImageSubresource image_subresource = { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .arrayLayer = 0, - }; - wsi->GetImageSubresourceLayout(chain->device, image->image, - &image_subresource, &image_layout); - const struct wsi_memory_allocate_info memory_wsi_info = { .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, .pNext = NULL, @@ -245,14 +371,67 @@ wsi_create_native_image(const struct wsi_swapchain *chain, if (result != VK_SUCCESS) goto fail; - image->size = reqs.size; - image->row_pitch = image_layout.rowPitch; - image->offset = 0; - image->fd = fd; + if (num_modifier_lists > 0) { + image->drm_modifier = wsi->image_get_modifier(image->image); + assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID); + + for (uint32_t j = 0; j < modifier_prop_count; j++) { + if (modifier_props[j].modifier == image->drm_modifier) { + image->num_planes = modifier_props[j].modifier_plane_count; + break; + } + } + + for (uint32_t p = 0; p < image->num_planes; p++) { + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT_KHR << p, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout image_layout; + wsi->GetImageSubresourceLayout(chain->device, image->image, + &image_subresource, &image_layout); + image->sizes[p] = image_layout.size; + image->row_pitches[p] = image_layout.rowPitch; + image->offsets[p] = image_layout.offset; + if (p == 0) { + image->fds[p] = fd; + } else { + image->fds[p] = dup(fd); + if (image->fds[p] == -1) { + for (uint32_t i = 0; i < p; i++) + close(image->fds[p]); + + goto fail; + } + } + } + } else { + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout image_layout; + wsi->GetImageSubresourceLayout(chain->device, image->image, + &image_subresource, &image_layout); + + image->drm_modifier = DRM_FORMAT_MOD_INVALID; + image->num_planes = 1; + image->sizes[0] = reqs.size; + image->row_pitches[0] = image_layout.rowPitch; + image->offsets[0] = 0; + image->fds[0] = fd; + } + + vk_free(&chain->alloc, modifier_props); + vk_free(&chain->alloc, image_modifiers); return VK_SUCCESS; fail: + vk_free(&chain->alloc, modifier_props); + vk_free(&chain->alloc, image_modifiers); wsi_destroy_image(chain, image); return result; @@ -385,8 +564,10 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, vk_zalloc(&chain->alloc, sizeof(VkCommandBuffer) * wsi->queue_family_count, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - if (!image->prime.blit_cmd_buffers) + if (!image->prime.blit_cmd_buffers) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; goto fail; + } for (uint32_t i = 0; i < wsi->queue_family_count; i++) { const VkCommandBufferAllocateInfo cmd_buffer_info = { @@ -445,10 +626,12 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, if (result != VK_SUCCESS) goto fail; - image->size = linear_size; - image->row_pitch = linear_stride; - image->offset = 0; - image->fd = fd; + image->drm_modifier = DRM_FORMAT_MOD_LINEAR; + image->num_planes = 1; + image->sizes[0] = linear_size; + image->row_pitches[0] = linear_stride; + image->offsets[0] = 0; + image->fds[0] = fd; return VK_SUCCESS; @@ -479,25 +662,251 @@ wsi_destroy_image(const struct wsi_swapchain *chain, } VkResult -wsi_prime_image_blit_to_linear(const struct wsi_swapchain *chain, - struct wsi_image *image, - VkQueue queue, - uint32_t waitSemaphoreCount, - const VkSemaphore *pWaitSemaphores) +wsi_common_get_surface_support(struct wsi_device *wsi_device, + int local_fd, + uint32_t queueFamilyIndex, + VkSurfaceKHR _surface, + const VkAllocationCallbacks *alloc, + VkBool32* pSupported) { - uint32_t queue_family = chain->wsi->queue_get_family_index(queue); + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; - 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); + return iface->get_support(surface, wsi_device, alloc, + queueFamilyIndex, local_fd, pSupported); +} + +VkResult +wsi_common_get_surface_capabilities(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_capabilities(surface, pSurfaceCapabilities); +} + +VkResult +wsi_common_get_surface_capabilities2(struct wsi_device *wsi_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_capabilities2(surface, pSurfaceInfo->pNext, + pSurfaceCapabilities); +} + +VkResult +wsi_common_get_surface_formats(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormatKHR *pSurfaceFormats) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_formats(surface, wsi_device, + pSurfaceFormatCount, pSurfaceFormats); +} + +VkResult +wsi_common_get_surface_formats2(struct wsi_device *wsi_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormat2KHR *pSurfaceFormats) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_formats2(surface, wsi_device, pSurfaceInfo->pNext, + pSurfaceFormatCount, pSurfaceFormats); +} + +VkResult +wsi_common_get_surface_present_modes(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + uint32_t *pPresentModeCount, + VkPresentModeKHR *pPresentModes) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_present_modes(surface, pPresentModeCount, + pPresentModes); +} + +VkResult +wsi_common_create_swapchain(struct wsi_device *wsi, + VkDevice device, + int fd, + const VkSwapchainCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSwapchainKHR *pSwapchain) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface); + struct wsi_interface *iface = wsi->wsi[surface->platform]; + struct wsi_swapchain *swapchain; + + VkResult result = iface->create_swapchain(surface, device, wsi, fd, + pCreateInfo, pAllocator, + &swapchain); + if (result != VK_SUCCESS) + return result; + + *pSwapchain = wsi_swapchain_to_handle(swapchain); + + return VK_SUCCESS; +} + +void +wsi_common_destroy_swapchain(VkDevice device, + VkSwapchainKHR _swapchain, + const VkAllocationCallbacks *pAllocator) +{ + WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); + if (!swapchain) + return; + + swapchain->destroy(swapchain, pAllocator); +} + +VkResult +wsi_common_get_images(VkSwapchainKHR _swapchain, + uint32_t *pSwapchainImageCount, + VkImage *pSwapchainImages) +{ + WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); + VK_OUTARRAY_MAKE(images, pSwapchainImages, pSwapchainImageCount); + + for (uint32_t i = 0; i < swapchain->image_count; i++) { + vk_outarray_append(&images, image) { + *image = swapchain->get_wsi_image(swapchain, i)->image; + } + } + + return vk_outarray_status(&images); +} + +VkResult +wsi_common_acquire_next_image(const struct wsi_device *wsi, + VkDevice device, + VkSwapchainKHR _swapchain, + uint64_t timeout, + VkSemaphore semaphore, + uint32_t *pImageIndex) +{ + WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); + + return swapchain->acquire_next_image(swapchain, timeout, + semaphore, pImageIndex); +} + +VkResult +wsi_common_queue_present(const struct wsi_device *wsi, + VkDevice device, + VkQueue queue, + int queue_family_index, + const VkPresentInfoKHR *pPresentInfo) +{ + VkResult final_result = VK_SUCCESS; + + const VkPresentRegionsKHR *regions = + vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR); + + for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) { + WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]); + VkResult result; + + if (swapchain->fences[0] == VK_NULL_HANDLE) { + const VkFenceCreateInfo fence_info = { + .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, + .pNext = NULL, + .flags = 0, + }; + result = wsi->CreateFence(device, &fence_info, + &swapchain->alloc, + &swapchain->fences[0]); + if (result != VK_SUCCESS) + goto fail_present; + } else { + wsi->ResetFences(device, 1, &swapchain->fences[0]); + } + + VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = NULL, + }; + + VkPipelineStageFlags *stage_flags = NULL; + if (i == 0) { + /* We only need/want to wait on semaphores once. After that, we're + * guaranteed ordering since it all happens on the same queue. + */ + submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount, + submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores, + + /* Set up the pWaitDstStageMasks */ + stage_flags = vk_alloc(&swapchain->alloc, + sizeof(VkPipelineStageFlags) * + pPresentInfo->waitSemaphoreCount, + 8, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + if (!stage_flags) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail_present; + } + for (uint32_t s = 0; s < pPresentInfo->waitSemaphoreCount; s++) + stage_flags[s] = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + + submit_info.pWaitDstStageMask = stage_flags; + } + + if (swapchain->use_prime_blit) { + /* If we are using prime blits, we need to perform the blit now. The + * command buffer is attached to the image. + */ + struct wsi_image *image = + swapchain->get_wsi_image(swapchain, pPresentInfo->pImageIndices[i]); + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = + &image->prime.blit_cmd_buffers[queue_family_index]; + } + + result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[0]); + vk_free(&swapchain->alloc, stage_flags); + if (result != VK_SUCCESS) + goto fail_present; + + const VkPresentRegionKHR *region = NULL; + if (regions && regions->pRegions) + region = ®ions->pRegions[i]; + + result = swapchain->queue_present(swapchain, + pPresentInfo->pImageIndices[i], + region); + if (result != VK_SUCCESS) + goto fail_present; + + VkFence last = swapchain->fences[2]; + swapchain->fences[2] = swapchain->fences[1]; + swapchain->fences[1] = swapchain->fences[0]; + swapchain->fences[0] = last; + + if (last != VK_NULL_HANDLE) { + wsi->WaitForFences(device, 1, &last, true, 1); + } + + fail_present: + if (pPresentInfo->pResults != NULL) + pPresentInfo->pResults[i] = result; + + /* Let the final result be our first unsuccessful result */ + if (final_result == VK_SUCCESS) + final_result = result; + } + + return final_result; }