blob: c82d4f9272098c076886239cd574c1fb47c41d21 [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 Daniel98bffae2018-08-01 13:25:41 -040015#include "vk/GrVkExtensions.h"
Greg Daniel6ddbafc2018-05-24 12:34:29 -040016#include "vk/GrVkImage.h"
jvanverth9f372462016-04-06 06:08:59 -070017#include "vk/GrVkTypes.h"
Greg Daniela31f4e52018-08-01 16:48:52 -040018#include "vk/GrVkUtil.h"
jvanverth9f372462016-04-06 06:08:59 -070019
20#ifdef VK_USE_PLATFORM_WIN32_KHR
21// windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
22#undef CreateSemaphore
23#endif
24
Greg Danielf730c182018-07-02 20:15:37 +000025#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fInstance, "vk" #F)
26#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fDevice, "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)?
jvanverth9f372462016-04-06 06:08:59 -070052
Greg Danield3e65aa2018-08-01 09:19:45 -040053 PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr;
54 PFN_vkGetDeviceProcAddr getDeviceProc = fGetDeviceProcAddr;
55 auto getProc = [getInstanceProc, getDeviceProc](const char* proc_name,
56 VkInstance instance, VkDevice device) {
57 if (device != VK_NULL_HANDLE) {
58 return getDeviceProc(device, proc_name);
59 }
60 return getInstanceProc(instance, proc_name);
61 };
Greg Danielf730c182018-07-02 20:15:37 +000062 GrVkBackendContext backendContext;
Greg Daniel98bffae2018-08-01 13:25:41 -040063 GrVkExtensions extensions;
64 if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, &extensions, &fDebugCallback,
Greg Daniel37329b32018-07-02 20:16:44 +000065 &fPresentQueueIndex, fCanPresentFn)) {
jvanverthb0d43522016-04-21 11:46:23 -070066 return;
67 }
68
Greg Daniela31f4e52018-08-01 16:48:52 -040069 if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) ||
70 !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) {
Greg Danielf730c182018-07-02 20:15:37 +000071 return;
72 }
73
74 fInstance = backendContext.fInstance;
75 fPhysicalDevice = backendContext.fPhysicalDevice;
76 fDevice = backendContext.fDevice;
77 fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex;
78 fGraphicsQueue = backendContext.fQueue;
Greg Danielc0b03d82018-08-03 14:41:15 -040079
80 PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties =
81 reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
82 backendContext.fGetProc("vkGetPhysicalDeviceProperties",
83 backendContext.fInstance,
84 VK_NULL_HANDLE));
85 if (!localGetPhysicalDeviceProperties) {
86 return;
87 }
88 VkPhysicalDeviceProperties physDeviceProperties;
89 localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties);
90 uint32_t physDevVersion = physDeviceProperties.apiVersion;
91
Greg Danielc8cd45a2018-07-12 10:02:37 -040092 fInterface.reset(new GrVkInterface(backendContext.fGetProc, fInstance, fDevice,
Greg Danielc0b03d82018-08-03 14:41:15 -040093 backendContext.fInstanceVersion, physDevVersion,
Greg Daniel98bffae2018-08-01 13:25:41 -040094 &extensions));
Greg Danielf730c182018-07-02 20:15:37 +000095
96 GET_PROC(DestroyInstance);
Greg Daniela31f4e52018-08-01 16:48:52 -040097 if (fDebugCallback != VK_NULL_HANDLE) {
98 GET_PROC(DestroyDebugReportCallbackEXT);
99 }
jvanverthb0d43522016-04-21 11:46:23 -0700100 GET_PROC(DestroySurfaceKHR);
101 GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
102 GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
103 GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
104 GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
Greg Danielf730c182018-07-02 20:15:37 +0000105 GET_DEV_PROC(DeviceWaitIdle);
106 GET_DEV_PROC(QueueWaitIdle);
107 GET_DEV_PROC(DestroyDevice);
jvanverthb0d43522016-04-21 11:46:23 -0700108 GET_DEV_PROC(CreateSwapchainKHR);
109 GET_DEV_PROC(DestroySwapchainKHR);
110 GET_DEV_PROC(GetSwapchainImagesKHR);
111 GET_DEV_PROC(AcquireNextImageKHR);
112 GET_DEV_PROC(QueuePresentKHR);
Greg Daniel35970ec2017-11-10 10:03:05 -0500113 GET_DEV_PROC(GetDeviceQueue);
jvanverth9f372462016-04-06 06:08:59 -0700114
Greg Danielf730c182018-07-02 20:15:37 +0000115 fContext = GrContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions);
jvanverth9f372462016-04-06 06:08:59 -0700116
Greg Danielf730c182018-07-02 20:15:37 +0000117 fSurface = fCreateVkSurfaceFn(fInstance);
jvanverth9f372462016-04-06 06:08:59 -0700118 if (VK_NULL_HANDLE == fSurface) {
Greg Danielf730c182018-07-02 20:15:37 +0000119 this->destroyContext();
jvanverth9f372462016-04-06 06:08:59 -0700120 return;
121 }
122
jvanverth9f372462016-04-06 06:08:59 -0700123 VkBool32 supported;
Greg Danielf730c182018-07-02 20:15:37 +0000124 VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex,
125 fSurface, &supported);
jvanverth9f372462016-04-06 06:08:59 -0700126 if (VK_SUCCESS != res) {
127 this->destroyContext();
128 return;
129 }
130
Jim Van Verthfbdc0802017-05-02 16:15:53 -0400131 if (!this->createSwapchain(-1, -1, fDisplayParams)) {
jvanverth9f372462016-04-06 06:08:59 -0700132 this->destroyContext();
133 return;
134 }
135
136 // create presentQueue
Greg Danielf730c182018-07-02 20:15:37 +0000137 fGetDeviceQueue(fDevice, fPresentQueueIndex, 0, &fPresentQueue);
jvanverth9f372462016-04-06 06:08:59 -0700138}
139
bsalomonccde4ab2016-07-27 08:50:12 -0700140bool VulkanWindowContext::createSwapchain(int width, int height,
brianosman05de2162016-05-06 13:28:57 -0700141 const DisplayParams& params) {
jvanverth9f372462016-04-06 06:08:59 -0700142 // check for capabilities
143 VkSurfaceCapabilitiesKHR caps;
Greg Danielf730c182018-07-02 20:15:37 +0000144 VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fPhysicalDevice, fSurface, &caps);
jvanverth9f372462016-04-06 06:08:59 -0700145 if (VK_SUCCESS != res) {
146 return false;
147 }
148
149 uint32_t surfaceFormatCount;
Greg Danielf730c182018-07-02 20:15:37 +0000150 res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
151 nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700152 if (VK_SUCCESS != res) {
153 return false;
154 }
155
156 SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
157 VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
Greg Danielf730c182018-07-02 20:15:37 +0000158 res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
159 surfaceFormats);
jvanverth9f372462016-04-06 06:08:59 -0700160 if (VK_SUCCESS != res) {
161 return false;
162 }
163
164 uint32_t presentModeCount;
Greg Danielf730c182018-07-02 20:15:37 +0000165 res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
166 nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700167 if (VK_SUCCESS != res) {
168 return false;
169 }
170
171 SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
172 VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
Greg Danielf730c182018-07-02 20:15:37 +0000173 res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
174 presentModes);
jvanverth9f372462016-04-06 06:08:59 -0700175 if (VK_SUCCESS != res) {
176 return false;
177 }
178
179 VkExtent2D extent = caps.currentExtent;
180 // use the hints
181 if (extent.width == (uint32_t)-1) {
182 extent.width = width;
183 extent.height = height;
184 }
185
jvanverth9fab59d2016-04-06 12:08:51 -0700186 // clamp width; to protect us from broken hints
jvanverth9f372462016-04-06 06:08:59 -0700187 if (extent.width < caps.minImageExtent.width) {
188 extent.width = caps.minImageExtent.width;
189 } else if (extent.width > caps.maxImageExtent.width) {
190 extent.width = caps.maxImageExtent.width;
191 }
192 // clamp height
193 if (extent.height < caps.minImageExtent.height) {
194 extent.height = caps.minImageExtent.height;
195 } else if (extent.height > caps.maxImageExtent.height) {
196 extent.height = caps.maxImageExtent.height;
197 }
jvanverth1d155962016-05-23 13:13:36 -0700198
jvanverth9f372462016-04-06 06:08:59 -0700199 fWidth = (int)extent.width;
200 fHeight = (int)extent.height;
201
202 uint32_t imageCount = caps.minImageCount + 2;
203 if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
204 // Application must settle for fewer images than desired:
205 imageCount = caps.maxImageCount;
206 }
207
208 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
209 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
210 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
211 SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
212 SkASSERT(caps.supportedTransforms & caps.currentTransform);
213 SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
214 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
215 VkCompositeAlphaFlagBitsKHR composite_alpha =
216 (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
217 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
218 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
219
Brian Osman294fe292018-07-09 10:23:19 -0400220 // Pick our surface format.
brianosman05de2162016-05-06 13:28:57 -0700221 VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
222 VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
brianosman05de2162016-05-06 13:28:57 -0700223 for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
Greg Daniel81b80592017-12-13 10:20:04 -0500224 VkFormat localFormat = surfaceFormats[i].format;
Brian Osman2b23c4b2018-06-01 12:25:08 -0400225 if (GrVkFormatIsSupported(localFormat)) {
Greg Daniel81b80592017-12-13 10:20:04 -0500226 surfaceFormat = localFormat;
brianosman05de2162016-05-06 13:28:57 -0700227 colorSpace = surfaceFormats[i].colorSpace;
228 break;
229 }
230 }
231 fDisplayParams = params;
csmartdalton578f0642017-02-24 16:04:47 -0700232 fSampleCount = params.fMSAASampleCount;
233 fStencilBits = 8;
brianosman05de2162016-05-06 13:28:57 -0700234
235 if (VK_FORMAT_UNDEFINED == surfaceFormat) {
236 return false;
237 }
jvanvertha4b0fed2016-04-27 11:42:21 -0700238
Greg Danielfaa095e2017-12-19 13:15:02 -0500239 SkColorType colorType;
240 switch (surfaceFormat) {
241 case VK_FORMAT_R8G8B8A8_UNORM: // fall through
242 case VK_FORMAT_R8G8B8A8_SRGB:
243 colorType = kRGBA_8888_SkColorType;
244 break;
245 case VK_FORMAT_B8G8R8A8_UNORM: // fall through
246 case VK_FORMAT_B8G8R8A8_SRGB:
247 colorType = kBGRA_8888_SkColorType;
248 break;
249 default:
250 return false;
251 }
252
jvanverth3d6ed3a2016-04-07 11:09:51 -0700253 // If mailbox mode is available, use it, as it is the lowest-latency non-
254 // tearing mode. If not, fall back to FIFO which is always available.
jvanverth9f372462016-04-06 06:08:59 -0700255 VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
jvanverth9f372462016-04-06 06:08:59 -0700256 for (uint32_t i = 0; i < presentModeCount; ++i) {
jvanverth3d6ed3a2016-04-07 11:09:51 -0700257 // use mailbox
258 if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
jvanverth9f372462016-04-06 06:08:59 -0700259 mode = presentModes[i];
jvanverth3d6ed3a2016-04-07 11:09:51 -0700260 break;
jvanverth9f372462016-04-06 06:08:59 -0700261 }
262 }
263
264 VkSwapchainCreateInfoKHR swapchainCreateInfo;
265 memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
266 swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
267 swapchainCreateInfo.surface = fSurface;
268 swapchainCreateInfo.minImageCount = imageCount;
jvanvertha4b0fed2016-04-27 11:42:21 -0700269 swapchainCreateInfo.imageFormat = surfaceFormat;
270 swapchainCreateInfo.imageColorSpace = colorSpace;
jvanverth9f372462016-04-06 06:08:59 -0700271 swapchainCreateInfo.imageExtent = extent;
272 swapchainCreateInfo.imageArrayLayers = 1;
273 swapchainCreateInfo.imageUsage = usageFlags;
274
Greg Danielf730c182018-07-02 20:15:37 +0000275 uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex };
276 if (fGraphicsQueueIndex != fPresentQueueIndex) {
jvanverth9f372462016-04-06 06:08:59 -0700277 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
278 swapchainCreateInfo.queueFamilyIndexCount = 2;
279 swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
280 } else {
281 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
282 swapchainCreateInfo.queueFamilyIndexCount = 0;
283 swapchainCreateInfo.pQueueFamilyIndices = nullptr;
284 }
285
Greg Daniele897b972016-10-06 13:57:57 -0400286 swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
jvanverth9f372462016-04-06 06:08:59 -0700287 swapchainCreateInfo.compositeAlpha = composite_alpha;
288 swapchainCreateInfo.presentMode = mode;
289 swapchainCreateInfo.clipped = true;
290 swapchainCreateInfo.oldSwapchain = fSwapchain;
291
Greg Danielf730c182018-07-02 20:15:37 +0000292 res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
jvanverth9f372462016-04-06 06:08:59 -0700293 if (VK_SUCCESS != res) {
294 return false;
295 }
296
297 // destroy the old swapchain
298 if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
Greg Danielf730c182018-07-02 20:15:37 +0000299 fDeviceWaitIdle(fDevice);
jvanverth9f372462016-04-06 06:08:59 -0700300
301 this->destroyBuffers();
302
Greg Danielf730c182018-07-02 20:15:37 +0000303 fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700304 }
305
Greg Danielfaa095e2017-12-19 13:15:02 -0500306 this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
jvanverth9f372462016-04-06 06:08:59 -0700307
308 return true;
309}
310
Greg Danielfaa095e2017-12-19 13:15:02 -0500311void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
Greg Danielf730c182018-07-02 20:15:37 +0000312 fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr);
jvanverth9f372462016-04-06 06:08:59 -0700313 SkASSERT(fImageCount);
314 fImages = new VkImage[fImageCount];
Greg Danielf730c182018-07-02 20:15:37 +0000315 fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages);
jvanverth9f372462016-04-06 06:08:59 -0700316
317 // set up initial image layouts and create surfaces
318 fImageLayouts = new VkImageLayout[fImageCount];
319 fSurfaces = new sk_sp<SkSurface>[fImageCount];
320 for (uint32_t i = 0; i < fImageCount; ++i) {
321 fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
322
egdanielb2df0c22016-05-13 11:30:37 -0700323 GrVkImageInfo info;
jvanverth9f372462016-04-06 06:08:59 -0700324 info.fImage = fImages[i];
Greg Daniel8385a8a2018-02-26 13:29:37 -0500325 info.fAlloc = GrVkAlloc();
egdaniel580fa592016-08-31 11:03:50 -0700326 info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
jvanverth9f372462016-04-06 06:08:59 -0700327 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
egdaniel58a8d922016-04-21 08:03:10 -0700328 info.fFormat = format;
jvanverth3622a172016-05-10 06:42:18 -0700329 info.fLevelCount = 1;
jvanverthaf236b52016-05-20 06:01:06 -0700330
Brian Salomonafdc6b12018-03-09 12:02:32 -0500331 GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
Greg Daniele79b4732017-04-20 14:07:46 -0400332
Brian Salomonafdc6b12018-03-09 12:02:32 -0500333 fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(fContext.get(),
334 backendRT,
335 kTopLeft_GrSurfaceOrigin,
336 colorType,
337 fDisplayParams.fColorSpace,
Ben Wagner37c54032018-04-13 14:30:23 -0400338 &fDisplayParams.fSurfaceProps);
jvanverth9f372462016-04-06 06:08:59 -0700339 }
340
341 // create the command pool for the command buffers
342 if (VK_NULL_HANDLE == fCommandPool) {
343 VkCommandPoolCreateInfo commandPoolInfo;
344 memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
345 commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
346 // this needs to be on the render queue
Greg Danielf730c182018-07-02 20:15:37 +0000347 commandPoolInfo.queueFamilyIndex = fGraphicsQueueIndex;
jvanverth9f372462016-04-06 06:08:59 -0700348 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
Greg Danielf730c182018-07-02 20:15:37 +0000349 GR_VK_CALL_ERRCHECK(fInterface,
350 CreateCommandPool(fDevice, &commandPoolInfo,
jvanverth9f372462016-04-06 06:08:59 -0700351 nullptr, &fCommandPool));
352 }
353
354 // set up the backbuffers
355 VkSemaphoreCreateInfo semaphoreInfo;
356 memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
357 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
358 semaphoreInfo.pNext = nullptr;
359 semaphoreInfo.flags = 0;
360 VkCommandBufferAllocateInfo commandBuffersInfo;
361 memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
362 commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
363 commandBuffersInfo.pNext = nullptr;
364 commandBuffersInfo.commandPool = fCommandPool;
365 commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
366 commandBuffersInfo.commandBufferCount = 2;
367 VkFenceCreateInfo fenceInfo;
368 memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
369 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
370 fenceInfo.pNext = nullptr;
371 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
372
Greg Daniel1f05f442016-10-27 16:37:17 -0400373 // we create one additional backbuffer structure here, because we want to
jvanverth9f372462016-04-06 06:08:59 -0700374 // give the command buffers they contain a chance to finish before we cycle back
375 fBackbuffers = new BackbufferInfo[fImageCount + 1];
376 for (uint32_t i = 0; i < fImageCount + 1; ++i) {
377 fBackbuffers[i].fImageIndex = -1;
Greg Danielf730c182018-07-02 20:15:37 +0000378 GR_VK_CALL_ERRCHECK(fInterface,
379 CreateSemaphore(fDevice, &semaphoreInfo,
jvanverth9f372462016-04-06 06:08:59 -0700380 nullptr, &fBackbuffers[i].fAcquireSemaphore));
Greg Danielf730c182018-07-02 20:15:37 +0000381 GR_VK_CALL_ERRCHECK(fInterface,
382 CreateSemaphore(fDevice, &semaphoreInfo,
jvanverth9f372462016-04-06 06:08:59 -0700383 nullptr, &fBackbuffers[i].fRenderSemaphore));
Greg Danielf730c182018-07-02 20:15:37 +0000384 GR_VK_CALL_ERRCHECK(fInterface,
385 AllocateCommandBuffers(fDevice, &commandBuffersInfo,
jvanverth9f372462016-04-06 06:08:59 -0700386 fBackbuffers[i].fTransitionCmdBuffers));
Greg Danielf730c182018-07-02 20:15:37 +0000387 GR_VK_CALL_ERRCHECK(fInterface,
388 CreateFence(fDevice, &fenceInfo, nullptr,
jvanverth9f372462016-04-06 06:08:59 -0700389 &fBackbuffers[i].fUsageFences[0]));
Greg Danielf730c182018-07-02 20:15:37 +0000390 GR_VK_CALL_ERRCHECK(fInterface,
391 CreateFence(fDevice, &fenceInfo, nullptr,
jvanverth9f372462016-04-06 06:08:59 -0700392 &fBackbuffers[i].fUsageFences[1]));
393 }
394 fCurrentBackbufferIndex = fImageCount;
395}
396
jvanvertha8d0d6c2016-05-05 12:32:03 -0700397void VulkanWindowContext::destroyBuffers() {
jvanverth9f372462016-04-06 06:08:59 -0700398
399 if (fBackbuffers) {
400 for (uint32_t i = 0; i < fImageCount + 1; ++i) {
Greg Danielf730c182018-07-02 20:15:37 +0000401 GR_VK_CALL_ERRCHECK(fInterface,
402 WaitForFences(fDevice, 2,
jvanverth9f372462016-04-06 06:08:59 -0700403 fBackbuffers[i].fUsageFences,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700404 true, UINT64_MAX));
jvanverth9f372462016-04-06 06:08:59 -0700405 fBackbuffers[i].fImageIndex = -1;
Greg Danielf730c182018-07-02 20:15:37 +0000406 GR_VK_CALL(fInterface,
407 DestroySemaphore(fDevice,
jvanverth9f372462016-04-06 06:08:59 -0700408 fBackbuffers[i].fAcquireSemaphore,
409 nullptr));
Greg Danielf730c182018-07-02 20:15:37 +0000410 GR_VK_CALL(fInterface,
411 DestroySemaphore(fDevice,
jvanverth9f372462016-04-06 06:08:59 -0700412 fBackbuffers[i].fRenderSemaphore,
413 nullptr));
Greg Danielf730c182018-07-02 20:15:37 +0000414 GR_VK_CALL(fInterface,
415 FreeCommandBuffers(fDevice, fCommandPool, 2,
jvanverth9f372462016-04-06 06:08:59 -0700416 fBackbuffers[i].fTransitionCmdBuffers));
Greg Danielf730c182018-07-02 20:15:37 +0000417 GR_VK_CALL(fInterface,
418 DestroyFence(fDevice, fBackbuffers[i].fUsageFences[0], 0));
419 GR_VK_CALL(fInterface,
420 DestroyFence(fDevice, fBackbuffers[i].fUsageFences[1], 0));
jvanverth9f372462016-04-06 06:08:59 -0700421 }
422 }
423
424 delete[] fBackbuffers;
425 fBackbuffers = nullptr;
426
jvanverthaf236b52016-05-20 06:01:06 -0700427 // Does this actually free the surfaces?
jvanverth9f372462016-04-06 06:08:59 -0700428 delete[] fSurfaces;
429 fSurfaces = nullptr;
430 delete[] fImageLayouts;
431 fImageLayouts = nullptr;
432 delete[] fImages;
433 fImages = nullptr;
434}
435
jvanvertha8d0d6c2016-05-05 12:32:03 -0700436VulkanWindowContext::~VulkanWindowContext() {
jvanverth9f372462016-04-06 06:08:59 -0700437 this->destroyContext();
438}
439
jvanvertha8d0d6c2016-05-05 12:32:03 -0700440void VulkanWindowContext::destroyContext() {
Greg Daniel37329b32018-07-02 20:16:44 +0000441 if (this->isValid()) {
442 fQueueWaitIdle(fPresentQueue);
443 fDeviceWaitIdle(fDevice);
jvanverth9f372462016-04-06 06:08:59 -0700444
Greg Daniel37329b32018-07-02 20:16:44 +0000445 this->destroyBuffers();
jvanverth9f372462016-04-06 06:08:59 -0700446
Greg Daniel37329b32018-07-02 20:16:44 +0000447 if (VK_NULL_HANDLE != fCommandPool) {
448 GR_VK_CALL(fInterface, DestroyCommandPool(fDevice, fCommandPool, nullptr));
449 fCommandPool = VK_NULL_HANDLE;
450 }
jvanverth9f372462016-04-06 06:08:59 -0700451
Greg Daniel37329b32018-07-02 20:16:44 +0000452 if (VK_NULL_HANDLE != fSwapchain) {
453 fDestroySwapchainKHR(fDevice, fSwapchain, nullptr);
454 fSwapchain = VK_NULL_HANDLE;
455 }
jvanverth9f372462016-04-06 06:08:59 -0700456
Greg Daniel37329b32018-07-02 20:16:44 +0000457 if (VK_NULL_HANDLE != fSurface) {
458 fDestroySurfaceKHR(fInstance, fSurface, nullptr);
459 fSurface = VK_NULL_HANDLE;
460 }
jvanverth9f372462016-04-06 06:08:59 -0700461 }
462
Greg Daniel02611d92017-07-25 10:05:01 -0400463 fContext.reset();
Greg Danielf730c182018-07-02 20:15:37 +0000464 fInterface.reset();
jvanverth9f372462016-04-06 06:08:59 -0700465
Greg Danielf730c182018-07-02 20:15:37 +0000466 if (VK_NULL_HANDLE != fDevice) {
467 fDestroyDevice(fDevice, nullptr);
468 fDevice = VK_NULL_HANDLE;
469 }
Greg Daniel37329b32018-07-02 20:16:44 +0000470
471#ifdef SK_ENABLE_VK_LAYERS
472 if (fDebugCallback != VK_NULL_HANDLE) {
Greg Daniela31f4e52018-08-01 16:48:52 -0400473 fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr);
Greg Daniel37329b32018-07-02 20:16:44 +0000474 }
475#endif
476
Greg Danielf730c182018-07-02 20:15:37 +0000477 fPhysicalDevice = VK_NULL_HANDLE;
478
479 if (VK_NULL_HANDLE != fInstance) {
480 fDestroyInstance(fInstance, nullptr);
481 fInstance = VK_NULL_HANDLE;
482 }
jvanverth9f372462016-04-06 06:08:59 -0700483}
484
jvanvertha8d0d6c2016-05-05 12:32:03 -0700485VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
jvanverth9f372462016-04-06 06:08:59 -0700486 SkASSERT(fBackbuffers);
487
488 ++fCurrentBackbufferIndex;
egdaniel804af7d2016-09-26 12:30:46 -0700489 if (fCurrentBackbufferIndex > fImageCount) {
jvanverth9f372462016-04-06 06:08:59 -0700490 fCurrentBackbufferIndex = 0;
491 }
492
493 BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
Greg Danielf730c182018-07-02 20:15:37 +0000494 GR_VK_CALL_ERRCHECK(fInterface,
495 WaitForFences(fDevice, 2, backbuffer->fUsageFences,
jvanverth9f372462016-04-06 06:08:59 -0700496 true, UINT64_MAX));
497 return backbuffer;
498}
499
jvanverthaf236b52016-05-20 06:01:06 -0700500sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
jvanverth9f372462016-04-06 06:08:59 -0700501 BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
502 SkASSERT(backbuffer);
503
504 // reset the fence
Greg Danielf730c182018-07-02 20:15:37 +0000505 GR_VK_CALL_ERRCHECK(fInterface,
506 ResetFences(fDevice, 2, backbuffer->fUsageFences));
jvanverth9f372462016-04-06 06:08:59 -0700507 // semaphores should be in unsignaled state
508
509 // acquire the image
Greg Danielf730c182018-07-02 20:15:37 +0000510 VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
jvanverthb0d43522016-04-21 11:46:23 -0700511 backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
512 &backbuffer->fImageIndex);
jvanverth9f372462016-04-06 06:08:59 -0700513 if (VK_ERROR_SURFACE_LOST_KHR == res) {
514 // need to figure out how to create a new vkSurface without the platformData*
jvanverth3d6ed3a2016-04-07 11:09:51 -0700515 // maybe use attach somehow? but need a Window
jvanverth9f372462016-04-06 06:08:59 -0700516 return nullptr;
517 }
jvanverth3d6ed3a2016-04-07 11:09:51 -0700518 if (VK_ERROR_OUT_OF_DATE_KHR == res) {
jvanverth9f372462016-04-06 06:08:59 -0700519 // tear swapchain down and try again
Greg Daniel1f05f442016-10-27 16:37:17 -0400520 if (!this->createSwapchain(-1, -1, fDisplayParams)) {
jvanverth9f372462016-04-06 06:08:59 -0700521 return nullptr;
522 }
Jim Van Verthd63c1022017-01-05 13:50:49 -0500523 backbuffer = this->getAvailableBackbuffer();
Greg Danielf730c182018-07-02 20:15:37 +0000524 GR_VK_CALL_ERRCHECK(fInterface,
525 ResetFences(fDevice, 2, backbuffer->fUsageFences));
jvanverth9f372462016-04-06 06:08:59 -0700526
527 // acquire the image
Greg Danielf730c182018-07-02 20:15:37 +0000528 res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
jvanverthb0d43522016-04-21 11:46:23 -0700529 backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
530 &backbuffer->fImageIndex);
jvanverth9f372462016-04-06 06:08:59 -0700531
532 if (VK_SUCCESS != res) {
533 return nullptr;
534 }
535 }
536
537 // set up layout transfer from initial to color attachment
538 VkImageLayout layout = fImageLayouts[backbuffer->fImageIndex];
egdaniel580fa592016-08-31 11:03:50 -0700539 SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
jvanverth9f372462016-04-06 06:08:59 -0700540 VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
541 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
542 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
543 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
jvanvertha8d0d6c2016-05-05 12:32:03 -0700544 VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
jvanverth9f372462016-04-06 06:08:59 -0700545 0 : VK_ACCESS_MEMORY_READ_BIT;
546 VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
547
548 VkImageMemoryBarrier imageMemoryBarrier = {
549 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
550 NULL, // pNext
551 srcAccessMask, // outputMask
552 dstAccessMask, // inputMask
553 layout, // oldLayout
554 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
555 fPresentQueueIndex, // srcQueueFamilyIndex
Greg Danielf730c182018-07-02 20:15:37 +0000556 fGraphicsQueueIndex, // dstQueueFamilyIndex
jvanverth9f372462016-04-06 06:08:59 -0700557 fImages[backbuffer->fImageIndex], // image
558 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
559 };
Greg Danielf730c182018-07-02 20:15:37 +0000560 GR_VK_CALL_ERRCHECK(fInterface,
jvanverth9f372462016-04-06 06:08:59 -0700561 ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[0], 0));
562 VkCommandBufferBeginInfo info;
563 memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
564 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
565 info.flags = 0;
Greg Danielf730c182018-07-02 20:15:37 +0000566 GR_VK_CALL_ERRCHECK(fInterface,
jvanverth9f372462016-04-06 06:08:59 -0700567 BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[0], &info));
568
Greg Danielf730c182018-07-02 20:15:37 +0000569 GR_VK_CALL(fInterface,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700570 CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[0],
571 srcStageMask, dstStageMask, 0,
572 0, nullptr,
573 0, nullptr,
574 1, &imageMemoryBarrier));
jvanverth9f372462016-04-06 06:08:59 -0700575
Greg Danielf730c182018-07-02 20:15:37 +0000576 GR_VK_CALL_ERRCHECK(fInterface,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700577 EndCommandBuffer(backbuffer->fTransitionCmdBuffers[0]));
jvanverth9f372462016-04-06 06:08:59 -0700578
egdaniel58a8d922016-04-21 08:03:10 -0700579 VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
jvanverth9f372462016-04-06 06:08:59 -0700580 // insert the layout transfer into the queue and wait on the acquire
581 VkSubmitInfo submitInfo;
582 memset(&submitInfo, 0, sizeof(VkSubmitInfo));
583 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
584 submitInfo.waitSemaphoreCount = 1;
585 submitInfo.pWaitSemaphores = &backbuffer->fAcquireSemaphore;
egdaniel58a8d922016-04-21 08:03:10 -0700586 submitInfo.pWaitDstStageMask = &waitDstStageFlags;
jvanverth9f372462016-04-06 06:08:59 -0700587 submitInfo.commandBufferCount = 1;
588 submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[0];
589 submitInfo.signalSemaphoreCount = 0;
jvanvertha8d0d6c2016-05-05 12:32:03 -0700590
Greg Danielf730c182018-07-02 20:15:37 +0000591 GR_VK_CALL_ERRCHECK(fInterface,
592 QueueSubmit(fGraphicsQueue, 1, &submitInfo,
jvanverth9f372462016-04-06 06:08:59 -0700593 backbuffer->fUsageFences[0]));
594
egdaniel580fa592016-08-31 11:03:50 -0700595 SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
Robert Phillipsba375a82018-04-11 10:08:06 -0400596 GrBackendRenderTarget backendRT = surface->getBackendRenderTarget(
597 SkSurface::kFlushRead_BackendHandleAccess);
598 backendRT.setVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
599
egdaniel580fa592016-08-31 11:03:50 -0700600
601 return sk_ref_sp(surface);
jvanverth9f372462016-04-06 06:08:59 -0700602}
603
jvanvertha8d0d6c2016-05-05 12:32:03 -0700604void VulkanWindowContext::swapBuffers() {
jvanverth9f372462016-04-06 06:08:59 -0700605
606 BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
egdaniel580fa592016-08-31 11:03:50 -0700607 SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
jvanverth9f372462016-04-06 06:08:59 -0700608
Robert Phillipsba375a82018-04-11 10:08:06 -0400609 GrBackendRenderTarget backendRT = surface->getBackendRenderTarget(
610 SkSurface::kFlushRead_BackendHandleAccess);
611 GrVkImageInfo imageInfo;
612 SkAssertResult(backendRT.getVkImageInfo(&imageInfo));
613 // Check to make sure we never change the actually wrapped image
614 SkASSERT(imageInfo.fImage == fImages[backbuffer->fImageIndex]);
615
616 VkImageLayout layout = imageInfo.fImageLayout;
Greg Daniel6ddbafc2018-05-24 12:34:29 -0400617 VkPipelineStageFlags srcStageMask = GrVkImage::LayoutToPipelineStageFlags(layout);
jvanverth9f372462016-04-06 06:08:59 -0700618 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
Greg Daniel6ddbafc2018-05-24 12:34:29 -0400619 VkAccessFlags srcAccessMask = GrVkImage::LayoutToSrcAccessMask(layout);
jvanverth9f372462016-04-06 06:08:59 -0700620 VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
621
622 VkImageMemoryBarrier imageMemoryBarrier = {
623 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
624 NULL, // pNext
625 srcAccessMask, // outputMask
626 dstAccessMask, // inputMask
627 layout, // oldLayout
628 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
Greg Danielf730c182018-07-02 20:15:37 +0000629 fGraphicsQueueIndex, // srcQueueFamilyIndex
jvanverth9f372462016-04-06 06:08:59 -0700630 fPresentQueueIndex, // dstQueueFamilyIndex
631 fImages[backbuffer->fImageIndex], // image
632 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
633 };
Greg Danielf730c182018-07-02 20:15:37 +0000634 GR_VK_CALL_ERRCHECK(fInterface,
jvanverth9f372462016-04-06 06:08:59 -0700635 ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[1], 0));
636 VkCommandBufferBeginInfo info;
637 memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
638 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
639 info.flags = 0;
Greg Danielf730c182018-07-02 20:15:37 +0000640 GR_VK_CALL_ERRCHECK(fInterface,
jvanverth9f372462016-04-06 06:08:59 -0700641 BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[1], &info));
Greg Danielf730c182018-07-02 20:15:37 +0000642 GR_VK_CALL(fInterface,
jvanvertha8d0d6c2016-05-05 12:32:03 -0700643 CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[1],
644 srcStageMask, dstStageMask, 0,
645 0, nullptr,
646 0, nullptr,
647 1, &imageMemoryBarrier));
Greg Danielf730c182018-07-02 20:15:37 +0000648 GR_VK_CALL_ERRCHECK(fInterface,
jvanverth9f372462016-04-06 06:08:59 -0700649 EndCommandBuffer(backbuffer->fTransitionCmdBuffers[1]));
650
651 fImageLayouts[backbuffer->fImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
652
653 // insert the layout transfer into the queue and wait on the acquire
654 VkSubmitInfo submitInfo;
655 memset(&submitInfo, 0, sizeof(VkSubmitInfo));
656 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
657 submitInfo.waitSemaphoreCount = 0;
658 submitInfo.pWaitDstStageMask = 0;
659 submitInfo.commandBufferCount = 1;
660 submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[1];
661 submitInfo.signalSemaphoreCount = 1;
662 submitInfo.pSignalSemaphores = &backbuffer->fRenderSemaphore;
663
Greg Danielf730c182018-07-02 20:15:37 +0000664 GR_VK_CALL_ERRCHECK(fInterface,
665 QueueSubmit(fGraphicsQueue, 1, &submitInfo,
jvanverth9f372462016-04-06 06:08:59 -0700666 backbuffer->fUsageFences[1]));
667
668 // Submit present operation to present queue
669 const VkPresentInfoKHR presentInfo =
670 {
671 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
672 NULL, // pNext
673 1, // waitSemaphoreCount
674 &backbuffer->fRenderSemaphore, // pWaitSemaphores
675 1, // swapchainCount
676 &fSwapchain, // pSwapchains
677 &backbuffer->fImageIndex, // pImageIndices
678 NULL // pResults
679 };
680
jvanverthb0d43522016-04-21 11:46:23 -0700681 fQueuePresentKHR(fPresentQueue, &presentInfo);
jvanverth9f372462016-04-06 06:08:59 -0700682}
jvanvertha8d0d6c2016-05-05 12:32:03 -0700683
684} //namespace sk_app