Path: blob/21.2-virgl/src/vulkan/wsi/wsi_common_win32.c
7326 views
/*1* Copyright © 2015 Intel Corporation2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS20* IN THE SOFTWARE.21*/2223#include <assert.h>24#include <stdlib.h>25#include <stdio.h>26#include <string.h>2728#include "vk_util.h"29#include "wsi_common_private.h"30#include "wsi_common_win32.h"3132#if defined(__GNUC__)33#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size34#endif3536struct wsi_win32;3738struct wsi_win32 {39struct wsi_interface base;4041struct wsi_device *wsi;4243const VkAllocationCallbacks *alloc;44VkPhysicalDevice physical_device;45};4647struct wsi_win32_image {48struct wsi_image base;49struct wsi_win32_swapchain *chain;50HDC dc;51HBITMAP bmp;52int bmp_row_pitch;53void *ppvBits;54};555657struct wsi_win32_swapchain {58struct wsi_swapchain base;59struct wsi_win32 *wsi;60VkIcdSurfaceWin32 *surface;61uint64_t flip_sequence;62VkResult status;63VkExtent2D extent;64HWND wnd;65HDC chain_dc;66struct wsi_win32_image images[0];67};6869VkBool3270wsi_win32_get_presentation_support(struct wsi_device *wsi_device)71{72return TRUE;73}7475VkResult76wsi_create_win32_surface(VkInstance instance,77const VkAllocationCallbacks *allocator,78const VkWin32SurfaceCreateInfoKHR *create_info,79VkSurfaceKHR *surface_khr)80{81VkIcdSurfaceWin32 *surface = vk_zalloc(allocator, sizeof *surface, 8,82VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);8384if (surface == NULL)85return VK_ERROR_OUT_OF_HOST_MEMORY;8687surface->base.platform = VK_ICD_WSI_PLATFORM_WIN32;8889surface->hinstance = create_info->hinstance;90surface->hwnd = create_info->hwnd;9192*surface_khr = VkIcdSurfaceBase_to_handle(&surface->base);93return VK_SUCCESS;94}9596static VkResult97wsi_win32_surface_get_support(VkIcdSurfaceBase *surface,98struct wsi_device *wsi_device,99uint32_t queueFamilyIndex,100VkBool32* pSupported)101{102*pSupported = true;103104return VK_SUCCESS;105}106107static VkResult108wsi_win32_surface_get_capabilities(VkIcdSurfaceBase *surface,109struct wsi_device *wsi_device,110VkSurfaceCapabilitiesKHR* caps)111{112caps->minImageCount = 1;113/* There is no real maximum */114caps->maxImageCount = 0;115116caps->currentExtent = (VkExtent2D) { UINT32_MAX, UINT32_MAX };117caps->minImageExtent = (VkExtent2D) { 1, 1 };118caps->maxImageExtent = (VkExtent2D) {119wsi_device->maxImageDimension2D,120wsi_device->maxImageDimension2D,121};122123caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;124caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;125caps->maxImageArrayLayers = 1;126127caps->supportedCompositeAlpha =128VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |129VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;130131caps->supportedUsageFlags =132VK_IMAGE_USAGE_TRANSFER_SRC_BIT |133VK_IMAGE_USAGE_SAMPLED_BIT |134VK_IMAGE_USAGE_TRANSFER_DST_BIT |135VK_IMAGE_USAGE_STORAGE_BIT |136VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;137138return VK_SUCCESS;139}140141static VkResult142wsi_win32_surface_get_capabilities2(VkIcdSurfaceBase *surface,143struct wsi_device *wsi_device,144const void *info_next,145VkSurfaceCapabilities2KHR* caps)146{147assert(caps->sType == VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR);148149VkResult result =150wsi_win32_surface_get_capabilities(surface, wsi_device,151&caps->surfaceCapabilities);152153vk_foreach_struct(ext, caps->pNext) {154switch (ext->sType) {155case VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR: {156VkSurfaceProtectedCapabilitiesKHR *protected = (void *)ext;157protected->supportsProtected = VK_FALSE;158break;159}160161default:162/* Ignored */163break;164}165}166167return result;168}169170171static const struct {172VkFormat format;173} available_surface_formats[] = {174{ .format = VK_FORMAT_B8G8R8A8_SRGB },175{ .format = VK_FORMAT_B8G8R8A8_UNORM },176};177178179static void180get_sorted_vk_formats(struct wsi_device *wsi_device, VkFormat *sorted_formats)181{182for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++)183sorted_formats[i] = available_surface_formats[i].format;184185if (wsi_device->force_bgra8_unorm_first) {186for (unsigned i = 0; i < ARRAY_SIZE(available_surface_formats); i++) {187if (sorted_formats[i] == VK_FORMAT_B8G8R8A8_UNORM) {188sorted_formats[i] = sorted_formats[0];189sorted_formats[0] = VK_FORMAT_B8G8R8A8_UNORM;190break;191}192}193}194}195196static VkResult197wsi_win32_surface_get_formats(VkIcdSurfaceBase *icd_surface,198struct wsi_device *wsi_device,199uint32_t* pSurfaceFormatCount,200VkSurfaceFormatKHR* pSurfaceFormats)201{202VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormatKHR, out, pSurfaceFormats, pSurfaceFormatCount);203204VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];205get_sorted_vk_formats(wsi_device, sorted_formats);206207for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {208vk_outarray_append_typed(VkSurfaceFormatKHR, &out, f) {209f->format = sorted_formats[i];210f->colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;211}212}213214return vk_outarray_status(&out);215}216217static VkResult218wsi_win32_surface_get_formats2(VkIcdSurfaceBase *icd_surface,219struct wsi_device *wsi_device,220const void *info_next,221uint32_t* pSurfaceFormatCount,222VkSurfaceFormat2KHR* pSurfaceFormats)223{224VK_OUTARRAY_MAKE_TYPED(VkSurfaceFormat2KHR, out, pSurfaceFormats, pSurfaceFormatCount);225226VkFormat sorted_formats[ARRAY_SIZE(available_surface_formats)];227get_sorted_vk_formats(wsi_device, sorted_formats);228229for (unsigned i = 0; i < ARRAY_SIZE(sorted_formats); i++) {230vk_outarray_append_typed(VkSurfaceFormat2KHR, &out, f) {231assert(f->sType == VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR);232f->surfaceFormat.format = sorted_formats[i];233f->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;234}235}236237return vk_outarray_status(&out);238}239240static const VkPresentModeKHR present_modes[] = {241//VK_PRESENT_MODE_MAILBOX_KHR,242VK_PRESENT_MODE_FIFO_KHR,243};244245static VkResult246wsi_win32_surface_get_present_modes(VkIcdSurfaceBase *surface,247uint32_t* pPresentModeCount,248VkPresentModeKHR* pPresentModes)249{250if (pPresentModes == NULL) {251*pPresentModeCount = ARRAY_SIZE(present_modes);252return VK_SUCCESS;253}254255*pPresentModeCount = MIN2(*pPresentModeCount, ARRAY_SIZE(present_modes));256typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);257258if (*pPresentModeCount < ARRAY_SIZE(present_modes))259return VK_INCOMPLETE;260else261return VK_SUCCESS;262}263264static VkResult265wsi_win32_surface_get_present_rectangles(VkIcdSurfaceBase *surface,266struct wsi_device *wsi_device,267uint32_t* pRectCount,268VkRect2D* pRects)269{270VK_OUTARRAY_MAKE_TYPED(VkRect2D, out, pRects, pRectCount);271272vk_outarray_append_typed(VkRect2D, &out, rect) {273/* We don't know a size so just return the usual "I don't know." */274*rect = (VkRect2D) {275.offset = { 0, 0 },276.extent = { UINT32_MAX, UINT32_MAX },277};278}279280return vk_outarray_status(&out);281}282283static uint32_t284select_memory_type(const struct wsi_device *wsi,285VkMemoryPropertyFlags props,286uint32_t type_bits)287{288for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) {289const VkMemoryType type = wsi->memory_props.memoryTypes[i];290if ((type_bits & (1 << i)) && (type.propertyFlags & props) == props)291return i;292}293294unreachable("No memory type found");295}296297VkResult298wsi_create_native_image(const struct wsi_swapchain *chain,299const VkSwapchainCreateInfoKHR *pCreateInfo,300uint32_t num_modifier_lists,301const uint32_t *num_modifiers,302const uint64_t *const *modifiers,303struct wsi_image *image)304{305const struct wsi_device *wsi = chain->wsi;306VkResult result;307308memset(image, 0, sizeof(*image));309for (int i = 0; i < ARRAY_SIZE(image->fds); i++)310image->fds[i] = -1;311312const struct wsi_image_create_info image_wsi_info = {313.sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO_MESA,314};315VkImageCreateInfo image_info = {316.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,317.pNext = &image_wsi_info,318.flags = 0,319.imageType = VK_IMAGE_TYPE_2D,320.format = pCreateInfo->imageFormat,321.extent = {322.width = pCreateInfo->imageExtent.width,323.height = pCreateInfo->imageExtent.height,324.depth = 1,325},326.mipLevels = 1,327.arrayLayers = 1,328.samples = VK_SAMPLE_COUNT_1_BIT,329.tiling = VK_IMAGE_TILING_OPTIMAL,330.usage = pCreateInfo->imageUsage,331.sharingMode = pCreateInfo->imageSharingMode,332.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount,333.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices,334.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,335};336337VkImageFormatListCreateInfoKHR image_format_list;338if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {339image_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT |340VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR;341342const VkImageFormatListCreateInfoKHR *format_list =343vk_find_struct_const(pCreateInfo->pNext,344IMAGE_FORMAT_LIST_CREATE_INFO_KHR);345346#ifndef NDEBUG347assume(format_list && format_list->viewFormatCount > 0);348bool format_found = false;349for (int i = 0; i < format_list->viewFormatCount; i++)350if (pCreateInfo->imageFormat == format_list->pViewFormats[i])351format_found = true;352assert(format_found);353#endif354355image_format_list = *format_list;356image_format_list.pNext = NULL;357__vk_append_struct(&image_info, &image_format_list);358}359360361result = wsi->CreateImage(chain->device, &image_info,362&chain->alloc, &image->image);363if (result != VK_SUCCESS)364goto fail;365366VkMemoryRequirements reqs;367wsi->GetImageMemoryRequirements(chain->device, image->image, &reqs);368369const struct wsi_memory_allocate_info memory_wsi_info = {370.sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA,371.pNext = NULL,372.implicit_sync = true,373};374const VkExportMemoryAllocateInfo memory_export_info = {375.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,376.pNext = &memory_wsi_info,377.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT,378};379const VkMemoryDedicatedAllocateInfo memory_dedicated_info = {380.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,381.pNext = &memory_export_info,382.image = image->image,383.buffer = VK_NULL_HANDLE,384};385const VkMemoryAllocateInfo memory_info = {386.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,387.pNext = &memory_dedicated_info,388.allocationSize = reqs.size,389.memoryTypeIndex = select_memory_type(wsi, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,390reqs.memoryTypeBits),391};392result = wsi->AllocateMemory(chain->device, &memory_info,393&chain->alloc, &image->memory);394if (result != VK_SUCCESS)395goto fail;396397result = wsi->BindImageMemory(chain->device, image->image,398image->memory, 0);399if (result != VK_SUCCESS)400goto fail;401402const VkImageSubresource image_subresource = {403.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,404.mipLevel = 0,405.arrayLayer = 0,406};407VkSubresourceLayout image_layout;408wsi->GetImageSubresourceLayout(chain->device, image->image,409&image_subresource, &image_layout);410411image->num_planes = 1;412image->sizes[0] = reqs.size;413image->row_pitches[0] = image_layout.rowPitch;414image->offsets[0] = 0;415416return VK_SUCCESS;417418fail:419wsi_destroy_image(chain, image);420421return result;422}423424static VkResult425wsi_win32_image_init(VkDevice device_h,426struct wsi_swapchain *drv_chain,427const VkSwapchainCreateInfoKHR *create_info,428const VkAllocationCallbacks *allocator,429struct wsi_win32_image *image)430{431struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *) drv_chain;432433VkResult result = wsi_create_native_image(&chain->base, create_info,4340, NULL, NULL,435&image->base);436if (result != VK_SUCCESS)437return result;438439VkIcdSurfaceWin32 *win32_surface = (VkIcdSurfaceWin32 *)create_info->surface;440chain->wnd = win32_surface->hwnd;441chain->chain_dc = GetDC(chain->wnd);442443image->dc = CreateCompatibleDC(chain->chain_dc);444HBITMAP bmp = NULL;445446BITMAPINFO info = { 0 };447info.bmiHeader.biSize = sizeof(BITMAPINFO);448info.bmiHeader.biWidth = create_info->imageExtent.width;449info.bmiHeader.biHeight = -create_info->imageExtent.height;450info.bmiHeader.biPlanes = 1;451info.bmiHeader.biBitCount = 32;452info.bmiHeader.biCompression = BI_RGB;453454bmp = CreateDIBSection(image->dc, &info, DIB_RGB_COLORS, &image->ppvBits, NULL, 0);455assert(bmp && image->ppvBits);456457SelectObject(image->dc, bmp);458459BITMAP header;460int status = GetObject(bmp, sizeof(BITMAP), &header);461(void)status;462image->bmp_row_pitch = header.bmWidthBytes;463image->bmp = bmp;464image->chain = chain;465466return VK_SUCCESS;467}468469static void470wsi_win32_image_finish(struct wsi_swapchain *drv_chain,471const VkAllocationCallbacks *allocator,472struct wsi_win32_image *image)473{474struct wsi_win32_swapchain *chain =475(struct wsi_win32_swapchain *) drv_chain;476477DeleteDC(image->dc);478if(image->bmp)479DeleteObject(image->bmp);480wsi_destroy_image(&chain->base, &image->base);481}482483static VkResult484wsi_win32_swapchain_destroy(struct wsi_swapchain *drv_chain,485const VkAllocationCallbacks *allocator)486{487struct wsi_win32_swapchain *chain =488(struct wsi_win32_swapchain *) drv_chain;489490for (uint32_t i = 0; i < chain->base.image_count; i++)491wsi_win32_image_finish(drv_chain, allocator, &chain->images[i]);492493DeleteDC(chain->chain_dc);494495wsi_swapchain_finish(&chain->base);496vk_free(allocator, chain);497return VK_SUCCESS;498}499500static struct wsi_image *501wsi_win32_get_wsi_image(struct wsi_swapchain *drv_chain,502uint32_t image_index)503{504struct wsi_win32_swapchain *chain =505(struct wsi_win32_swapchain *) drv_chain;506507return &chain->images[image_index].base;508}509510static VkResult511wsi_win32_acquire_next_image(struct wsi_swapchain *drv_chain,512const VkAcquireNextImageInfoKHR *info,513uint32_t *image_index)514{515struct wsi_win32_swapchain *chain =516(struct wsi_win32_swapchain *)drv_chain;517518/* Bail early if the swapchain is broken */519if (chain->status != VK_SUCCESS)520return chain->status;521522*image_index = 0;523return VK_SUCCESS;524}525526static VkResult527wsi_win32_queue_present(struct wsi_swapchain *drv_chain,528uint32_t image_index,529const VkPresentRegionKHR *damage)530{531struct wsi_win32_swapchain *chain = (struct wsi_win32_swapchain *) drv_chain;532assert(image_index < chain->base.image_count);533struct wsi_win32_image *image = &chain->images[image_index];534VkResult result;535536char *ptr;537char *dptr = image->ppvBits;538result = chain->base.wsi->MapMemory(chain->base.device,539image->base.memory,5400, image->base.sizes[0], 0, (void**)&ptr);541542for (unsigned h = 0; h < chain->extent.height; h++) {543memcpy(dptr, ptr, chain->extent.width * 4);544dptr += image->bmp_row_pitch;545ptr += image->base.row_pitches[0];546}547if(StretchBlt(chain->chain_dc, 0, 0, chain->extent.width, chain->extent.height, image->dc, 0, 0, chain->extent.width, chain->extent.height, SRCCOPY))548result = VK_SUCCESS;549else550result = VK_ERROR_MEMORY_MAP_FAILED;551552chain->base.wsi->UnmapMemory(chain->base.device, image->base.memory);553if (result != VK_SUCCESS)554chain->status = result;555556if (result != VK_SUCCESS)557return result;558559return chain->status;560}561562static VkResult563wsi_win32_surface_create_swapchain(564VkIcdSurfaceBase *icd_surface,565VkDevice device,566struct wsi_device *wsi_device,567const VkSwapchainCreateInfoKHR *create_info,568const VkAllocationCallbacks *allocator,569struct wsi_swapchain **swapchain_out)570{571VkIcdSurfaceWin32 *surface = (VkIcdSurfaceWin32 *)icd_surface;572struct wsi_win32 *wsi =573(struct wsi_win32 *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32];574575assert(create_info->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);576577const unsigned num_images = create_info->minImageCount;578struct wsi_win32_swapchain *chain;579size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);580581chain = vk_zalloc(allocator, size,5828, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);583584if (chain == NULL)585return VK_ERROR_OUT_OF_HOST_MEMORY;586587VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device,588create_info, allocator);589if (result != VK_SUCCESS) {590vk_free(allocator, chain);591return result;592}593594chain->base.destroy = wsi_win32_swapchain_destroy;595chain->base.get_wsi_image = wsi_win32_get_wsi_image;596chain->base.acquire_next_image = wsi_win32_acquire_next_image;597chain->base.queue_present = wsi_win32_queue_present;598chain->base.present_mode = wsi_swapchain_get_present_mode(wsi_device, create_info);599chain->base.image_count = num_images;600chain->extent = create_info->imageExtent;601602chain->wsi = wsi;603chain->status = VK_SUCCESS;604605chain->surface = surface;606607for (uint32_t image = 0; image < chain->base.image_count; image++) {608result = wsi_win32_image_init(device, &chain->base,609create_info, allocator,610&chain->images[image]);611if (result != VK_SUCCESS) {612while (image > 0) {613--image;614wsi_win32_image_finish(&chain->base, allocator,615&chain->images[image]);616}617vk_free(allocator, chain);618goto fail_init_images;619}620}621622*swapchain_out = &chain->base;623624return VK_SUCCESS;625626fail_init_images:627return result;628}629630631VkResult632wsi_win32_init_wsi(struct wsi_device *wsi_device,633const VkAllocationCallbacks *alloc,634VkPhysicalDevice physical_device)635{636struct wsi_win32 *wsi;637VkResult result;638639wsi = vk_alloc(alloc, sizeof(*wsi), 8,640VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);641if (!wsi) {642result = VK_ERROR_OUT_OF_HOST_MEMORY;643goto fail;644}645646wsi->physical_device = physical_device;647wsi->alloc = alloc;648wsi->wsi = wsi_device;649650wsi->base.get_support = wsi_win32_surface_get_support;651wsi->base.get_capabilities2 = wsi_win32_surface_get_capabilities2;652wsi->base.get_formats = wsi_win32_surface_get_formats;653wsi->base.get_formats2 = wsi_win32_surface_get_formats2;654wsi->base.get_present_modes = wsi_win32_surface_get_present_modes;655wsi->base.get_present_rectangles = wsi_win32_surface_get_present_rectangles;656wsi->base.create_swapchain = wsi_win32_surface_create_swapchain;657658wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = &wsi->base;659660return VK_SUCCESS;661662fail:663wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32] = NULL;664665return result;666}667668void669wsi_win32_finish_wsi(struct wsi_device *wsi_device,670const VkAllocationCallbacks *alloc)671{672struct wsi_win32 *wsi =673(struct wsi_win32 *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WIN32];674if (!wsi)675return;676677vk_free(alloc, wsi);678}679680681