1 /*
2 * Copyright © 2015 Intel Corporation
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 DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "vk_format.h"
30 #include "vk_instance.h"
31 #include "vk_physical_device.h"
32 #include "vk_util.h"
33 #include "wsi_common_entrypoints.h"
34 #include "wsi_common_private.h"
35
36 #if defined(__GNUC__)
37 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
38 #endif
39
40 struct wsi_win32;
41
42 struct wsi_win32 {
43 struct wsi_interface base;
44
45 struct wsi_device *wsi;
46
47 const VkAllocationCallbacks *alloc;
48 VkPhysicalDevice physical_device;
49 };
50
51 struct wsi_win32_image {
52 struct wsi_image base;
53 struct wsi_win32_swapchain *chain;
54 HDC dc;
55 HBITMAP bmp;
56 int bmp_row_pitch;
57 void *ppvBits;
58 };
59
60
61 struct wsi_win32_swapchain {
62 struct wsi_swapchain base;
63 struct wsi_win32 *wsi;
64 VkIcdSurfaceWin32 *surface;
65 uint64_t flip_sequence;
66 VkResult status;
67 VkExtent2D extent;
68 HWND wnd;
69 HDC chain_dc;
70 struct wsi_win32_image images[0];
71 };
72
73 VKAPI_ATTR VkBool32 VKAPI_CALL
wsi_GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex)74 wsi_GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
75 uint32_t queueFamilyIndex)
76 {
77 return TRUE;
78 }
79
80 VKAPI_ATTR VkResult VKAPI_CALL
wsi_CreateWin32SurfaceKHR(VkInstance _instance,const VkWin32SurfaceCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSurfaceKHR * pSurface)81 wsi_CreateWin32SurfaceKHR(VkInstance _instance,
82 const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
83 const VkAllocationCallbacks *pAllocator,
84 VkSurfaceKHR *pSurface)
85 {
86 VK_FROM_HANDLE(vk_instance, instance, _instance);
87 VkIcdSurfaceWin32 *surface;
88
89 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR);
90
91 surface = vk_zalloc2(&instance->alloc, pAllocator, sizeof(*surface), 8,
92 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
93
94 if (surface == NULL)
95 return VK_ERROR_OUT_OF_HOST_MEMORY;
96
97 surface->base.platform = VK_ICD_WSI_PLATFORM_WIN32;
98
99 surface->hinstance = pCreateInfo->hinstance;
100 surface->hwnd = pCreateInfo->hwnd;
101
102 *pSurface = VkIcdSurfaceBase_to_handle(&surface->base);
103
104 return VK_SUCCESS;
105 }
106
107 static VkResult
wsi_win32_surface_get_support(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t queueFamilyIndex,VkBool32 * pSupported)108 wsi_win32_surface_get_support(VkIcdSurfaceBase *surface,
109 struct wsi_device *wsi_device,
110 uint32_t queueFamilyIndex,
111 VkBool32* pSupported)
112 {
113 *pSupported = true;
114
115 return VK_SUCCESS;
116 }
117
118 static VkResult
wsi_win32_surface_get_capabilities(VkIcdSurfaceBase * surf,struct wsi_device * wsi_device,VkSurfaceCapabilitiesKHR * caps)119 wsi_win32_surface_get_capabilities(VkIcdSurfaceBase *surf,
120 struct wsi_device *wsi_device,
121 VkSurfaceCapabilitiesKHR* caps)
122 {
123 VkIcdSurfaceWin32 *surface = (VkIcdSurfaceWin32 *)surf;
124
125 RECT win_rect;
126 if (!GetClientRect(surface->hwnd, &win_rect))
127 return VK_ERROR_SURFACE_LOST_KHR;
128
129 caps->minImageCount = 1;
130 /* There is no real maximum */
131 caps->maxImageCount = 0;
132
133 caps->currentExtent = (VkExtent2D) {
134 win_rect.right - win_rect.left,
135 win_rect.bottom - win_rect.top
136 };
137 caps->minImageExtent = (VkExtent2D) { 1, 1 };
138 caps->maxImageExtent = (VkExtent2D) {
139 wsi_device->maxImageDimension2D,
140 wsi_device->maxImageDimension2D,
141 };
142
143 caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
144 caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
145 caps->maxImageArrayLayers = 1;
146
147 caps->supportedCompositeAlpha =
148 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
149 VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
150
151 caps->supportedUsageFlags =
152 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
153 VK_IMAGE_USAGE_SAMPLED_BIT |
154 VK_IMAGE_USAGE_TRANSFER_DST_BIT |
155 VK_IMAGE_USAGE_STORAGE_BIT |
156 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
157 VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
158
159 return VK_SUCCESS;
160 }
161
162 static VkResult
wsi_win32_surface_get_capabilities2(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,const void * info_next,VkSurfaceCapabilities2KHR * caps)163 wsi_win32_surface_get_capabilities2(VkIcdSurfaceBase *surface,
164 struct wsi_device *wsi_device,
165 const void *info_next,
166 VkSurfaceCapabilities2KHR* caps)
167 {
168 assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
169
170 VkResult result =
171 wsi_win32_surface_get_capabilities(surface, wsi_device,
172 &caps->surfaceCapabilities);
173
174 vk_foreach_struct(ext, caps->pNext) {
175 switch (ext->sType) {
176 case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
177 VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;
178 protected->supportsProtected = VK_FALSE;
179 break;
180 }
181
182 default:
183 /* Ignored */
184 break;
185 }
186 }
187
188 return result;
189 }
190
191
192 static const struct {
193 VkFormat format;
194 } available_surface_formats[] = {
195 { .format = VK_FORMAT_B8G8R8A8_SRGB },
196 { .format = VK_FORMAT_B8G8R8A8_UNORM },
197 };
198
199
200 static void
get_sorted_vk_formats(struct wsi_device * wsi_device,VkFormat * sorted_formats)201 get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats)
202 {
203 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++)
204 sorted_formats[i] = available_surface_formats[i].format;
205
206 if (wsi_device->force_bgra8_unorm_first) {
207 for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
208 if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) {
209 sorted_formats[i] = sorted_formats[0];
210 sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM;
211 break;
212 }
213 }
214 }
215 }
216
217 static VkResult
wsi_win32_surface_get_formats(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,uint32_t * pSurfaceFormatCount,VkSurfaceFormatKHR * pSurfaceFormats)218 wsi_win32_surface_get_formats(VkIcdSurfaceBase *icd_surface,
219 struct wsi_device *wsi_device,
220 uint32_t* pSurfaceFormatCount,
221 VkSurfaceFormatKHR* pSurfaceFormats)
222 {
223 VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out, pSurfaceFormats, pSurfaceFormatCount);
224
225 VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
226 get_sorted_vk_formats(wsi_device, sorted_formats);
227
228 for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
229 vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) {
230 f->format = sorted_formats[i];
231 f->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
232 }
233 }
234
235 return vk_outarray_status(&out);
236 }
237
238 static VkResult
wsi_win32_surface_get_formats2(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,const void * info_next,uint32_t * pSurfaceFormatCount,VkSurfaceFormat2KHR * pSurfaceFormats)239 wsi_win32_surface_get_formats2(VkIcdSurfaceBase *icd_surface,
240 struct wsi_device *wsi_device,
241 const void *info_next,
242 uint32_t* pSurfaceFormatCount,
243 VkSurfaceFormat2KHR* pSurfaceFormats)
244 {
245 VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out, pSurfaceFormats, pSurfaceFormatCount);
246
247 VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
248 get_sorted_vk_formats(wsi_device, sorted_formats);
249
250 for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
251 vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) {
252 assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
253 f->surfaceFormat.format = sorted_formats[i];
254 f->surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
255 }
256 }
257
258 return vk_outarray_status(&out);
259 }
260
261 static const VkPresentModeKHR present_modes[] = {
262 //VK_PRESENT_MODE_MAILBOX_KHR,
263 VK_PRESENT_MODE_FIFO_KHR,
264 };
265
266 static VkResult
wsi_win32_surface_get_present_modes(VkIcdSurfaceBase * surface,uint32_t * pPresentModeCount,VkPresentModeKHR * pPresentModes)267 wsi_win32_surface_get_present_modes(VkIcdSurfaceBase *surface,
268 uint32_t* pPresentModeCount,
269 VkPresentModeKHR* pPresentModes)
270 {
271 if (pPresentModes == NULL) {
272 *pPresentModeCount = ARRAY_SIZE(present_modes);
273 return VK_SUCCESS;
274 }
275
276 *pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes));
277 typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
278
279 if (*pPresentModeCount < ARRAY_SIZE(present_modes))
280 return VK_INCOMPLETE;
281 else
282 return VK_SUCCESS;
283 }
284
285 static VkResult
wsi_win32_surface_get_present_rectangles(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t * pRectCount,VkRect2D * pRects)286 wsi_win32_surface_get_present_rectangles(VkIcdSurfaceBase *surface,
287 struct wsi_device *wsi_device,
288 uint32_t* pRectCount,
289 VkRect2D* pRects)
290 {
291 VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount);
292
293 vk_outarray_append_typed(VkRect2D, &out, rect) {
294 /* We don't know a size so just return the usual "I don't know." */
295 *rect = (VkRect2D) {
296 .offset = { 0, 0 },
297 .extent = { UINT32_MAX, UINT32_MAX },
298 };
299 }
300
301 return vk_outarray_status(&out);
302 }
303
304 static VkResult
wsi_win32_image_init(VkDevice device_h,struct wsi_win32_swapchain * chain,const VkSwapchainCreateInfoKHR * create_info,const VkAllocationCallbacks * allocator,struct wsi_win32_image * image)305 wsi_win32_image_init(VkDevice device_h,
306 struct wsi_win32_swapchain *chain,
307 const VkSwapchainCreateInfoKHR *create_info,
308 const VkAllocationCallbacks *allocator,
309 struct wsi_win32_image *image)
310 {
311 assert(chain->base.use_buffer_blit);
312 VkResult result = wsi_create_image(&chain->base, &chain->base.image_info,
313 &image->base);
314 if (result != VK_SUCCESS)
315 return result;
316
317 VkIcdSurfaceWin32 *win32_surface = (VkIcdSurfaceWin32 *)create_info->surface;
318 chain->wnd = win32_surface->hwnd;
319 chain->chain_dc = GetDC(chain->wnd);
320
321 image->dc = CreateCompatibleDC(chain->chain_dc);
322 HBITMAP bmp = NULL;
323
324 BITMAPINFO info = { 0 };
325 info.bmiHeader.biSize = sizeof(BITMAPINFO);
326 info.bmiHeader.biWidth = create_info->imageExtent.width;
327 info.bmiHeader.biHeight = -create_info->imageExtent.height;
328 info.bmiHeader.biPlanes = 1;
329 info.bmiHeader.biBitCount = 32;
330 info.bmiHeader.biCompression = BI_RGB;
331
332 bmp = CreateDIBSection(image->dc, &info, DIB_RGB_COLORS, &image->ppvBits, NULL, 0);
333 assert(bmp && image->ppvBits);
334
335 SelectObject(image->dc, bmp);
336
337 BITMAP header;
338 int status = GetObject(bmp, sizeof(BITMAP), &header);
339 (void)status;
340 image->bmp_row_pitch = header.bmWidthBytes;
341 image->bmp = bmp;
342 image->chain = chain;
343
344 return VK_SUCCESS;
345 }
346
347 static void
wsi_win32_image_finish(struct wsi_win32_swapchain * chain,const VkAllocationCallbacks * allocator,struct wsi_win32_image * image)348 wsi_win32_image_finish(struct wsi_win32_swapchain *chain,
349 const VkAllocationCallbacks *allocator,
350 struct wsi_win32_image *image)
351 {
352 DeleteDC(image->dc);
353 if(image->bmp)
354 DeleteObject(image->bmp);
355 wsi_destroy_image(&chain->base, &image->base);
356 }
357
358 static VkResult
wsi_win32_swapchain_destroy(struct wsi_swapchain * drv_chain,const VkAllocationCallbacks * allocator)359 wsi_win32_swapchain_destroy(struct wsi_swapchain *drv_chain,
360 const VkAllocationCallbacks *allocator)
361 {
362 struct wsi_win32_swapchain *chain =
363 (struct wsi_win32_swapchain *) drv_chain;
364
365 for (uint32_t i = 0; i < chain->base.image_count; i++)
366 wsi_win32_image_finish(chain, allocator, &chain->images[i]);
367
368 DeleteDC(chain->chain_dc);
369
370 wsi_swapchain_finish(&chain->base);
371 vk_free(allocator, chain);
372 return VK_SUCCESS;
373 }
374
375 static struct wsi_image *
wsi_win32_get_wsi_image(struct wsi_swapchain * drv_chain,uint32_t image_index)376 wsi_win32_get_wsi_image(struct wsi_swapchain *drv_chain,
377 uint32_t image_index)
378 {
379 struct wsi_win32_swapchain *chain =
380 (struct wsi_win32_swapchain *) drv_chain;
381
382 return &chain->images[image_index].base;
383 }
384
385 static VkResult
wsi_win32_acquire_next_image(struct wsi_swapchain * drv_chain,const VkAcquireNextImageInfoKHR * info,uint32_t * image_index)386 wsi_win32_acquire_next_image(struct wsi_swapchain *drv_chain,
387 const VkAcquireNextImageInfoKHR *info,
388 uint32_t *image_index)
389 {
390 struct wsi_win32_swapchain *chain =
391 (struct wsi_win32_swapchain *)drv_chain;
392
393 /* Bail early if the swapchain is broken */
394 if (chain->status != VK_SUCCESS)
395 return chain->status;
396
397 *image_index = 0;
398 return VK_SUCCESS;
399 }
400
401 static VkResult
wsi_win32_queue_present(struct wsi_swapchain * drv_chain,uint32_t image_index,const VkPresentRegionKHR * damage)402 wsi_win32_queue_present(struct wsi_swapchain *drv_chain,
403 uint32_t image_index,
404 const VkPresentRegionKHR *damage)
405 {
406 struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *) drv_chain;
407 assert(image_index < chain->base.image_count);
408 struct wsi_win32_image *image = &chain->images[image_index];
409
410 assert(chain->base.use_buffer_blit);
411
412 char *ptr = image->base.cpu_map;
413 char *dptr = image->ppvBits;
414
415 for (unsigned h = 0; h < chain->extent.height; h++) {
416 memcpy(dptr, ptr, chain->extent.width * 4);
417 dptr += image->bmp_row_pitch;
418 ptr += image->base.row_pitches[0];
419 }
420 if (!StretchBlt(chain->chain_dc, 0, 0, chain->extent.width, chain->extent.height, image->dc, 0, 0, chain->extent.width, chain->extent.height, SRCCOPY))
421 chain->status = VK_ERROR_MEMORY_MAP_FAILED;
422
423 return chain->status;
424 }
425
426 static VkResult
wsi_win32_surface_create_swapchain(VkIcdSurfaceBase * icd_surface,VkDevice device,struct wsi_device * wsi_device,const VkSwapchainCreateInfoKHR * create_info,const VkAllocationCallbacks * allocator,struct wsi_swapchain ** swapchain_out)427 wsi_win32_surface_create_swapchain(
428 VkIcdSurfaceBase *icd_surface,
429 VkDevice device,
430 struct wsi_device *wsi_device,
431 const VkSwapchainCreateInfoKHR *create_info,
432 const VkAllocationCallbacks *allocator,
433 struct wsi_swapchain **swapchain_out)
434 {
435 VkIcdSurfaceWin32 *surface = (VkIcdSurfaceWin32 *)icd_surface;
436 struct wsi_win32 *wsi =
437 (struct wsi_win32 *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32];
438
439 assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
440
441 const unsigned num_images = create_info->minImageCount;
442 struct wsi_win32_swapchain *chain;
443 size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
444
445 chain = vk_zalloc(allocator, size,
446 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
447
448 if (chain == NULL)
449 return VK_ERROR_OUT_OF_HOST_MEMORY;
450
451 VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
452 create_info, allocator, false);
453 if (result != VK_SUCCESS) {
454 vk_free(allocator, chain);
455 return result;
456 }
457
458 chain->base.destroy = wsi_win32_swapchain_destroy;
459 chain->base.get_wsi_image = wsi_win32_get_wsi_image;
460 chain->base.acquire_next_image = wsi_win32_acquire_next_image;
461 chain->base.queue_present = wsi_win32_queue_present;
462 chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
463 chain->base.image_count = num_images;
464 chain->extent = create_info->imageExtent;
465
466 chain->wsi = wsi;
467 chain->status = VK_SUCCESS;
468
469 chain->surface = surface;
470
471 assert(wsi_device->sw);
472 chain->base.use_buffer_blit = true;
473
474 result = wsi_configure_cpu_image(&chain->base, create_info, NULL /*alloc_shm*/, &chain->base.image_info);
475 if (result != VK_SUCCESS) {
476 vk_free(allocator, chain);
477 goto fail_init_images;
478 }
479
480 for (uint32_t image = 0; image < chain->base.image_count; image++) {
481 result = wsi_win32_image_init(device, chain,
482 create_info, allocator,
483 &chain->images[image]);
484 if (result != VK_SUCCESS) {
485 while (image > 0) {
486 --image;
487 wsi_win32_image_finish(chain, allocator,
488 &chain->images[image]);
489 }
490 wsi_destroy_image_info(&chain->base, &chain->base.image_info);
491 vk_free(allocator, chain);
492 goto fail_init_images;
493 }
494 }
495
496 *swapchain_out = &chain->base;
497
498 return VK_SUCCESS;
499
500 fail_init_images:
501 return result;
502 }
503
504
505 VkResult
wsi_win32_init_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc,VkPhysicalDevice physical_device)506 wsi_win32_init_wsi(struct wsi_device *wsi_device,
507 const VkAllocationCallbacks *alloc,
508 VkPhysicalDevice physical_device)
509 {
510 struct wsi_win32 *wsi;
511 VkResult result;
512
513 wsi = vk_alloc(alloc, sizeof(*wsi), 8,
514 VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
515 if (!wsi) {
516 result = VK_ERROR_OUT_OF_HOST_MEMORY;
517 goto fail;
518 }
519
520 wsi->physical_device = physical_device;
521 wsi->alloc = alloc;
522 wsi->wsi = wsi_device;
523
524 wsi->base.get_support = wsi_win32_surface_get_support;
525 wsi->base.get_capabilities2 = wsi_win32_surface_get_capabilities2;
526 wsi->base.get_formats = wsi_win32_surface_get_formats;
527 wsi->base.get_formats2 = wsi_win32_surface_get_formats2;
528 wsi->base.get_present_modes = wsi_win32_surface_get_present_modes;
529 wsi->base.get_present_rectangles = wsi_win32_surface_get_present_rectangles;
530 wsi->base.create_swapchain = wsi_win32_surface_create_swapchain;
531
532 wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = &wsi->base;
533
534 return VK_SUCCESS;
535
536 fail:
537 wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = NULL;
538
539 return result;
540 }
541
542 void
wsi_win32_finish_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc)543 wsi_win32_finish_wsi(struct wsi_device *wsi_device,
544 const VkAllocationCallbacks *alloc)
545 {
546 struct wsi_win32 *wsi =
547 (struct wsi_win32 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32];
548 if (!wsi)
549 return;
550
551 vk_free(alloc, wsi);
552 }
553