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 40struct wsi_win32; 41 42struct wsi_win32 { 43 struct wsi_interface base; 44 45 struct wsi_device *wsi; 46 47 const VkAllocationCallbacks *alloc; 48 VkPhysicalDevice physical_device; 49}; 50 51struct 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 61struct 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 73VKAPI_ATTR VkBool32 VKAPI_CALL 74wsi_GetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice, 75 uint32_t queueFamilyIndex) 76{ 77 return TRUE; 78} 79 80VKAPI_ATTR VkResult VKAPI_CALL 81wsi_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 107static VkResult 108wsi_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 118static VkResult 119wsi_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 162static VkResult 163wsi_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 192static const struct { 193 VkFormat format; 194} available_surface_formats[] = { 195 { .format = VK_FORMAT_B8G8R8A8_SRGB }, 196 { .format = VK_FORMAT_B8G8R8A8_UNORM }, 197}; 198 199 200static void 201get_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 217static VkResult 218wsi_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 238static VkResult 239wsi_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 261static const VkPresentModeKHR present_modes[] = { 262 //VK_PRESENT_MODE_MAILBOX_KHR, 263 VK_PRESENT_MODE_FIFO_KHR, 264}; 265 266static VkResult 267wsi_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 285static VkResult 286wsi_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 304static VkResult 305wsi_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 347static void 348wsi_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 358static VkResult 359wsi_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 375static struct wsi_image * 376wsi_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 385static VkResult 386wsi_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 401static VkResult 402wsi_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 426static VkResult 427wsi_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 500fail_init_images: 501 return result; 502} 503 504 505VkResult 506wsi_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 536fail: 537 wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = NULL; 538 539 return result; 540} 541 542void 543wsi_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