diff --git a/src/gallium/frontends/lavapipe/lvp_extensions.py b/src/gallium/frontends/lavapipe/lvp_extensions.py index c420333bd7d..ec321e4a229 100644 --- a/src/gallium/frontends/lavapipe/lvp_extensions.py +++ b/src/gallium/frontends/lavapipe/lvp_extensions.py @@ -103,6 +103,7 @@ EXTENSIONS = [ Extension('VK_KHR_uniform_buffer_standard_layout', 1, False), Extension('VK_KHR_variable_pointers', 1, False), Extension('VK_KHR_wayland_surface', 6, 'VK_USE_PLATFORM_WAYLAND_KHR'), + Extension('VK_KHR_win32_surface', 6, 'VK_USE_PLATFORM_WIN32_KHR'), Extension('VK_KHR_xcb_surface', 6, 'VK_USE_PLATFORM_XCB_KHR'), Extension('VK_KHR_xlib_surface', 6, 'VK_USE_PLATFORM_XLIB_KHR'), Extension('VK_EXT_acquire_xlib_display', 1, 'VK_USE_PLATFORM_XLIB_XRANDR_EXT'), diff --git a/src/gallium/frontends/lavapipe/lvp_wsi_win32.c b/src/gallium/frontends/lavapipe/lvp_wsi_win32.c new file mode 100644 index 00000000000..09f284796ce --- /dev/null +++ b/src/gallium/frontends/lavapipe/lvp_wsi_win32.c @@ -0,0 +1,54 @@ +/* + * Copyright © 2016 Red Hat + * based on intel anv code: + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "wsi_common_win32.h" +#include "lvp_private.h" + +VkBool32 VKAPI_CALL lvp_GetPhysicalDeviceWin32PresentationSupportKHR( + VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex) +{ + LVP_FROM_HANDLE(lvp_physical_device, physical_device, physicalDevice); + + return wsi_win32_get_presentation_support(&physical_device->wsi_device); +} + +VkResult VKAPI_CALL lvp_CreateWin32SurfaceKHR( + VkInstance _instance, + const VkWin32SurfaceCreateInfoKHR* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkSurfaceKHR* pSurface) +{ + LVP_FROM_HANDLE(lvp_instance, instance, _instance); + const VkAllocationCallbacks *alloc; + assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR); + + if (pAllocator) + alloc = pAllocator; + else + alloc = &instance->vk.alloc; + + return wsi_create_win32_surface(_instance, alloc, pCreateInfo, pSurface); +} diff --git a/src/gallium/frontends/lavapipe/meson.build b/src/gallium/frontends/lavapipe/meson.build index 40cd4c6b27d..129e538bfed 100644 --- a/src/gallium/frontends/lavapipe/meson.build +++ b/src/gallium/frontends/lavapipe/meson.build @@ -55,6 +55,11 @@ if with_platform_wayland liblvp_files += files('lvp_wsi_wayland.c') endif +if with_platform_windows + lvp_flags += '-DVK_USE_PLATFORM_WIN32_KHR' + liblvp_files += files('lvp_wsi_win32.c') +endif + liblavapipe_st = static_library( 'lavapipe_st', [liblvp_files, lvp_entrypoints, lvp_extensions_c, sha1_h], diff --git a/src/vulkan/meson.build b/src/vulkan/meson.build index 9558a957844..53e7d6a82b5 100644 --- a/src/vulkan/meson.build +++ b/src/vulkan/meson.build @@ -46,6 +46,9 @@ if with_platform_wayland vulkan_wsi_deps += dep_wayland_client vulkan_wsi_list += ['wayland'] endif +if with_platform_windows + vulkan_wsi_args += ['-DVK_USE_PLATFORM_WIN32_KHR'] +endif if system_has_kms_drm and not with_platform_android vulkan_wsi_args += '-DVK_USE_PLATFORM_DISPLAY_KHR' vulkan_wsi_deps += [dep_libdrm] diff --git a/src/vulkan/util/vk_extensions_gen.py b/src/vulkan/util/vk_extensions_gen.py index 2ec31f2deb1..ca3a6a992cb 100644 --- a/src/vulkan/util/vk_extensions_gen.py +++ b/src/vulkan/util/vk_extensions_gen.py @@ -153,7 +153,8 @@ extern const struct vk_device_extension_table vk_android_allowed_device_extensio # define ANDROID_API_LEVEL 0 #endif -#define ${driver.upper()}_HAS_SURFACE (VK_USE_PLATFORM_WAYLAND_KHR || \\ +#define ${driver.upper()}_HAS_SURFACE (VK_USE_PLATFORM_WIN32_KHR || \\ + VK_USE_PLATFORM_WAYLAND_KHR || \\ VK_USE_PLATFORM_XCB_KHR || \\ VK_USE_PLATFORM_XLIB_KHR || \\ VK_USE_PLATFORM_DISPLAY_KHR) diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build index ca948cefb26..1deafa0c5e3 100644 --- a/src/vulkan/wsi/meson.build +++ b/src/vulkan/wsi/meson.build @@ -38,6 +38,10 @@ if with_platform_wayland ] endif +if with_platform_windows + files_vulkan_wsi += files('wsi_common_win32.c') +endif + if system_has_kms_drm and not with_platform_android files_vulkan_wsi += files('wsi_common_display.c') endif diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index c1c4f718bd3..b1360edb911 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -117,6 +117,12 @@ wsi_device_init(struct wsi_device *wsi, goto fail; #endif +#ifdef VK_USE_PLATFORM_WIN32_KHR + result = wsi_win32_init_wsi(wsi, alloc, pdevice); + if (result != VK_SUCCESS) + goto fail; +#endif + #ifdef VK_USE_PLATFORM_DISPLAY_KHR result = wsi_display_init_wsi(wsi, alloc, display_fd); if (result != VK_SUCCESS) @@ -152,6 +158,7 @@ wsi_device_init(struct wsi_device *wsi, return VK_SUCCESS; #if defined(VK_USE_PLATFORM_XCB_KHR) || \ defined(VK_USE_PLATFORM_WAYLAND_KHR) || \ + defined(VK_USE_PLATFORM_WIN32_KHR) || \ defined(VK_USE_PLATFORM_DISPLAY_KHR) fail: wsi_device_finish(wsi, alloc); @@ -169,6 +176,9 @@ wsi_device_finish(struct wsi_device *wsi, #ifdef VK_USE_PLATFORM_WAYLAND_KHR wsi_wl_finish_wsi(wsi, alloc); #endif +#ifdef VK_USE_PLATFORM_WIN32_KHR + wsi_win32_finish_wsi(wsi, alloc); +#endif #ifdef VK_USE_PLATFORM_XCB_KHR wsi_x11_finish_wsi(wsi, alloc); #endif diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h index 4b569d54704..1fe8211f9cb 100644 --- a/src/vulkan/wsi/wsi_common_private.h +++ b/src/vulkan/wsi/wsi_common_private.h @@ -150,6 +150,11 @@ VkResult wsi_wl_init_wsi(struct wsi_device *wsi_device, VkPhysicalDevice physical_device); void wsi_wl_finish_wsi(struct wsi_device *wsi_device, const VkAllocationCallbacks *alloc); +VkResult wsi_win32_init_wsi(struct wsi_device *wsi_device, + const VkAllocationCallbacks *alloc, + VkPhysicalDevice physical_device); +void wsi_win32_finish_wsi(struct wsi_device *wsi_device, + const VkAllocationCallbacks *alloc); VkResult diff --git a/src/vulkan/wsi/wsi_common_win32.c b/src/vulkan/wsi/wsi_common_win32.c new file mode 100644 index 00000000000..fa6f898e590 --- /dev/null +++ b/src/vulkan/wsi/wsi_common_win32.c @@ -0,0 +1,675 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include + +#include "vk_util.h" +#include "wsi_common_private.h" +#include "wsi_common_win32.h" + +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size +#endif + +struct wsi_win32; + +struct wsi_win32 { + struct wsi_interface base; + + struct wsi_device *wsi; + + const VkAllocationCallbacks *alloc; + VkPhysicalDevice physical_device; +}; + +struct wsi_win32_image { + struct wsi_image base; + struct wsi_win32_swapchain *chain; + HDC dc; + HBITMAP bmp; + int bmp_row_pitch; + void *ppvBits; +}; + + +struct wsi_win32_swapchain { + struct wsi_swapchain base; + struct wsi_win32 *wsi; + VkIcdSurfaceWin32 *surface; + uint64_t flip_sequence; + VkResult status; + VkExtent2D extent; + HWND wnd; + HDC chain_dc; + struct wsi_win32_image images[0]; +}; + +VkBool32 +wsi_win32_get_presentation_support(struct wsi_device *wsi_device) +{ + return TRUE; +} + +VkResult +wsi_create_win32_surface(VkInstance instance, + const VkAllocationCallbacks *allocator, + const VkWin32SurfaceCreateInfoKHR *create_info, + VkSurfaceKHR *surface_khr) +{ + VkIcdSurfaceWin32 *surface = vk_zalloc(allocator, sizeof *surface, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (surface == NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + surface->base.platform = VK_ICD_WSI_PLATFORM_WIN32; + + surface->hinstance = create_info->hinstance; + surface->hwnd = create_info->hwnd; + + *surface_khr = VkIcdSurfaceBase_to_handle(&surface->base); + return VK_SUCCESS; +} + +static VkResult +wsi_win32_surface_get_support(VkIcdSurfaceBase *surface, + struct wsi_device *wsi_device, + uint32_t queueFamilyIndex, + VkBool32* pSupported) +{ + *pSupported = true; + + return VK_SUCCESS; +} + +static VkResult +wsi_win32_surface_get_capabilities(VkIcdSurfaceBase *surface, + struct wsi_device *wsi_device, + VkSurfaceCapabilitiesKHR* caps) +{ + caps->minImageCount = 1; + /* There is no real maximum */ + caps->maxImageCount = 0; + + caps->currentExtent = (VkExtent2D) { UINT32_MAX, UINT32_MAX }; + caps->minImageExtent = (VkExtent2D) { 1, 1 }; + caps->maxImageExtent = (VkExtent2D) { + wsi_device->maxImageDimension2D, + wsi_device->maxImageDimension2D, + }; + + caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + caps->maxImageArrayLayers = 1; + + caps->supportedCompositeAlpha = + VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; + + caps->supportedUsageFlags = + VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + return VK_SUCCESS; +} + +static VkResult +wsi_win32_surface_get_capabilities2(VkIcdSurfaceBase *surface, + struct wsi_device *wsi_device, + const void *info_next, + VkSurfaceCapabilities2KHR* caps) +{ + assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR); + + VkResult result = + wsi_win32_surface_get_capabilities(surface, wsi_device, + &caps->surfaceCapabilities); + + vk_foreach_struct(ext, caps->pNext) { + switch (ext->sType) { + case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: { + VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext; + protected->supportsProtected = VK_FALSE; + break; + } + + default: + /* Ignored */ + break; + } + } + + return result; +} + + +static const struct { + VkFormat format; +} available_surface_formats[] = { + { .format = VK_FORMAT_B8G8R8A8_SRGB }, + { .format = VK_FORMAT_B8G8R8A8_UNORM }, +}; + + +static void +get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats) +{ + for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) + sorted_formats[i] = available_surface_formats[i].format; + + if (wsi_device->force_bgra8_unorm_first) { + for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) { + if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) { + sorted_formats[i] = sorted_formats[0]; + sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM; + break; + } + } + } +} + +static VkResult +wsi_win32_surface_get_formats(VkIcdSurfaceBase *icd_surface, + struct wsi_device *wsi_device, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormatKHR* pSurfaceFormats) +{ + VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out, pSurfaceFormats, pSurfaceFormatCount); + + VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)]; + get_sorted_vk_formats(wsi_device, sorted_formats); + + for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { + vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) { + f->format = sorted_formats[i]; + f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + } + } + + return vk_outarray_status(&out); +} + +static VkResult +wsi_win32_surface_get_formats2(VkIcdSurfaceBase *icd_surface, + struct wsi_device *wsi_device, + const void *info_next, + uint32_t* pSurfaceFormatCount, + VkSurfaceFormat2KHR* pSurfaceFormats) +{ + VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out, pSurfaceFormats, pSurfaceFormatCount); + + VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)]; + get_sorted_vk_formats(wsi_device, sorted_formats); + + for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) { + vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) { + assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR); + f->surfaceFormat.format = sorted_formats[i]; + f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + } + } + + return vk_outarray_status(&out); +} + +static const VkPresentModeKHR present_modes[] = { + //VK_PRESENT_MODE_MAILBOX_KHR, + VK_PRESENT_MODE_FIFO_KHR, +}; + +static VkResult +wsi_win32_surface_get_present_modes(VkIcdSurfaceBase *surface, + uint32_t* pPresentModeCount, + VkPresentModeKHR* pPresentModes) +{ + if (pPresentModes == NULL) { + *pPresentModeCount = ARRAY_SIZE(present_modes); + return VK_SUCCESS; + } + + *pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes)); + typed_memcpy(pPresentModes, present_modes, *pPresentModeCount); + + if (*pPresentModeCount < ARRAY_SIZE(present_modes)) + return VK_INCOMPLETE; + else + return VK_SUCCESS; +} + +static VkResult +wsi_win32_surface_get_present_rectangles(VkIcdSurfaceBase *surface, + struct wsi_device *wsi_device, + uint32_t* pRectCount, + VkRect2D* pRects) +{ + VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount); + + vk_outarray_append_typed(VkRect2D, &out, rect) { + /* We don't know a size so just return the usual "I don't know." */ + *rect = (VkRect2D) { + .offset = { 0, 0 }, + .extent = { UINT32_MAX, UINT32_MAX }, + }; + } + + return vk_outarray_status(&out); +} + +static uint32_t +select_memory_type(const struct wsi_device *wsi, + VkMemoryPropertyFlags props, + uint32_t type_bits) +{ + for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) { + const VkMemoryType type = wsi->memory_props.memoryTypes[i]; + if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props) + return i; + } + + unreachable("No memory type found"); +} + +VkResult +wsi_create_native_image(const struct wsi_swapchain *chain, + const VkSwapchainCreateInfoKHR *pCreateInfo, + uint32_t num_modifier_lists, + const uint32_t *num_modifiers, + const uint64_t *const *modifiers, + struct wsi_image *image) +{ + const struct wsi_device *wsi = chain->wsi; + VkResult result; + + memset(image, 0, sizeof(*image)); + for (int i = 0; i < ARRAY_SIZE(image->fds); i++) + image->fds[i] = -1; + + VkImageCreateInfo image_info = { + .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO, + .flags = 0, + .imageType = VK_IMAGE_TYPE_2D, + .format = pCreateInfo->imageFormat, + .extent = { + .width = pCreateInfo->imageExtent.width, + .height = pCreateInfo->imageExtent.height, + .depth = 1, + }, + .mipLevels = 1, + .arrayLayers = 1, + .samples = VK_SAMPLE_COUNT_1_BIT, + .tiling = VK_IMAGE_TILING_OPTIMAL, + .usage = pCreateInfo->imageUsage, + .sharingMode = pCreateInfo->imageSharingMode, + .queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount, + .pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices, + .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, + }; + + VkImageFormatListCreateInfoKHR image_format_list; + if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) { + image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | + VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR; + + const VkImageFormatListCreateInfoKHR *format_list = + vk_find_struct_const(pCreateInfo->pNext, + IMAGE_FORMAT_LIST_CREATE_INFO_KHR); + +#ifndef NDEBUG + assume(format_list && format_list->viewFormatCount > 0); + bool format_found = false; + for (int i = 0; i < format_list->viewFormatCount; i++) + if (pCreateInfo->imageFormat == format_list->pViewFormats[i]) + format_found = true; + assert(format_found); +#endif + + image_format_list = *format_list; + image_format_list.pNext = NULL; + __vk_append_struct(&image_info, &image_format_list); + } + + + result = wsi->CreateImage(chain->device, &image_info, + &chain->alloc, &image->image); + if (result != VK_SUCCESS) + goto fail; + + VkMemoryRequirements reqs; + wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs); + + const struct wsi_memory_allocate_info memory_wsi_info = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA, + .pNext = NULL, + .implicit_sync = true, + }; + const VkExportMemoryAllocateInfo memory_export_info = { + .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, + .pNext = &memory_wsi_info, + .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, + .pNext = &memory_export_info, + .image = image->image, + .buffer = VK_NULL_HANDLE, + }; + const VkMemoryAllocateInfo memory_info = { + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memory_dedicated_info, + .allocationSize = reqs.size, + .memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, + reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &memory_info, + &chain->alloc, &image->memory); + if (result != VK_SUCCESS) + goto fail; + + result = wsi->BindImageMemory(chain->device, image->image, + image->memory, 0); + if (result != VK_SUCCESS) + goto fail; + + const VkImageSubresource image_subresource = { + .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, + .mipLevel = 0, + .arrayLayer = 0, + }; + VkSubresourceLayout image_layout; + wsi->GetImageSubresourceLayout(chain->device, image->image, + &image_subresource, &image_layout); + + image->num_planes = 1; + image->sizes[0] = reqs.size; + image->row_pitches[0] = image_layout.rowPitch; + image->offsets[0] = 0; + + return VK_SUCCESS; + +fail: + wsi_destroy_image(chain, image); + + return result; +} + +static VkResult +wsi_win32_image_init(VkDevice device_h, + struct wsi_swapchain *drv_chain, + const VkSwapchainCreateInfoKHR *create_info, + const VkAllocationCallbacks *allocator, + struct wsi_win32_image *image) +{ + struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *) drv_chain; + + VkResult result = wsi_create_native_image(&chain->base, create_info, + 0, NULL, NULL, + &image->base); + if (result != VK_SUCCESS) + return result; + + VkIcdSurfaceWin32 *win32_surface = (VkIcdSurfaceWin32 *)create_info->surface; + chain->wnd = win32_surface->hwnd; + chain->chain_dc = GetDC(chain->wnd); + + image->dc = CreateCompatibleDC(chain->chain_dc); + HBITMAP bmp = NULL; + + BITMAPINFO info = { 0 }; + info.bmiHeader.biSize = sizeof(BITMAPINFO); + info.bmiHeader.biWidth = create_info->imageExtent.width; + info.bmiHeader.biHeight = -create_info->imageExtent.height; + info.bmiHeader.biPlanes = 1; + info.bmiHeader.biBitCount = 32; + info.bmiHeader.biCompression = BI_RGB; + + bmp = CreateDIBSection(image->dc, &info, DIB_RGB_COLORS, &image->ppvBits, NULL, 0); + assert(bmp && image->ppvBits); + + SelectObject(image->dc, bmp); + + BITMAP header; + int status = GetObject(bmp, sizeof(BITMAP), &header); + (void)status; + image->bmp_row_pitch = header.bmWidthBytes; + image->bmp = bmp; + image->chain = chain; + + return VK_SUCCESS; +} + +static void +wsi_win32_image_finish(struct wsi_swapchain *drv_chain, + const VkAllocationCallbacks *allocator, + struct wsi_win32_image *image) +{ + struct wsi_win32_swapchain *chain = + (struct wsi_win32_swapchain *) drv_chain; + + DeleteDC(image->dc); + if(image->bmp) + DeleteObject(image->bmp); + wsi_destroy_image(&chain->base, &image->base); +} + +static VkResult +wsi_win32_swapchain_destroy(struct wsi_swapchain *drv_chain, + const VkAllocationCallbacks *allocator) +{ + struct wsi_win32_swapchain *chain = + (struct wsi_win32_swapchain *) drv_chain; + + for (uint32_t i = 0; i < chain->base.image_count; i++) + wsi_win32_image_finish(drv_chain, allocator, &chain->images[i]); + + DeleteDC(chain->chain_dc); + + wsi_swapchain_finish(&chain->base); + vk_free(allocator, chain); + return VK_SUCCESS; +} + +static struct wsi_image * +wsi_win32_get_wsi_image(struct wsi_swapchain *drv_chain, + uint32_t image_index) +{ + struct wsi_win32_swapchain *chain = + (struct wsi_win32_swapchain *) drv_chain; + + return &chain->images[image_index].base; +} + +static VkResult +wsi_win32_acquire_next_image(struct wsi_swapchain *drv_chain, + const VkAcquireNextImageInfoKHR *info, + uint32_t *image_index) +{ + struct wsi_win32_swapchain *chain = + (struct wsi_win32_swapchain *)drv_chain; + + /* Bail early if the swapchain is broken */ + if (chain->status != VK_SUCCESS) + return chain->status; + + *image_index = 0; + return VK_SUCCESS; +} + +static VkResult +wsi_win32_queue_present(struct wsi_swapchain *drv_chain, + uint32_t image_index, + const VkPresentRegionKHR *damage) +{ + struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *) drv_chain; + assert(image_index < chain->base.image_count); + struct wsi_win32_image *image = &chain->images[image_index]; + VkResult result; + + char *ptr; + char *dptr = image->ppvBits; + result = chain->base.wsi->MapMemory(chain->base.device, + image->base.memory, + 0, 0, 0, (void**)&ptr); + + for (unsigned h = 0; h < chain->extent.height; h++) { + memcpy(dptr, ptr, chain->extent.width * 4); + dptr += image->bmp_row_pitch; + ptr += image->base.row_pitches[0]; + } + if(StretchBlt(chain->chain_dc, 0, 0, chain->extent.width, chain->extent.height, image->dc, 0, 0, chain->extent.width, chain->extent.height, SRCCOPY)) + result = VK_SUCCESS; + else + result = VK_ERROR_MEMORY_MAP_FAILED; + + chain->base.wsi->UnmapMemory(chain->base.device, image->base.memory); + if (result != VK_SUCCESS) + chain->status = result; + + if (result != VK_SUCCESS) + return result; + + return chain->status; +} + +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) +{ + VkIcdSurfaceWin32 *surface = (VkIcdSurfaceWin32 *)icd_surface; + struct wsi_win32 *wsi = + (struct wsi_win32 *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32]; + + assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR); + + const unsigned num_images = create_info->minImageCount; + struct wsi_win32_swapchain *chain; + size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]); + + chain = vk_zalloc(allocator, size, + 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + + if (chain == NULL) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device, + create_info, allocator); + if (result != VK_SUCCESS) { + vk_free(allocator, chain); + return result; + } + + chain->base.destroy = wsi_win32_swapchain_destroy; + chain->base.get_wsi_image = wsi_win32_get_wsi_image; + chain->base.acquire_next_image = wsi_win32_acquire_next_image; + chain->base.queue_present = wsi_win32_queue_present; + chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info); + chain->base.image_count = num_images; + chain->extent = create_info->imageExtent; + + chain->wsi = wsi; + chain->status = VK_SUCCESS; + + chain->surface = surface; + + for (uint32_t image = 0; image < chain->base.image_count; image++) { + result = wsi_win32_image_init(device, &chain->base, + create_info, allocator, + &chain->images[image]); + if (result != VK_SUCCESS) { + while (image > 0) { + --image; + wsi_win32_image_finish(&chain->base, allocator, + &chain->images[image]); + } + vk_free(allocator, chain); + goto fail_init_images; + } + } + + *swapchain_out = &chain->base; + + return VK_SUCCESS; + +fail_init_images: + return result; +} + + +VkResult +wsi_win32_init_wsi(struct wsi_device *wsi_device, + const VkAllocationCallbacks *alloc, + VkPhysicalDevice physical_device) +{ + struct wsi_win32 *wsi; + VkResult result; + + wsi = vk_alloc(alloc, sizeof(*wsi), 8, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); + if (!wsi) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; + } + + wsi->physical_device = physical_device; + wsi->alloc = alloc; + wsi->wsi = wsi_device; + + wsi->base.get_support = wsi_win32_surface_get_support; + wsi->base.get_capabilities2 = wsi_win32_surface_get_capabilities2; + wsi->base.get_formats = wsi_win32_surface_get_formats; + wsi->base.get_formats2 = wsi_win32_surface_get_formats2; + wsi->base.get_present_modes = wsi_win32_surface_get_present_modes; + wsi->base.get_present_rectangles = wsi_win32_surface_get_present_rectangles; + wsi->base.create_swapchain = wsi_win32_surface_create_swapchain; + + wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = &wsi->base; + + return VK_SUCCESS; + +fail: + wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = NULL; + + return result; +} + +void +wsi_win32_finish_wsi(struct wsi_device *wsi_device, + const VkAllocationCallbacks *alloc) +{ + struct wsi_win32 *wsi = + (struct wsi_win32 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32]; + if (!wsi) + return; + + vk_free(alloc, wsi); +} diff --git a/src/vulkan/wsi/wsi_common_win32.h b/src/vulkan/wsi/wsi_common_win32.h new file mode 100644 index 00000000000..661ba9dea80 --- /dev/null +++ b/src/vulkan/wsi/wsi_common_win32.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef WSI_COMMON_WIN32_H +#define WSI_COMMON_WIN32_H + +#include "wsi_common.h" +#include + +VkBool32 +wsi_win32_get_presentation_support(struct wsi_device *wsi_device); + +VkResult +wsi_create_win32_surface(VkInstance instance, + const VkAllocationCallbacks *pAllocator, + const VkWin32SurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); +#endif