1cb93a386Sopenharmony_ci 2cb93a386Sopenharmony_ci/* 3cb93a386Sopenharmony_ci * Copyright 2015 Google Inc. 4cb93a386Sopenharmony_ci * 5cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 6cb93a386Sopenharmony_ci * found in the LICENSE file. 7cb93a386Sopenharmony_ci */ 8cb93a386Sopenharmony_ci 9cb93a386Sopenharmony_ci#include "tools/sk_app/VulkanWindowContext.h" 10cb93a386Sopenharmony_ci 11cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 12cb93a386Sopenharmony_ci#include "include/gpu/GrBackendSemaphore.h" 13cb93a386Sopenharmony_ci#include "include/gpu/GrBackendSurface.h" 14cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 15cb93a386Sopenharmony_ci#include "src/core/SkAutoMalloc.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#include "include/gpu/vk/GrVkExtensions.h" 18cb93a386Sopenharmony_ci#include "include/gpu/vk/GrVkTypes.h" 19cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkImage.h" 20cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkUtil.h" 21cb93a386Sopenharmony_ci 22cb93a386Sopenharmony_ci#ifdef VK_USE_PLATFORM_WIN32_KHR 23cb93a386Sopenharmony_ci// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW 24cb93a386Sopenharmony_ci#undef CreateSemaphore 25cb93a386Sopenharmony_ci#endif 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fInstance, "vk" #F) 28cb93a386Sopenharmony_ci#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fDevice, "vk" #F) 29cb93a386Sopenharmony_ci 30cb93a386Sopenharmony_cinamespace sk_app { 31cb93a386Sopenharmony_ci 32cb93a386Sopenharmony_ciVulkanWindowContext::VulkanWindowContext(const DisplayParams& params, 33cb93a386Sopenharmony_ci CreateVkSurfaceFn createVkSurface, 34cb93a386Sopenharmony_ci CanPresentFn canPresent, 35cb93a386Sopenharmony_ci PFN_vkGetInstanceProcAddr instProc, 36cb93a386Sopenharmony_ci PFN_vkGetDeviceProcAddr devProc) 37cb93a386Sopenharmony_ci : WindowContext(params) 38cb93a386Sopenharmony_ci , fCreateVkSurfaceFn(createVkSurface) 39cb93a386Sopenharmony_ci , fCanPresentFn(canPresent) 40cb93a386Sopenharmony_ci , fSurface(VK_NULL_HANDLE) 41cb93a386Sopenharmony_ci , fSwapchain(VK_NULL_HANDLE) 42cb93a386Sopenharmony_ci , fImages(nullptr) 43cb93a386Sopenharmony_ci , fImageLayouts(nullptr) 44cb93a386Sopenharmony_ci , fSurfaces(nullptr) 45cb93a386Sopenharmony_ci , fBackbuffers(nullptr) { 46cb93a386Sopenharmony_ci fGetInstanceProcAddr = instProc; 47cb93a386Sopenharmony_ci fGetDeviceProcAddr = devProc; 48cb93a386Sopenharmony_ci this->initializeContext(); 49cb93a386Sopenharmony_ci} 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_civoid VulkanWindowContext::initializeContext() { 52cb93a386Sopenharmony_ci SkASSERT(!fContext); 53cb93a386Sopenharmony_ci // any config code here (particularly for msaa)? 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_ci PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr; 56cb93a386Sopenharmony_ci PFN_vkGetDeviceProcAddr getDeviceProc = fGetDeviceProcAddr; 57cb93a386Sopenharmony_ci auto getProc = [getInstanceProc, getDeviceProc](const char* proc_name, 58cb93a386Sopenharmony_ci VkInstance instance, VkDevice device) { 59cb93a386Sopenharmony_ci if (device != VK_NULL_HANDLE) { 60cb93a386Sopenharmony_ci return getDeviceProc(device, proc_name); 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci return getInstanceProc(instance, proc_name); 63cb93a386Sopenharmony_ci }; 64cb93a386Sopenharmony_ci GrVkBackendContext backendContext; 65cb93a386Sopenharmony_ci GrVkExtensions extensions; 66cb93a386Sopenharmony_ci VkPhysicalDeviceFeatures2 features; 67cb93a386Sopenharmony_ci if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, &extensions, &features, 68cb93a386Sopenharmony_ci &fDebugCallback, &fPresentQueueIndex, fCanPresentFn)) { 69cb93a386Sopenharmony_ci sk_gpu_test::FreeVulkanFeaturesStructs(&features); 70cb93a386Sopenharmony_ci return; 71cb93a386Sopenharmony_ci } 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ci if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) || 74cb93a386Sopenharmony_ci !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) { 75cb93a386Sopenharmony_ci sk_gpu_test::FreeVulkanFeaturesStructs(&features); 76cb93a386Sopenharmony_ci return; 77cb93a386Sopenharmony_ci } 78cb93a386Sopenharmony_ci 79cb93a386Sopenharmony_ci fInstance = backendContext.fInstance; 80cb93a386Sopenharmony_ci fPhysicalDevice = backendContext.fPhysicalDevice; 81cb93a386Sopenharmony_ci fDevice = backendContext.fDevice; 82cb93a386Sopenharmony_ci fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex; 83cb93a386Sopenharmony_ci fGraphicsQueue = backendContext.fQueue; 84cb93a386Sopenharmony_ci 85cb93a386Sopenharmony_ci PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties = 86cb93a386Sopenharmony_ci reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>( 87cb93a386Sopenharmony_ci backendContext.fGetProc("vkGetPhysicalDeviceProperties", 88cb93a386Sopenharmony_ci backendContext.fInstance, 89cb93a386Sopenharmony_ci VK_NULL_HANDLE)); 90cb93a386Sopenharmony_ci if (!localGetPhysicalDeviceProperties) { 91cb93a386Sopenharmony_ci sk_gpu_test::FreeVulkanFeaturesStructs(&features); 92cb93a386Sopenharmony_ci return; 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci VkPhysicalDeviceProperties physDeviceProperties; 95cb93a386Sopenharmony_ci localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties); 96cb93a386Sopenharmony_ci uint32_t physDevVersion = physDeviceProperties.apiVersion; 97cb93a386Sopenharmony_ci 98cb93a386Sopenharmony_ci fInterface.reset(new GrVkInterface(backendContext.fGetProc, fInstance, fDevice, 99cb93a386Sopenharmony_ci backendContext.fInstanceVersion, physDevVersion, 100cb93a386Sopenharmony_ci &extensions)); 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci GET_PROC(DestroyInstance); 103cb93a386Sopenharmony_ci if (fDebugCallback != VK_NULL_HANDLE) { 104cb93a386Sopenharmony_ci GET_PROC(DestroyDebugReportCallbackEXT); 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci GET_PROC(DestroySurfaceKHR); 107cb93a386Sopenharmony_ci GET_PROC(GetPhysicalDeviceSurfaceSupportKHR); 108cb93a386Sopenharmony_ci GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR); 109cb93a386Sopenharmony_ci GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR); 110cb93a386Sopenharmony_ci GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR); 111cb93a386Sopenharmony_ci GET_DEV_PROC(DeviceWaitIdle); 112cb93a386Sopenharmony_ci GET_DEV_PROC(QueueWaitIdle); 113cb93a386Sopenharmony_ci GET_DEV_PROC(DestroyDevice); 114cb93a386Sopenharmony_ci GET_DEV_PROC(CreateSwapchainKHR); 115cb93a386Sopenharmony_ci GET_DEV_PROC(DestroySwapchainKHR); 116cb93a386Sopenharmony_ci GET_DEV_PROC(GetSwapchainImagesKHR); 117cb93a386Sopenharmony_ci GET_DEV_PROC(AcquireNextImageKHR); 118cb93a386Sopenharmony_ci GET_DEV_PROC(QueuePresentKHR); 119cb93a386Sopenharmony_ci GET_DEV_PROC(GetDeviceQueue); 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci fContext = GrDirectContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions); 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci fSurface = fCreateVkSurfaceFn(fInstance); 124cb93a386Sopenharmony_ci if (VK_NULL_HANDLE == fSurface) { 125cb93a386Sopenharmony_ci this->destroyContext(); 126cb93a386Sopenharmony_ci sk_gpu_test::FreeVulkanFeaturesStructs(&features); 127cb93a386Sopenharmony_ci return; 128cb93a386Sopenharmony_ci } 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci VkBool32 supported; 131cb93a386Sopenharmony_ci VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex, 132cb93a386Sopenharmony_ci fSurface, &supported); 133cb93a386Sopenharmony_ci if (VK_SUCCESS != res) { 134cb93a386Sopenharmony_ci this->destroyContext(); 135cb93a386Sopenharmony_ci sk_gpu_test::FreeVulkanFeaturesStructs(&features); 136cb93a386Sopenharmony_ci return; 137cb93a386Sopenharmony_ci } 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci if (!this->createSwapchain(-1, -1, fDisplayParams)) { 140cb93a386Sopenharmony_ci this->destroyContext(); 141cb93a386Sopenharmony_ci sk_gpu_test::FreeVulkanFeaturesStructs(&features); 142cb93a386Sopenharmony_ci return; 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci // create presentQueue 146cb93a386Sopenharmony_ci fGetDeviceQueue(fDevice, fPresentQueueIndex, 0, &fPresentQueue); 147cb93a386Sopenharmony_ci sk_gpu_test::FreeVulkanFeaturesStructs(&features); 148cb93a386Sopenharmony_ci} 149cb93a386Sopenharmony_ci 150cb93a386Sopenharmony_cibool VulkanWindowContext::createSwapchain(int width, int height, 151cb93a386Sopenharmony_ci const DisplayParams& params) { 152cb93a386Sopenharmony_ci // check for capabilities 153cb93a386Sopenharmony_ci VkSurfaceCapabilitiesKHR caps; 154cb93a386Sopenharmony_ci VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fPhysicalDevice, fSurface, &caps); 155cb93a386Sopenharmony_ci if (VK_SUCCESS != res) { 156cb93a386Sopenharmony_ci return false; 157cb93a386Sopenharmony_ci } 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_ci uint32_t surfaceFormatCount; 160cb93a386Sopenharmony_ci res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount, 161cb93a386Sopenharmony_ci nullptr); 162cb93a386Sopenharmony_ci if (VK_SUCCESS != res) { 163cb93a386Sopenharmony_ci return false; 164cb93a386Sopenharmony_ci } 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ci SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR)); 167cb93a386Sopenharmony_ci VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get(); 168cb93a386Sopenharmony_ci res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount, 169cb93a386Sopenharmony_ci surfaceFormats); 170cb93a386Sopenharmony_ci if (VK_SUCCESS != res) { 171cb93a386Sopenharmony_ci return false; 172cb93a386Sopenharmony_ci } 173cb93a386Sopenharmony_ci 174cb93a386Sopenharmony_ci uint32_t presentModeCount; 175cb93a386Sopenharmony_ci res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount, 176cb93a386Sopenharmony_ci nullptr); 177cb93a386Sopenharmony_ci if (VK_SUCCESS != res) { 178cb93a386Sopenharmony_ci return false; 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR)); 182cb93a386Sopenharmony_ci VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get(); 183cb93a386Sopenharmony_ci res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount, 184cb93a386Sopenharmony_ci presentModes); 185cb93a386Sopenharmony_ci if (VK_SUCCESS != res) { 186cb93a386Sopenharmony_ci return false; 187cb93a386Sopenharmony_ci } 188cb93a386Sopenharmony_ci 189cb93a386Sopenharmony_ci VkExtent2D extent = caps.currentExtent; 190cb93a386Sopenharmony_ci // use the hints 191cb93a386Sopenharmony_ci if (extent.width == (uint32_t)-1) { 192cb93a386Sopenharmony_ci extent.width = width; 193cb93a386Sopenharmony_ci extent.height = height; 194cb93a386Sopenharmony_ci } 195cb93a386Sopenharmony_ci 196cb93a386Sopenharmony_ci // clamp width; to protect us from broken hints 197cb93a386Sopenharmony_ci if (extent.width < caps.minImageExtent.width) { 198cb93a386Sopenharmony_ci extent.width = caps.minImageExtent.width; 199cb93a386Sopenharmony_ci } else if (extent.width > caps.maxImageExtent.width) { 200cb93a386Sopenharmony_ci extent.width = caps.maxImageExtent.width; 201cb93a386Sopenharmony_ci } 202cb93a386Sopenharmony_ci // clamp height 203cb93a386Sopenharmony_ci if (extent.height < caps.minImageExtent.height) { 204cb93a386Sopenharmony_ci extent.height = caps.minImageExtent.height; 205cb93a386Sopenharmony_ci } else if (extent.height > caps.maxImageExtent.height) { 206cb93a386Sopenharmony_ci extent.height = caps.maxImageExtent.height; 207cb93a386Sopenharmony_ci } 208cb93a386Sopenharmony_ci 209cb93a386Sopenharmony_ci fWidth = (int)extent.width; 210cb93a386Sopenharmony_ci fHeight = (int)extent.height; 211cb93a386Sopenharmony_ci 212cb93a386Sopenharmony_ci uint32_t imageCount = caps.minImageCount + 2; 213cb93a386Sopenharmony_ci if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) { 214cb93a386Sopenharmony_ci // Application must settle for fewer images than desired: 215cb93a386Sopenharmony_ci imageCount = caps.maxImageCount; 216cb93a386Sopenharmony_ci } 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_ci VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 219cb93a386Sopenharmony_ci VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 220cb93a386Sopenharmony_ci VK_IMAGE_USAGE_TRANSFER_DST_BIT; 221cb93a386Sopenharmony_ci SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags); 222cb93a386Sopenharmony_ci if (caps.supportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) { 223cb93a386Sopenharmony_ci usageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; 224cb93a386Sopenharmony_ci } 225cb93a386Sopenharmony_ci if (caps.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) { 226cb93a386Sopenharmony_ci usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT; 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci SkASSERT(caps.supportedTransforms & caps.currentTransform); 229cb93a386Sopenharmony_ci SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | 230cb93a386Sopenharmony_ci VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)); 231cb93a386Sopenharmony_ci VkCompositeAlphaFlagBitsKHR composite_alpha = 232cb93a386Sopenharmony_ci (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ? 233cb93a386Sopenharmony_ci VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR : 234cb93a386Sopenharmony_ci VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 235cb93a386Sopenharmony_ci 236cb93a386Sopenharmony_ci // Pick our surface format. 237cb93a386Sopenharmony_ci VkFormat surfaceFormat = VK_FORMAT_UNDEFINED; 238cb93a386Sopenharmony_ci VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 239cb93a386Sopenharmony_ci for (uint32_t i = 0; i < surfaceFormatCount; ++i) { 240cb93a386Sopenharmony_ci VkFormat localFormat = surfaceFormats[i].format; 241cb93a386Sopenharmony_ci if (GrVkFormatIsSupported(localFormat)) { 242cb93a386Sopenharmony_ci surfaceFormat = localFormat; 243cb93a386Sopenharmony_ci colorSpace = surfaceFormats[i].colorSpace; 244cb93a386Sopenharmony_ci break; 245cb93a386Sopenharmony_ci } 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci fDisplayParams = params; 248cb93a386Sopenharmony_ci fSampleCount = std::max(1, params.fMSAASampleCount); 249cb93a386Sopenharmony_ci fStencilBits = 8; 250cb93a386Sopenharmony_ci 251cb93a386Sopenharmony_ci if (VK_FORMAT_UNDEFINED == surfaceFormat) { 252cb93a386Sopenharmony_ci return false; 253cb93a386Sopenharmony_ci } 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci SkColorType colorType; 256cb93a386Sopenharmony_ci switch (surfaceFormat) { 257cb93a386Sopenharmony_ci case VK_FORMAT_R8G8B8A8_UNORM: // fall through 258cb93a386Sopenharmony_ci case VK_FORMAT_R8G8B8A8_SRGB: 259cb93a386Sopenharmony_ci colorType = kRGBA_8888_SkColorType; 260cb93a386Sopenharmony_ci break; 261cb93a386Sopenharmony_ci case VK_FORMAT_B8G8R8A8_UNORM: // fall through 262cb93a386Sopenharmony_ci colorType = kBGRA_8888_SkColorType; 263cb93a386Sopenharmony_ci break; 264cb93a386Sopenharmony_ci default: 265cb93a386Sopenharmony_ci return false; 266cb93a386Sopenharmony_ci } 267cb93a386Sopenharmony_ci 268cb93a386Sopenharmony_ci // If mailbox mode is available, use it, as it is the lowest-latency non- 269cb93a386Sopenharmony_ci // tearing mode. If not, fall back to FIFO which is always available. 270cb93a386Sopenharmony_ci VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; 271cb93a386Sopenharmony_ci bool hasImmediate = false; 272cb93a386Sopenharmony_ci for (uint32_t i = 0; i < presentModeCount; ++i) { 273cb93a386Sopenharmony_ci // use mailbox 274cb93a386Sopenharmony_ci if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) { 275cb93a386Sopenharmony_ci mode = VK_PRESENT_MODE_MAILBOX_KHR; 276cb93a386Sopenharmony_ci } 277cb93a386Sopenharmony_ci if (VK_PRESENT_MODE_IMMEDIATE_KHR == presentModes[i]) { 278cb93a386Sopenharmony_ci hasImmediate = true; 279cb93a386Sopenharmony_ci } 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci if (params.fDisableVsync && hasImmediate) { 282cb93a386Sopenharmony_ci mode = VK_PRESENT_MODE_IMMEDIATE_KHR; 283cb93a386Sopenharmony_ci } 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_ci VkSwapchainCreateInfoKHR swapchainCreateInfo; 286cb93a386Sopenharmony_ci memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR)); 287cb93a386Sopenharmony_ci swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 288cb93a386Sopenharmony_ci swapchainCreateInfo.surface = fSurface; 289cb93a386Sopenharmony_ci swapchainCreateInfo.minImageCount = imageCount; 290cb93a386Sopenharmony_ci swapchainCreateInfo.imageFormat = surfaceFormat; 291cb93a386Sopenharmony_ci swapchainCreateInfo.imageColorSpace = colorSpace; 292cb93a386Sopenharmony_ci swapchainCreateInfo.imageExtent = extent; 293cb93a386Sopenharmony_ci swapchainCreateInfo.imageArrayLayers = 1; 294cb93a386Sopenharmony_ci swapchainCreateInfo.imageUsage = usageFlags; 295cb93a386Sopenharmony_ci 296cb93a386Sopenharmony_ci uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex }; 297cb93a386Sopenharmony_ci if (fGraphicsQueueIndex != fPresentQueueIndex) { 298cb93a386Sopenharmony_ci swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; 299cb93a386Sopenharmony_ci swapchainCreateInfo.queueFamilyIndexCount = 2; 300cb93a386Sopenharmony_ci swapchainCreateInfo.pQueueFamilyIndices = queueFamilies; 301cb93a386Sopenharmony_ci } else { 302cb93a386Sopenharmony_ci swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 303cb93a386Sopenharmony_ci swapchainCreateInfo.queueFamilyIndexCount = 0; 304cb93a386Sopenharmony_ci swapchainCreateInfo.pQueueFamilyIndices = nullptr; 305cb93a386Sopenharmony_ci } 306cb93a386Sopenharmony_ci 307cb93a386Sopenharmony_ci swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 308cb93a386Sopenharmony_ci swapchainCreateInfo.compositeAlpha = composite_alpha; 309cb93a386Sopenharmony_ci swapchainCreateInfo.presentMode = mode; 310cb93a386Sopenharmony_ci swapchainCreateInfo.clipped = true; 311cb93a386Sopenharmony_ci swapchainCreateInfo.oldSwapchain = fSwapchain; 312cb93a386Sopenharmony_ci 313cb93a386Sopenharmony_ci res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain); 314cb93a386Sopenharmony_ci if (VK_SUCCESS != res) { 315cb93a386Sopenharmony_ci return false; 316cb93a386Sopenharmony_ci } 317cb93a386Sopenharmony_ci 318cb93a386Sopenharmony_ci // destroy the old swapchain 319cb93a386Sopenharmony_ci if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) { 320cb93a386Sopenharmony_ci fDeviceWaitIdle(fDevice); 321cb93a386Sopenharmony_ci 322cb93a386Sopenharmony_ci this->destroyBuffers(); 323cb93a386Sopenharmony_ci 324cb93a386Sopenharmony_ci fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr); 325cb93a386Sopenharmony_ci } 326cb93a386Sopenharmony_ci 327cb93a386Sopenharmony_ci if (!this->createBuffers(swapchainCreateInfo.imageFormat, usageFlags, colorType, 328cb93a386Sopenharmony_ci swapchainCreateInfo.imageSharingMode)) { 329cb93a386Sopenharmony_ci fDeviceWaitIdle(fDevice); 330cb93a386Sopenharmony_ci 331cb93a386Sopenharmony_ci this->destroyBuffers(); 332cb93a386Sopenharmony_ci 333cb93a386Sopenharmony_ci fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr); 334cb93a386Sopenharmony_ci } 335cb93a386Sopenharmony_ci 336cb93a386Sopenharmony_ci return true; 337cb93a386Sopenharmony_ci} 338cb93a386Sopenharmony_ci 339cb93a386Sopenharmony_cibool VulkanWindowContext::createBuffers(VkFormat format, VkImageUsageFlags usageFlags, 340cb93a386Sopenharmony_ci SkColorType colorType, 341cb93a386Sopenharmony_ci VkSharingMode sharingMode) { 342cb93a386Sopenharmony_ci fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr); 343cb93a386Sopenharmony_ci SkASSERT(fImageCount); 344cb93a386Sopenharmony_ci fImages = new VkImage[fImageCount]; 345cb93a386Sopenharmony_ci fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages); 346cb93a386Sopenharmony_ci 347cb93a386Sopenharmony_ci // set up initial image layouts and create surfaces 348cb93a386Sopenharmony_ci fImageLayouts = new VkImageLayout[fImageCount]; 349cb93a386Sopenharmony_ci fSurfaces = new sk_sp<SkSurface>[fImageCount]; 350cb93a386Sopenharmony_ci for (uint32_t i = 0; i < fImageCount; ++i) { 351cb93a386Sopenharmony_ci fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED; 352cb93a386Sopenharmony_ci 353cb93a386Sopenharmony_ci GrVkImageInfo info; 354cb93a386Sopenharmony_ci info.fImage = fImages[i]; 355cb93a386Sopenharmony_ci info.fAlloc = GrVkAlloc(); 356cb93a386Sopenharmony_ci info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; 357cb93a386Sopenharmony_ci info.fImageTiling = VK_IMAGE_TILING_OPTIMAL; 358cb93a386Sopenharmony_ci info.fFormat = format; 359cb93a386Sopenharmony_ci info.fImageUsageFlags = usageFlags; 360cb93a386Sopenharmony_ci info.fLevelCount = 1; 361cb93a386Sopenharmony_ci info.fCurrentQueueFamily = fPresentQueueIndex; 362cb93a386Sopenharmony_ci info.fSharingMode = sharingMode; 363cb93a386Sopenharmony_ci 364cb93a386Sopenharmony_ci if (usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) { 365cb93a386Sopenharmony_ci GrBackendTexture backendTexture(fWidth, fHeight, info); 366cb93a386Sopenharmony_ci fSurfaces[i] = SkSurface::MakeFromBackendTexture( 367cb93a386Sopenharmony_ci fContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, 368cb93a386Sopenharmony_ci fDisplayParams.fMSAASampleCount, 369cb93a386Sopenharmony_ci colorType, fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps); 370cb93a386Sopenharmony_ci } else { 371cb93a386Sopenharmony_ci if (fDisplayParams.fMSAASampleCount > 1) { 372cb93a386Sopenharmony_ci return false; 373cb93a386Sopenharmony_ci } 374cb93a386Sopenharmony_ci GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info); 375cb93a386Sopenharmony_ci fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget( 376cb93a386Sopenharmony_ci fContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, colorType, 377cb93a386Sopenharmony_ci fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps); 378cb93a386Sopenharmony_ci 379cb93a386Sopenharmony_ci } 380cb93a386Sopenharmony_ci if (!fSurfaces[i]) { 381cb93a386Sopenharmony_ci return false; 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci } 384cb93a386Sopenharmony_ci 385cb93a386Sopenharmony_ci // set up the backbuffers 386cb93a386Sopenharmony_ci VkSemaphoreCreateInfo semaphoreInfo; 387cb93a386Sopenharmony_ci memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo)); 388cb93a386Sopenharmony_ci semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 389cb93a386Sopenharmony_ci semaphoreInfo.pNext = nullptr; 390cb93a386Sopenharmony_ci semaphoreInfo.flags = 0; 391cb93a386Sopenharmony_ci 392cb93a386Sopenharmony_ci // we create one additional backbuffer structure here, because we want to 393cb93a386Sopenharmony_ci // give the command buffers they contain a chance to finish before we cycle back 394cb93a386Sopenharmony_ci fBackbuffers = new BackbufferInfo[fImageCount + 1]; 395cb93a386Sopenharmony_ci for (uint32_t i = 0; i < fImageCount + 1; ++i) { 396cb93a386Sopenharmony_ci fBackbuffers[i].fImageIndex = -1; 397cb93a386Sopenharmony_ci SkDEBUGCODE(VkResult result = )GR_VK_CALL(fInterface, 398cb93a386Sopenharmony_ci CreateSemaphore(fDevice, &semaphoreInfo, nullptr, 399cb93a386Sopenharmony_ci &fBackbuffers[i].fRenderSemaphore)); 400cb93a386Sopenharmony_ci SkASSERT(result == VK_SUCCESS); 401cb93a386Sopenharmony_ci } 402cb93a386Sopenharmony_ci fCurrentBackbufferIndex = fImageCount; 403cb93a386Sopenharmony_ci return true; 404cb93a386Sopenharmony_ci} 405cb93a386Sopenharmony_ci 406cb93a386Sopenharmony_civoid VulkanWindowContext::destroyBuffers() { 407cb93a386Sopenharmony_ci 408cb93a386Sopenharmony_ci if (fBackbuffers) { 409cb93a386Sopenharmony_ci for (uint32_t i = 0; i < fImageCount + 1; ++i) { 410cb93a386Sopenharmony_ci fBackbuffers[i].fImageIndex = -1; 411cb93a386Sopenharmony_ci GR_VK_CALL(fInterface, 412cb93a386Sopenharmony_ci DestroySemaphore(fDevice, 413cb93a386Sopenharmony_ci fBackbuffers[i].fRenderSemaphore, 414cb93a386Sopenharmony_ci nullptr)); 415cb93a386Sopenharmony_ci } 416cb93a386Sopenharmony_ci } 417cb93a386Sopenharmony_ci 418cb93a386Sopenharmony_ci delete[] fBackbuffers; 419cb93a386Sopenharmony_ci fBackbuffers = nullptr; 420cb93a386Sopenharmony_ci 421cb93a386Sopenharmony_ci // Does this actually free the surfaces? 422cb93a386Sopenharmony_ci delete[] fSurfaces; 423cb93a386Sopenharmony_ci fSurfaces = nullptr; 424cb93a386Sopenharmony_ci delete[] fImageLayouts; 425cb93a386Sopenharmony_ci fImageLayouts = nullptr; 426cb93a386Sopenharmony_ci delete[] fImages; 427cb93a386Sopenharmony_ci fImages = nullptr; 428cb93a386Sopenharmony_ci} 429cb93a386Sopenharmony_ci 430cb93a386Sopenharmony_ciVulkanWindowContext::~VulkanWindowContext() { 431cb93a386Sopenharmony_ci this->destroyContext(); 432cb93a386Sopenharmony_ci} 433cb93a386Sopenharmony_ci 434cb93a386Sopenharmony_civoid VulkanWindowContext::destroyContext() { 435cb93a386Sopenharmony_ci if (this->isValid()) { 436cb93a386Sopenharmony_ci fQueueWaitIdle(fPresentQueue); 437cb93a386Sopenharmony_ci fDeviceWaitIdle(fDevice); 438cb93a386Sopenharmony_ci 439cb93a386Sopenharmony_ci this->destroyBuffers(); 440cb93a386Sopenharmony_ci 441cb93a386Sopenharmony_ci if (VK_NULL_HANDLE != fSwapchain) { 442cb93a386Sopenharmony_ci fDestroySwapchainKHR(fDevice, fSwapchain, nullptr); 443cb93a386Sopenharmony_ci fSwapchain = VK_NULL_HANDLE; 444cb93a386Sopenharmony_ci } 445cb93a386Sopenharmony_ci 446cb93a386Sopenharmony_ci if (VK_NULL_HANDLE != fSurface) { 447cb93a386Sopenharmony_ci fDestroySurfaceKHR(fInstance, fSurface, nullptr); 448cb93a386Sopenharmony_ci fSurface = VK_NULL_HANDLE; 449cb93a386Sopenharmony_ci } 450cb93a386Sopenharmony_ci } 451cb93a386Sopenharmony_ci 452cb93a386Sopenharmony_ci SkASSERT(fContext->unique()); 453cb93a386Sopenharmony_ci fContext.reset(); 454cb93a386Sopenharmony_ci fInterface.reset(); 455cb93a386Sopenharmony_ci 456cb93a386Sopenharmony_ci if (VK_NULL_HANDLE != fDevice) { 457cb93a386Sopenharmony_ci fDestroyDevice(fDevice, nullptr); 458cb93a386Sopenharmony_ci fDevice = VK_NULL_HANDLE; 459cb93a386Sopenharmony_ci } 460cb93a386Sopenharmony_ci 461cb93a386Sopenharmony_ci#ifdef SK_ENABLE_VK_LAYERS 462cb93a386Sopenharmony_ci if (fDebugCallback != VK_NULL_HANDLE) { 463cb93a386Sopenharmony_ci fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr); 464cb93a386Sopenharmony_ci } 465cb93a386Sopenharmony_ci#endif 466cb93a386Sopenharmony_ci 467cb93a386Sopenharmony_ci fPhysicalDevice = VK_NULL_HANDLE; 468cb93a386Sopenharmony_ci 469cb93a386Sopenharmony_ci if (VK_NULL_HANDLE != fInstance) { 470cb93a386Sopenharmony_ci fDestroyInstance(fInstance, nullptr); 471cb93a386Sopenharmony_ci fInstance = VK_NULL_HANDLE; 472cb93a386Sopenharmony_ci } 473cb93a386Sopenharmony_ci} 474cb93a386Sopenharmony_ci 475cb93a386Sopenharmony_ciVulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() { 476cb93a386Sopenharmony_ci SkASSERT(fBackbuffers); 477cb93a386Sopenharmony_ci 478cb93a386Sopenharmony_ci ++fCurrentBackbufferIndex; 479cb93a386Sopenharmony_ci if (fCurrentBackbufferIndex > fImageCount) { 480cb93a386Sopenharmony_ci fCurrentBackbufferIndex = 0; 481cb93a386Sopenharmony_ci } 482cb93a386Sopenharmony_ci 483cb93a386Sopenharmony_ci BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex; 484cb93a386Sopenharmony_ci return backbuffer; 485cb93a386Sopenharmony_ci} 486cb93a386Sopenharmony_ci 487cb93a386Sopenharmony_cisk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() { 488cb93a386Sopenharmony_ci BackbufferInfo* backbuffer = this->getAvailableBackbuffer(); 489cb93a386Sopenharmony_ci SkASSERT(backbuffer); 490cb93a386Sopenharmony_ci 491cb93a386Sopenharmony_ci // semaphores should be in unsignaled state 492cb93a386Sopenharmony_ci VkSemaphoreCreateInfo semaphoreInfo; 493cb93a386Sopenharmony_ci memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo)); 494cb93a386Sopenharmony_ci semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 495cb93a386Sopenharmony_ci semaphoreInfo.pNext = nullptr; 496cb93a386Sopenharmony_ci semaphoreInfo.flags = 0; 497cb93a386Sopenharmony_ci VkSemaphore semaphore; 498cb93a386Sopenharmony_ci SkDEBUGCODE(VkResult result = )GR_VK_CALL(fInterface, CreateSemaphore(fDevice, &semaphoreInfo, 499cb93a386Sopenharmony_ci nullptr, &semaphore)); 500cb93a386Sopenharmony_ci SkASSERT(result == VK_SUCCESS); 501cb93a386Sopenharmony_ci 502cb93a386Sopenharmony_ci // acquire the image 503cb93a386Sopenharmony_ci VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX, 504cb93a386Sopenharmony_ci semaphore, VK_NULL_HANDLE, 505cb93a386Sopenharmony_ci &backbuffer->fImageIndex); 506cb93a386Sopenharmony_ci if (VK_ERROR_SURFACE_LOST_KHR == res) { 507cb93a386Sopenharmony_ci // need to figure out how to create a new vkSurface without the platformData* 508cb93a386Sopenharmony_ci // maybe use attach somehow? but need a Window 509cb93a386Sopenharmony_ci GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr)); 510cb93a386Sopenharmony_ci return nullptr; 511cb93a386Sopenharmony_ci } 512cb93a386Sopenharmony_ci if (VK_ERROR_OUT_OF_DATE_KHR == res) { 513cb93a386Sopenharmony_ci // tear swapchain down and try again 514cb93a386Sopenharmony_ci if (!this->createSwapchain(-1, -1, fDisplayParams)) { 515cb93a386Sopenharmony_ci GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr)); 516cb93a386Sopenharmony_ci return nullptr; 517cb93a386Sopenharmony_ci } 518cb93a386Sopenharmony_ci backbuffer = this->getAvailableBackbuffer(); 519cb93a386Sopenharmony_ci 520cb93a386Sopenharmony_ci // acquire the image 521cb93a386Sopenharmony_ci res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX, 522cb93a386Sopenharmony_ci semaphore, VK_NULL_HANDLE, 523cb93a386Sopenharmony_ci &backbuffer->fImageIndex); 524cb93a386Sopenharmony_ci 525cb93a386Sopenharmony_ci if (VK_SUCCESS != res) { 526cb93a386Sopenharmony_ci GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr)); 527cb93a386Sopenharmony_ci return nullptr; 528cb93a386Sopenharmony_ci } 529cb93a386Sopenharmony_ci } 530cb93a386Sopenharmony_ci 531cb93a386Sopenharmony_ci SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get(); 532cb93a386Sopenharmony_ci 533cb93a386Sopenharmony_ci GrBackendSemaphore beSemaphore; 534cb93a386Sopenharmony_ci beSemaphore.initVulkan(semaphore); 535cb93a386Sopenharmony_ci 536cb93a386Sopenharmony_ci surface->wait(1, &beSemaphore); 537cb93a386Sopenharmony_ci 538cb93a386Sopenharmony_ci return sk_ref_sp(surface); 539cb93a386Sopenharmony_ci} 540cb93a386Sopenharmony_ci 541cb93a386Sopenharmony_civoid VulkanWindowContext::swapBuffers() { 542cb93a386Sopenharmony_ci 543cb93a386Sopenharmony_ci BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex; 544cb93a386Sopenharmony_ci SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get(); 545cb93a386Sopenharmony_ci 546cb93a386Sopenharmony_ci GrBackendSemaphore beSemaphore; 547cb93a386Sopenharmony_ci beSemaphore.initVulkan(backbuffer->fRenderSemaphore); 548cb93a386Sopenharmony_ci 549cb93a386Sopenharmony_ci GrFlushInfo info; 550cb93a386Sopenharmony_ci info.fNumSemaphores = 1; 551cb93a386Sopenharmony_ci info.fSignalSemaphores = &beSemaphore; 552cb93a386Sopenharmony_ci GrBackendSurfaceMutableState presentState(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, fPresentQueueIndex); 553cb93a386Sopenharmony_ci surface->flush(info, &presentState); 554cb93a386Sopenharmony_ci surface->recordingContext()->asDirectContext()->submit(); 555cb93a386Sopenharmony_ci 556cb93a386Sopenharmony_ci // Submit present operation to present queue 557cb93a386Sopenharmony_ci const VkPresentInfoKHR presentInfo = 558cb93a386Sopenharmony_ci { 559cb93a386Sopenharmony_ci VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType 560cb93a386Sopenharmony_ci nullptr, // pNext 561cb93a386Sopenharmony_ci 1, // waitSemaphoreCount 562cb93a386Sopenharmony_ci &backbuffer->fRenderSemaphore, // pWaitSemaphores 563cb93a386Sopenharmony_ci 1, // swapchainCount 564cb93a386Sopenharmony_ci &fSwapchain, // pSwapchains 565cb93a386Sopenharmony_ci &backbuffer->fImageIndex, // pImageIndices 566cb93a386Sopenharmony_ci nullptr // pResults 567cb93a386Sopenharmony_ci }; 568cb93a386Sopenharmony_ci 569cb93a386Sopenharmony_ci fQueuePresentKHR(fPresentQueue, &presentInfo); 570cb93a386Sopenharmony_ci} 571cb93a386Sopenharmony_ci 572cb93a386Sopenharmony_ci} //namespace sk_app 573