1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2017 Intel Corporation
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg#include "wsi_common_private.h"
25b8e80941Smrg#include "drm-uapi/drm_fourcc.h"
26b8e80941Smrg#include "util/macros.h"
27b8e80941Smrg#include "util/xmlconfig.h"
28b8e80941Smrg#include "vk_util.h"
29b8e80941Smrg
30b8e80941Smrg#include <time.h>
31b8e80941Smrg#include <unistd.h>
32b8e80941Smrg#include <xf86drm.h>
33b8e80941Smrg#include <stdlib.h>
34b8e80941Smrg#include <stdio.h>
35b8e80941Smrg
36b8e80941SmrgVkResult
37b8e80941Smrgwsi_device_init(struct wsi_device *wsi,
38b8e80941Smrg                VkPhysicalDevice pdevice,
39b8e80941Smrg                WSI_FN_GetPhysicalDeviceProcAddr proc_addr,
40b8e80941Smrg                const VkAllocationCallbacks *alloc,
41b8e80941Smrg                int display_fd,
42b8e80941Smrg                const struct driOptionCache *dri_options)
43b8e80941Smrg{
44b8e80941Smrg   const char *present_mode;
45b8e80941Smrg   VkResult result;
46b8e80941Smrg
47b8e80941Smrg   memset(wsi, 0, sizeof(*wsi));
48b8e80941Smrg
49b8e80941Smrg   wsi->instance_alloc = *alloc;
50b8e80941Smrg   wsi->pdevice = pdevice;
51b8e80941Smrg
52b8e80941Smrg#define WSI_GET_CB(func) \
53b8e80941Smrg   PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
54b8e80941Smrg   WSI_GET_CB(GetPhysicalDeviceProperties2);
55b8e80941Smrg   WSI_GET_CB(GetPhysicalDeviceMemoryProperties);
56b8e80941Smrg   WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties);
57b8e80941Smrg#undef WSI_GET_CB
58b8e80941Smrg
59b8e80941Smrg   wsi->pci_bus_info.sType =
60b8e80941Smrg      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT;
61b8e80941Smrg   VkPhysicalDeviceProperties2 pdp2 = {
62b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
63b8e80941Smrg      .pNext = &wsi->pci_bus_info,
64b8e80941Smrg   };
65b8e80941Smrg   GetPhysicalDeviceProperties2(pdevice, &pdp2);
66b8e80941Smrg
67b8e80941Smrg   wsi->maxImageDimension2D = pdp2.properties.limits.maxImageDimension2D;
68b8e80941Smrg   wsi->override_present_mode = VK_PRESENT_MODE_MAX_ENUM_KHR;
69b8e80941Smrg
70b8e80941Smrg   GetPhysicalDeviceMemoryProperties(pdevice, &wsi->memory_props);
71b8e80941Smrg   GetPhysicalDeviceQueueFamilyProperties(pdevice, &wsi->queue_family_count, NULL);
72b8e80941Smrg
73b8e80941Smrg#define WSI_GET_CB(func) \
74b8e80941Smrg   wsi->func = (PFN_vk##func)proc_addr(pdevice, "vk" #func)
75b8e80941Smrg   WSI_GET_CB(AllocateMemory);
76b8e80941Smrg   WSI_GET_CB(AllocateCommandBuffers);
77b8e80941Smrg   WSI_GET_CB(BindBufferMemory);
78b8e80941Smrg   WSI_GET_CB(BindImageMemory);
79b8e80941Smrg   WSI_GET_CB(BeginCommandBuffer);
80b8e80941Smrg   WSI_GET_CB(CmdCopyImageToBuffer);
81b8e80941Smrg   WSI_GET_CB(CreateBuffer);
82b8e80941Smrg   WSI_GET_CB(CreateCommandPool);
83b8e80941Smrg   WSI_GET_CB(CreateFence);
84b8e80941Smrg   WSI_GET_CB(CreateImage);
85b8e80941Smrg   WSI_GET_CB(DestroyBuffer);
86b8e80941Smrg   WSI_GET_CB(DestroyCommandPool);
87b8e80941Smrg   WSI_GET_CB(DestroyFence);
88b8e80941Smrg   WSI_GET_CB(DestroyImage);
89b8e80941Smrg   WSI_GET_CB(EndCommandBuffer);
90b8e80941Smrg   WSI_GET_CB(FreeMemory);
91b8e80941Smrg   WSI_GET_CB(FreeCommandBuffers);
92b8e80941Smrg   WSI_GET_CB(GetBufferMemoryRequirements);
93b8e80941Smrg   WSI_GET_CB(GetImageMemoryRequirements);
94b8e80941Smrg   WSI_GET_CB(GetImageSubresourceLayout);
95b8e80941Smrg   WSI_GET_CB(GetMemoryFdKHR);
96b8e80941Smrg   WSI_GET_CB(GetPhysicalDeviceFormatProperties);
97b8e80941Smrg   WSI_GET_CB(GetPhysicalDeviceFormatProperties2KHR);
98b8e80941Smrg   WSI_GET_CB(ResetFences);
99b8e80941Smrg   WSI_GET_CB(QueueSubmit);
100b8e80941Smrg   WSI_GET_CB(WaitForFences);
101b8e80941Smrg#undef WSI_GET_CB
102b8e80941Smrg
103b8e80941Smrg#ifdef VK_USE_PLATFORM_XCB_KHR
104b8e80941Smrg   result = wsi_x11_init_wsi(wsi, alloc, dri_options);
105b8e80941Smrg   if (result != VK_SUCCESS)
106b8e80941Smrg      goto fail;
107b8e80941Smrg#endif
108b8e80941Smrg
109b8e80941Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR
110b8e80941Smrg   result = wsi_wl_init_wsi(wsi, alloc, pdevice);
111b8e80941Smrg   if (result != VK_SUCCESS)
112b8e80941Smrg      goto fail;
113b8e80941Smrg#endif
114b8e80941Smrg
115b8e80941Smrg#ifdef VK_USE_PLATFORM_DISPLAY_KHR
116b8e80941Smrg   result = wsi_display_init_wsi(wsi, alloc, display_fd);
117b8e80941Smrg   if (result != VK_SUCCESS)
118b8e80941Smrg      goto fail;
119b8e80941Smrg#endif
120b8e80941Smrg
121b8e80941Smrg   present_mode = getenv("MESA_VK_WSI_PRESENT_MODE");
122b8e80941Smrg   if (present_mode) {
123b8e80941Smrg      if (!strcmp(present_mode, "fifo")) {
124b8e80941Smrg         wsi->override_present_mode = VK_PRESENT_MODE_FIFO_KHR;
125b8e80941Smrg      } else if (!strcmp(present_mode, "mailbox")) {
126b8e80941Smrg         wsi->override_present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
127b8e80941Smrg      } else if (!strcmp(present_mode, "immediate")) {
128b8e80941Smrg         wsi->override_present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
129b8e80941Smrg      } else {
130b8e80941Smrg         fprintf(stderr, "Invalid MESA_VK_WSI_PRESENT_MODE value!\n");
131b8e80941Smrg      }
132b8e80941Smrg   }
133b8e80941Smrg
134b8e80941Smrg   if (dri_options) {
135b8e80941Smrg      if (driCheckOption(dri_options, "adaptive_sync", DRI_BOOL))
136b8e80941Smrg         wsi->enable_adaptive_sync = driQueryOptionb(dri_options,
137b8e80941Smrg                                                     "adaptive_sync");
138b8e80941Smrg   }
139b8e80941Smrg
140b8e80941Smrg   return VK_SUCCESS;
141b8e80941Smrg
142b8e80941Smrgfail:
143b8e80941Smrg   wsi_device_finish(wsi, alloc);
144b8e80941Smrg   return result;
145b8e80941Smrg}
146b8e80941Smrg
147b8e80941Smrgvoid
148b8e80941Smrgwsi_device_finish(struct wsi_device *wsi,
149b8e80941Smrg                  const VkAllocationCallbacks *alloc)
150b8e80941Smrg{
151b8e80941Smrg#ifdef VK_USE_PLATFORM_DISPLAY_KHR
152b8e80941Smrg   wsi_display_finish_wsi(wsi, alloc);
153b8e80941Smrg#endif
154b8e80941Smrg#ifdef VK_USE_PLATFORM_WAYLAND_KHR
155b8e80941Smrg   wsi_wl_finish_wsi(wsi, alloc);
156b8e80941Smrg#endif
157b8e80941Smrg#ifdef VK_USE_PLATFORM_XCB_KHR
158b8e80941Smrg   wsi_x11_finish_wsi(wsi, alloc);
159b8e80941Smrg#endif
160b8e80941Smrg}
161b8e80941Smrg
162b8e80941Smrgbool
163b8e80941Smrgwsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd)
164b8e80941Smrg{
165b8e80941Smrg   drmDevicePtr fd_device;
166b8e80941Smrg   int ret = drmGetDevice2(drm_fd, 0, &fd_device);
167b8e80941Smrg   if (ret)
168b8e80941Smrg      return false;
169b8e80941Smrg
170b8e80941Smrg   bool match = false;
171b8e80941Smrg   switch (fd_device->bustype) {
172b8e80941Smrg   case DRM_BUS_PCI:
173b8e80941Smrg      match = wsi->pci_bus_info.pciDomain == fd_device->businfo.pci->domain &&
174b8e80941Smrg              wsi->pci_bus_info.pciBus == fd_device->businfo.pci->bus &&
175b8e80941Smrg              wsi->pci_bus_info.pciDevice == fd_device->businfo.pci->dev &&
176b8e80941Smrg              wsi->pci_bus_info.pciFunction == fd_device->businfo.pci->func;
177b8e80941Smrg      break;
178b8e80941Smrg
179b8e80941Smrg   default:
180b8e80941Smrg      break;
181b8e80941Smrg   }
182b8e80941Smrg
183b8e80941Smrg   drmFreeDevice(&fd_device);
184b8e80941Smrg
185b8e80941Smrg   return match;
186b8e80941Smrg}
187b8e80941Smrg
188b8e80941SmrgVkResult
189b8e80941Smrgwsi_swapchain_init(const struct wsi_device *wsi,
190b8e80941Smrg                   struct wsi_swapchain *chain,
191b8e80941Smrg                   VkDevice device,
192b8e80941Smrg                   const VkSwapchainCreateInfoKHR *pCreateInfo,
193b8e80941Smrg                   const VkAllocationCallbacks *pAllocator)
194b8e80941Smrg{
195b8e80941Smrg   VkResult result;
196b8e80941Smrg
197b8e80941Smrg   memset(chain, 0, sizeof(*chain));
198b8e80941Smrg
199b8e80941Smrg   chain->wsi = wsi;
200b8e80941Smrg   chain->device = device;
201b8e80941Smrg   chain->alloc = *pAllocator;
202b8e80941Smrg   chain->use_prime_blit = false;
203b8e80941Smrg
204b8e80941Smrg   chain->cmd_pools =
205b8e80941Smrg      vk_zalloc(pAllocator, sizeof(VkCommandPool) * wsi->queue_family_count, 8,
206b8e80941Smrg                VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
207b8e80941Smrg   if (!chain->cmd_pools)
208b8e80941Smrg      return VK_ERROR_OUT_OF_HOST_MEMORY;
209b8e80941Smrg
210b8e80941Smrg   for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
211b8e80941Smrg      const VkCommandPoolCreateInfo cmd_pool_info = {
212b8e80941Smrg         .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
213b8e80941Smrg         .pNext = NULL,
214b8e80941Smrg         .flags = 0,
215b8e80941Smrg         .queueFamilyIndex = i,
216b8e80941Smrg      };
217b8e80941Smrg      result = wsi->CreateCommandPool(device, &cmd_pool_info, &chain->alloc,
218b8e80941Smrg                                      &chain->cmd_pools[i]);
219b8e80941Smrg      if (result != VK_SUCCESS)
220b8e80941Smrg         goto fail;
221b8e80941Smrg   }
222b8e80941Smrg
223b8e80941Smrg   return VK_SUCCESS;
224b8e80941Smrg
225b8e80941Smrgfail:
226b8e80941Smrg   wsi_swapchain_finish(chain);
227b8e80941Smrg   return result;
228b8e80941Smrg}
229b8e80941Smrg
230b8e80941Smrgstatic bool
231b8e80941Smrgwsi_swapchain_is_present_mode_supported(struct wsi_device *wsi,
232b8e80941Smrg                                        const VkSwapchainCreateInfoKHR *pCreateInfo,
233b8e80941Smrg                                        VkPresentModeKHR mode)
234b8e80941Smrg{
235b8e80941Smrg      ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface);
236b8e80941Smrg      struct wsi_interface *iface = wsi->wsi[surface->platform];
237b8e80941Smrg      VkPresentModeKHR *present_modes;
238b8e80941Smrg      uint32_t present_mode_count;
239b8e80941Smrg      bool supported = false;
240b8e80941Smrg      VkResult result;
241b8e80941Smrg
242b8e80941Smrg      result = iface->get_present_modes(surface, &present_mode_count, NULL);
243b8e80941Smrg      if (result != VK_SUCCESS)
244b8e80941Smrg         return supported;
245b8e80941Smrg
246b8e80941Smrg      present_modes = malloc(present_mode_count * sizeof(*present_modes));
247b8e80941Smrg      if (!present_modes)
248b8e80941Smrg         return supported;
249b8e80941Smrg
250b8e80941Smrg      result = iface->get_present_modes(surface, &present_mode_count,
251b8e80941Smrg                                        present_modes);
252b8e80941Smrg      if (result != VK_SUCCESS)
253b8e80941Smrg         goto fail;
254b8e80941Smrg
255b8e80941Smrg      for (uint32_t i = 0; i < present_mode_count; i++) {
256b8e80941Smrg         if (present_modes[i] == mode) {
257b8e80941Smrg            supported = true;
258b8e80941Smrg            break;
259b8e80941Smrg         }
260b8e80941Smrg      }
261b8e80941Smrg
262b8e80941Smrgfail:
263b8e80941Smrg      free(present_modes);
264b8e80941Smrg      return supported;
265b8e80941Smrg}
266b8e80941Smrg
267b8e80941Smrgenum VkPresentModeKHR
268b8e80941Smrgwsi_swapchain_get_present_mode(struct wsi_device *wsi,
269b8e80941Smrg                               const VkSwapchainCreateInfoKHR *pCreateInfo)
270b8e80941Smrg{
271b8e80941Smrg   if (wsi->override_present_mode == VK_PRESENT_MODE_MAX_ENUM_KHR)
272b8e80941Smrg      return pCreateInfo->presentMode;
273b8e80941Smrg
274b8e80941Smrg   if (!wsi_swapchain_is_present_mode_supported(wsi, pCreateInfo,
275b8e80941Smrg                                                wsi->override_present_mode)) {
276b8e80941Smrg      fprintf(stderr, "Unsupported MESA_VK_WSI_PRESENT_MODE value!\n");
277b8e80941Smrg      return pCreateInfo->presentMode;
278b8e80941Smrg   }
279b8e80941Smrg
280b8e80941Smrg   return wsi->override_present_mode;
281b8e80941Smrg}
282b8e80941Smrg
283b8e80941Smrgvoid
284b8e80941Smrgwsi_swapchain_finish(struct wsi_swapchain *chain)
285b8e80941Smrg{
286b8e80941Smrg   for (unsigned i = 0; i < ARRAY_SIZE(chain->fences); i++)
287b8e80941Smrg      chain->wsi->DestroyFence(chain->device, chain->fences[i], &chain->alloc);
288b8e80941Smrg
289b8e80941Smrg   for (uint32_t i = 0; i < chain->wsi->queue_family_count; i++) {
290b8e80941Smrg      chain->wsi->DestroyCommandPool(chain->device, chain->cmd_pools[i],
291b8e80941Smrg                                     &chain->alloc);
292b8e80941Smrg   }
293b8e80941Smrg   vk_free(&chain->alloc, chain->cmd_pools);
294b8e80941Smrg}
295b8e80941Smrg
296b8e80941Smrgstatic uint32_t
297b8e80941Smrgselect_memory_type(const struct wsi_device *wsi,
298b8e80941Smrg                   VkMemoryPropertyFlags props,
299b8e80941Smrg                   uint32_t type_bits)
300b8e80941Smrg{
301b8e80941Smrg   for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) {
302b8e80941Smrg       const VkMemoryType type = wsi->memory_props.memoryTypes[i];
303b8e80941Smrg       if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props)
304b8e80941Smrg         return i;
305b8e80941Smrg   }
306b8e80941Smrg
307b8e80941Smrg   unreachable("No memory type found");
308b8e80941Smrg}
309b8e80941Smrg
310b8e80941Smrgstatic uint32_t
311b8e80941Smrgvk_format_size(VkFormat format)
312b8e80941Smrg{
313b8e80941Smrg   switch (format) {
314b8e80941Smrg   case VK_FORMAT_B8G8R8A8_UNORM:
315b8e80941Smrg   case VK_FORMAT_B8G8R8A8_SRGB:
316b8e80941Smrg      return 4;
317b8e80941Smrg   default:
318b8e80941Smrg      unreachable("Unknown WSI Format");
319b8e80941Smrg   }
320b8e80941Smrg}
321b8e80941Smrg
322b8e80941Smrgstatic inline uint32_t
323b8e80941Smrgalign_u32(uint32_t v, uint32_t a)
324b8e80941Smrg{
325b8e80941Smrg   assert(a != 0 && a == (a & -a));
326b8e80941Smrg   return (v + a - 1) & ~(a - 1);
327b8e80941Smrg}
328b8e80941Smrg
329b8e80941SmrgVkResult
330b8e80941Smrgwsi_create_native_image(const struct wsi_swapchain *chain,
331b8e80941Smrg                        const VkSwapchainCreateInfoKHR *pCreateInfo,
332b8e80941Smrg                        uint32_t num_modifier_lists,
333b8e80941Smrg                        const uint32_t *num_modifiers,
334b8e80941Smrg                        const uint64_t *const *modifiers,
335b8e80941Smrg                        struct wsi_image *image)
336b8e80941Smrg{
337b8e80941Smrg   const struct wsi_device *wsi = chain->wsi;
338b8e80941Smrg   VkResult result;
339b8e80941Smrg
340b8e80941Smrg   memset(image, 0, sizeof(*image));
341b8e80941Smrg   for (int i = 0; i < ARRAY_SIZE(image->fds); i++)
342b8e80941Smrg      image->fds[i] = -1;
343b8e80941Smrg
344b8e80941Smrg   struct wsi_image_create_info image_wsi_info = {
345b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA,
346b8e80941Smrg      .pNext = NULL,
347b8e80941Smrg   };
348b8e80941Smrg
349b8e80941Smrg   uint32_t image_modifier_count = 0, modifier_prop_count = 0;
350b8e80941Smrg   struct wsi_format_modifier_properties *modifier_props = NULL;
351b8e80941Smrg   uint64_t *image_modifiers = NULL;
352b8e80941Smrg   if (num_modifier_lists == 0) {
353b8e80941Smrg      /* If we don't have modifiers, fall back to the legacy "scanout" flag */
354b8e80941Smrg      image_wsi_info.scanout = true;
355b8e80941Smrg   } else {
356b8e80941Smrg      /* The winsys can't request modifiers if we don't support them. */
357b8e80941Smrg      assert(wsi->supports_modifiers);
358b8e80941Smrg      struct wsi_format_modifier_properties_list modifier_props_list = {
359b8e80941Smrg         .sType = VK_STRUCTURE_TYPE_WSI_FORMAT_MODIFIER_PROPERTIES_LIST_MESA,
360b8e80941Smrg         .pNext = NULL,
361b8e80941Smrg      };
362b8e80941Smrg      VkFormatProperties2 format_props = {
363b8e80941Smrg         .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
364b8e80941Smrg         .pNext = &modifier_props_list,
365b8e80941Smrg      };
366b8e80941Smrg      wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice,
367b8e80941Smrg                                                 pCreateInfo->imageFormat,
368b8e80941Smrg                                                 &format_props);
369b8e80941Smrg      assert(modifier_props_list.modifier_count > 0);
370b8e80941Smrg      modifier_props = vk_alloc(&chain->alloc,
371b8e80941Smrg                                sizeof(*modifier_props) *
372b8e80941Smrg                                modifier_props_list.modifier_count,
373b8e80941Smrg                                8,
374b8e80941Smrg                                VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
375b8e80941Smrg      if (!modifier_props) {
376b8e80941Smrg         result = VK_ERROR_OUT_OF_HOST_MEMORY;
377b8e80941Smrg         goto fail;
378b8e80941Smrg      }
379b8e80941Smrg
380b8e80941Smrg      modifier_props_list.modifier_properties = modifier_props;
381b8e80941Smrg      wsi->GetPhysicalDeviceFormatProperties2KHR(wsi->pdevice,
382b8e80941Smrg                                                 pCreateInfo->imageFormat,
383b8e80941Smrg                                                 &format_props);
384b8e80941Smrg      modifier_prop_count = modifier_props_list.modifier_count;
385b8e80941Smrg
386b8e80941Smrg      uint32_t max_modifier_count = 0;
387b8e80941Smrg      for (uint32_t l = 0; l < num_modifier_lists; l++)
388b8e80941Smrg         max_modifier_count = MAX2(max_modifier_count, num_modifiers[l]);
389b8e80941Smrg
390b8e80941Smrg      image_modifiers = vk_alloc(&chain->alloc,
391b8e80941Smrg                                 sizeof(*image_modifiers) *
392b8e80941Smrg                                 max_modifier_count,
393b8e80941Smrg                                 8,
394b8e80941Smrg                                 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
395b8e80941Smrg      if (!image_modifiers) {
396b8e80941Smrg         result = VK_ERROR_OUT_OF_HOST_MEMORY;
397b8e80941Smrg         goto fail;
398b8e80941Smrg      }
399b8e80941Smrg
400b8e80941Smrg      image_modifier_count = 0;
401b8e80941Smrg      for (uint32_t l = 0; l < num_modifier_lists; l++) {
402b8e80941Smrg         /* Walk the modifier lists and construct a list of supported
403b8e80941Smrg          * modifiers.
404b8e80941Smrg          */
405b8e80941Smrg         for (uint32_t i = 0; i < num_modifiers[l]; i++) {
406b8e80941Smrg            for (uint32_t j = 0; j < modifier_prop_count; j++) {
407b8e80941Smrg               if (modifier_props[j].modifier == modifiers[l][i])
408b8e80941Smrg                  image_modifiers[image_modifier_count++] = modifiers[l][i];
409b8e80941Smrg            }
410b8e80941Smrg         }
411b8e80941Smrg
412b8e80941Smrg         /* We only want to take the modifiers from the first list */
413b8e80941Smrg         if (image_modifier_count > 0)
414b8e80941Smrg            break;
415b8e80941Smrg      }
416b8e80941Smrg
417b8e80941Smrg      if (image_modifier_count > 0) {
418b8e80941Smrg         image_wsi_info.modifier_count = image_modifier_count;
419b8e80941Smrg         image_wsi_info.modifiers = image_modifiers;
420b8e80941Smrg      } else {
421b8e80941Smrg         /* TODO: Add a proper error here */
422b8e80941Smrg         assert(!"Failed to find a supported modifier!  This should never "
423b8e80941Smrg                 "happen because LINEAR should always be available");
424b8e80941Smrg         result = VK_ERROR_OUT_OF_HOST_MEMORY;
425b8e80941Smrg         goto fail;
426b8e80941Smrg      }
427b8e80941Smrg   }
428b8e80941Smrg
429b8e80941Smrg   const VkImageCreateInfo image_info = {
430b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
431b8e80941Smrg      .pNext = &image_wsi_info,
432b8e80941Smrg      .flags = 0,
433b8e80941Smrg      .imageType = VK_IMAGE_TYPE_2D,
434b8e80941Smrg      .format = pCreateInfo->imageFormat,
435b8e80941Smrg      .extent = {
436b8e80941Smrg         .width = pCreateInfo->imageExtent.width,
437b8e80941Smrg         .height = pCreateInfo->imageExtent.height,
438b8e80941Smrg         .depth = 1,
439b8e80941Smrg      },
440b8e80941Smrg      .mipLevels = 1,
441b8e80941Smrg      .arrayLayers = 1,
442b8e80941Smrg      .samples = VK_SAMPLE_COUNT_1_BIT,
443b8e80941Smrg      .tiling = VK_IMAGE_TILING_OPTIMAL,
444b8e80941Smrg      .usage = pCreateInfo->imageUsage,
445b8e80941Smrg      .sharingMode = pCreateInfo->imageSharingMode,
446b8e80941Smrg      .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
447b8e80941Smrg      .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
448b8e80941Smrg      .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
449b8e80941Smrg   };
450b8e80941Smrg   result = wsi->CreateImage(chain->device, &image_info,
451b8e80941Smrg                             &chain->alloc, &image->image);
452b8e80941Smrg   if (result != VK_SUCCESS)
453b8e80941Smrg      goto fail;
454b8e80941Smrg
455b8e80941Smrg   VkMemoryRequirements reqs;
456b8e80941Smrg   wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
457b8e80941Smrg
458b8e80941Smrg   const struct wsi_memory_allocate_info memory_wsi_info = {
459b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
460b8e80941Smrg      .pNext = NULL,
461b8e80941Smrg      .implicit_sync = true,
462b8e80941Smrg   };
463b8e80941Smrg   const VkExportMemoryAllocateInfo memory_export_info = {
464b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
465b8e80941Smrg      .pNext = &memory_wsi_info,
466b8e80941Smrg      .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
467b8e80941Smrg   };
468b8e80941Smrg   const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
469b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
470b8e80941Smrg      .pNext = &memory_export_info,
471b8e80941Smrg      .image = image->image,
472b8e80941Smrg      .buffer = VK_NULL_HANDLE,
473b8e80941Smrg   };
474b8e80941Smrg   const VkMemoryAllocateInfo memory_info = {
475b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
476b8e80941Smrg      .pNext = &memory_dedicated_info,
477b8e80941Smrg      .allocationSize = reqs.size,
478b8e80941Smrg      .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
479b8e80941Smrg                                            reqs.memoryTypeBits),
480b8e80941Smrg   };
481b8e80941Smrg   result = wsi->AllocateMemory(chain->device, &memory_info,
482b8e80941Smrg                                &chain->alloc, &image->memory);
483b8e80941Smrg   if (result != VK_SUCCESS)
484b8e80941Smrg      goto fail;
485b8e80941Smrg
486b8e80941Smrg   result = wsi->BindImageMemory(chain->device, image->image,
487b8e80941Smrg                                 image->memory, 0);
488b8e80941Smrg   if (result != VK_SUCCESS)
489b8e80941Smrg      goto fail;
490b8e80941Smrg
491b8e80941Smrg   const VkMemoryGetFdInfoKHR memory_get_fd_info = {
492b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
493b8e80941Smrg      .pNext = NULL,
494b8e80941Smrg      .memory = image->memory,
495b8e80941Smrg      .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
496b8e80941Smrg   };
497b8e80941Smrg   int fd;
498b8e80941Smrg   result = wsi->GetMemoryFdKHR(chain->device, &memory_get_fd_info, &fd);
499b8e80941Smrg   if (result != VK_SUCCESS)
500b8e80941Smrg      goto fail;
501b8e80941Smrg
502b8e80941Smrg   if (num_modifier_lists > 0) {
503b8e80941Smrg      image->drm_modifier = wsi->image_get_modifier(image->image);
504b8e80941Smrg      assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID);
505b8e80941Smrg
506b8e80941Smrg      for (uint32_t j = 0; j < modifier_prop_count; j++) {
507b8e80941Smrg         if (modifier_props[j].modifier == image->drm_modifier) {
508b8e80941Smrg            image->num_planes = modifier_props[j].modifier_plane_count;
509b8e80941Smrg            break;
510b8e80941Smrg         }
511b8e80941Smrg      }
512b8e80941Smrg
513b8e80941Smrg      for (uint32_t p = 0; p < image->num_planes; p++) {
514b8e80941Smrg         const VkImageSubresource image_subresource = {
515b8e80941Smrg            .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << p,
516b8e80941Smrg            .mipLevel = 0,
517b8e80941Smrg            .arrayLayer = 0,
518b8e80941Smrg         };
519b8e80941Smrg         VkSubresourceLayout image_layout;
520b8e80941Smrg         wsi->GetImageSubresourceLayout(chain->device, image->image,
521b8e80941Smrg                                        &image_subresource, &image_layout);
522b8e80941Smrg         image->sizes[p] = image_layout.size;
523b8e80941Smrg         image->row_pitches[p] = image_layout.rowPitch;
524b8e80941Smrg         image->offsets[p] = image_layout.offset;
525b8e80941Smrg         if (p == 0) {
526b8e80941Smrg            image->fds[p] = fd;
527b8e80941Smrg         } else {
528b8e80941Smrg            image->fds[p] = dup(fd);
529b8e80941Smrg            if (image->fds[p] == -1) {
530b8e80941Smrg               for (uint32_t i = 0; i < p; i++)
531b8e80941Smrg                  close(image->fds[p]);
532b8e80941Smrg
533b8e80941Smrg               goto fail;
534b8e80941Smrg            }
535b8e80941Smrg         }
536b8e80941Smrg      }
537b8e80941Smrg   } else {
538b8e80941Smrg      const VkImageSubresource image_subresource = {
539b8e80941Smrg         .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
540b8e80941Smrg         .mipLevel = 0,
541b8e80941Smrg         .arrayLayer = 0,
542b8e80941Smrg      };
543b8e80941Smrg      VkSubresourceLayout image_layout;
544b8e80941Smrg      wsi->GetImageSubresourceLayout(chain->device, image->image,
545b8e80941Smrg                                     &image_subresource, &image_layout);
546b8e80941Smrg
547b8e80941Smrg      image->drm_modifier = DRM_FORMAT_MOD_INVALID;
548b8e80941Smrg      image->num_planes = 1;
549b8e80941Smrg      image->sizes[0] = reqs.size;
550b8e80941Smrg      image->row_pitches[0] = image_layout.rowPitch;
551b8e80941Smrg      image->offsets[0] = 0;
552b8e80941Smrg      image->fds[0] = fd;
553b8e80941Smrg   }
554b8e80941Smrg
555b8e80941Smrg   vk_free(&chain->alloc, modifier_props);
556b8e80941Smrg   vk_free(&chain->alloc, image_modifiers);
557b8e80941Smrg
558b8e80941Smrg   return VK_SUCCESS;
559b8e80941Smrg
560b8e80941Smrgfail:
561b8e80941Smrg   vk_free(&chain->alloc, modifier_props);
562b8e80941Smrg   vk_free(&chain->alloc, image_modifiers);
563b8e80941Smrg   wsi_destroy_image(chain, image);
564b8e80941Smrg
565b8e80941Smrg   return result;
566b8e80941Smrg}
567b8e80941Smrg
568b8e80941Smrg#define WSI_PRIME_LINEAR_STRIDE_ALIGN 256
569b8e80941Smrg
570b8e80941SmrgVkResult
571b8e80941Smrgwsi_create_prime_image(const struct wsi_swapchain *chain,
572b8e80941Smrg                       const VkSwapchainCreateInfoKHR *pCreateInfo,
573b8e80941Smrg                       bool use_modifier,
574b8e80941Smrg                       struct wsi_image *image)
575b8e80941Smrg{
576b8e80941Smrg   const struct wsi_device *wsi = chain->wsi;
577b8e80941Smrg   VkResult result;
578b8e80941Smrg
579b8e80941Smrg   memset(image, 0, sizeof(*image));
580b8e80941Smrg
581b8e80941Smrg   const uint32_t cpp = vk_format_size(pCreateInfo->imageFormat);
582b8e80941Smrg   const uint32_t linear_stride = align_u32(pCreateInfo->imageExtent.width * cpp,
583b8e80941Smrg                                            WSI_PRIME_LINEAR_STRIDE_ALIGN);
584b8e80941Smrg
585b8e80941Smrg   uint32_t linear_size = linear_stride * pCreateInfo->imageExtent.height;
586b8e80941Smrg   linear_size = align_u32(linear_size, 4096);
587b8e80941Smrg
588b8e80941Smrg   const VkExternalMemoryBufferCreateInfo prime_buffer_external_info = {
589b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
590b8e80941Smrg      .pNext = NULL,
591b8e80941Smrg      .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
592b8e80941Smrg   };
593b8e80941Smrg   const VkBufferCreateInfo prime_buffer_info = {
594b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
595b8e80941Smrg      .pNext = &prime_buffer_external_info,
596b8e80941Smrg      .size = linear_size,
597b8e80941Smrg      .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT,
598b8e80941Smrg      .sharingMode = VK_SHARING_MODE_EXCLUSIVE,
599b8e80941Smrg   };
600b8e80941Smrg   result = wsi->CreateBuffer(chain->device, &prime_buffer_info,
601b8e80941Smrg                              &chain->alloc, &image->prime.buffer);
602b8e80941Smrg   if (result != VK_SUCCESS)
603b8e80941Smrg      goto fail;
604b8e80941Smrg
605b8e80941Smrg   VkMemoryRequirements reqs;
606b8e80941Smrg   wsi->GetBufferMemoryRequirements(chain->device, image->prime.buffer, &reqs);
607b8e80941Smrg   assert(reqs.size <= linear_size);
608b8e80941Smrg
609b8e80941Smrg   const struct wsi_memory_allocate_info memory_wsi_info = {
610b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,
611b8e80941Smrg      .pNext = NULL,
612b8e80941Smrg      .implicit_sync = true,
613b8e80941Smrg   };
614b8e80941Smrg   const VkExportMemoryAllocateInfo prime_memory_export_info = {
615b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
616b8e80941Smrg      .pNext = &memory_wsi_info,
617b8e80941Smrg      .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
618b8e80941Smrg   };
619b8e80941Smrg   const VkMemoryDedicatedAllocateInfo prime_memory_dedicated_info = {
620b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
621b8e80941Smrg      .pNext = &prime_memory_export_info,
622b8e80941Smrg      .image = VK_NULL_HANDLE,
623b8e80941Smrg      .buffer = image->prime.buffer,
624b8e80941Smrg   };
625b8e80941Smrg   const VkMemoryAllocateInfo prime_memory_info = {
626b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
627b8e80941Smrg      .pNext = &prime_memory_dedicated_info,
628b8e80941Smrg      .allocationSize = linear_size,
629b8e80941Smrg      .memoryTypeIndex = select_memory_type(wsi, 0, reqs.memoryTypeBits),
630b8e80941Smrg   };
631b8e80941Smrg   result = wsi->AllocateMemory(chain->device, &prime_memory_info,
632b8e80941Smrg                                &chain->alloc, &image->prime.memory);
633b8e80941Smrg   if (result != VK_SUCCESS)
634b8e80941Smrg      goto fail;
635b8e80941Smrg
636b8e80941Smrg   result = wsi->BindBufferMemory(chain->device, image->prime.buffer,
637b8e80941Smrg                                  image->prime.memory, 0);
638b8e80941Smrg   if (result != VK_SUCCESS)
639b8e80941Smrg      goto fail;
640b8e80941Smrg
641b8e80941Smrg   const VkImageCreateInfo image_info = {
642b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
643b8e80941Smrg      .pNext = NULL,
644b8e80941Smrg      .flags = 0,
645b8e80941Smrg      .imageType = VK_IMAGE_TYPE_2D,
646b8e80941Smrg      .format = pCreateInfo->imageFormat,
647b8e80941Smrg      .extent = {
648b8e80941Smrg         .width = pCreateInfo->imageExtent.width,
649b8e80941Smrg         .height = pCreateInfo->imageExtent.height,
650b8e80941Smrg         .depth = 1,
651b8e80941Smrg      },
652b8e80941Smrg      .mipLevels = 1,
653b8e80941Smrg      .arrayLayers = 1,
654b8e80941Smrg      .samples = VK_SAMPLE_COUNT_1_BIT,
655b8e80941Smrg      .tiling = VK_IMAGE_TILING_OPTIMAL,
656b8e80941Smrg      .usage = pCreateInfo->imageUsage | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
657b8e80941Smrg      .sharingMode = pCreateInfo->imageSharingMode,
658b8e80941Smrg      .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,
659b8e80941Smrg      .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,
660b8e80941Smrg      .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
661b8e80941Smrg   };
662b8e80941Smrg   result = wsi->CreateImage(chain->device, &image_info,
663b8e80941Smrg                             &chain->alloc, &image->image);
664b8e80941Smrg   if (result != VK_SUCCESS)
665b8e80941Smrg      goto fail;
666b8e80941Smrg
667b8e80941Smrg   wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
668b8e80941Smrg
669b8e80941Smrg   const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
670b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
671b8e80941Smrg      .pNext = NULL,
672b8e80941Smrg      .image = image->image,
673b8e80941Smrg      .buffer = VK_NULL_HANDLE,
674b8e80941Smrg   };
675b8e80941Smrg   const VkMemoryAllocateInfo memory_info = {
676b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
677b8e80941Smrg      .pNext = &memory_dedicated_info,
678b8e80941Smrg      .allocationSize = reqs.size,
679b8e80941Smrg      .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
680b8e80941Smrg                                            reqs.memoryTypeBits),
681b8e80941Smrg   };
682b8e80941Smrg   result = wsi->AllocateMemory(chain->device, &memory_info,
683b8e80941Smrg                                &chain->alloc, &image->memory);
684b8e80941Smrg   if (result != VK_SUCCESS)
685b8e80941Smrg      goto fail;
686b8e80941Smrg
687b8e80941Smrg   result = wsi->BindImageMemory(chain->device, image->image,
688b8e80941Smrg                                 image->memory, 0);
689b8e80941Smrg   if (result != VK_SUCCESS)
690b8e80941Smrg      goto fail;
691b8e80941Smrg
692b8e80941Smrg   image->prime.blit_cmd_buffers =
693b8e80941Smrg      vk_zalloc(&chain->alloc,
694b8e80941Smrg                sizeof(VkCommandBuffer) * wsi->queue_family_count, 8,
695b8e80941Smrg                VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
696b8e80941Smrg   if (!image->prime.blit_cmd_buffers) {
697b8e80941Smrg      result = VK_ERROR_OUT_OF_HOST_MEMORY;
698b8e80941Smrg      goto fail;
699b8e80941Smrg   }
700b8e80941Smrg
701b8e80941Smrg   for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
702b8e80941Smrg      const VkCommandBufferAllocateInfo cmd_buffer_info = {
703b8e80941Smrg         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
704b8e80941Smrg         .pNext = NULL,
705b8e80941Smrg         .commandPool = chain->cmd_pools[i],
706b8e80941Smrg         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
707b8e80941Smrg         .commandBufferCount = 1,
708b8e80941Smrg      };
709b8e80941Smrg      result = wsi->AllocateCommandBuffers(chain->device, &cmd_buffer_info,
710b8e80941Smrg                                           &image->prime.blit_cmd_buffers[i]);
711b8e80941Smrg      if (result != VK_SUCCESS)
712b8e80941Smrg         goto fail;
713b8e80941Smrg
714b8e80941Smrg      const VkCommandBufferBeginInfo begin_info = {
715b8e80941Smrg         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
716b8e80941Smrg      };
717b8e80941Smrg      wsi->BeginCommandBuffer(image->prime.blit_cmd_buffers[i], &begin_info);
718b8e80941Smrg
719b8e80941Smrg      struct VkBufferImageCopy buffer_image_copy = {
720b8e80941Smrg         .bufferOffset = 0,
721b8e80941Smrg         .bufferRowLength = linear_stride / cpp,
722b8e80941Smrg         .bufferImageHeight = 0,
723b8e80941Smrg         .imageSubresource = {
724b8e80941Smrg            .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
725b8e80941Smrg            .mipLevel = 0,
726b8e80941Smrg            .baseArrayLayer = 0,
727b8e80941Smrg            .layerCount = 1,
728b8e80941Smrg         },
729b8e80941Smrg         .imageOffset = { .x = 0, .y = 0, .z = 0 },
730b8e80941Smrg         .imageExtent = {
731b8e80941Smrg            .width = pCreateInfo->imageExtent.width,
732b8e80941Smrg            .height = pCreateInfo->imageExtent.height,
733b8e80941Smrg            .depth = 1,
734b8e80941Smrg         },
735b8e80941Smrg      };
736b8e80941Smrg      wsi->CmdCopyImageToBuffer(image->prime.blit_cmd_buffers[i],
737b8e80941Smrg                                image->image,
738b8e80941Smrg                                VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
739b8e80941Smrg                                image->prime.buffer,
740b8e80941Smrg                                1, &buffer_image_copy);
741b8e80941Smrg
742b8e80941Smrg      result = wsi->EndCommandBuffer(image->prime.blit_cmd_buffers[i]);
743b8e80941Smrg      if (result != VK_SUCCESS)
744b8e80941Smrg         goto fail;
745b8e80941Smrg   }
746b8e80941Smrg
747b8e80941Smrg   const VkMemoryGetFdInfoKHR linear_memory_get_fd_info = {
748b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
749b8e80941Smrg      .pNext = NULL,
750b8e80941Smrg      .memory = image->prime.memory,
751b8e80941Smrg      .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,
752b8e80941Smrg   };
753b8e80941Smrg   int fd;
754b8e80941Smrg   result = wsi->GetMemoryFdKHR(chain->device, &linear_memory_get_fd_info, &fd);
755b8e80941Smrg   if (result != VK_SUCCESS)
756b8e80941Smrg      goto fail;
757b8e80941Smrg
758b8e80941Smrg   image->drm_modifier = use_modifier ? DRM_FORMAT_MOD_LINEAR : DRM_FORMAT_MOD_INVALID;
759b8e80941Smrg   image->num_planes = 1;
760b8e80941Smrg   image->sizes[0] = linear_size;
761b8e80941Smrg   image->row_pitches[0] = linear_stride;
762b8e80941Smrg   image->offsets[0] = 0;
763b8e80941Smrg   image->fds[0] = fd;
764b8e80941Smrg
765b8e80941Smrg   return VK_SUCCESS;
766b8e80941Smrg
767b8e80941Smrgfail:
768b8e80941Smrg   wsi_destroy_image(chain, image);
769b8e80941Smrg
770b8e80941Smrg   return result;
771b8e80941Smrg}
772b8e80941Smrg
773b8e80941Smrgvoid
774b8e80941Smrgwsi_destroy_image(const struct wsi_swapchain *chain,
775b8e80941Smrg                  struct wsi_image *image)
776b8e80941Smrg{
777b8e80941Smrg   const struct wsi_device *wsi = chain->wsi;
778b8e80941Smrg
779b8e80941Smrg   if (image->prime.blit_cmd_buffers) {
780b8e80941Smrg      for (uint32_t i = 0; i < wsi->queue_family_count; i++) {
781b8e80941Smrg         wsi->FreeCommandBuffers(chain->device, chain->cmd_pools[i],
782b8e80941Smrg                                 1, &image->prime.blit_cmd_buffers[i]);
783b8e80941Smrg      }
784b8e80941Smrg      vk_free(&chain->alloc, image->prime.blit_cmd_buffers);
785b8e80941Smrg   }
786b8e80941Smrg
787b8e80941Smrg   wsi->FreeMemory(chain->device, image->memory, &chain->alloc);
788b8e80941Smrg   wsi->DestroyImage(chain->device, image->image, &chain->alloc);
789b8e80941Smrg   wsi->FreeMemory(chain->device, image->prime.memory, &chain->alloc);
790b8e80941Smrg   wsi->DestroyBuffer(chain->device, image->prime.buffer, &chain->alloc);
791b8e80941Smrg}
792b8e80941Smrg
793b8e80941SmrgVkResult
794b8e80941Smrgwsi_common_get_surface_support(struct wsi_device *wsi_device,
795b8e80941Smrg                               uint32_t queueFamilyIndex,
796b8e80941Smrg                               VkSurfaceKHR _surface,
797b8e80941Smrg                               VkBool32* pSupported)
798b8e80941Smrg{
799b8e80941Smrg   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
800b8e80941Smrg   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
801b8e80941Smrg
802b8e80941Smrg   return iface->get_support(surface, wsi_device,
803b8e80941Smrg                             queueFamilyIndex, pSupported);
804b8e80941Smrg}
805b8e80941Smrg
806b8e80941SmrgVkResult
807b8e80941Smrgwsi_common_get_surface_capabilities(struct wsi_device *wsi_device,
808b8e80941Smrg                                    VkSurfaceKHR _surface,
809b8e80941Smrg                                    VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
810b8e80941Smrg{
811b8e80941Smrg   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
812b8e80941Smrg   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
813b8e80941Smrg
814b8e80941Smrg   VkSurfaceCapabilities2KHR caps2 = {
815b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
816b8e80941Smrg   };
817b8e80941Smrg
818b8e80941Smrg   VkResult result = iface->get_capabilities2(surface, wsi_device, NULL, &caps2);
819b8e80941Smrg
820b8e80941Smrg   if (result == VK_SUCCESS)
821b8e80941Smrg      *pSurfaceCapabilities = caps2.surfaceCapabilities;
822b8e80941Smrg
823b8e80941Smrg   return result;
824b8e80941Smrg}
825b8e80941Smrg
826b8e80941SmrgVkResult
827b8e80941Smrgwsi_common_get_surface_capabilities2(struct wsi_device *wsi_device,
828b8e80941Smrg                                     const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
829b8e80941Smrg                                     VkSurfaceCapabilities2KHR *pSurfaceCapabilities)
830b8e80941Smrg{
831b8e80941Smrg   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
832b8e80941Smrg   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
833b8e80941Smrg
834b8e80941Smrg   return iface->get_capabilities2(surface, wsi_device, pSurfaceInfo->pNext,
835b8e80941Smrg                                   pSurfaceCapabilities);
836b8e80941Smrg}
837b8e80941Smrg
838b8e80941SmrgVkResult
839b8e80941Smrgwsi_common_get_surface_capabilities2ext(
840b8e80941Smrg   struct wsi_device *wsi_device,
841b8e80941Smrg   VkSurfaceKHR _surface,
842b8e80941Smrg   VkSurfaceCapabilities2EXT *pSurfaceCapabilities)
843b8e80941Smrg{
844b8e80941Smrg   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
845b8e80941Smrg   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
846b8e80941Smrg
847b8e80941Smrg   assert(pSurfaceCapabilities->sType ==
848b8e80941Smrg          VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT);
849b8e80941Smrg
850b8e80941Smrg   struct wsi_surface_supported_counters counters = {
851b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_WSI_SURFACE_SUPPORTED_COUNTERS_MESA,
852b8e80941Smrg      .pNext = pSurfaceCapabilities->pNext,
853b8e80941Smrg      .supported_surface_counters = 0,
854b8e80941Smrg   };
855b8e80941Smrg
856b8e80941Smrg   VkSurfaceCapabilities2KHR caps2 = {
857b8e80941Smrg      .sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR,
858b8e80941Smrg      .pNext = &counters,
859b8e80941Smrg   };
860b8e80941Smrg
861b8e80941Smrg   VkResult result = iface->get_capabilities2(surface, wsi_device, NULL, &caps2);
862b8e80941Smrg
863b8e80941Smrg   if (result == VK_SUCCESS) {
864b8e80941Smrg      VkSurfaceCapabilities2EXT *ext_caps = pSurfaceCapabilities;
865b8e80941Smrg      VkSurfaceCapabilitiesKHR khr_caps = caps2.surfaceCapabilities;
866b8e80941Smrg
867b8e80941Smrg      ext_caps->minImageCount = khr_caps.minImageCount;
868b8e80941Smrg      ext_caps->maxImageCount = khr_caps.maxImageCount;
869b8e80941Smrg      ext_caps->currentExtent = khr_caps.currentExtent;
870b8e80941Smrg      ext_caps->minImageExtent = khr_caps.minImageExtent;
871b8e80941Smrg      ext_caps->maxImageExtent = khr_caps.maxImageExtent;
872b8e80941Smrg      ext_caps->maxImageArrayLayers = khr_caps.maxImageArrayLayers;
873b8e80941Smrg      ext_caps->supportedTransforms = khr_caps.supportedTransforms;
874b8e80941Smrg      ext_caps->currentTransform = khr_caps.currentTransform;
875b8e80941Smrg      ext_caps->supportedCompositeAlpha = khr_caps.supportedCompositeAlpha;
876b8e80941Smrg      ext_caps->supportedUsageFlags = khr_caps.supportedUsageFlags;
877b8e80941Smrg      ext_caps->supportedSurfaceCounters = counters.supported_surface_counters;
878b8e80941Smrg   }
879b8e80941Smrg
880b8e80941Smrg   return result;
881b8e80941Smrg}
882b8e80941Smrg
883b8e80941SmrgVkResult
884b8e80941Smrgwsi_common_get_surface_formats(struct wsi_device *wsi_device,
885b8e80941Smrg                               VkSurfaceKHR _surface,
886b8e80941Smrg                               uint32_t *pSurfaceFormatCount,
887b8e80941Smrg                               VkSurfaceFormatKHR *pSurfaceFormats)
888b8e80941Smrg{
889b8e80941Smrg   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
890b8e80941Smrg   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
891b8e80941Smrg
892b8e80941Smrg   return iface->get_formats(surface, wsi_device,
893b8e80941Smrg                             pSurfaceFormatCount, pSurfaceFormats);
894b8e80941Smrg}
895b8e80941Smrg
896b8e80941SmrgVkResult
897b8e80941Smrgwsi_common_get_surface_formats2(struct wsi_device *wsi_device,
898b8e80941Smrg                                const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo,
899b8e80941Smrg                                uint32_t *pSurfaceFormatCount,
900b8e80941Smrg                                VkSurfaceFormat2KHR *pSurfaceFormats)
901b8e80941Smrg{
902b8e80941Smrg   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface);
903b8e80941Smrg   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
904b8e80941Smrg
905b8e80941Smrg   return iface->get_formats2(surface, wsi_device, pSurfaceInfo->pNext,
906b8e80941Smrg                              pSurfaceFormatCount, pSurfaceFormats);
907b8e80941Smrg}
908b8e80941Smrg
909b8e80941SmrgVkResult
910b8e80941Smrgwsi_common_get_surface_present_modes(struct wsi_device *wsi_device,
911b8e80941Smrg                                     VkSurfaceKHR _surface,
912b8e80941Smrg                                     uint32_t *pPresentModeCount,
913b8e80941Smrg                                     VkPresentModeKHR *pPresentModes)
914b8e80941Smrg{
915b8e80941Smrg   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
916b8e80941Smrg   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
917b8e80941Smrg
918b8e80941Smrg   return iface->get_present_modes(surface, pPresentModeCount,
919b8e80941Smrg                                   pPresentModes);
920b8e80941Smrg}
921b8e80941Smrg
922b8e80941SmrgVkResult
923b8e80941Smrgwsi_common_get_present_rectangles(struct wsi_device *wsi_device,
924b8e80941Smrg                                  VkSurfaceKHR _surface,
925b8e80941Smrg                                  uint32_t* pRectCount,
926b8e80941Smrg                                  VkRect2D* pRects)
927b8e80941Smrg{
928b8e80941Smrg   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface);
929b8e80941Smrg   struct wsi_interface *iface = wsi_device->wsi[surface->platform];
930b8e80941Smrg
931b8e80941Smrg   return iface->get_present_rectangles(surface, wsi_device,
932b8e80941Smrg                                        pRectCount, pRects);
933b8e80941Smrg}
934b8e80941Smrg
935b8e80941SmrgVkResult
936b8e80941Smrgwsi_common_create_swapchain(struct wsi_device *wsi,
937b8e80941Smrg                            VkDevice device,
938b8e80941Smrg                            const VkSwapchainCreateInfoKHR *pCreateInfo,
939b8e80941Smrg                            const VkAllocationCallbacks *pAllocator,
940b8e80941Smrg                            VkSwapchainKHR *pSwapchain)
941b8e80941Smrg{
942b8e80941Smrg   ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface);
943b8e80941Smrg   struct wsi_interface *iface = wsi->wsi[surface->platform];
944b8e80941Smrg   struct wsi_swapchain *swapchain;
945b8e80941Smrg
946b8e80941Smrg   VkResult result = iface->create_swapchain(surface, device, wsi,
947b8e80941Smrg                                             pCreateInfo, pAllocator,
948b8e80941Smrg                                             &swapchain);
949b8e80941Smrg   if (result != VK_SUCCESS)
950b8e80941Smrg      return result;
951b8e80941Smrg
952b8e80941Smrg   *pSwapchain = wsi_swapchain_to_handle(swapchain);
953b8e80941Smrg
954b8e80941Smrg   return VK_SUCCESS;
955b8e80941Smrg}
956b8e80941Smrg
957b8e80941Smrgvoid
958b8e80941Smrgwsi_common_destroy_swapchain(VkDevice device,
959b8e80941Smrg                             VkSwapchainKHR _swapchain,
960b8e80941Smrg                             const VkAllocationCallbacks *pAllocator)
961b8e80941Smrg{
962b8e80941Smrg   WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
963b8e80941Smrg   if (!swapchain)
964b8e80941Smrg      return;
965b8e80941Smrg
966b8e80941Smrg   swapchain->destroy(swapchain, pAllocator);
967b8e80941Smrg}
968b8e80941Smrg
969b8e80941SmrgVkResult
970b8e80941Smrgwsi_common_get_images(VkSwapchainKHR _swapchain,
971b8e80941Smrg                      uint32_t *pSwapchainImageCount,
972b8e80941Smrg                      VkImage *pSwapchainImages)
973b8e80941Smrg{
974b8e80941Smrg   WSI_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain);
975b8e80941Smrg   VK_OUTARRAY_MAKE(images, pSwapchainImages, pSwapchainImageCount);
976b8e80941Smrg
977b8e80941Smrg   for (uint32_t i = 0; i < swapchain->image_count; i++) {
978b8e80941Smrg      vk_outarray_append(&images, image) {
979b8e80941Smrg         *image = swapchain->get_wsi_image(swapchain, i)->image;
980b8e80941Smrg      }
981b8e80941Smrg   }
982b8e80941Smrg
983b8e80941Smrg   return vk_outarray_status(&images);
984b8e80941Smrg}
985b8e80941Smrg
986b8e80941SmrgVkResult
987b8e80941Smrgwsi_common_acquire_next_image2(const struct wsi_device *wsi,
988b8e80941Smrg                               VkDevice device,
989b8e80941Smrg                               const VkAcquireNextImageInfoKHR *pAcquireInfo,
990b8e80941Smrg                               uint32_t *pImageIndex)
991b8e80941Smrg{
992b8e80941Smrg   WSI_FROM_HANDLE(wsi_swapchain, swapchain, pAcquireInfo->swapchain);
993b8e80941Smrg
994b8e80941Smrg   return swapchain->acquire_next_image(swapchain, pAcquireInfo, pImageIndex);
995b8e80941Smrg}
996b8e80941Smrg
997b8e80941SmrgVkResult
998b8e80941Smrgwsi_common_queue_present(const struct wsi_device *wsi,
999b8e80941Smrg                         VkDevice device,
1000b8e80941Smrg                         VkQueue queue,
1001b8e80941Smrg                         int queue_family_index,
1002b8e80941Smrg                         const VkPresentInfoKHR *pPresentInfo)
1003b8e80941Smrg{
1004b8e80941Smrg   VkResult final_result = VK_SUCCESS;
1005b8e80941Smrg
1006b8e80941Smrg   const VkPresentRegionsKHR *regions =
1007b8e80941Smrg      vk_find_struct_const(pPresentInfo->pNext, PRESENT_REGIONS_KHR);
1008b8e80941Smrg
1009b8e80941Smrg   for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
1010b8e80941Smrg      WSI_FROM_HANDLE(wsi_swapchain, swapchain, pPresentInfo->pSwapchains[i]);
1011b8e80941Smrg      VkResult result;
1012b8e80941Smrg
1013b8e80941Smrg      if (swapchain->fences[0] == VK_NULL_HANDLE) {
1014b8e80941Smrg         const VkFenceCreateInfo fence_info = {
1015b8e80941Smrg            .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1016b8e80941Smrg            .pNext = NULL,
1017b8e80941Smrg            .flags = 0,
1018b8e80941Smrg         };
1019b8e80941Smrg         result = wsi->CreateFence(device, &fence_info,
1020b8e80941Smrg                                   &swapchain->alloc,
1021b8e80941Smrg                                   &swapchain->fences[0]);
1022b8e80941Smrg         if (result != VK_SUCCESS)
1023b8e80941Smrg            goto fail_present;
1024b8e80941Smrg      } else {
1025b8e80941Smrg         wsi->ResetFences(device, 1, &swapchain->fences[0]);
1026b8e80941Smrg      }
1027b8e80941Smrg
1028b8e80941Smrg      VkSubmitInfo submit_info = {
1029b8e80941Smrg         .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
1030b8e80941Smrg         .pNext = NULL,
1031b8e80941Smrg      };
1032b8e80941Smrg
1033b8e80941Smrg      VkPipelineStageFlags *stage_flags = NULL;
1034b8e80941Smrg      if (i == 0) {
1035b8e80941Smrg         /* We only need/want to wait on semaphores once.  After that, we're
1036b8e80941Smrg          * guaranteed ordering since it all happens on the same queue.
1037b8e80941Smrg          */
1038b8e80941Smrg         submit_info.waitSemaphoreCount = pPresentInfo->waitSemaphoreCount;
1039b8e80941Smrg         submit_info.pWaitSemaphores = pPresentInfo->pWaitSemaphores;
1040b8e80941Smrg
1041b8e80941Smrg         /* Set up the pWaitDstStageMasks */
1042b8e80941Smrg         stage_flags = vk_alloc(&swapchain->alloc,
1043b8e80941Smrg                                sizeof(VkPipelineStageFlags) *
1044b8e80941Smrg                                pPresentInfo->waitSemaphoreCount,
1045b8e80941Smrg                                8,
1046b8e80941Smrg                                VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
1047b8e80941Smrg         if (!stage_flags) {
1048b8e80941Smrg            result = VK_ERROR_OUT_OF_HOST_MEMORY;
1049b8e80941Smrg            goto fail_present;
1050b8e80941Smrg         }
1051b8e80941Smrg         for (uint32_t s = 0; s < pPresentInfo->waitSemaphoreCount; s++)
1052b8e80941Smrg            stage_flags[s] = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
1053b8e80941Smrg
1054b8e80941Smrg         submit_info.pWaitDstStageMask = stage_flags;
1055b8e80941Smrg      }
1056b8e80941Smrg
1057b8e80941Smrg      if (swapchain->use_prime_blit) {
1058b8e80941Smrg         /* If we are using prime blits, we need to perform the blit now.  The
1059b8e80941Smrg          * command buffer is attached to the image.
1060b8e80941Smrg          */
1061b8e80941Smrg         struct wsi_image *image =
1062b8e80941Smrg            swapchain->get_wsi_image(swapchain, pPresentInfo->pImageIndices[i]);
1063b8e80941Smrg         submit_info.commandBufferCount = 1;
1064b8e80941Smrg         submit_info.pCommandBuffers =
1065b8e80941Smrg            &image->prime.blit_cmd_buffers[queue_family_index];
1066b8e80941Smrg      }
1067b8e80941Smrg
1068b8e80941Smrg      result = wsi->QueueSubmit(queue, 1, &submit_info, swapchain->fences[0]);
1069b8e80941Smrg      vk_free(&swapchain->alloc, stage_flags);
1070b8e80941Smrg      if (result != VK_SUCCESS)
1071b8e80941Smrg         goto fail_present;
1072b8e80941Smrg
1073b8e80941Smrg      const VkPresentRegionKHR *region = NULL;
1074b8e80941Smrg      if (regions && regions->pRegions)
1075b8e80941Smrg         region = &regions->pRegions[i];
1076b8e80941Smrg
1077b8e80941Smrg      result = swapchain->queue_present(swapchain,
1078b8e80941Smrg                                        pPresentInfo->pImageIndices[i],
1079b8e80941Smrg                                        region);
1080b8e80941Smrg      if (result != VK_SUCCESS)
1081b8e80941Smrg         goto fail_present;
1082b8e80941Smrg
1083b8e80941Smrg      VkFence last = swapchain->fences[2];
1084b8e80941Smrg      swapchain->fences[2] = swapchain->fences[1];
1085b8e80941Smrg      swapchain->fences[1] = swapchain->fences[0];
1086b8e80941Smrg      swapchain->fences[0] = last;
1087b8e80941Smrg
1088b8e80941Smrg      if (last != VK_NULL_HANDLE) {
1089b8e80941Smrg         wsi->WaitForFences(device, 1, &last, true, 1);
1090b8e80941Smrg      }
1091b8e80941Smrg
1092b8e80941Smrg   fail_present:
1093b8e80941Smrg      if (pPresentInfo->pResults != NULL)
1094b8e80941Smrg         pPresentInfo->pResults[i] = result;
1095b8e80941Smrg
1096b8e80941Smrg      /* Let the final result be our first unsuccessful result */
1097b8e80941Smrg      if (final_result == VK_SUCCESS)
1098b8e80941Smrg         final_result = result;
1099b8e80941Smrg   }
1100b8e80941Smrg
1101b8e80941Smrg   return final_result;
1102b8e80941Smrg}
1103b8e80941Smrg
1104b8e80941Smrguint64_t
1105b8e80941Smrgwsi_common_get_current_time(void)
1106b8e80941Smrg{
1107b8e80941Smrg   struct timespec current;
1108b8e80941Smrg   clock_gettime(CLOCK_MONOTONIC, &current);
1109b8e80941Smrg   return current.tv_nsec + current.tv_sec * 1000000000ull;
1110b8e80941Smrg}
1111