1 /*
2 * Copyright 2021 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 /** VK_EXT_headless_surface */
25
26 #include "util/macros.h"
27 #include "util/hash_table.h"
28 #include "util/timespec.h"
29 #include "util/u_thread.h"
30 #include "util/xmlconfig.h"
31 #include "vk_util.h"
32 #include "vk_enum_to_str.h"
33 #include "vk_instance.h"
34 #include "vk_physical_device.h"
35 #include "wsi_common_entrypoints.h"
36 #include "wsi_common_private.h"
37 #include "wsi_common_queue.h"
38
39 #include "drm-uapi/drm_fourcc.h"
40
41 struct wsi_headless_format {
42 VkFormat format;
43 struct u_vector modifiers;
44 };
45
46 struct wsi_headless {
47 struct wsi_interface base;
48
49 struct wsi_device *wsi;
50
51 const VkAllocationCallbacks *alloc;
52 VkPhysicalDevice physical_device;
53 };
54
55 static VkResult
wsi_headless_surface_get_support(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t queueFamilyIndex,VkBool32 * pSupported)56 wsi_headless_surface_get_support(VkIcdSurfaceBase *surface,
57 struct wsi_device *wsi_device,
58 uint32_t queueFamilyIndex,
59 VkBool32* pSupported)
60 {
61 *pSupported = true;
62
63 return VK_SUCCESS;
64 }
65
66 static const VkPresentModeKHR present_modes[] = {
67 VK_PRESENT_MODE_MAILBOX_KHR,
68 VK_PRESENT_MODE_FIFO_KHR,
69 };
70
71 static VkResult
wsi_headless_surface_get_capabilities(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,VkSurfaceCapabilitiesKHR * caps)72 wsi_headless_surface_get_capabilities(VkIcdSurfaceBase *surface,
73 struct wsi_device *wsi_device,
74 VkSurfaceCapabilitiesKHR* caps)
75 {
76 /* For true mailbox mode, we need at least 4 images:
77 * 1) One to scan out from
78 * 2) One to have queued for scan-out
79 * 3) One to be currently held by the Wayland compositor
80 * 4) One to render to
81 */
82 caps->minImageCount = 4;
83 /* There is no real maximum */
84 caps->maxImageCount = 0;
85
86 caps->currentExtent = (VkExtent2D) { -1, -1 };
87 caps->minImageExtent = (VkExtent2D) { 1, 1 };
88 caps->maxImageExtent = (VkExtent2D) {
89 wsi_device->maxImageDimension2D,
90 wsi_device->maxImageDimension2D,
91 };
92
93 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
94 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
95 caps->maxImageArrayLayers = 1;
96
97 caps->supportedCompositeAlpha =
98 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
99 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
100
101 caps->supportedUsageFlags = wsi_caps_get_image_usage();
102
103 VK_FROM_HANDLE(vk_physical_device, pdevice, wsi_device->pdevice);
104 if (pdevice->supported_extensions.EXT_attachment_feedback_loop_layout)
105 caps->supportedUsageFlags |= VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT;
106
107 return VK_SUCCESS;
108 }
109
110 static VkResult
wsi_headless_surface_get_capabilities2(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,const void * info_next,VkSurfaceCapabilities2KHR * caps)111 wsi_headless_surface_get_capabilities2(VkIcdSurfaceBase *surface,
112 struct wsi_device *wsi_device,
113 const void *info_next,
114 VkSurfaceCapabilities2KHR* caps)
115 {
116 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
117
118 VkResult result =
119 wsi_headless_surface_get_capabilities(surface, wsi_device,
120 &caps->surfaceCapabilities);
121
122 vk_foreach_struct(ext, caps->pNext) {
123 switch (ext->sType) {
124 case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
125 VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;
126 protected->supportsProtected = VK_FALSE;
127 break;
128 }
129
130 default:
131 /* Ignored */
132 break;
133 }
134 }
135
136 return result;
137 }
138
139 static VkResult
wsi_headless_surface_get_formats(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,uint32_t * pSurfaceFormatCount,VkSurfaceFormatKHR * pSurfaceFormats)140 wsi_headless_surface_get_formats(VkIcdSurfaceBase *icd_surface,
141 struct wsi_device *wsi_device,
142 uint32_t* pSurfaceFormatCount,
143 VkSurfaceFormatKHR* pSurfaceFormats)
144 {
145 struct wsi_headless *wsi =
146 (struct wsi_headless *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_HEADLESS];
147
148 VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out, pSurfaceFormats, pSurfaceFormatCount);
149
150 if (wsi->wsi->force_bgra8_unorm_first) {
151 vk_outarray_append_typed(VkSurfaceFormatKHR, &out, out_fmt) {
152 out_fmt->format = VK_FORMAT_B8G8R8A8_UNORM;
153 out_fmt->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
154 }
155 vk_outarray_append_typed(VkSurfaceFormatKHR, &out, out_fmt) {
156 out_fmt->format = VK_FORMAT_R8G8B8A8_UNORM;
157 out_fmt->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
158 }
159 } else {
160 vk_outarray_append_typed(VkSurfaceFormatKHR, &out, out_fmt) {
161 out_fmt->format = VK_FORMAT_R8G8B8A8_UNORM;
162 out_fmt->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
163 }
164 vk_outarray_append_typed(VkSurfaceFormatKHR, &out, out_fmt) {
165 out_fmt->format = VK_FORMAT_B8G8R8A8_UNORM;
166 out_fmt->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
167 }
168 }
169
170 return vk_outarray_status(&out);
171 }
172
173 static VkResult
wsi_headless_surface_get_formats2(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,const void * info_next,uint32_t * pSurfaceFormatCount,VkSurfaceFormat2KHR * pSurfaceFormats)174 wsi_headless_surface_get_formats2(VkIcdSurfaceBase *icd_surface,
175 struct wsi_device *wsi_device,
176 const void *info_next,
177 uint32_t* pSurfaceFormatCount,
178 VkSurfaceFormat2KHR* pSurfaceFormats)
179 {
180 struct wsi_headless *wsi =
181 (struct wsi_headless *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_HEADLESS];
182
183 VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out, pSurfaceFormats, pSurfaceFormatCount);
184
185 if (wsi->wsi->force_bgra8_unorm_first) {
186 vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, out_fmt) {
187 out_fmt->surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM;
188 out_fmt->surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
189 }
190 vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, out_fmt) {
191 out_fmt->surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM;
192 out_fmt->surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
193 }
194 } else {
195 vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, out_fmt) {
196 out_fmt->surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM;
197 out_fmt->surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
198 }
199 vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, out_fmt) {
200 out_fmt->surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM;
201 out_fmt->surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
202 }
203 }
204
205 return vk_outarray_status(&out);
206 }
207
208 static VkResult
wsi_headless_surface_get_present_modes(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t * pPresentModeCount,VkPresentModeKHR * pPresentModes)209 wsi_headless_surface_get_present_modes(VkIcdSurfaceBase *surface,
210 struct wsi_device *wsi_device,
211 uint32_t* pPresentModeCount,
212 VkPresentModeKHR* pPresentModes)
213 {
214 if (pPresentModes == NULL) {
215 *pPresentModeCount = ARRAY_SIZE(present_modes);
216 return VK_SUCCESS;
217 }
218
219 *pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes));
220 typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
221
222 if (*pPresentModeCount < ARRAY_SIZE(present_modes))
223 return VK_INCOMPLETE;
224 else
225 return VK_SUCCESS;
226 }
227
228 static VkResult
wsi_headless_surface_get_present_rectangles(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t * pRectCount,VkRect2D * pRects)229 wsi_headless_surface_get_present_rectangles(VkIcdSurfaceBase *surface,
230 struct wsi_device *wsi_device,
231 uint32_t* pRectCount,
232 VkRect2D* pRects)
233 {
234 VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount);
235
236 vk_outarray_append_typed(VkRect2D, &out, rect) {
237 /* We don't know a size so just return the usual "I don't know." */
238 *rect = (VkRect2D) {
239 .offset = { 0, 0 },
240 .extent = { UINT32_MAX, UINT32_MAX },
241 };
242 }
243
244 return vk_outarray_status(&out);
245 }
246
247 struct wsi_headless_image {
248 struct wsi_image base;
249 bool busy;
250 };
251
252 struct wsi_headless_swapchain {
253 struct wsi_swapchain base;
254
255 VkExtent2D extent;
256 VkFormat vk_format;
257
258 struct u_vector modifiers;
259
260 VkPresentModeKHR present_mode;
261 bool fifo_ready;
262
263 struct wsi_headless_image images[0];
264 };
265 VK_DEFINE_NONDISP_HANDLE_CASTS(wsi_headless_swapchain, base.base, VkSwapchainKHR,
266 VK_OBJECT_TYPE_SWAPCHAIN_KHR)
267
268 static struct wsi_image *
wsi_headless_swapchain_get_wsi_image(struct wsi_swapchain * wsi_chain,uint32_t image_index)269 wsi_headless_swapchain_get_wsi_image(struct wsi_swapchain *wsi_chain,
270 uint32_t image_index)
271 {
272 struct wsi_headless_swapchain *chain =
273 (struct wsi_headless_swapchain *)wsi_chain;
274 return &chain->images[image_index].base;
275 }
276
277 static VkResult
wsi_headless_swapchain_acquire_next_image(struct wsi_swapchain * wsi_chain,const VkAcquireNextImageInfoKHR * info,uint32_t * image_index)278 wsi_headless_swapchain_acquire_next_image(struct wsi_swapchain *wsi_chain,
279 const VkAcquireNextImageInfoKHR *info,
280 uint32_t *image_index)
281 {
282 struct wsi_headless_swapchain *chain =
283 (struct wsi_headless_swapchain *)wsi_chain;
284 struct timespec start_time, end_time;
285 struct timespec rel_timeout;
286
287 timespec_from_nsec(&rel_timeout, info->timeout);
288
289 clock_gettime(CLOCK_MONOTONIC, &start_time);
290 timespec_add(&end_time, &rel_timeout, &start_time);
291
292 while (1) {
293 /* Try to find a free image. */
294 for (uint32_t i = 0; i < chain->base.image_count; i++) {
295 if (!chain->images[i].busy) {
296 /* We found a non-busy image */
297 *image_index = i;
298 chain->images[i].busy = true;
299 return VK_SUCCESS;
300 }
301 }
302
303 /* Check for timeout. */
304 struct timespec current_time;
305 clock_gettime(CLOCK_MONOTONIC, ¤t_time);
306 if (timespec_after(¤t_time, &end_time))
307 return VK_NOT_READY;
308 }
309 }
310
311 static VkResult
wsi_headless_swapchain_queue_present(struct wsi_swapchain * wsi_chain,uint32_t image_index,uint64_t present_id,const VkPresentRegionKHR * damage)312 wsi_headless_swapchain_queue_present(struct wsi_swapchain *wsi_chain,
313 uint32_t image_index,
314 uint64_t present_id,
315 const VkPresentRegionKHR *damage)
316 {
317 struct wsi_headless_swapchain *chain =
318 (struct wsi_headless_swapchain *)wsi_chain;
319
320 assert(image_index < chain->base.image_count);
321
322 chain->images[image_index].busy = false;
323
324 return VK_SUCCESS;
325 }
326
327 static VkResult
wsi_headless_swapchain_destroy(struct wsi_swapchain * wsi_chain,const VkAllocationCallbacks * pAllocator)328 wsi_headless_swapchain_destroy(struct wsi_swapchain *wsi_chain,
329 const VkAllocationCallbacks *pAllocator)
330 {
331 struct wsi_headless_swapchain *chain =
332 (struct wsi_headless_swapchain *)wsi_chain;
333
334 for (uint32_t i = 0; i < chain->base.image_count; i++) {
335 if (chain->images[i].base.image != VK_NULL_HANDLE)
336 wsi_destroy_image(&chain->base, &chain->images[i].base);
337 }
338
339 u_vector_finish(&chain->modifiers);
340
341 wsi_swapchain_finish(&chain->base);
342
343 vk_free(pAllocator, chain);
344
345 return VK_SUCCESS;
346 }
347
348 static const struct VkDrmFormatModifierPropertiesEXT *
get_modifier_props(const struct wsi_image_info * info,uint64_t modifier)349 get_modifier_props(const struct wsi_image_info *info, uint64_t modifier)
350 {
351 for (uint32_t i = 0; i < info->modifier_prop_count; i++) {
352 if (info->modifier_props[i].drmFormatModifier == modifier)
353 return &info->modifier_props[i];
354 }
355 return NULL;
356 }
357
358 static VkResult
wsi_create_null_image_mem(const struct wsi_swapchain * chain,const struct wsi_image_info * info,struct wsi_image * image)359 wsi_create_null_image_mem(const struct wsi_swapchain *chain,
360 const struct wsi_image_info *info,
361 struct wsi_image *image)
362 {
363 const struct wsi_device *wsi = chain->wsi;
364 VkResult result;
365
366 VkMemoryRequirements reqs;
367 wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);
368
369 const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
370 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
371 .pNext = NULL,
372 .image = image->image,
373 .buffer = VK_NULL_HANDLE,
374 };
375 const VkMemoryAllocateInfo memory_info = {
376 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
377 .pNext = &memory_dedicated_info,
378 .allocationSize = reqs.size,
379 .memoryTypeIndex =
380 wsi_select_device_memory_type(wsi, reqs.memoryTypeBits),
381 };
382 result = wsi->AllocateMemory(chain->device, &memory_info,
383 &chain->alloc, &image->memory);
384 if (result != VK_SUCCESS)
385 return result;
386
387 image->dma_buf_fd = -1;
388
389 if (info->drm_mod_list.drmFormatModifierCount > 0) {
390 VkImageDrmFormatModifierPropertiesEXT image_mod_props = {
391 .sType = VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT,
392 };
393 result = wsi->GetImageDrmFormatModifierPropertiesEXT(chain->device,
394 image->image,
395 &image_mod_props);
396 if (result != VK_SUCCESS)
397 return result;
398
399 image->drm_modifier = image_mod_props.drmFormatModifier;
400 assert(image->drm_modifier != DRM_FORMAT_MOD_INVALID);
401
402 const struct VkDrmFormatModifierPropertiesEXT *mod_props =
403 get_modifier_props(info, image->drm_modifier);
404 image->num_planes = mod_props->drmFormatModifierPlaneCount;
405
406 for (uint32_t p = 0; p < image->num_planes; p++) {
407 const VkImageSubresource image_subresource = {
408 .aspectMask = VK_IMAGE_ASPECT_PLANE_0_BIT << p,
409 .mipLevel = 0,
410 .arrayLayer = 0,
411 };
412 VkSubresourceLayout image_layout;
413 wsi->GetImageSubresourceLayout(chain->device, image->image,
414 &image_subresource, &image_layout);
415 image->sizes[p] = image_layout.size;
416 image->row_pitches[p] = image_layout.rowPitch;
417 image->offsets[p] = image_layout.offset;
418 }
419 } else {
420 const VkImageSubresource image_subresource = {
421 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
422 .mipLevel = 0,
423 .arrayLayer = 0,
424 };
425 VkSubresourceLayout image_layout;
426 wsi->GetImageSubresourceLayout(chain->device, image->image,
427 &image_subresource, &image_layout);
428
429 image->drm_modifier = DRM_FORMAT_MOD_INVALID;
430 image->num_planes = 1;
431 image->sizes[0] = reqs.size;
432 image->row_pitches[0] = image_layout.rowPitch;
433 image->offsets[0] = 0;
434 }
435
436 return VK_SUCCESS;
437 }
438
439 static VkResult
wsi_headless_surface_create_swapchain(VkIcdSurfaceBase * icd_surface,VkDevice device,struct wsi_device * wsi_device,const VkSwapchainCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,struct wsi_swapchain ** swapchain_out)440 wsi_headless_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
441 VkDevice device,
442 struct wsi_device *wsi_device,
443 const VkSwapchainCreateInfoKHR* pCreateInfo,
444 const VkAllocationCallbacks* pAllocator,
445 struct wsi_swapchain **swapchain_out)
446 {
447 struct wsi_headless_swapchain *chain;
448 VkResult result;
449
450 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
451
452 int num_images = pCreateInfo->minImageCount;
453
454 size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
455 chain = vk_zalloc(pAllocator, size, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
456 if (chain == NULL)
457 return VK_ERROR_OUT_OF_HOST_MEMORY;
458
459 struct wsi_drm_image_params drm_params = {
460 .base.image_type = WSI_IMAGE_TYPE_DRM,
461 .same_gpu = true,
462 };
463
464 result = wsi_swapchain_init(wsi_device, &chain->base, device,
465 pCreateInfo, &drm_params.base, pAllocator);
466 if (result != VK_SUCCESS) {
467 vk_free(pAllocator, chain);
468 return result;
469 }
470
471 chain->base.destroy = wsi_headless_swapchain_destroy;
472 chain->base.get_wsi_image = wsi_headless_swapchain_get_wsi_image;
473 chain->base.acquire_next_image = wsi_headless_swapchain_acquire_next_image;
474 chain->base.queue_present = wsi_headless_swapchain_queue_present;
475 chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, pCreateInfo);
476 chain->base.image_count = num_images;
477 chain->extent = pCreateInfo->imageExtent;
478 chain->vk_format = pCreateInfo->imageFormat;
479
480 result = wsi_configure_image(&chain->base, pCreateInfo,
481 0, &chain->base.image_info);
482 if (result != VK_SUCCESS) {
483 goto fail;
484 }
485 chain->base.image_info.create_mem = wsi_create_null_image_mem;
486
487
488 for (uint32_t i = 0; i < chain->base.image_count; i++) {
489 result = wsi_create_image(&chain->base, &chain->base.image_info,
490 &chain->images[i].base);
491 if (result != VK_SUCCESS)
492 return result;
493
494 chain->images[i].busy = false;
495 }
496
497 *swapchain_out = &chain->base;
498
499 return VK_SUCCESS;
500
501 fail:
502 wsi_headless_swapchain_destroy(&chain->base, pAllocator);
503
504 return result;
505 }
506
507 VkResult
wsi_headless_init_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc,VkPhysicalDevice physical_device)508 wsi_headless_init_wsi(struct wsi_device *wsi_device,
509 const VkAllocationCallbacks *alloc,
510 VkPhysicalDevice physical_device)
511 {
512 struct wsi_headless *wsi;
513 VkResult result;
514
515 wsi = vk_alloc(alloc, sizeof(*wsi), 8,
516 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
517 if (!wsi) {
518 result = VK_ERROR_OUT_OF_HOST_MEMORY;
519 goto fail;
520 }
521
522 wsi->physical_device = physical_device;
523 wsi->alloc = alloc;
524 wsi->wsi = wsi_device;
525
526 wsi->base.get_support = wsi_headless_surface_get_support;
527 wsi->base.get_capabilities2 = wsi_headless_surface_get_capabilities2;
528 wsi->base.get_formats = wsi_headless_surface_get_formats;
529 wsi->base.get_formats2 = wsi_headless_surface_get_formats2;
530 wsi->base.get_present_modes = wsi_headless_surface_get_present_modes;
531 wsi->base.get_present_rectangles = wsi_headless_surface_get_present_rectangles;
532 wsi->base.create_swapchain = wsi_headless_surface_create_swapchain;
533
534 wsi_device->wsi[VK_ICD_WSI_PLATFORM_HEADLESS] = &wsi->base;
535
536 return VK_SUCCESS;
537
538 fail:
539 wsi_device->wsi[VK_ICD_WSI_PLATFORM_HEADLESS] = NULL;
540
541 return result;
542 }
543
544 void
wsi_headless_finish_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc)545 wsi_headless_finish_wsi(struct wsi_device *wsi_device,
546 const VkAllocationCallbacks *alloc)
547 {
548 struct wsi_headless *wsi =
549 (struct wsi_headless *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_HEADLESS];
550 if (!wsi)
551 return;
552
553 vk_free(alloc, wsi);
554 }
555
wsi_CreateHeadlessSurfaceEXT(VkInstance _instance,const VkHeadlessSurfaceCreateInfoEXT * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSurfaceKHR * pSurface)556 VkResult wsi_CreateHeadlessSurfaceEXT(
557 VkInstance _instance,
558 const VkHeadlessSurfaceCreateInfoEXT* pCreateInfo,
559 const VkAllocationCallbacks* pAllocator,
560 VkSurfaceKHR* pSurface)
561 {
562 VK_FROM_HANDLE(vk_instance, instance, _instance);
563 VkIcdSurfaceHeadless *surface;
564
565 surface = vk_alloc2(&instance->alloc, pAllocator, sizeof *surface, 8,
566 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
567 if (surface == NULL)
568 return VK_ERROR_OUT_OF_HOST_MEMORY;
569
570 surface->base.platform = VK_ICD_WSI_PLATFORM_HEADLESS;
571
572 *pSurface = VkIcdSurfaceBase_to_handle(&surface->base);
573 return VK_SUCCESS;
574 }
575