blob: ad0e15ca7b8a26a25d6a8b45de4e7de9a234bdaf [file] [log] [blame]
jvanverth9f372462016-04-06 06:08:59 -07001
2/*
3 * Copyright 2015 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
Greg Daniele79b4732017-04-20 14:07:46 -04009#include "GrBackendSurface.h"
jvanverth9f372462016-04-06 06:08:59 -070010#include "GrContext.h"
Hal Canary95e3c052017-01-11 12:44:43 -050011#include "SkAutoMalloc.h"
jvanverth9f372462016-04-06 06:08:59 -070012#include "SkSurface.h"
jvanvertha8d0d6c2016-05-05 12:32:03 -070013#include "VulkanWindowContext.h"
jvanverth9f372462016-04-06 06:08:59 -070014
Greg Daniel6ddbafc2018-05-24 12:34:29 -040015#include "vk/GrVkImage.h"
jvanverth9f372462016-04-06 06:08:59 -070016#include "vk/GrVkInterface.h"
17#include "vk/GrVkUtil.h"
18#include "vk/GrVkTypes.h"
19
20#ifdef VK_USE_PLATFORM_WIN32_KHR
21// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
22#undef CreateSemaphore
23#endif
24
Greg Daniel35970ec2017-11-10 10:03:05 -050025#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(instance, "vk" #F)
26#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(device, "vk" #F)
jvanverthb0d43522016-04-21 11:46:23 -070027
jvanvertha8d0d6c2016-05-05 12:32:03 -070028namespace sk_app {
29
bsalomond1bdd1f2016-07-26 12:02:50 -070030VulkanWindowContext::VulkanWindowContext(const DisplayParams& params,
31 CreateVkSurfaceFn createVkSurface,
Greg Daniel35970ec2017-11-10 10:03:05 -050032 CanPresentFn canPresent,
33 PFN_vkGetInstanceProcAddr instProc,
34 PFN_vkGetDeviceProcAddr devProc)
Jim Van Verthfbdc0802017-05-02 16:15:53 -040035 : WindowContext(params)
36 , fCreateVkSurfaceFn(createVkSurface)
37 , fCanPresentFn(canPresent)
jvanverthaf236b52016-05-20 06:01:06 -070038 , fSurface(VK_NULL_HANDLE)
jvanvertha8d0d6c2016-05-05 12:32:03 -070039 , fSwapchain(VK_NULL_HANDLE)
jvanverthaf236b52016-05-20 06:01:06 -070040 , fImages(nullptr)
41 , fImageLayouts(nullptr)
42 , fSurfaces(nullptr)
jvanvertha8d0d6c2016-05-05 12:32:03 -070043 , fCommandPool(VK_NULL_HANDLE)
44 , fBackbuffers(nullptr) {
Greg Daniel35970ec2017-11-10 10:03:05 -050045 fGetInstanceProcAddr = instProc;
46 fGetDeviceProcAddr = devProc;
Jim Van Verthfbdc0802017-05-02 16:15:53 -040047 this->initializeContext();
48}
jvanverth9f372462016-04-06 06:08:59 -070049
Jim Van Verthfbdc0802017-05-02 16:15:53 -040050void VulkanWindowContext::initializeContext() {
jvanverth9f372462016-04-06 06:08:59 -070051 // any config code here (particularly for msaa)?
Greg Daniel35970ec2017-11-10 10:03:05 -050052 fBackendContext.reset(GrVkBackendContext::Create(fGetInstanceProcAddr, fGetDeviceProcAddr,
Jim Van Verthfbdc0802017-05-02 16:15:53 -040053 &fPresentQueueIndex, fCanPresentFn));
jvanverth9f372462016-04-06 06:08:59 -070054
jvanverthb0d43522016-04-21 11:46:23 -070055 if (!(fBackendContext->fExtensions & kKHR_surface_GrVkExtensionFlag) ||
56 !(fBackendContext->fExtensions & kKHR_swapchain_GrVkExtensionFlag)) {
57 fBackendContext.reset(nullptr);
58 return;
59 }
60
61 VkInstance instance = fBackendContext->fInstance;
62 VkDevice device = fBackendContext->fDevice;
63 GET_PROC(DestroySurfaceKHR);
64 GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
65 GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
66 GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
67 GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
68 GET_DEV_PROC(CreateSwapchainKHR);
69 GET_DEV_PROC(DestroySwapchainKHR);
70 GET_DEV_PROC(GetSwapchainImagesKHR);
71 GET_DEV_PROC(AcquireNextImageKHR);
72 GET_DEV_PROC(QueuePresentKHR);
Greg Daniel35970ec2017-11-10 10:03:05 -050073 GET_DEV_PROC(GetDeviceQueue);
jvanverth9f372462016-04-06 06:08:59 -070074
Brian Salomon384fab42017-12-07 12:33:05 -050075 fContext = GrContext::MakeVulkan(fBackendContext, fDisplayParams.fGrContextOptions);
jvanverth9f372462016-04-06 06:08:59 -070076
Jim Van Verthfbdc0802017-05-02 16:15:53 -040077 fSurface = fCreateVkSurfaceFn(instance);
jvanverth9f372462016-04-06 06:08:59 -070078 if (VK_NULL_HANDLE == fSurface) {
79 fBackendContext.reset(nullptr);
80 return;
81 }
82
jvanverth9f372462016-04-06 06:08:59 -070083 VkBool32 supported;
jvanverthb0d43522016-04-21 11:46:23 -070084 VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fBackendContext->fPhysicalDevice,
85 fPresentQueueIndex, fSurface,
86 &supported);
jvanverth9f372462016-04-06 06:08:59 -070087 if (VK_SUCCESS != res) {
88 this->destroyContext();
89 return;
90 }
91
Jim Van Verthfbdc0802017-05-02 16:15:53 -040092 if (!this->createSwapchain(-1, -1, fDisplayParams)) {
jvanverth9f372462016-04-06 06:08:59 -070093 this->destroyContext();
94 return;
95 }
96
97 // create presentQueue
Greg Daniel35970ec2017-11-10 10:03:05 -050098 fGetDeviceQueue(fBackendContext->fDevice, fPresentQueueIndex, 0, &fPresentQueue);
jvanverth9f372462016-04-06 06:08:59 -070099}
100
bsalomonccde4ab2016-07-27 08:50:12 -0700101bool VulkanWindowContext::createSwapchain(int width, int height,
brianosman05de2162016-05-06 13:28:57 -0700102 const DisplayParams& params) {
jvanverth9f372462016-04-06 06:08:59 -0700103 // check for capabilities
104 VkSurfaceCapabilitiesKHR caps;
jvanverthb0d43522016-04-21 11:46:23 -0700105 VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fBackendContext->fPhysicalDevice,
106 fSurface, &caps);
jvanverth9f372462016-04-06 06:08:59 -0700107 if (VK_SUCCESS != res) {
108 return false;
109 }
110
111 uint32_t surfaceFormatCount;
jvanverthb0d43522016-04-21 11:46:23 -0700112 res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
113 &surfaceFormatCount, nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700114 if (VK_SUCCESS != res) {
115 return false;
116 }
117
118 SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
119 VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
jvanverthb0d43522016-04-21 11:46:23 -0700120 res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
121 &surfaceFormatCount, surfaceFormats);
jvanverth9f372462016-04-06 06:08:59 -0700122 if (VK_SUCCESS != res) {
123 return false;
124 }
125
126 uint32_t presentModeCount;
jvanverthb0d43522016-04-21 11:46:23 -0700127 res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
128 &presentModeCount, nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700129 if (VK_SUCCESS != res) {
130 return false;
131 }
132
133 SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
134 VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
jvanverthb0d43522016-04-21 11:46:23 -0700135 res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700136 &presentModeCount, presentModes);
jvanverth9f372462016-04-06 06:08:59 -0700137 if (VK_SUCCESS != res) {
138 return false;
139 }
140
141 VkExtent2D extent = caps.currentExtent;
142 // use the hints
143 if (extent.width == (uint32_t)-1) {
144 extent.width = width;
145 extent.height = height;
146 }
147
jvanverth9fab59d2016-04-06 12:08:51 -0700148 // clamp width; to protect us from broken hints
jvanverth9f372462016-04-06 06:08:59 -0700149 if (extent.width < caps.minImageExtent.width) {
150 extent.width = caps.minImageExtent.width;
151 } else if (extent.width > caps.maxImageExtent.width) {
152 extent.width = caps.maxImageExtent.width;
153 }
154 // clamp height
155 if (extent.height < caps.minImageExtent.height) {
156 extent.height = caps.minImageExtent.height;
157 } else if (extent.height > caps.maxImageExtent.height) {
158 extent.height = caps.maxImageExtent.height;
159 }
jvanverth1d155962016-05-23 13:13:36 -0700160
jvanverth9f372462016-04-06 06:08:59 -0700161 fWidth = (int)extent.width;
162 fHeight = (int)extent.height;
163
164 uint32_t imageCount = caps.minImageCount + 2;
165 if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
166 // Application must settle for fewer images than desired:
167 imageCount = caps.maxImageCount;
168 }
169
170 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
171 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
172 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
173 SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
174 SkASSERT(caps.supportedTransforms & caps.currentTransform);
175 SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
176 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
177 VkCompositeAlphaFlagBitsKHR composite_alpha =
178 (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
179 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
180 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
181
brianosman05de2162016-05-06 13:28:57 -0700182 // Pick our surface format. For now, just make sure it matches our sRGB request:
183 VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
184 VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
brianosman05de2162016-05-06 13:28:57 -0700185 for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
Greg Daniel81b80592017-12-13 10:20:04 -0500186 VkFormat localFormat = surfaceFormats[i].format;
Brian Osman2b23c4b2018-06-01 12:25:08 -0400187 if (GrVkFormatIsSupported(localFormat)) {
Greg Daniel81b80592017-12-13 10:20:04 -0500188 surfaceFormat = localFormat;
brianosman05de2162016-05-06 13:28:57 -0700189 colorSpace = surfaceFormats[i].colorSpace;
190 break;
191 }
192 }
193 fDisplayParams = params;
csmartdalton578f0642017-02-24 16:04:47 -0700194 fSampleCount = params.fMSAASampleCount;
195 fStencilBits = 8;
brianosman05de2162016-05-06 13:28:57 -0700196
197 if (VK_FORMAT_UNDEFINED == surfaceFormat) {
198 return false;
199 }
jvanvertha4b0fed2016-04-27 11:42:21 -0700200
Greg Danielfaa095e2017-12-19 13:15:02 -0500201 SkColorType colorType;
202 switch (surfaceFormat) {
203 case VK_FORMAT_R8G8B8A8_UNORM: // fall through
204 case VK_FORMAT_R8G8B8A8_SRGB:
205 colorType = kRGBA_8888_SkColorType;
206 break;
207 case VK_FORMAT_B8G8R8A8_UNORM: // fall through
208 case VK_FORMAT_B8G8R8A8_SRGB:
209 colorType = kBGRA_8888_SkColorType;
210 break;
211 default:
212 return false;
213 }
214
jvanverth3d6ed3a2016-04-07 11:09:51 -0700215 // If mailbox mode is available, use it, as it is the lowest-latency non-
216 // tearing mode. If not, fall back to FIFO which is always available.
jvanverth9f372462016-04-06 06:08:59 -0700217 VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
jvanverth9f372462016-04-06 06:08:59 -0700218 for (uint32_t i = 0; i < presentModeCount; ++i) {
jvanverth3d6ed3a2016-04-07 11:09:51 -0700219 // use mailbox
220 if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
jvanverth9f372462016-04-06 06:08:59 -0700221 mode = presentModes[i];
jvanverth3d6ed3a2016-04-07 11:09:51 -0700222 break;
jvanverth9f372462016-04-06 06:08:59 -0700223 }
224 }
225
226 VkSwapchainCreateInfoKHR swapchainCreateInfo;
227 memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
228 swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
229 swapchainCreateInfo.surface = fSurface;
230 swapchainCreateInfo.minImageCount = imageCount;
jvanvertha4b0fed2016-04-27 11:42:21 -0700231 swapchainCreateInfo.imageFormat = surfaceFormat;
232 swapchainCreateInfo.imageColorSpace = colorSpace;
jvanverth9f372462016-04-06 06:08:59 -0700233 swapchainCreateInfo.imageExtent = extent;
234 swapchainCreateInfo.imageArrayLayers = 1;
235 swapchainCreateInfo.imageUsage = usageFlags;
236
jvanverthb0d43522016-04-21 11:46:23 -0700237 uint32_t queueFamilies[] = { fBackendContext->fGraphicsQueueIndex, fPresentQueueIndex };
238 if (fBackendContext->fGraphicsQueueIndex != fPresentQueueIndex) {
jvanverth9f372462016-04-06 06:08:59 -0700239 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
240 swapchainCreateInfo.queueFamilyIndexCount = 2;
241 swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
242 } else {
243 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
244 swapchainCreateInfo.queueFamilyIndexCount = 0;
245 swapchainCreateInfo.pQueueFamilyIndices = nullptr;
246 }
247
Greg Daniele897b972016-10-06 13:57:57 -0400248 swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
jvanverth9f372462016-04-06 06:08:59 -0700249 swapchainCreateInfo.compositeAlpha = composite_alpha;
250 swapchainCreateInfo.presentMode = mode;
251 swapchainCreateInfo.clipped = true;
252 swapchainCreateInfo.oldSwapchain = fSwapchain;
253
jvanverthb0d43522016-04-21 11:46:23 -0700254 res = fCreateSwapchainKHR(fBackendContext->fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
jvanverth9f372462016-04-06 06:08:59 -0700255 if (VK_SUCCESS != res) {
256 return false;
257 }
258
259 // destroy the old swapchain
260 if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
261 GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
262
263 this->destroyBuffers();
264
jvanverthb0d43522016-04-21 11:46:23 -0700265 fDestroySwapchainKHR(fBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700266 }
267
Greg Danielfaa095e2017-12-19 13:15:02 -0500268 this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
jvanverth9f372462016-04-06 06:08:59 -0700269
270 return true;
271}
272
Greg Danielfaa095e2017-12-19 13:15:02 -0500273void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
jvanverthb0d43522016-04-21 11:46:23 -0700274 fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700275 SkASSERT(fImageCount);
276 fImages = new VkImage[fImageCount];
jvanverthb0d43522016-04-21 11:46:23 -0700277 fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, fImages);
jvanverth9f372462016-04-06 06:08:59 -0700278
279 // set up initial image layouts and create surfaces
280 fImageLayouts = new VkImageLayout[fImageCount];
281 fSurfaces = new sk_sp<SkSurface>[fImageCount];
282 for (uint32_t i = 0; i < fImageCount; ++i) {
283 fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
284
egdanielb2df0c22016-05-13 11:30:37 -0700285 GrVkImageInfo info;
jvanverth9f372462016-04-06 06:08:59 -0700286 info.fImage = fImages[i];
Greg Daniel8385a8a2018-02-26 13:29:37 -0500287 info.fAlloc = GrVkAlloc();
egdaniel580fa592016-08-31 11:03:50 -0700288 info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
jvanverth9f372462016-04-06 06:08:59 -0700289 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
egdaniel58a8d922016-04-21 08:03:10 -0700290 info.fFormat = format;
jvanverth3622a172016-05-10 06:42:18 -0700291 info.fLevelCount = 1;
jvanverthaf236b52016-05-20 06:01:06 -0700292
Brian Salomonafdc6b12018-03-09 12:02:32 -0500293 GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
Greg Daniele79b4732017-04-20 14:07:46 -0400294
Brian Salomonafdc6b12018-03-09 12:02:32 -0500295 fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(fContext.get(),
296 backendRT,
297 kTopLeft_GrSurfaceOrigin,
298 colorType,
299 fDisplayParams.fColorSpace,
Ben Wagner37c54032018-04-13 14:30:23 -0400300 &fDisplayParams.fSurfaceProps);
jvanverth9f372462016-04-06 06:08:59 -0700301 }
302
303 // create the command pool for the command buffers
304 if (VK_NULL_HANDLE == fCommandPool) {
305 VkCommandPoolCreateInfo commandPoolInfo;
306 memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
307 commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
308 // this needs to be on the render queue
jvanverthb0d43522016-04-21 11:46:23 -0700309 commandPoolInfo.queueFamilyIndex = fBackendContext->fGraphicsQueueIndex;
jvanverth9f372462016-04-06 06:08:59 -0700310 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
311 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
312 CreateCommandPool(fBackendContext->fDevice, &commandPoolInfo,
313 nullptr, &fCommandPool));
314 }
315
316 // set up the backbuffers
317 VkSemaphoreCreateInfo semaphoreInfo;
318 memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
319 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
320 semaphoreInfo.pNext = nullptr;
321 semaphoreInfo.flags = 0;
322 VkCommandBufferAllocateInfo commandBuffersInfo;
323 memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
324 commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
325 commandBuffersInfo.pNext = nullptr;
326 commandBuffersInfo.commandPool = fCommandPool;
327 commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
328 commandBuffersInfo.commandBufferCount = 2;
329 VkFenceCreateInfo fenceInfo;
330 memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
331 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
332 fenceInfo.pNext = nullptr;
333 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
334
Greg Daniel1f05f442016-10-27 16:37:17 -0400335 // we create one additional backbuffer structure here, because we want to
jvanverth9f372462016-04-06 06:08:59 -0700336 // give the command buffers they contain a chance to finish before we cycle back
337 fBackbuffers = new BackbufferInfo[fImageCount + 1];
338 for (uint32_t i = 0; i < fImageCount + 1; ++i) {
339 fBackbuffers[i].fImageIndex = -1;
340 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
341 CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
342 nullptr, &fBackbuffers[i].fAcquireSemaphore));
343 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
344 CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
345 nullptr, &fBackbuffers[i].fRenderSemaphore));
346 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
347 AllocateCommandBuffers(fBackendContext->fDevice, &commandBuffersInfo,
348 fBackbuffers[i].fTransitionCmdBuffers));
349 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
350 CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
351 &fBackbuffers[i].fUsageFences[0]));
352 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
353 CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
354 &fBackbuffers[i].fUsageFences[1]));
355 }
356 fCurrentBackbufferIndex = fImageCount;
357}
358
jvanvertha8d0d6c2016-05-05 12:32:03 -0700359void VulkanWindowContext::destroyBuffers() {
jvanverth9f372462016-04-06 06:08:59 -0700360
361 if (fBackbuffers) {
362 for (uint32_t i = 0; i < fImageCount + 1; ++i) {
363 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700364 WaitForFences(fBackendContext->fDevice, 2,
jvanverth9f372462016-04-06 06:08:59 -0700365 fBackbuffers[i].fUsageFences,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700366 true, UINT64_MAX));
jvanverth9f372462016-04-06 06:08:59 -0700367 fBackbuffers[i].fImageIndex = -1;
368 GR_VK_CALL(fBackendContext->fInterface,
369 DestroySemaphore(fBackendContext->fDevice,
370 fBackbuffers[i].fAcquireSemaphore,
371 nullptr));
372 GR_VK_CALL(fBackendContext->fInterface,
373 DestroySemaphore(fBackendContext->fDevice,
374 fBackbuffers[i].fRenderSemaphore,
375 nullptr));
376 GR_VK_CALL(fBackendContext->fInterface,
377 FreeCommandBuffers(fBackendContext->fDevice, fCommandPool, 2,
378 fBackbuffers[i].fTransitionCmdBuffers));
379 GR_VK_CALL(fBackendContext->fInterface,
380 DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[0], 0));
381 GR_VK_CALL(fBackendContext->fInterface,
382 DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[1], 0));
383 }
384 }
385
386 delete[] fBackbuffers;
387 fBackbuffers = nullptr;
388
jvanverthaf236b52016-05-20 06:01:06 -0700389 // Does this actually free the surfaces?
jvanverth9f372462016-04-06 06:08:59 -0700390 delete[] fSurfaces;
391 fSurfaces = nullptr;
392 delete[] fImageLayouts;
393 fImageLayouts = nullptr;
394 delete[] fImages;
395 fImages = nullptr;
396}
397
jvanvertha8d0d6c2016-05-05 12:32:03 -0700398VulkanWindowContext::~VulkanWindowContext() {
jvanverth9f372462016-04-06 06:08:59 -0700399 this->destroyContext();
400}
401
jvanvertha8d0d6c2016-05-05 12:32:03 -0700402void VulkanWindowContext::destroyContext() {
jvanverth9f372462016-04-06 06:08:59 -0700403 if (!fBackendContext.get()) {
404 return;
405 }
406
jvanverth85f758c2016-05-27 06:47:08 -0700407 GR_VK_CALL(fBackendContext->fInterface, QueueWaitIdle(fPresentQueue));
jvanverth9f372462016-04-06 06:08:59 -0700408 GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
409
410 this->destroyBuffers();
411
412 if (VK_NULL_HANDLE != fCommandPool) {
413 GR_VK_CALL(fBackendContext->fInterface, DestroyCommandPool(fBackendContext->fDevice,
414 fCommandPool, nullptr));
415 fCommandPool = VK_NULL_HANDLE;
416 }
417
418 if (VK_NULL_HANDLE != fSwapchain) {
jvanverthb0d43522016-04-21 11:46:23 -0700419 fDestroySwapchainKHR(fBackendContext->fDevice, fSwapchain, nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700420 fSwapchain = VK_NULL_HANDLE;
421 }
422
423 if (VK_NULL_HANDLE != fSurface) {
jvanverthb0d43522016-04-21 11:46:23 -0700424 fDestroySurfaceKHR(fBackendContext->fInstance, fSurface, nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700425 fSurface = VK_NULL_HANDLE;
426 }
427
Greg Daniel02611d92017-07-25 10:05:01 -0400428 fContext.reset();
jvanverth9f372462016-04-06 06:08:59 -0700429
430 fBackendContext.reset(nullptr);
431}
432
jvanvertha8d0d6c2016-05-05 12:32:03 -0700433VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
jvanverth9f372462016-04-06 06:08:59 -0700434 SkASSERT(fBackbuffers);
435
436 ++fCurrentBackbufferIndex;
egdaniel804af7d2016-09-26 12:30:46 -0700437 if (fCurrentBackbufferIndex > fImageCount) {
jvanverth9f372462016-04-06 06:08:59 -0700438 fCurrentBackbufferIndex = 0;
439 }
440
441 BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
jvanverth9f372462016-04-06 06:08:59 -0700442 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
443 WaitForFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences,
444 true, UINT64_MAX));
445 return backbuffer;
446}
447
jvanverthaf236b52016-05-20 06:01:06 -0700448sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
jvanverth9f372462016-04-06 06:08:59 -0700449 BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
450 SkASSERT(backbuffer);
451
452 // reset the fence
453 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
454 ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences));
455 // semaphores should be in unsignaled state
456
457 // acquire the image
jvanverthb0d43522016-04-21 11:46:23 -0700458 VkResult res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX,
459 backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
460 &backbuffer->fImageIndex);
jvanverth9f372462016-04-06 06:08:59 -0700461 if (VK_ERROR_SURFACE_LOST_KHR == res) {
462 // need to figure out how to create a new vkSurface without the platformData*
jvanverth3d6ed3a2016-04-07 11:09:51 -0700463 // maybe use attach somehow? but need a Window
jvanverth9f372462016-04-06 06:08:59 -0700464 return nullptr;
465 }
jvanverth3d6ed3a2016-04-07 11:09:51 -0700466 if (VK_ERROR_OUT_OF_DATE_KHR == res) {
jvanverth9f372462016-04-06 06:08:59 -0700467 // tear swapchain down and try again
Greg Daniel1f05f442016-10-27 16:37:17 -0400468 if (!this->createSwapchain(-1, -1, fDisplayParams)) {
jvanverth9f372462016-04-06 06:08:59 -0700469 return nullptr;
470 }
Jim Van Verthd63c1022017-01-05 13:50:49 -0500471 backbuffer = this->getAvailableBackbuffer();
472 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
473 ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences));
jvanverth9f372462016-04-06 06:08:59 -0700474
475 // acquire the image
jvanvertha8d0d6c2016-05-05 12:32:03 -0700476 res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX,
jvanverthb0d43522016-04-21 11:46:23 -0700477 backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
478 &backbuffer->fImageIndex);
jvanverth9f372462016-04-06 06:08:59 -0700479
480 if (VK_SUCCESS != res) {
481 return nullptr;
482 }
483 }
484
485 // set up layout transfer from initial to color attachment
486 VkImageLayout layout = fImageLayouts[backbuffer->fImageIndex];
egdaniel580fa592016-08-31 11:03:50 -0700487 SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
jvanverth9f372462016-04-06 06:08:59 -0700488 VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
489 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
490 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
491 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
jvanvertha8d0d6c2016-05-05 12:32:03 -0700492 VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
jvanverth9f372462016-04-06 06:08:59 -0700493 0 : VK_ACCESS_MEMORY_READ_BIT;
494 VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
495
496 VkImageMemoryBarrier imageMemoryBarrier = {
497 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
498 NULL, // pNext
499 srcAccessMask, // outputMask
500 dstAccessMask, // inputMask
501 layout, // oldLayout
502 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
503 fPresentQueueIndex, // srcQueueFamilyIndex
jvanverthb0d43522016-04-21 11:46:23 -0700504 fBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex
jvanverth9f372462016-04-06 06:08:59 -0700505 fImages[backbuffer->fImageIndex], // image
506 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
507 };
508 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
509 ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[0], 0));
510 VkCommandBufferBeginInfo info;
511 memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
512 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
513 info.flags = 0;
514 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
515 BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[0], &info));
516
jvanvertha8d0d6c2016-05-05 12:32:03 -0700517 GR_VK_CALL(fBackendContext->fInterface,
518 CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[0],
519 srcStageMask, dstStageMask, 0,
520 0, nullptr,
521 0, nullptr,
522 1, &imageMemoryBarrier));
jvanverth9f372462016-04-06 06:08:59 -0700523
524 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700525 EndCommandBuffer(backbuffer->fTransitionCmdBuffers[0]));
jvanverth9f372462016-04-06 06:08:59 -0700526
egdaniel58a8d922016-04-21 08:03:10 -0700527 VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
jvanverth9f372462016-04-06 06:08:59 -0700528 // insert the layout transfer into the queue and wait on the acquire
529 VkSubmitInfo submitInfo;
530 memset(&submitInfo, 0, sizeof(VkSubmitInfo));
531 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
532 submitInfo.waitSemaphoreCount = 1;
533 submitInfo.pWaitSemaphores = &backbuffer->fAcquireSemaphore;
egdaniel58a8d922016-04-21 08:03:10 -0700534 submitInfo.pWaitDstStageMask = &waitDstStageFlags;
jvanverth9f372462016-04-06 06:08:59 -0700535 submitInfo.commandBufferCount = 1;
536 submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[0];
537 submitInfo.signalSemaphoreCount = 0;
jvanvertha8d0d6c2016-05-05 12:32:03 -0700538
jvanverth9f372462016-04-06 06:08:59 -0700539 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700540 QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
jvanverth9f372462016-04-06 06:08:59 -0700541 backbuffer->fUsageFences[0]));
542
egdaniel580fa592016-08-31 11:03:50 -0700543 SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
Robert Phillipsba375a82018-04-11 10:08:06 -0400544 GrBackendRenderTarget backendRT = surface->getBackendRenderTarget(
545 SkSurface::kFlushRead_BackendHandleAccess);
546 backendRT.setVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
547
egdaniel580fa592016-08-31 11:03:50 -0700548
549 return sk_ref_sp(surface);
jvanverth9f372462016-04-06 06:08:59 -0700550}
551
jvanvertha8d0d6c2016-05-05 12:32:03 -0700552void VulkanWindowContext::swapBuffers() {
jvanverth9f372462016-04-06 06:08:59 -0700553
554 BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
egdaniel580fa592016-08-31 11:03:50 -0700555 SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
jvanverth9f372462016-04-06 06:08:59 -0700556
Robert Phillipsba375a82018-04-11 10:08:06 -0400557 GrBackendRenderTarget backendRT = surface->getBackendRenderTarget(
558 SkSurface::kFlushRead_BackendHandleAccess);
559 GrVkImageInfo imageInfo;
560 SkAssertResult(backendRT.getVkImageInfo(&imageInfo));
561 // Check to make sure we never change the actually wrapped image
562 SkASSERT(imageInfo.fImage == fImages[backbuffer->fImageIndex]);
563
564 VkImageLayout layout = imageInfo.fImageLayout;
Greg Daniel6ddbafc2018-05-24 12:34:29 -0400565 VkPipelineStageFlags srcStageMask = GrVkImage::LayoutToPipelineStageFlags(layout);
jvanverth9f372462016-04-06 06:08:59 -0700566 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
Greg Daniel6ddbafc2018-05-24 12:34:29 -0400567 VkAccessFlags srcAccessMask = GrVkImage::LayoutToSrcAccessMask(layout);
jvanverth9f372462016-04-06 06:08:59 -0700568 VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
569
570 VkImageMemoryBarrier imageMemoryBarrier = {
571 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
572 NULL, // pNext
573 srcAccessMask, // outputMask
574 dstAccessMask, // inputMask
575 layout, // oldLayout
576 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
jvanverthb0d43522016-04-21 11:46:23 -0700577 fBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex
jvanverth9f372462016-04-06 06:08:59 -0700578 fPresentQueueIndex, // dstQueueFamilyIndex
579 fImages[backbuffer->fImageIndex], // image
580 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
581 };
582 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
583 ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[1], 0));
584 VkCommandBufferBeginInfo info;
585 memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
586 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
587 info.flags = 0;
588 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
589 BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[1], &info));
590 GR_VK_CALL(fBackendContext->fInterface,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700591 CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[1],
592 srcStageMask, dstStageMask, 0,
593 0, nullptr,
594 0, nullptr,
595 1, &imageMemoryBarrier));
jvanverth9f372462016-04-06 06:08:59 -0700596 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
597 EndCommandBuffer(backbuffer->fTransitionCmdBuffers[1]));
598
599 fImageLayouts[backbuffer->fImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
600
601 // insert the layout transfer into the queue and wait on the acquire
602 VkSubmitInfo submitInfo;
603 memset(&submitInfo, 0, sizeof(VkSubmitInfo));
604 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
605 submitInfo.waitSemaphoreCount = 0;
606 submitInfo.pWaitDstStageMask = 0;
607 submitInfo.commandBufferCount = 1;
608 submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[1];
609 submitInfo.signalSemaphoreCount = 1;
610 submitInfo.pSignalSemaphores = &backbuffer->fRenderSemaphore;
611
612 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700613 QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
jvanverth9f372462016-04-06 06:08:59 -0700614 backbuffer->fUsageFences[1]));
615
616 // Submit present operation to present queue
617 const VkPresentInfoKHR presentInfo =
618 {
619 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
620 NULL, // pNext
621 1, // waitSemaphoreCount
622 &backbuffer->fRenderSemaphore, // pWaitSemaphores
623 1, // swapchainCount
624 &fSwapchain, // pSwapchains
625 &backbuffer->fImageIndex, // pImageIndices
626 NULL // pResults
627 };
628
jvanverthb0d43522016-04-21 11:46:23 -0700629 fQueuePresentKHR(fPresentQueue, &presentInfo);
jvanverth9f372462016-04-06 06:08:59 -0700630}
jvanvertha8d0d6c2016-05-05 12:32:03 -0700631
632} //namespace sk_app