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