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