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 
VulkanManager(RenderThread & thread)37 VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
38 
destroy()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 
initialize()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.
getAvailableBackbuffer(VulkanSurface * surface)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 
getBackbufferSurface(VulkanSurface * surface)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 
destroyBuffers(VulkanSurface * surface)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 
destroySurface(VulkanSurface * surface)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 
createBuffers(VulkanSurface * surface,VkFormat format,VkExtent2D extent)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 
createSwapchain(VulkanSurface * surface)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 
createSurface(ANativeWindow * window)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
layoutToPipelineStageFlags(const VkImageLayout 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
layoutToSrcAccessMask(const VkImageLayout 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 
swapBuffers(VulkanSurface * surface)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 
getAge(VulkanSurface * surface)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