VulkanManager.cpp revision 0e3cba31460e0698def0310003b7d291f1174afa
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "VulkanManager.h" 18 19#include "DeviceInfo.h" 20#include "RenderThread.h" 21 22#include <GrContext.h> 23#include <GrTypes.h> 24#include <vk/GrVkTypes.h> 25 26namespace android { 27namespace uirenderer { 28namespace renderthread { 29 30#define GET_PROC(F) m ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F) 31#define GET_DEV_PROC(F) m ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F) 32 33VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) { 34} 35 36void VulkanManager::destroy() { 37 if (!hasVkContext()) return; 38 39 if (VK_NULL_HANDLE != mCommandPool) { 40 mDestroyCommandPool(mBackendContext->fDevice, mCommandPool, nullptr); 41 mCommandPool = VK_NULL_HANDLE; 42 } 43} 44 45void VulkanManager::initialize() { 46 if (hasVkContext()) { return; } 47 48 auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; }; 49 50 mBackendContext.reset(GrVkBackendContext::Create(&mPresentQueueIndex, canPresent)); 51 52 // Get all the addresses of needed vulkan functions 53 VkInstance instance = mBackendContext->fInstance; 54 VkDevice device = mBackendContext->fDevice; 55 GET_PROC(CreateAndroidSurfaceKHR); 56 GET_PROC(DestroySurfaceKHR); 57 GET_PROC(GetPhysicalDeviceSurfaceSupportKHR); 58 GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR); 59 GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR); 60 GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR); 61 GET_DEV_PROC(CreateSwapchainKHR); 62 GET_DEV_PROC(DestroySwapchainKHR); 63 GET_DEV_PROC(GetSwapchainImagesKHR); 64 GET_DEV_PROC(AcquireNextImageKHR); 65 GET_DEV_PROC(QueuePresentKHR); 66 GET_DEV_PROC(CreateCommandPool); 67 GET_DEV_PROC(DestroyCommandPool); 68 GET_DEV_PROC(AllocateCommandBuffers); 69 GET_DEV_PROC(FreeCommandBuffers); 70 GET_DEV_PROC(ResetCommandBuffer); 71 GET_DEV_PROC(BeginCommandBuffer); 72 GET_DEV_PROC(EndCommandBuffer); 73 GET_DEV_PROC(CmdPipelineBarrier); 74 GET_DEV_PROC(GetDeviceQueue); 75 GET_DEV_PROC(QueueSubmit); 76 GET_DEV_PROC(QueueWaitIdle); 77 GET_DEV_PROC(DeviceWaitIdle); 78 GET_DEV_PROC(CreateSemaphore); 79 GET_DEV_PROC(DestroySemaphore); 80 GET_DEV_PROC(CreateFence); 81 GET_DEV_PROC(DestroyFence); 82 GET_DEV_PROC(WaitForFences); 83 GET_DEV_PROC(ResetFences); 84 85 // create the command pool for the command buffers 86 if (VK_NULL_HANDLE == mCommandPool) { 87 VkCommandPoolCreateInfo commandPoolInfo; 88 memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo)); 89 commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; 90 // this needs to be on the render queue 91 commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex; 92 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; 93 SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice, 94 &commandPoolInfo, nullptr, &mCommandPool); 95 SkASSERT(VK_SUCCESS == res); 96 } 97 98 mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue); 99 100 mRenderThread.setGrContext(GrContext::Create(kVulkan_GrBackend, 101 (GrBackendContext) mBackendContext.get())); 102 DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize()); 103} 104 105// Returns the next BackbufferInfo to use for the next draw. The function will make sure all 106// previous uses have finished before returning. 107VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) { 108 SkASSERT(surface->mBackbuffers); 109 110 ++surface->mCurrentBackbufferIndex; 111 if (surface->mCurrentBackbufferIndex > surface->mImageCount) { 112 surface->mCurrentBackbufferIndex = 0; 113 } 114 115 VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers + 116 surface->mCurrentBackbufferIndex; 117 118 // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely 119 // reuse its commands buffers. 120 VkResult res = mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences, 121 true, UINT64_MAX); 122 if (res != VK_SUCCESS) { 123 return nullptr; 124 } 125 126 return backbuffer; 127} 128 129 130SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) { 131 VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface); 132 SkASSERT(backbuffer); 133 134 VkResult res; 135 136 res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences); 137 SkASSERT(VK_SUCCESS == res); 138 139 // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has 140 // finished presenting and that it is safe to begin sending new commands to the returned image. 141 res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX, 142 backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex); 143 144 if (VK_ERROR_SURFACE_LOST_KHR == res) { 145 // need to figure out how to create a new vkSurface without the platformData* 146 // maybe use attach somehow? but need a Window 147 return nullptr; 148 } 149 if (VK_ERROR_OUT_OF_DATE_KHR == res) { 150 // tear swapchain down and try again 151 if (!createSwapchain(surface)) { 152 return nullptr; 153 } 154 155 // acquire the image 156 res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX, 157 backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex); 158 159 if (VK_SUCCESS != res) { 160 return nullptr; 161 } 162 } 163 164 // set up layout transfer from initial to color attachment 165 VkImageLayout layout = surface->mImageLayouts[backbuffer->mImageIndex]; 166 SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout); 167 VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? 168 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT : 169 VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 170 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 171 VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? 172 0 : VK_ACCESS_MEMORY_READ_BIT; 173 VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 174 175 VkImageMemoryBarrier imageMemoryBarrier = { 176 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType 177 NULL, // pNext 178 srcAccessMask, // outputMask 179 dstAccessMask, // inputMask 180 layout, // oldLayout 181 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout 182 mPresentQueueIndex, // srcQueueFamilyIndex 183 mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex 184 surface->mImages[backbuffer->mImageIndex], // image 185 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange 186 }; 187 mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0); 188 189 VkCommandBufferBeginInfo info; 190 memset(&info, 0, sizeof(VkCommandBufferBeginInfo)); 191 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 192 info.flags = 0; 193 mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info); 194 195 mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, 196 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); 197 198 mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]); 199 200 VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 201 // insert the layout transfer into the queue and wait on the acquire 202 VkSubmitInfo submitInfo; 203 memset(&submitInfo, 0, sizeof(VkSubmitInfo)); 204 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 205 submitInfo.waitSemaphoreCount = 1; 206 // Wait to make sure aquire semaphore set above has signaled. 207 submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore; 208 submitInfo.pWaitDstStageMask = &waitDstStageFlags; 209 submitInfo.commandBufferCount = 1; 210 submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0]; 211 submitInfo.signalSemaphoreCount = 0; 212 213 // Attach first fence to submission here so we can track when the command buffer finishes. 214 mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[0]); 215 216 // We need to notify Skia that we changed the layout of the wrapped VkImage 217 GrVkImageInfo* imageInfo; 218 sk_sp<SkSurface> skSurface = surface->mSurfaces[backbuffer->mImageIndex]; 219 skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo, 220 SkSurface::kFlushRead_BackendHandleAccess); 221 imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); 222 223 surface->mBackbuffer = std::move(skSurface); 224 return surface->mBackbuffer.get(); 225} 226 227void VulkanManager::destroyBuffers(VulkanSurface* surface) { 228 if (surface->mBackbuffers) { 229 for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) { 230 mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true, 231 UINT64_MAX); 232 surface->mBackbuffers[i].mImageIndex = -1; 233 mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore, 234 nullptr); 235 mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore, 236 nullptr); 237 mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2, 238 surface->mBackbuffers[i].mTransitionCmdBuffers); 239 mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0); 240 mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0); 241 } 242 } 243 244 delete[] surface->mBackbuffers; 245 surface->mBackbuffers = nullptr; 246 delete[] surface->mSurfaces; 247 surface->mSurfaces = nullptr; 248 delete[] surface->mImageLayouts; 249 surface->mImageLayouts = nullptr; 250 delete[] surface->mImages; 251 surface->mImages = nullptr; 252} 253 254void VulkanManager::destroySurface(VulkanSurface* surface) { 255 // Make sure all submit commands have finished before starting to destroy objects. 256 if (VK_NULL_HANDLE != mPresentQueue) { 257 mQueueWaitIdle(mPresentQueue); 258 } 259 mDeviceWaitIdle(mBackendContext->fDevice); 260 261 destroyBuffers(surface); 262 263 if (VK_NULL_HANDLE != surface->mSwapchain) { 264 mDestroySwapchainKHR(mBackendContext->fDevice, surface->mSwapchain, nullptr); 265 surface->mSwapchain = VK_NULL_HANDLE; 266 } 267 268 if (VK_NULL_HANDLE != surface->mVkSurface) { 269 mDestroySurfaceKHR(mBackendContext->fInstance, surface->mVkSurface, nullptr); 270 surface->mVkSurface = VK_NULL_HANDLE; 271 } 272 delete surface; 273} 274 275void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) { 276 mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount, 277 nullptr); 278 SkASSERT(surface->mImageCount); 279 surface->mImages = new VkImage[surface->mImageCount]; 280 mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, 281 &surface->mImageCount, surface->mImages); 282 283 SkSurfaceProps props(0, kUnknown_SkPixelGeometry); 284 285 bool wantSRGB = VK_FORMAT_R8G8B8A8_SRGB == format; 286 GrPixelConfig config = wantSRGB ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig; 287 288 // set up initial image layouts and create surfaces 289 surface->mImageLayouts = new VkImageLayout[surface->mImageCount]; 290 surface->mSurfaces = new sk_sp<SkSurface>[surface->mImageCount]; 291 for (uint32_t i = 0; i < surface->mImageCount; ++i) { 292 GrBackendRenderTargetDesc desc; 293 GrVkImageInfo info; 294 info.fImage = surface->mImages[i]; 295 info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 }; 296 info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; 297 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL; 298 info.fFormat = format; 299 info.fLevelCount = 1; 300 301 desc.fWidth = extent.width; 302 desc.fHeight = extent.height; 303 desc.fConfig = config; 304 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 305 desc.fSampleCnt = 0; 306 desc.fStencilBits = 0; 307 desc.fRenderTargetHandle = (GrBackendObject) &info; 308 309 surface->mSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(), 310 desc, &props); 311 surface->mImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED; 312 } 313 314 SkASSERT(mCommandPool != VK_NULL_HANDLE); 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 = mCommandPool; 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 335 // we create one additional backbuffer structure here, because we want to 336 // give the command buffers they contain a chance to finish before we cycle back 337 surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1]; 338 for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) { 339 SkDEBUGCODE(VkResult res); 340 surface->mBackbuffers[i].mImageIndex = -1; 341 SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr, 342 &surface->mBackbuffers[i].mAcquireSemaphore); 343 SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr, 344 &surface->mBackbuffers[i].mRenderSemaphore); 345 SkDEBUGCODE(res = ) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo, 346 surface->mBackbuffers[i].mTransitionCmdBuffers); 347 SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr, 348 &surface->mBackbuffers[i].mUsageFences[0]); 349 SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr, 350 &surface->mBackbuffers[i].mUsageFences[1]); 351 SkASSERT(VK_SUCCESS == res); 352 } 353 surface->mCurrentBackbufferIndex = surface->mImageCount; 354} 355 356bool VulkanManager::createSwapchain(VulkanSurface* surface) { 357 // check for capabilities 358 VkSurfaceCapabilitiesKHR caps; 359 VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice, 360 surface->mVkSurface, &caps); 361 if (VK_SUCCESS != res) { 362 return false; 363 } 364 365 uint32_t surfaceFormatCount; 366 res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface, 367 &surfaceFormatCount, nullptr); 368 if (VK_SUCCESS != res) { 369 return false; 370 } 371 372 SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR)); 373 VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get(); 374 res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface, 375 &surfaceFormatCount, surfaceFormats); 376 if (VK_SUCCESS != res) { 377 return false; 378 } 379 380 uint32_t presentModeCount; 381 res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice, 382 surface->mVkSurface, &presentModeCount, nullptr); 383 if (VK_SUCCESS != res) { 384 return false; 385 } 386 387 SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR)); 388 VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get(); 389 res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice, 390 surface->mVkSurface, &presentModeCount, presentModes); 391 if (VK_SUCCESS != res) { 392 return false; 393 } 394 395 VkExtent2D extent = caps.currentExtent; 396 // clamp width; to handle currentExtent of -1 and protect us from broken hints 397 if (extent.width < caps.minImageExtent.width) { 398 extent.width = caps.minImageExtent.width; 399 } 400 SkASSERT(extent.width <= caps.maxImageExtent.width); 401 // clamp height 402 if (extent.height < caps.minImageExtent.height) { 403 extent.height = caps.minImageExtent.height; 404 } 405 SkASSERT(extent.height <= caps.maxImageExtent.height); 406 407 uint32_t imageCount = caps.minImageCount + 2; 408 if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) { 409 // Application must settle for fewer images than desired: 410 imageCount = caps.maxImageCount; 411 } 412 413 // Currently Skia requires the images to be color attchments and support all transfer 414 // operations. 415 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | 416 VK_IMAGE_USAGE_TRANSFER_SRC_BIT | 417 VK_IMAGE_USAGE_TRANSFER_DST_BIT; 418 SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags); 419 SkASSERT(caps.supportedTransforms & caps.currentTransform); 420 SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | 421 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)); 422 VkCompositeAlphaFlagBitsKHR composite_alpha = 423 (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ? 424 VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR : 425 VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 426 427 // Pick our surface format. For now, just make sure it matches our sRGB request: 428 VkFormat surfaceFormat = VK_FORMAT_UNDEFINED; 429 VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 430 431 bool wantSRGB = false; 432#ifdef ANDROID_ENABLE_LINEAR_BLENDING 433 wantSRGB = true; 434#endif 435 for (uint32_t i = 0; i < surfaceFormatCount; ++i) { 436 // We are assuming we can get either R8G8B8A8_UNORM or R8G8B8A8_SRGB 437 VkFormat desiredFormat = wantSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; 438 if (desiredFormat == surfaceFormats[i].format) { 439 surfaceFormat = surfaceFormats[i].format; 440 colorSpace = surfaceFormats[i].colorSpace; 441 } 442 } 443 444 if (VK_FORMAT_UNDEFINED == surfaceFormat) { 445 return false; 446 } 447 448 // If mailbox mode is available, use it, as it is the lowest-latency non- 449 // tearing mode. If not, fall back to FIFO which is always available. 450 VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR; 451 for (uint32_t i = 0; i < presentModeCount; ++i) { 452 // use mailbox 453 if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) { 454 mode = presentModes[i]; 455 break; 456 } 457 } 458 459 VkSwapchainCreateInfoKHR swapchainCreateInfo; 460 memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR)); 461 swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 462 swapchainCreateInfo.surface = surface->mVkSurface; 463 swapchainCreateInfo.minImageCount = imageCount; 464 swapchainCreateInfo.imageFormat = surfaceFormat; 465 swapchainCreateInfo.imageColorSpace = colorSpace; 466 swapchainCreateInfo.imageExtent = extent; 467 swapchainCreateInfo.imageArrayLayers = 1; 468 swapchainCreateInfo.imageUsage = usageFlags; 469 470 uint32_t queueFamilies[] = { mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex }; 471 if (mBackendContext->fGraphicsQueueIndex != mPresentQueueIndex) { 472 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; 473 swapchainCreateInfo.queueFamilyIndexCount = 2; 474 swapchainCreateInfo.pQueueFamilyIndices = queueFamilies; 475 } else { 476 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 477 swapchainCreateInfo.queueFamilyIndexCount = 0; 478 swapchainCreateInfo.pQueueFamilyIndices = nullptr; 479 } 480 481 swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; 482 swapchainCreateInfo.compositeAlpha = composite_alpha; 483 swapchainCreateInfo.presentMode = mode; 484 swapchainCreateInfo.clipped = true; 485 swapchainCreateInfo.oldSwapchain = surface->mSwapchain; 486 487 res = mCreateSwapchainKHR(mBackendContext->fDevice, &swapchainCreateInfo, nullptr, 488 &surface->mSwapchain); 489 if (VK_SUCCESS != res) { 490 return false; 491 } 492 493 // destroy the old swapchain 494 if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) { 495 mDeviceWaitIdle(mBackendContext->fDevice); 496 497 destroyBuffers(surface); 498 499 mDestroySwapchainKHR(mBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr); 500 } 501 502 createBuffers(surface, surfaceFormat, extent); 503 504 return true; 505} 506 507 508VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) { 509 initialize(); 510 511 if (!window) { 512 return nullptr; 513 } 514 515 VulkanSurface* surface = new VulkanSurface(); 516 517 VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo; 518 memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR)); 519 surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR; 520 surfaceCreateInfo.pNext = nullptr; 521 surfaceCreateInfo.flags = 0; 522 surfaceCreateInfo.window = window; 523 524 VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo, 525 nullptr, &surface->mVkSurface); 526 if (VK_SUCCESS != res) { 527 delete surface; 528 return nullptr; 529 } 530 531SkDEBUGCODE( 532 VkBool32 supported; 533 res = mGetPhysicalDeviceSurfaceSupportKHR(mBackendContext->fPhysicalDevice, 534 mPresentQueueIndex, surface->mVkSurface, &supported); 535 // All physical devices and queue families on Android must be capable of presentation with any 536 // native window. 537 SkASSERT(VK_SUCCESS == res && supported); 538); 539 540 if (!createSwapchain(surface)) { 541 destroySurface(surface); 542 return nullptr; 543 } 544 545 return surface; 546} 547 548// Helper to know which src stage flags we need to set when transitioning to the present layout 549static VkPipelineStageFlags layoutToPipelineStageFlags(const VkImageLayout layout) { 550 if (VK_IMAGE_LAYOUT_GENERAL == layout) { 551 return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; 552 } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout || 553 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) { 554 return VK_PIPELINE_STAGE_TRANSFER_BIT; 555 } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout || 556 VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout || 557 VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout || 558 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) { 559 return VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; 560 } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) { 561 return VK_PIPELINE_STAGE_HOST_BIT; 562 } 563 564 SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout); 565 return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; 566} 567 568// Helper to know which src access mask we need to set when transitioning to the present layout 569static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) { 570 VkAccessFlags flags = 0; 571 if (VK_IMAGE_LAYOUT_GENERAL == layout) { 572 flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | 573 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | 574 VK_ACCESS_TRANSFER_WRITE_BIT | 575 VK_ACCESS_TRANSFER_READ_BIT | 576 VK_ACCESS_SHADER_READ_BIT | 577 VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT; 578 } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) { 579 flags = VK_ACCESS_HOST_WRITE_BIT; 580 } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) { 581 flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 582 } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) { 583 flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; 584 } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) { 585 flags = VK_ACCESS_TRANSFER_WRITE_BIT; 586 } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) { 587 flags = VK_ACCESS_TRANSFER_READ_BIT; 588 } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) { 589 flags = VK_ACCESS_SHADER_READ_BIT; 590 } 591 return flags; 592} 593 594void VulkanManager::swapBuffers(VulkanSurface* surface) { 595 VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers + 596 surface->mCurrentBackbufferIndex; 597 GrVkImageInfo* imageInfo; 598 SkSurface* skSurface = surface->mSurfaces[backbuffer->mImageIndex].get(); 599 skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo, 600 SkSurface::kFlushRead_BackendHandleAccess); 601 // Check to make sure we never change the actually wrapped image 602 SkASSERT(imageInfo->fImage == surface->mImages[backbuffer->mImageIndex]); 603 604 // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all 605 // previous work is complete for before presenting. So we first add the necessary barrier here. 606 VkImageLayout layout = imageInfo->fImageLayout; 607 VkPipelineStageFlags srcStageMask = layoutToPipelineStageFlags(layout); 608 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; 609 VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout); 610 VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; 611 612 VkImageMemoryBarrier imageMemoryBarrier = { 613 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType 614 NULL, // pNext 615 srcAccessMask, // outputMask 616 dstAccessMask, // inputMask 617 layout, // oldLayout 618 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout 619 mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex 620 mPresentQueueIndex, // dstQueueFamilyIndex 621 surface->mImages[backbuffer->mImageIndex], // image 622 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange 623 }; 624 625 mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0); 626 VkCommandBufferBeginInfo info; 627 memset(&info, 0, sizeof(VkCommandBufferBeginInfo)); 628 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 629 info.flags = 0; 630 mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info); 631 mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, 632 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); 633 mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]); 634 635 surface->mImageLayouts[backbuffer->mImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; 636 637 // insert the layout transfer into the queue and wait on the acquire 638 VkSubmitInfo submitInfo; 639 memset(&submitInfo, 0, sizeof(VkSubmitInfo)); 640 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 641 submitInfo.waitSemaphoreCount = 0; 642 submitInfo.pWaitDstStageMask = 0; 643 submitInfo.commandBufferCount = 1; 644 submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1]; 645 submitInfo.signalSemaphoreCount = 1; 646 // When this command buffer finishes we will signal this semaphore so that we know it is now 647 // safe to present the image to the screen. 648 submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore; 649 650 // Attach second fence to submission here so we can track when the command buffer finishes. 651 mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[1]); 652 653 // Submit present operation to present queue. We use a semaphore here to make sure all rendering 654 // to the image is complete and that the layout has been change to present on the graphics 655 // queue. 656 const VkPresentInfoKHR presentInfo = 657 { 658 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType 659 NULL, // pNext 660 1, // waitSemaphoreCount 661 &backbuffer->mRenderSemaphore, // pWaitSemaphores 662 1, // swapchainCount 663 &surface->mSwapchain, // pSwapchains 664 &backbuffer->mImageIndex, // pImageIndices 665 NULL // pResults 666 }; 667 668 mQueuePresentKHR(mPresentQueue, &presentInfo); 669 670 surface->mBackbuffer.reset(); 671} 672 673} /* namespace renderthread */ 674} /* namespace uirenderer */ 675} /* namespace android */ 676