1 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 9 #include "GrBackendSurface.h" 10 #include "GrContext.h" 11 #include "SkAutoMalloc.h" 12 #include "SkSurface.h" 13 #include "VulkanWindowContext.h" 14 15 #include "vk/GrVkInterface.h" 16 #include "vk/GrVkMemory.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 25 #define GET_PROC(F) f ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F) 26 #define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F) 27 28 namespace sk_app { 29 30 VulkanWindowContext::VulkanWindowContext(const DisplayParams& params, 31 CreateVkSurfaceFn createVkSurface, 32 CanPresentFn canPresent) 33 : WindowContext(params) 34 , fCreateVkSurfaceFn(createVkSurface) 35 , fCanPresentFn(canPresent) 36 , fSurface(VK_NULL_HANDLE) 37 , fSwapchain(VK_NULL_HANDLE) 38 , fImages(nullptr) 39 , fImageLayouts(nullptr) 40 , fSurfaces(nullptr) 41 , fCommandPool(VK_NULL_HANDLE) 42 , fBackbuffers(nullptr) { 43 this->initializeContext(); 44 } 45 46 void VulkanWindowContext::initializeContext() { 47 // any config code here (particularly for msaa)? 48 fBackendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr, vkGetDeviceProcAddr, 49 &fPresentQueueIndex, fCanPresentFn)); 50 51 if (!(fBackendContext->fExtensions & kKHR_surface_GrVkExtensionFlag) || 52 !(fBackendContext->fExtensions & kKHR_swapchain_GrVkExtensionFlag)) { 53 fBackendContext.reset(nullptr); 54 return; 55 } 56 57 VkInstance instance = fBackendContext->fInstance; 58 VkDevice device = fBackendContext->fDevice; 59 GET_PROC(DestroySurfaceKHR); 60 GET_PROC(GetPhysicalDeviceSurfaceSupportKHR); 61 GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR); 62 GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR); 63 GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR); 64 GET_DEV_PROC(CreateSwapchainKHR); 65 GET_DEV_PROC(DestroySwapchainKHR); 66 GET_DEV_PROC(GetSwapchainImagesKHR); 67 GET_DEV_PROC(AcquireNextImageKHR); 68 GET_DEV_PROC(QueuePresentKHR); 69 70 fContext = GrContext::Create(kVulkan_GrBackend, (GrBackendContext) fBackendContext.get(), 71 fDisplayParams.fGrContextOptions); 72 73 fSurface = fCreateVkSurfaceFn(instance); 74 if (VK_NULL_HANDLE == fSurface) { 75 fBackendContext.reset(nullptr); 76 return; 77 } 78 79 VkBool32 supported; 80 VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fBackendContext->fPhysicalDevice, 81 fPresentQueueIndex, fSurface, 82 &supported); 83 if (VK_SUCCESS != res) { 84 this->destroyContext(); 85 return; 86 } 87 88 if (!this->createSwapchain(-1, -1, fDisplayParams)) { 89 this->destroyContext(); 90 return; 91 } 92 93 // create presentQueue 94 vkGetDeviceQueue(fBackendContext->fDevice, fPresentQueueIndex, 0, &fPresentQueue); 95 } 96 97 bool VulkanWindowContext::createSwapchain(int width, int height, 98 const DisplayParams& params) { 99 // check for capabilities 100 VkSurfaceCapabilitiesKHR caps; 101 VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fBackendContext->fPhysicalDevice, 102 fSurface, &caps); 103 if (VK_SUCCESS != res) { 104 return false; 105 } 106 107 uint32_t surfaceFormatCount; 108 res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface, 109 &surfaceFormatCount, nullptr); 110 if (VK_SUCCESS != res) { 111 return false; 112 } 113 114 SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR)); 115 VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get(); 116 res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface, 117 &surfaceFormatCount, surfaceFormats); 118 if (VK_SUCCESS != res) { 119 return false; 120 } 121 122 uint32_t presentModeCount; 123 res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface, 124 &presentModeCount, nullptr); 125 if (VK_SUCCESS != res) { 126 return false; 127 } 128 129 SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR)); 130 VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get(); 131 res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface, 132 &presentModeCount, presentModes); 133 if (VK_SUCCESS != res) { 134 return false; 135 } 136 137 VkExtent2D extent = caps.currentExtent; 138 // use the hints 139 if (extent.width == (uint32_t)-1) { 140 extent.width = width; 141 extent.height = height; 142 } 143 144 // clamp width; to protect us from broken hints 145 if (extent.width < caps.minImageExtent.width) { 146 extent.width = caps.minImageExtent.width; 147 } else if (extent.width > caps.maxImageExtent.width) { 148 extent.width = caps.maxImageExtent.width; 149 } 150 // clamp height 151 if (extent.height < caps.minImageExtent.height) { 152 extent.height = caps.minImageExtent.height; 153 } else if (extent.height > caps.maxImageExtent.height) { 154 extent.height = caps.maxImageExtent.height; 155 } 156 157 fWidth = (int)extent.width; 158 fHeight = (int)extent.height; 159 160 uint32_t imageCount = caps.minImageCount + 2; 161 if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) { 162 // Application must settle for fewer images than desired: 163 imageCount = caps.maxImageCount; 164 } 165 166 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 167 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 168 VK_IMAGE_USAGE_TRANSFER_DST_BIT; 169 SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags); 170 SkASSERT(caps.supportedTransforms & caps.currentTransform); 171 SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | 172 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)); 173 VkCompositeAlphaFlagBitsKHR composite_alpha = 174 (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ? 175 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR : 176 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 177 178 // Pick our surface format. For now, just make sure it matches our sRGB request: 179 VkFormat surfaceFormat = VK_FORMAT_UNDEFINED; 180 VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 181 auto srgbColorSpace = SkColorSpace::MakeSRGB(); 182 bool wantSRGB = srgbColorSpace == params.fColorSpace; 183 for (uint32_t i = 0; i < surfaceFormatCount; ++i) { 184 GrPixelConfig config = GrVkFormatToPixelConfig(surfaceFormats[i].format); 185 if (kUnknown_GrPixelConfig != config && 186 GrPixelConfigIsSRGB(config) == wantSRGB) { 187 surfaceFormat = surfaceFormats[i].format; 188 colorSpace = surfaceFormats[i].colorSpace; 189 break; 190 } 191 } 192 fDisplayParams = params; 193 fSampleCount = params.fMSAASampleCount; 194 fStencilBits = 8; 195 196 if (VK_FORMAT_UNDEFINED == surfaceFormat) { 197 return false; 198 } 199 200 // If mailbox mode is available, use it, as it is the lowest-latency non- 201 // tearing mode. If not, fall back to FIFO which is always available. 202 VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; 203 for (uint32_t i = 0; i < presentModeCount; ++i) { 204 // use mailbox 205 if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) { 206 mode = presentModes[i]; 207 break; 208 } 209 } 210 211 VkSwapchainCreateInfoKHR swapchainCreateInfo; 212 memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR)); 213 swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 214 swapchainCreateInfo.surface = fSurface; 215 swapchainCreateInfo.minImageCount = imageCount; 216 swapchainCreateInfo.imageFormat = surfaceFormat; 217 swapchainCreateInfo.imageColorSpace = colorSpace; 218 swapchainCreateInfo.imageExtent = extent; 219 swapchainCreateInfo.imageArrayLayers = 1; 220 swapchainCreateInfo.imageUsage = usageFlags; 221 222 uint32_t queueFamilies[] = { fBackendContext->fGraphicsQueueIndex, fPresentQueueIndex }; 223 if (fBackendContext->fGraphicsQueueIndex != fPresentQueueIndex) { 224 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; 225 swapchainCreateInfo.queueFamilyIndexCount = 2; 226 swapchainCreateInfo.pQueueFamilyIndices = queueFamilies; 227 } else { 228 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 229 swapchainCreateInfo.queueFamilyIndexCount = 0; 230 swapchainCreateInfo.pQueueFamilyIndices = nullptr; 231 } 232 233 swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 234 swapchainCreateInfo.compositeAlpha = composite_alpha; 235 swapchainCreateInfo.presentMode = mode; 236 swapchainCreateInfo.clipped = true; 237 swapchainCreateInfo.oldSwapchain = fSwapchain; 238 239 res = fCreateSwapchainKHR(fBackendContext->fDevice, &swapchainCreateInfo, nullptr, &fSwapchain); 240 if (VK_SUCCESS != res) { 241 return false; 242 } 243 244 // destroy the old swapchain 245 if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) { 246 GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice)); 247 248 this->destroyBuffers(); 249 250 fDestroySwapchainKHR(fBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr); 251 } 252 253 this->createBuffers(swapchainCreateInfo.imageFormat); 254 255 return true; 256 } 257 258 void VulkanWindowContext::createBuffers(VkFormat format) { 259 fPixelConfig = GrVkFormatToPixelConfig(format); 260 SkASSERT(kUnknown_GrPixelConfig != fPixelConfig); 261 262 fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, nullptr); 263 SkASSERT(fImageCount); 264 fImages = new VkImage[fImageCount]; 265 fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, fImages); 266 267 // set up initial image layouts and create surfaces 268 fImageLayouts = new VkImageLayout[fImageCount]; 269 fSurfaces = new sk_sp<SkSurface>[fImageCount]; 270 for (uint32_t i = 0; i < fImageCount; ++i) { 271 fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED; 272 273 GrVkImageInfo info; 274 info.fImage = fImages[i]; 275 info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 }; 276 info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; 277 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL; 278 info.fFormat = format; 279 info.fLevelCount = 1; 280 281 GrBackendTexture backendTex(fWidth, fHeight, info); 282 283 fSurfaces[i] = SkSurface::MakeFromBackendTextureAsRenderTarget(fContext, backendTex, 284 kTopLeft_GrSurfaceOrigin, 285 fSampleCount, 286 fDisplayParams.fColorSpace, 287 &fSurfaceProps); 288 } 289 290 // create the command pool for the command buffers 291 if (VK_NULL_HANDLE == fCommandPool) { 292 VkCommandPoolCreateInfo commandPoolInfo; 293 memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo)); 294 commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; 295 // this needs to be on the render queue 296 commandPoolInfo.queueFamilyIndex = fBackendContext->fGraphicsQueueIndex; 297 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; 298 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 299 CreateCommandPool(fBackendContext->fDevice, &commandPoolInfo, 300 nullptr, &fCommandPool)); 301 } 302 303 // set up the backbuffers 304 VkSemaphoreCreateInfo semaphoreInfo; 305 memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo)); 306 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 307 semaphoreInfo.pNext = nullptr; 308 semaphoreInfo.flags = 0; 309 VkCommandBufferAllocateInfo commandBuffersInfo; 310 memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo)); 311 commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 312 commandBuffersInfo.pNext = nullptr; 313 commandBuffersInfo.commandPool = fCommandPool; 314 commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 315 commandBuffersInfo.commandBufferCount = 2; 316 VkFenceCreateInfo fenceInfo; 317 memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo)); 318 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 319 fenceInfo.pNext = nullptr; 320 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; 321 322 // we create one additional backbuffer structure here, because we want to 323 // give the command buffers they contain a chance to finish before we cycle back 324 fBackbuffers = new BackbufferInfo[fImageCount + 1]; 325 for (uint32_t i = 0; i < fImageCount + 1; ++i) { 326 fBackbuffers[i].fImageIndex = -1; 327 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 328 CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo, 329 nullptr, &fBackbuffers[i].fAcquireSemaphore)); 330 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 331 CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo, 332 nullptr, &fBackbuffers[i].fRenderSemaphore)); 333 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 334 AllocateCommandBuffers(fBackendContext->fDevice, &commandBuffersInfo, 335 fBackbuffers[i].fTransitionCmdBuffers)); 336 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 337 CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr, 338 &fBackbuffers[i].fUsageFences[0])); 339 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 340 CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr, 341 &fBackbuffers[i].fUsageFences[1])); 342 } 343 fCurrentBackbufferIndex = fImageCount; 344 } 345 346 void VulkanWindowContext::destroyBuffers() { 347 348 if (fBackbuffers) { 349 for (uint32_t i = 0; i < fImageCount + 1; ++i) { 350 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 351 WaitForFences(fBackendContext->fDevice, 2, 352 fBackbuffers[i].fUsageFences, 353 true, UINT64_MAX)); 354 fBackbuffers[i].fImageIndex = -1; 355 GR_VK_CALL(fBackendContext->fInterface, 356 DestroySemaphore(fBackendContext->fDevice, 357 fBackbuffers[i].fAcquireSemaphore, 358 nullptr)); 359 GR_VK_CALL(fBackendContext->fInterface, 360 DestroySemaphore(fBackendContext->fDevice, 361 fBackbuffers[i].fRenderSemaphore, 362 nullptr)); 363 GR_VK_CALL(fBackendContext->fInterface, 364 FreeCommandBuffers(fBackendContext->fDevice, fCommandPool, 2, 365 fBackbuffers[i].fTransitionCmdBuffers)); 366 GR_VK_CALL(fBackendContext->fInterface, 367 DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[0], 0)); 368 GR_VK_CALL(fBackendContext->fInterface, 369 DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[1], 0)); 370 } 371 } 372 373 delete[] fBackbuffers; 374 fBackbuffers = nullptr; 375 376 // Does this actually free the surfaces? 377 delete[] fSurfaces; 378 fSurfaces = nullptr; 379 delete[] fImageLayouts; 380 fImageLayouts = nullptr; 381 delete[] fImages; 382 fImages = nullptr; 383 } 384 385 VulkanWindowContext::~VulkanWindowContext() { 386 this->destroyContext(); 387 } 388 389 void VulkanWindowContext::destroyContext() { 390 if (!fBackendContext.get()) { 391 return; 392 } 393 394 GR_VK_CALL(fBackendContext->fInterface, QueueWaitIdle(fPresentQueue)); 395 GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice)); 396 397 this->destroyBuffers(); 398 399 if (VK_NULL_HANDLE != fCommandPool) { 400 GR_VK_CALL(fBackendContext->fInterface, DestroyCommandPool(fBackendContext->fDevice, 401 fCommandPool, nullptr)); 402 fCommandPool = VK_NULL_HANDLE; 403 } 404 405 if (VK_NULL_HANDLE != fSwapchain) { 406 fDestroySwapchainKHR(fBackendContext->fDevice, fSwapchain, nullptr); 407 fSwapchain = VK_NULL_HANDLE; 408 } 409 410 if (VK_NULL_HANDLE != fSurface) { 411 fDestroySurfaceKHR(fBackendContext->fInstance, fSurface, nullptr); 412 fSurface = VK_NULL_HANDLE; 413 } 414 415 fContext->unref(); 416 417 fBackendContext.reset(nullptr); 418 } 419 420 VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() { 421 SkASSERT(fBackbuffers); 422 423 ++fCurrentBackbufferIndex; 424 if (fCurrentBackbufferIndex > fImageCount) { 425 fCurrentBackbufferIndex = 0; 426 } 427 428 BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex; 429 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 430 WaitForFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences, 431 true, UINT64_MAX)); 432 return backbuffer; 433 } 434 435 sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() { 436 BackbufferInfo* backbuffer = this->getAvailableBackbuffer(); 437 SkASSERT(backbuffer); 438 439 // reset the fence 440 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 441 ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences)); 442 // semaphores should be in unsignaled state 443 444 // acquire the image 445 VkResult res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX, 446 backbuffer->fAcquireSemaphore, VK_NULL_HANDLE, 447 &backbuffer->fImageIndex); 448 if (VK_ERROR_SURFACE_LOST_KHR == res) { 449 // need to figure out how to create a new vkSurface without the platformData* 450 // maybe use attach somehow? but need a Window 451 return nullptr; 452 } 453 if (VK_ERROR_OUT_OF_DATE_KHR == res) { 454 // tear swapchain down and try again 455 if (!this->createSwapchain(-1, -1, fDisplayParams)) { 456 return nullptr; 457 } 458 backbuffer = this->getAvailableBackbuffer(); 459 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 460 ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences)); 461 462 // acquire the image 463 res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX, 464 backbuffer->fAcquireSemaphore, VK_NULL_HANDLE, 465 &backbuffer->fImageIndex); 466 467 if (VK_SUCCESS != res) { 468 return nullptr; 469 } 470 } 471 472 // set up layout transfer from initial to color attachment 473 VkImageLayout layout = fImageLayouts[backbuffer->fImageIndex]; 474 SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout); 475 VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? 476 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT : 477 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 478 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 479 VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? 480 0 : VK_ACCESS_MEMORY_READ_BIT; 481 VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 482 483 VkImageMemoryBarrier imageMemoryBarrier = { 484 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType 485 NULL, // pNext 486 srcAccessMask, // outputMask 487 dstAccessMask, // inputMask 488 layout, // oldLayout 489 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout 490 fPresentQueueIndex, // srcQueueFamilyIndex 491 fBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex 492 fImages[backbuffer->fImageIndex], // image 493 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange 494 }; 495 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 496 ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[0], 0)); 497 VkCommandBufferBeginInfo info; 498 memset(&info, 0, sizeof(VkCommandBufferBeginInfo)); 499 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 500 info.flags = 0; 501 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 502 BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[0], &info)); 503 504 GR_VK_CALL(fBackendContext->fInterface, 505 CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[0], 506 srcStageMask, dstStageMask, 0, 507 0, nullptr, 508 0, nullptr, 509 1, &imageMemoryBarrier)); 510 511 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 512 EndCommandBuffer(backbuffer->fTransitionCmdBuffers[0])); 513 514 VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 515 // insert the layout transfer into the queue and wait on the acquire 516 VkSubmitInfo submitInfo; 517 memset(&submitInfo, 0, sizeof(VkSubmitInfo)); 518 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 519 submitInfo.waitSemaphoreCount = 1; 520 submitInfo.pWaitSemaphores = &backbuffer->fAcquireSemaphore; 521 submitInfo.pWaitDstStageMask = &waitDstStageFlags; 522 submitInfo.commandBufferCount = 1; 523 submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[0]; 524 submitInfo.signalSemaphoreCount = 0; 525 526 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 527 QueueSubmit(fBackendContext->fQueue, 1, &submitInfo, 528 backbuffer->fUsageFences[0])); 529 530 GrVkImageInfo* imageInfo; 531 SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get(); 532 surface->getRenderTargetHandle((GrBackendObject*)&imageInfo, 533 SkSurface::kFlushRead_BackendHandleAccess); 534 imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 535 536 return sk_ref_sp(surface); 537 } 538 539 void VulkanWindowContext::swapBuffers() { 540 541 BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex; 542 GrVkImageInfo* imageInfo; 543 SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get(); 544 surface->getRenderTargetHandle((GrBackendObject*)&imageInfo, 545 SkSurface::kFlushRead_BackendHandleAccess); 546 // Check to make sure we never change the actually wrapped image 547 SkASSERT(imageInfo->fImage == fImages[backbuffer->fImageIndex]); 548 549 VkImageLayout layout = imageInfo->fImageLayout; 550 VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout); 551 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 552 VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout); 553 VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; 554 555 VkImageMemoryBarrier imageMemoryBarrier = { 556 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType 557 NULL, // pNext 558 srcAccessMask, // outputMask 559 dstAccessMask, // inputMask 560 layout, // oldLayout 561 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout 562 fBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex 563 fPresentQueueIndex, // dstQueueFamilyIndex 564 fImages[backbuffer->fImageIndex], // image 565 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange 566 }; 567 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 568 ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[1], 0)); 569 VkCommandBufferBeginInfo info; 570 memset(&info, 0, sizeof(VkCommandBufferBeginInfo)); 571 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 572 info.flags = 0; 573 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 574 BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[1], &info)); 575 GR_VK_CALL(fBackendContext->fInterface, 576 CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[1], 577 srcStageMask, dstStageMask, 0, 578 0, nullptr, 579 0, nullptr, 580 1, &imageMemoryBarrier)); 581 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 582 EndCommandBuffer(backbuffer->fTransitionCmdBuffers[1])); 583 584 fImageLayouts[backbuffer->fImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; 585 586 // insert the layout transfer into the queue and wait on the acquire 587 VkSubmitInfo submitInfo; 588 memset(&submitInfo, 0, sizeof(VkSubmitInfo)); 589 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 590 submitInfo.waitSemaphoreCount = 0; 591 submitInfo.pWaitDstStageMask = 0; 592 submitInfo.commandBufferCount = 1; 593 submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[1]; 594 submitInfo.signalSemaphoreCount = 1; 595 submitInfo.pSignalSemaphores = &backbuffer->fRenderSemaphore; 596 597 GR_VK_CALL_ERRCHECK(fBackendContext->fInterface, 598 QueueSubmit(fBackendContext->fQueue, 1, &submitInfo, 599 backbuffer->fUsageFences[1])); 600 601 // Submit present operation to present queue 602 const VkPresentInfoKHR presentInfo = 603 { 604 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType 605 NULL, // pNext 606 1, // waitSemaphoreCount 607 &backbuffer->fRenderSemaphore, // pWaitSemaphores 608 1, // swapchainCount 609 &fSwapchain, // pSwapchains 610 &backbuffer->fImageIndex, // pImageIndices 611 NULL // pResults 612 }; 613 614 fQueuePresentKHR(fPresentQueue, &presentInfo); 615 } 616 617 } //namespace sk_app 618