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 #define D3D12_IGNORE_SDK_LAYERS
37 #include <dxgi1_4.h>
38 #include <directx/d3d12.h>
39 #include <dxguids/dxguids.h>
40 
41 #include <dcomp.h>
42 
43 #if defined(__GNUC__)
44 #pragma GCC diagnostic ignored "-Wint-to-pointer-cast"      // warning: cast to pointer from integer of different size
45 #endif
46 
47 struct wsi_win32;
48 
49 struct wsi_win32 {
50    struct wsi_interface                     base;
51 
52    struct wsi_device *wsi;
53 
54    const VkAllocationCallbacks *alloc;
55    VkPhysicalDevice physical_device;
56    struct {
57       IDXGIFactory4 *factory;
58       IDCompositionDevice *dcomp;
59    } dxgi;
60 };
61 
62 enum wsi_win32_image_state {
63    WSI_IMAGE_IDLE,
64    WSI_IMAGE_DRAWING,
65    WSI_IMAGE_QUEUED,
66 };
67 
68 struct wsi_win32_image {
69    struct wsi_image base;
70    enum wsi_win32_image_state state;
71    struct wsi_win32_swapchain *chain;
72    struct {
73       ID3D12Resource *swapchain_res;
74    } dxgi;
75    struct {
76       HDC dc;
77       HBITMAP bmp;
78       int bmp_row_pitch;
79       void *ppvBits;
80    } sw;
81 };
82 
83 struct wsi_win32_surface {
84    VkIcdSurfaceWin32 base;
85 
86    /* The first time a swapchain is created against this surface, a DComp
87     * target/visual will be created for it and that swapchain will be bound.
88     * When a new swapchain is created, we delay changing the visual's content
89     * until that swapchain has completed its first present once, otherwise the
90     * window will flash white. When the currently-bound swapchain is destroyed,
91     * the visual's content is unset.
92     */
93    IDCompositionTarget *target;
94    IDCompositionVisual *visual;
95    struct wsi_win32_swapchain *current_swapchain;
96 };
97 
98 struct wsi_win32_swapchain {
99    struct wsi_swapchain         base;
100    IDXGISwapChain3            *dxgi;
101    struct wsi_win32           *wsi;
102    wsi_win32_surface          *surface;
103    uint64_t                     flip_sequence;
104    VkResult                     status;
105    VkExtent2D                 extent;
106    HWND wnd;
107    HDC chain_dc;
108    struct wsi_win32_image     images[0];
109 };
110 
111 VKAPI_ATTR VkBool32 VKAPI_CALL
wsi_GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,uint32_t queueFamilyIndex)112 wsi_GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice,
113                                                  uint32_t queueFamilyIndex)
114 {
115    return true;
116 }
117 
118 VKAPI_ATTR VkResult VKAPI_CALL
wsi_CreateWin32SurfaceKHR(VkInstance _instance,const VkWin32SurfaceCreateInfoKHR * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSurfaceKHR * pSurface)119 wsi_CreateWin32SurfaceKHR(VkInstance _instance,
120                           const VkWin32SurfaceCreateInfoKHR *pCreateInfo,
121                           const VkAllocationCallbacks *pAllocator,
122                           VkSurfaceKHR *pSurface)
123 {
124    VK_FROM_HANDLE(vk_instance, instance, _instance);
125    wsi_win32_surface *surface;
126 
127    assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR);
128 
129    surface = (wsi_win32_surface *)vk_zalloc2(&instance->alloc, pAllocator, sizeof(*surface), 8,
130                         VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
131 
132    if (surface == NULL)
133       return VK_ERROR_OUT_OF_HOST_MEMORY;
134 
135    surface->base.base.platform = VK_ICD_WSI_PLATFORM_WIN32;
136 
137    surface->base.hinstance = pCreateInfo->hinstance;
138    surface->base.hwnd = pCreateInfo->hwnd;
139 
140    *pSurface = VkIcdSurfaceBase_to_handle(&surface->base.base);
141 
142    return VK_SUCCESS;
143 }
144 
145 void
wsi_win32_surface_destroy(VkIcdSurfaceBase * icd_surface,VkInstance _instance,const VkAllocationCallbacks * pAllocator)146 wsi_win32_surface_destroy(VkIcdSurfaceBase *icd_surface, VkInstance _instance,
147                           const VkAllocationCallbacks *pAllocator)
148 {
149    VK_FROM_HANDLE(vk_instance, instance, _instance);
150    wsi_win32_surface *surface = (wsi_win32_surface *)icd_surface;
151    if (surface->visual)
152       surface->visual->Release();
153    if (surface->target)
154       surface->target->Release();
155    vk_free2(&instance->alloc, pAllocator, icd_surface);
156 }
157 
158 static VkResult
wsi_win32_surface_get_support(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t queueFamilyIndex,VkBool32 * pSupported)159 wsi_win32_surface_get_support(VkIcdSurfaceBase *surface,
160                               struct wsi_device *wsi_device,
161                               uint32_t queueFamilyIndex,
162                               VkBool32* pSupported)
163 {
164    *pSupported = true;
165 
166    return VK_SUCCESS;
167 }
168 
169 static VkResult
wsi_win32_surface_get_capabilities(VkIcdSurfaceBase * surf,struct wsi_device * wsi_device,VkSurfaceCapabilitiesKHR * caps)170 wsi_win32_surface_get_capabilities(VkIcdSurfaceBase *surf,
171                                    struct wsi_device *wsi_device,
172                                    VkSurfaceCapabilitiesKHR* caps)
173 {
174    VkIcdSurfaceWin32 *surface = (VkIcdSurfaceWin32 *)surf;
175 
176    RECT win_rect;
177    if (!GetClientRect(surface->hwnd, &win_rect))
178       return VK_ERROR_SURFACE_LOST_KHR;
179 
180    caps->minImageCount = 1;
181 
182    if (!wsi_device->sw && wsi_device->win32.get_d3d12_command_queue) {
183       /* DXGI doesn't support random presenting order (images need to
184        * be presented in the order they were acquired), so we can't
185        * expose more than two image per swapchain.
186        */
187       caps->minImageCount = caps->maxImageCount = 2;
188    } else {
189       caps->minImageCount = 1;
190       /* Software callbacke, there is no real maximum */
191       caps->maxImageCount = 0;
192    }
193 
194    caps->currentExtent = {
195       (uint32_t)win_rect.right - (uint32_t)win_rect.left,
196       (uint32_t)win_rect.bottom - (uint32_t)win_rect.top
197    };
198    caps->minImageExtent = { 1u, 1u };
199    caps->maxImageExtent = {
200       wsi_device->maxImageDimension2D,
201       wsi_device->maxImageDimension2D,
202    };
203 
204    caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
205    caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
206    caps->maxImageArrayLayers = 1;
207 
208    caps->supportedCompositeAlpha =
209       VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
210       VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
211 
212    caps->supportedUsageFlags =
213       VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
214       VK_IMAGE_USAGE_SAMPLED_BIT |
215       VK_IMAGE_USAGE_TRANSFER_DST_BIT |
216       VK_IMAGE_USAGE_STORAGE_BIT |
217       VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
218       VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
219 
220    VK_FROM_HANDLE(vk_physical_device, pdevice, wsi_device->pdevice);
221    if (pdevice->supported_extensions.EXT_attachment_feedback_loop_layout)
222       caps->supportedUsageFlags |= VK_IMAGE_USAGE_ATTACHMENT_FEEDBACK_LOOP_BIT_EXT;
223 
224    return VK_SUCCESS;
225 }
226 
227 static VkResult
wsi_win32_surface_get_capabilities2(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,const void * info_next,VkSurfaceCapabilities2KHR * caps)228 wsi_win32_surface_get_capabilities2(VkIcdSurfaceBase *surface,
229                                     struct wsi_device *wsi_device,
230                                     const void *info_next,
231                                     VkSurfaceCapabilities2KHR* caps)
232 {
233    assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);
234 
235    const VkSurfacePresentModeEXT *present_mode =
236       (const VkSurfacePresentModeEXT *)vk_find_struct_const(info_next, SURFACE_PRESENT_MODE_EXT);
237 
238    VkResult result =
239       wsi_win32_surface_get_capabilities(surface, wsi_device,
240                                       &caps->surfaceCapabilities);
241 
242    vk_foreach_struct(ext, caps->pNext) {
243       switch (ext->sType) {
244       case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {
245          VkSurfaceProtectedCapabilitiesKHR *protected_cap = (VkSurfaceProtectedCapabilitiesKHR *)ext;
246          protected_cap->supportsProtected = VK_FALSE;
247          break;
248       }
249 
250       case VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT: {
251          /* Unsupported. */
252          VkSurfacePresentScalingCapabilitiesEXT *scaling =
253             (VkSurfacePresentScalingCapabilitiesEXT *)ext;
254          scaling->supportedPresentScaling = 0;
255          scaling->supportedPresentGravityX = 0;
256          scaling->supportedPresentGravityY = 0;
257          scaling->minScaledImageExtent = caps->surfaceCapabilities.minImageExtent;
258          scaling->maxScaledImageExtent = caps->surfaceCapabilities.maxImageExtent;
259          break;
260       }
261 
262       case VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT: {
263          /* Unsupported, just report the input present mode. */
264          VkSurfacePresentModeCompatibilityEXT *compat =
265             (VkSurfacePresentModeCompatibilityEXT *)ext;
266          if (compat->pPresentModes) {
267             if (compat->presentModeCount) {
268                assert(present_mode);
269                compat->pPresentModes[0] = present_mode->presentMode;
270                compat->presentModeCount = 1;
271             }
272          } else {
273             if (!present_mode)
274                wsi_common_vk_warn_once("Use of VkSurfacePresentModeCompatibilityEXT "
275                                        "without a VkSurfacePresentModeEXT set. This is an "
276                                        "application bug.\n");
277             compat->presentModeCount = 1;
278          }
279          break;
280       }
281 
282       default:
283          /* Ignored */
284          break;
285       }
286    }
287 
288    return result;
289 }
290 
291 
292 static const struct {
293    VkFormat     format;
294 } available_surface_formats[] = {
295    { VK_FORMAT_B8G8R8A8_SRGB },
296    { VK_FORMAT_B8G8R8A8_UNORM },
297 };
298 
299 
300 static void
get_sorted_vk_formats(struct wsi_device * wsi_device,VkFormat * sorted_formats)301 get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats)
302 {
303    for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++)
304       sorted_formats[i] = available_surface_formats[i].format;
305 
306    if (wsi_device->force_bgra8_unorm_first) {
307       for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {
308          if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) {
309             sorted_formats[i] = sorted_formats[0];
310             sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM;
311             break;
312          }
313       }
314    }
315 }
316 
317 static VkResult
wsi_win32_surface_get_formats(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,uint32_t * pSurfaceFormatCount,VkSurfaceFormatKHR * pSurfaceFormats)318 wsi_win32_surface_get_formats(VkIcdSurfaceBase *icd_surface,
319                               struct wsi_device *wsi_device,
320                               uint32_t* pSurfaceFormatCount,
321                               VkSurfaceFormatKHR* pSurfaceFormats)
322 {
323    VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out, pSurfaceFormats, pSurfaceFormatCount);
324 
325    VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
326    get_sorted_vk_formats(wsi_device, sorted_formats);
327 
328    for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
329       vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) {
330          f->format = sorted_formats[i];
331          f->colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
332       }
333    }
334 
335    return vk_outarray_status(&out);
336 }
337 
338 static VkResult
wsi_win32_surface_get_formats2(VkIcdSurfaceBase * icd_surface,struct wsi_device * wsi_device,const void * info_next,uint32_t * pSurfaceFormatCount,VkSurfaceFormat2KHR * pSurfaceFormats)339 wsi_win32_surface_get_formats2(VkIcdSurfaceBase *icd_surface,
340                                struct wsi_device *wsi_device,
341                                const void *info_next,
342                                uint32_t* pSurfaceFormatCount,
343                                VkSurfaceFormat2KHR* pSurfaceFormats)
344 {
345    VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out, pSurfaceFormats, pSurfaceFormatCount);
346 
347    VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];
348    get_sorted_vk_formats(wsi_device, sorted_formats);
349 
350    for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {
351       vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) {
352          assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);
353          f->surfaceFormat.format = sorted_formats[i];
354          f->surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
355       }
356    }
357 
358    return vk_outarray_status(&out);
359 }
360 
361 static const VkPresentModeKHR present_modes_gdi[] = {
362    VK_PRESENT_MODE_FIFO_KHR,
363 };
364 static const VkPresentModeKHR present_modes_dxgi[] = {
365    VK_PRESENT_MODE_IMMEDIATE_KHR,
366    VK_PRESENT_MODE_MAILBOX_KHR,
367    VK_PRESENT_MODE_FIFO_KHR,
368 };
369 
370 static VkResult
wsi_win32_surface_get_present_modes(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t * pPresentModeCount,VkPresentModeKHR * pPresentModes)371 wsi_win32_surface_get_present_modes(VkIcdSurfaceBase *surface,
372                                     struct wsi_device *wsi_device,
373                                     uint32_t* pPresentModeCount,
374                                     VkPresentModeKHR* pPresentModes)
375 {
376    const VkPresentModeKHR *array;
377    size_t array_size;
378    if (wsi_device->sw || !wsi_device->win32.get_d3d12_command_queue) {
379       array = present_modes_gdi;
380       array_size = ARRAY_SIZE(present_modes_gdi);
381    } else {
382       array = present_modes_dxgi;
383       array_size = ARRAY_SIZE(present_modes_dxgi);
384    }
385 
386    if (pPresentModes == NULL) {
387       *pPresentModeCount = array_size;
388       return VK_SUCCESS;
389    }
390 
391    *pPresentModeCount = MIN2(*pPresentModeCount, array_size);
392    typed_memcpy(pPresentModes, array, *pPresentModeCount);
393 
394    if (*pPresentModeCount < array_size)
395       return VK_INCOMPLETE;
396    else
397       return VK_SUCCESS;
398 }
399 
400 static VkResult
wsi_win32_surface_get_present_rectangles(VkIcdSurfaceBase * surface,struct wsi_device * wsi_device,uint32_t * pRectCount,VkRect2D * pRects)401 wsi_win32_surface_get_present_rectangles(VkIcdSurfaceBase *surface,
402                                       struct wsi_device *wsi_device,
403                                       uint32_t* pRectCount,
404                                       VkRect2D* pRects)
405 {
406    VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount);
407 
408    vk_outarray_append_typed(VkRect2D, &out, rect) {
409       /* We don't know a size so just return the usual "I don't know." */
410       *rect = {
411          { 0, 0 },
412          { UINT32_MAX, UINT32_MAX },
413       };
414    }
415 
416    return vk_outarray_status(&out);
417 }
418 
419 static VkResult
wsi_create_dxgi_image_mem(const struct wsi_swapchain * drv_chain,const struct wsi_image_info * info,struct wsi_image * image)420 wsi_create_dxgi_image_mem(const struct wsi_swapchain *drv_chain,
421                           const struct wsi_image_info *info,
422                           struct wsi_image *image)
423 {
424    struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *)drv_chain;
425    const struct wsi_device *wsi = chain->base.wsi;
426 
427    assert(chain->base.blit.type != WSI_SWAPCHAIN_BUFFER_BLIT);
428 
429    struct wsi_win32_image *win32_image =
430       container_of(image, struct wsi_win32_image, base);
431    uint32_t image_idx =
432       ((uintptr_t)win32_image - (uintptr_t)chain->images) /
433       sizeof(*win32_image);
434    if (FAILED(chain->dxgi->GetBuffer(image_idx,
435                                      IID_PPV_ARGS(&win32_image->dxgi.swapchain_res))))
436       return VK_ERROR_OUT_OF_DEVICE_MEMORY;
437 
438    VkResult result =
439       wsi->win32.create_image_memory(chain->base.device,
440                                      win32_image->dxgi.swapchain_res,
441                                      &chain->base.alloc,
442                                      chain->base.blit.type == WSI_SWAPCHAIN_NO_BLIT ?
443                                      &image->memory : &image->blit.memory);
444    if (result != VK_SUCCESS)
445       return result;
446 
447    if (chain->base.blit.type == WSI_SWAPCHAIN_NO_BLIT)
448       return VK_SUCCESS;
449 
450    VkImageCreateInfo create = info->create;
451 
452    create.usage &= ~VK_IMAGE_USAGE_STORAGE_BIT;
453    create.initialLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
454 
455    result = wsi->CreateImage(chain->base.device, &create,
456                              &chain->base.alloc, &image->blit.image);
457    if (result != VK_SUCCESS)
458       return result;
459 
460    result = wsi->BindImageMemory(chain->base.device, image->blit.image,
461                                  image->blit.memory, 0);
462    if (result != VK_SUCCESS)
463       return result;
464 
465    VkMemoryRequirements reqs;
466    wsi->GetImageMemoryRequirements(chain->base.device, image->image, &reqs);
467 
468    const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {
469       VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
470       nullptr,
471       image->blit.image,
472       VK_NULL_HANDLE,
473    };
474    const VkMemoryAllocateInfo memory_info = {
475       VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
476       &memory_dedicated_info,
477       reqs.size,
478       info->select_image_memory_type(wsi, reqs.memoryTypeBits),
479    };
480 
481    return wsi->AllocateMemory(chain->base.device, &memory_info,
482                               &chain->base.alloc, &image->memory);
483 }
484 
485 enum wsi_swapchain_blit_type
wsi_dxgi_image_needs_blit(const struct wsi_device * wsi,const struct wsi_dxgi_image_params * params,VkDevice device)486 wsi_dxgi_image_needs_blit(const struct wsi_device *wsi,
487                           const struct wsi_dxgi_image_params *params,
488                           VkDevice device)
489 {
490    if (wsi->win32.requires_blits && wsi->win32.requires_blits(device))
491       return WSI_SWAPCHAIN_IMAGE_BLIT;
492    else if (params->storage_image)
493       return WSI_SWAPCHAIN_IMAGE_BLIT;
494    return WSI_SWAPCHAIN_NO_BLIT;
495 }
496 
497 VkResult
wsi_dxgi_configure_image(const struct wsi_swapchain * chain,const VkSwapchainCreateInfoKHR * pCreateInfo,const struct wsi_dxgi_image_params * params,struct wsi_image_info * info)498 wsi_dxgi_configure_image(const struct wsi_swapchain *chain,
499                          const VkSwapchainCreateInfoKHR *pCreateInfo,
500                          const struct wsi_dxgi_image_params *params,
501                          struct wsi_image_info *info)
502 {
503    VkResult result =
504       wsi_configure_image(chain, pCreateInfo, 0, info);
505    if (result != VK_SUCCESS)
506       return result;
507 
508    info->create_mem = wsi_create_dxgi_image_mem;
509 
510    if (chain->blit.type != WSI_SWAPCHAIN_NO_BLIT) {
511       wsi_configure_image_blit_image(chain, info);
512       info->select_image_memory_type = wsi_select_device_memory_type;
513       info->select_blit_dst_memory_type = wsi_select_device_memory_type;
514    }
515 
516    return VK_SUCCESS;
517 }
518 
519 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)520 wsi_win32_image_init(VkDevice device_h,
521                      struct wsi_win32_swapchain *chain,
522                      const VkSwapchainCreateInfoKHR *create_info,
523                      const VkAllocationCallbacks *allocator,
524                      struct wsi_win32_image *image)
525 {
526    VkResult result = wsi_create_image(&chain->base, &chain->base.image_info,
527                                       &image->base);
528    if (result != VK_SUCCESS)
529       return result;
530 
531    VkIcdSurfaceWin32 *win32_surface = (VkIcdSurfaceWin32 *)create_info->surface;
532    chain->wnd = win32_surface->hwnd;
533    image->chain = chain;
534 
535    if (chain->dxgi)
536       return VK_SUCCESS;
537 
538    chain->chain_dc = GetDC(chain->wnd);
539    image->sw.dc = CreateCompatibleDC(chain->chain_dc);
540    HBITMAP bmp = NULL;
541 
542    BITMAPINFO info = { 0 };
543    info.bmiHeader.biSize = sizeof(BITMAPINFO);
544    info.bmiHeader.biWidth = create_info->imageExtent.width;
545    info.bmiHeader.biHeight = -create_info->imageExtent.height;
546    info.bmiHeader.biPlanes = 1;
547    info.bmiHeader.biBitCount = 32;
548    info.bmiHeader.biCompression = BI_RGB;
549 
550    bmp = CreateDIBSection(image->sw.dc, &info, DIB_RGB_COLORS, &image->sw.ppvBits, NULL, 0);
551    assert(bmp && image->sw.ppvBits);
552 
553    SelectObject(image->sw.dc, bmp);
554 
555    BITMAP header;
556    int status = GetObject(bmp, sizeof(BITMAP), &header);
557    (void)status;
558    image->sw.bmp_row_pitch = header.bmWidthBytes;
559    image->sw.bmp = bmp;
560 
561    return VK_SUCCESS;
562 }
563 
564 static void
wsi_win32_image_finish(struct wsi_win32_swapchain * chain,const VkAllocationCallbacks * allocator,struct wsi_win32_image * image)565 wsi_win32_image_finish(struct wsi_win32_swapchain *chain,
566                        const VkAllocationCallbacks *allocator,
567                        struct wsi_win32_image *image)
568 {
569    if (image->dxgi.swapchain_res)
570       image->dxgi.swapchain_res->Release();
571 
572    if (image->sw.dc)
573       DeleteDC(image->sw.dc);
574    if(image->sw.bmp)
575       DeleteObject(image->sw.bmp);
576    wsi_destroy_image(&chain->base, &image->base);
577 }
578 
579 static VkResult
wsi_win32_swapchain_destroy(struct wsi_swapchain * drv_chain,const VkAllocationCallbacks * allocator)580 wsi_win32_swapchain_destroy(struct wsi_swapchain *drv_chain,
581                             const VkAllocationCallbacks *allocator)
582 {
583    struct wsi_win32_swapchain *chain =
584       (struct wsi_win32_swapchain *) drv_chain;
585 
586    for (uint32_t i = 0; i < chain->base.image_count; i++)
587       wsi_win32_image_finish(chain, allocator, &chain->images[i]);
588 
589    DeleteDC(chain->chain_dc);
590 
591    if (chain->surface->current_swapchain == chain)
592       chain->surface->current_swapchain = NULL;
593 
594    if (chain->dxgi)
595       chain->dxgi->Release();
596 
597    wsi_swapchain_finish(&chain->base);
598    vk_free(allocator, chain);
599    return VK_SUCCESS;
600 }
601 
602 static struct wsi_image *
wsi_win32_get_wsi_image(struct wsi_swapchain * drv_chain,uint32_t image_index)603 wsi_win32_get_wsi_image(struct wsi_swapchain *drv_chain,
604                         uint32_t image_index)
605 {
606    struct wsi_win32_swapchain *chain =
607       (struct wsi_win32_swapchain *) drv_chain;
608 
609    return &chain->images[image_index].base;
610 }
611 
612 static VkResult
wsi_win32_release_images(struct wsi_swapchain * drv_chain,uint32_t count,const uint32_t * indices)613 wsi_win32_release_images(struct wsi_swapchain *drv_chain,
614                          uint32_t count, const uint32_t *indices)
615 {
616    struct wsi_win32_swapchain *chain =
617       (struct wsi_win32_swapchain *)drv_chain;
618 
619    if (chain->status == VK_ERROR_SURFACE_LOST_KHR)
620       return chain->status;
621 
622    for (uint32_t i = 0; i < count; i++) {
623       uint32_t index = indices[i];
624       assert(index < chain->base.image_count);
625       assert(chain->images[index].state == WSI_IMAGE_DRAWING);
626       chain->images[index].state = WSI_IMAGE_IDLE;
627    }
628 
629    return VK_SUCCESS;
630 }
631 
632 
633 static VkResult
wsi_win32_acquire_next_image(struct wsi_swapchain * drv_chain,const VkAcquireNextImageInfoKHR * info,uint32_t * image_index)634 wsi_win32_acquire_next_image(struct wsi_swapchain *drv_chain,
635                              const VkAcquireNextImageInfoKHR *info,
636                              uint32_t *image_index)
637 {
638    struct wsi_win32_swapchain *chain =
639       (struct wsi_win32_swapchain *)drv_chain;
640 
641    /* Bail early if the swapchain is broken */
642    if (chain->status != VK_SUCCESS)
643       return chain->status;
644 
645    for (uint32_t i = 0; i < chain->base.image_count; i++) {
646       if (chain->images[i].state == WSI_IMAGE_IDLE) {
647          *image_index = i;
648          chain->images[i].state = WSI_IMAGE_DRAWING;
649          return VK_SUCCESS;
650       }
651    }
652 
653    assert(chain->dxgi);
654    uint32_t index = chain->dxgi->GetCurrentBackBufferIndex();
655    if (chain->images[index].state == WSI_IMAGE_DRAWING) {
656       index = (index + 1) % chain->base.image_count;
657       assert(chain->images[index].state == WSI_IMAGE_QUEUED);
658    }
659    if (chain->wsi->wsi->WaitForFences(chain->base.device, 1,
660                                       &chain->base.fences[index],
661                                       false, info->timeout) != VK_SUCCESS)
662       return VK_TIMEOUT;
663 
664    *image_index = index;
665    chain->images[index].state = WSI_IMAGE_DRAWING;
666    return VK_SUCCESS;
667 }
668 
669 static VkResult
wsi_win32_queue_present_dxgi(struct wsi_win32_swapchain * chain,struct wsi_win32_image * image,const VkPresentRegionKHR * damage)670 wsi_win32_queue_present_dxgi(struct wsi_win32_swapchain *chain,
671                              struct wsi_win32_image *image,
672                              const VkPresentRegionKHR *damage)
673 {
674    uint32_t rect_count = damage ? damage->rectangleCount : 0;
675    STACK_ARRAY(RECT, rects, rect_count);
676 
677    for (uint32_t r = 0; r < rect_count; r++) {
678       rects[r].left = damage->pRectangles[r].offset.x;
679       rects[r].top = damage->pRectangles[r].offset.y;
680       rects[r].right = damage->pRectangles[r].offset.x + damage->pRectangles[r].extent.width;
681       rects[r].bottom = damage->pRectangles[r].offset.y + damage->pRectangles[r].extent.height;
682    }
683 
684    DXGI_PRESENT_PARAMETERS params = {
685       rect_count,
686       rects,
687    };
688 
689    image->state = WSI_IMAGE_QUEUED;
690    UINT sync_interval = chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR ? 1 : 0;
691    UINT present_flags = chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR ?
692       DXGI_PRESENT_ALLOW_TEARING : 0;
693 
694    HRESULT hres = chain->dxgi->Present1(sync_interval, present_flags, &params);
695    switch (hres) {
696    case DXGI_ERROR_DEVICE_REMOVED: return VK_ERROR_DEVICE_LOST;
697    case E_OUTOFMEMORY: return VK_ERROR_OUT_OF_DEVICE_MEMORY;
698    default:
699       if (FAILED(hres))
700          return VK_ERROR_OUT_OF_HOST_MEMORY;
701       break;
702    }
703 
704    if (chain->surface->current_swapchain != chain) {
705       chain->surface->visual->SetContent(chain->dxgi);
706       chain->wsi->dxgi.dcomp->Commit();
707       chain->surface->current_swapchain = chain;
708    }
709 
710    /* Mark the other image idle */
711    chain->status = VK_SUCCESS;
712    return VK_SUCCESS;
713 }
714 
715 static VkResult
wsi_win32_queue_present(struct wsi_swapchain * drv_chain,uint32_t image_index,uint64_t present_id,const VkPresentRegionKHR * damage)716 wsi_win32_queue_present(struct wsi_swapchain *drv_chain,
717                         uint32_t image_index,
718                         uint64_t present_id,
719                         const VkPresentRegionKHR *damage)
720 {
721    struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *) drv_chain;
722    assert(image_index < chain->base.image_count);
723    struct wsi_win32_image *image = &chain->images[image_index];
724 
725    assert(image->state == WSI_IMAGE_DRAWING);
726 
727    if (chain->dxgi)
728       return wsi_win32_queue_present_dxgi(chain, image, damage);
729 
730    char *ptr = (char *)image->base.cpu_map;
731    char *dptr = (char *)image->sw.ppvBits;
732 
733    for (unsigned h = 0; h < chain->extent.height; h++) {
734       memcpy(dptr, ptr, chain->extent.width * 4);
735       dptr += image->sw.bmp_row_pitch;
736       ptr += image->base.row_pitches[0];
737    }
738    if (!StretchBlt(chain->chain_dc, 0, 0, chain->extent.width, chain->extent.height, image->sw.dc, 0, 0, chain->extent.width, chain->extent.height, SRCCOPY))
739       chain->status = VK_ERROR_MEMORY_MAP_FAILED;
740 
741    image->state = WSI_IMAGE_IDLE;
742 
743    return chain->status;
744 }
745 
746 static VkResult
wsi_win32_surface_create_swapchain_dxgi(wsi_win32_surface * surface,VkDevice device,struct wsi_win32 * wsi,const VkSwapchainCreateInfoKHR * create_info,struct wsi_win32_swapchain * chain)747 wsi_win32_surface_create_swapchain_dxgi(
748    wsi_win32_surface *surface,
749    VkDevice device,
750    struct wsi_win32 *wsi,
751    const VkSwapchainCreateInfoKHR *create_info,
752    struct wsi_win32_swapchain *chain)
753 {
754    IDXGIFactory4 *factory = wsi->dxgi.factory;
755    ID3D12CommandQueue *queue =
756       (ID3D12CommandQueue *)wsi->wsi->win32.get_d3d12_command_queue(device);
757 
758    DXGI_SWAP_CHAIN_DESC1 desc = {
759       create_info->imageExtent.width,
760       create_info->imageExtent.height,
761       DXGI_FORMAT_B8G8R8A8_UNORM,
762       create_info->imageArrayLayers > 1,  // Stereo
763       { 1 },                              // SampleDesc
764       0,                                  // Usage (filled in below)
765       create_info->minImageCount,
766       DXGI_SCALING_STRETCH,
767       DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL,
768       DXGI_ALPHA_MODE_UNSPECIFIED,
769       chain->base.present_mode == VK_PRESENT_MODE_IMMEDIATE_KHR ?
770          DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0u
771    };
772 
773    if (create_info->imageUsage &
774        (VK_IMAGE_USAGE_SAMPLED_BIT |
775         VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT))
776       desc.BufferUsage |= DXGI_USAGE_SHADER_INPUT;
777 
778    if (create_info->imageUsage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)
779       desc.BufferUsage |= DXGI_USAGE_RENDER_TARGET_OUTPUT;
780 
781    IDXGISwapChain1 *swapchain1;
782    if (FAILED(factory->CreateSwapChainForComposition(queue, &desc, NULL, &swapchain1)) ||
783        FAILED(swapchain1->QueryInterface(&chain->dxgi)))
784       return VK_ERROR_INITIALIZATION_FAILED;
785 
786    swapchain1->Release();
787 
788    if (!surface->target &&
789        FAILED(wsi->dxgi.dcomp->CreateTargetForHwnd(surface->base.hwnd, false, &surface->target)))
790       return VK_ERROR_INITIALIZATION_FAILED;
791 
792    if (!surface->visual) {
793       if (FAILED(wsi->dxgi.dcomp->CreateVisual(&surface->visual)) ||
794           FAILED(surface->target->SetRoot(surface->visual)) ||
795           FAILED(surface->visual->SetContent(chain->dxgi)) ||
796           FAILED(wsi->dxgi.dcomp->Commit()))
797          return VK_ERROR_INITIALIZATION_FAILED;
798 
799       surface->current_swapchain = chain;
800    }
801    return VK_SUCCESS;
802 }
803 
804 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)805 wsi_win32_surface_create_swapchain(
806    VkIcdSurfaceBase *icd_surface,
807    VkDevice device,
808    struct wsi_device *wsi_device,
809    const VkSwapchainCreateInfoKHR *create_info,
810    const VkAllocationCallbacks *allocator,
811    struct wsi_swapchain **swapchain_out)
812 {
813    wsi_win32_surface *surface = (wsi_win32_surface *)icd_surface;
814    struct wsi_win32 *wsi =
815       (struct wsi_win32 *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32];
816 
817    assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
818 
819    const unsigned num_images = create_info->minImageCount;
820    struct wsi_win32_swapchain *chain;
821    size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
822 
823    chain = (wsi_win32_swapchain *)vk_zalloc(allocator, size,
824                      8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
825 
826    if (chain == NULL)
827       return VK_ERROR_OUT_OF_HOST_MEMORY;
828 
829    struct wsi_dxgi_image_params dxgi_image_params = {
830       { WSI_IMAGE_TYPE_DXGI },
831    };
832    dxgi_image_params.storage_image = (create_info->imageUsage & VK_IMAGE_USAGE_STORAGE_BIT) != 0;
833 
834    struct wsi_cpu_image_params cpu_image_params = {
835       { WSI_IMAGE_TYPE_CPU },
836    };
837 
838    bool supports_dxgi = wsi->dxgi.factory &&
839                         wsi->dxgi.dcomp &&
840                         wsi->wsi->win32.get_d3d12_command_queue;
841    struct wsi_base_image_params *image_params = supports_dxgi ?
842       &dxgi_image_params.base : &cpu_image_params.base;
843 
844    VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,
845                                         create_info, image_params,
846                                         allocator);
847    if (result != VK_SUCCESS) {
848       vk_free(allocator, chain);
849       return result;
850    }
851 
852    chain->base.destroy = wsi_win32_swapchain_destroy;
853    chain->base.get_wsi_image = wsi_win32_get_wsi_image;
854    chain->base.acquire_next_image = wsi_win32_acquire_next_image;
855    chain->base.release_images = wsi_win32_release_images;
856    chain->base.queue_present = wsi_win32_queue_present;
857    chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);
858    chain->extent = create_info->imageExtent;
859 
860    chain->wsi = wsi;
861    chain->status = VK_SUCCESS;
862 
863    chain->surface = surface;
864 
865    if (image_params->image_type == WSI_IMAGE_TYPE_DXGI) {
866       result = wsi_win32_surface_create_swapchain_dxgi(surface, device, wsi, create_info, chain);
867       if (result != VK_SUCCESS)
868          goto fail;
869    }
870 
871    for (uint32_t image = 0; image < num_images; image++) {
872       result = wsi_win32_image_init(device, chain,
873                                     create_info, allocator,
874                                     &chain->images[image]);
875       if (result != VK_SUCCESS)
876          goto fail;
877 
878       chain->base.image_count++;
879    }
880 
881    *swapchain_out = &chain->base;
882 
883    return VK_SUCCESS;
884 
885 fail:
886    if (surface->visual) {
887       surface->visual->SetContent(NULL);
888       surface->current_swapchain = NULL;
889       wsi->dxgi.dcomp->Commit();
890    }
891    wsi_win32_swapchain_destroy(&chain->base, allocator);
892    return result;
893 }
894 
895 static IDXGIFactory4 *
dxgi_get_factory(bool debug)896 dxgi_get_factory(bool debug)
897 {
898    HMODULE dxgi_mod = LoadLibraryA("DXGI.DLL");
899    if (!dxgi_mod) {
900       return NULL;
901    }
902 
903    typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY2)(UINT flags, REFIID riid, void **ppFactory);
904    PFN_CREATE_DXGI_FACTORY2 CreateDXGIFactory2;
905 
906    CreateDXGIFactory2 = (PFN_CREATE_DXGI_FACTORY2)GetProcAddress(dxgi_mod, "CreateDXGIFactory2");
907    if (!CreateDXGIFactory2) {
908       return NULL;
909    }
910 
911    UINT flags = 0;
912    if (debug)
913       flags |= DXGI_CREATE_FACTORY_DEBUG;
914 
915    IDXGIFactory4 *factory;
916    HRESULT hr = CreateDXGIFactory2(flags, IID_PPV_ARGS(&factory));
917    if (FAILED(hr)) {
918       return NULL;
919    }
920 
921    return factory;
922 }
923 
924 static IDCompositionDevice *
dcomp_get_device()925 dcomp_get_device()
926 {
927    HMODULE dcomp_mod = LoadLibraryA("DComp.DLL");
928    if (!dcomp_mod) {
929       return NULL;
930    }
931 
932    typedef HRESULT (STDAPICALLTYPE *PFN_DCOMP_CREATE_DEVICE)(IDXGIDevice *, REFIID, void **);
933    PFN_DCOMP_CREATE_DEVICE DCompositionCreateDevice;
934 
935    DCompositionCreateDevice = (PFN_DCOMP_CREATE_DEVICE)GetProcAddress(dcomp_mod, "DCompositionCreateDevice");
936    if (!DCompositionCreateDevice) {
937       return NULL;
938    }
939 
940    IDCompositionDevice *device;
941    HRESULT hr = DCompositionCreateDevice(NULL, IID_PPV_ARGS(&device));
942    if (FAILED(hr)) {
943       return NULL;
944    }
945 
946    return device;
947 }
948 
949 VkResult
wsi_win32_init_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc,VkPhysicalDevice physical_device)950 wsi_win32_init_wsi(struct wsi_device *wsi_device,
951                    const VkAllocationCallbacks *alloc,
952                    VkPhysicalDevice physical_device)
953 {
954    struct wsi_win32 *wsi;
955    VkResult result;
956 
957    wsi = (wsi_win32 *)vk_zalloc(alloc, sizeof(*wsi), 8,
958                    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
959    if (!wsi) {
960       result = VK_ERROR_OUT_OF_HOST_MEMORY;
961       goto fail;
962    }
963 
964    wsi->physical_device = physical_device;
965    wsi->alloc = alloc;
966    wsi->wsi = wsi_device;
967 
968    if (!wsi_device->sw) {
969       wsi->dxgi.factory = dxgi_get_factory(WSI_DEBUG & WSI_DEBUG_DXGI);
970       if (!wsi->dxgi.factory) {
971          vk_free(alloc, wsi);
972          result = VK_ERROR_INITIALIZATION_FAILED;
973          goto fail;
974       }
975       wsi->dxgi.dcomp = dcomp_get_device();
976       if (!wsi->dxgi.dcomp) {
977          wsi->dxgi.factory->Release();
978          vk_free(alloc, wsi);
979          result = VK_ERROR_INITIALIZATION_FAILED;
980          goto fail;
981       }
982    }
983 
984    wsi->base.get_support = wsi_win32_surface_get_support;
985    wsi->base.get_capabilities2 = wsi_win32_surface_get_capabilities2;
986    wsi->base.get_formats = wsi_win32_surface_get_formats;
987    wsi->base.get_formats2 = wsi_win32_surface_get_formats2;
988    wsi->base.get_present_modes = wsi_win32_surface_get_present_modes;
989    wsi->base.get_present_rectangles = wsi_win32_surface_get_present_rectangles;
990    wsi->base.create_swapchain = wsi_win32_surface_create_swapchain;
991 
992    wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = &wsi->base;
993 
994    return VK_SUCCESS;
995 
996 fail:
997    wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = NULL;
998 
999    return result;
1000 }
1001 
1002 void
wsi_win32_finish_wsi(struct wsi_device * wsi_device,const VkAllocationCallbacks * alloc)1003 wsi_win32_finish_wsi(struct wsi_device *wsi_device,
1004                   const VkAllocationCallbacks *alloc)
1005 {
1006    struct wsi_win32 *wsi =
1007       (struct wsi_win32 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32];
1008    if (!wsi)
1009       return;
1010 
1011    if (wsi->dxgi.factory)
1012       wsi->dxgi.factory->Release();
1013    if (wsi->dxgi.dcomp)
1014       wsi->dxgi.dcomp->Release();
1015 
1016    vk_free(alloc, wsi);
1017 }
1018