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