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