*/
#include "wsi_common_private.h"
+#include "drm_fourcc.h"
#include "util/macros.h"
#include "vk_util.h"
-void
+#include <unistd.h>
+
+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);
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
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,
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
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,
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,
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;
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 = {
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;
}
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
.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
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)
region = ®ions->pRegions[i];
result = swapchain->queue_present(swapchain,
- queue,
- pPresentInfo->waitSemaphoreCount,
- pPresentInfo->pWaitSemaphores,
pPresentInfo->pImageIndices[i],
region);
if (result != VK_SUCCESS)