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 <GrContext.h>
26 #include <GrTypes.h>
27 #include <vk/GrVkTypes.h>
28 
29 namespace android {
30 namespace uirenderer {
31 namespace renderthread {
32 
33 #define GET_PROC(F) m ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F)
34 #define GET_DEV_PROC(F) m ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F)
35 
VulkanManager(RenderThread & thread)36 VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {
37 }
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()) { return; }
54 
55     auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; };
56 
57     mBackendContext.reset(GrVkBackendContext::Create(&mPresentQueueIndex, canPresent));
58 
59     // Get all the addresses of needed vulkan functions
60     VkInstance instance = mBackendContext->fInstance;
61     VkDevice device = mBackendContext->fDevice;
62     GET_PROC(CreateAndroidSurfaceKHR);
63     GET_PROC(DestroySurfaceKHR);
64     GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
65     GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
66     GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
67     GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
68     GET_DEV_PROC(CreateSwapchainKHR);
69     GET_DEV_PROC(DestroySwapchainKHR);
70     GET_DEV_PROC(GetSwapchainImagesKHR);
71     GET_DEV_PROC(AcquireNextImageKHR);
72     GET_DEV_PROC(QueuePresentKHR);
73     GET_DEV_PROC(CreateCommandPool);
74     GET_DEV_PROC(DestroyCommandPool);
75     GET_DEV_PROC(AllocateCommandBuffers);
76     GET_DEV_PROC(FreeCommandBuffers);
77     GET_DEV_PROC(ResetCommandBuffer);
78     GET_DEV_PROC(BeginCommandBuffer);
79     GET_DEV_PROC(EndCommandBuffer);
80     GET_DEV_PROC(CmdPipelineBarrier);
81     GET_DEV_PROC(GetDeviceQueue);
82     GET_DEV_PROC(QueueSubmit);
83     GET_DEV_PROC(QueueWaitIdle);
84     GET_DEV_PROC(DeviceWaitIdle);
85     GET_DEV_PROC(CreateSemaphore);
86     GET_DEV_PROC(DestroySemaphore);
87     GET_DEV_PROC(CreateFence);
88     GET_DEV_PROC(DestroyFence);
89     GET_DEV_PROC(WaitForFences);
90     GET_DEV_PROC(ResetFences);
91 
92     // create the command pool for the command buffers
93     if (VK_NULL_HANDLE == mCommandPool) {
94         VkCommandPoolCreateInfo commandPoolInfo;
95         memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
96         commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
97         // this needs to be on the render queue
98         commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex;
99         commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
100         SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice,
101                 &commandPoolInfo, nullptr, &mCommandPool);
102         SkASSERT(VK_SUCCESS == res);
103     }
104 
105     mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue);
106 
107     mRenderThread.setGrContext(GrContext::Create(kVulkan_GrBackend,
108             (GrBackendContext) mBackendContext.get()));
109     DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
110 
111     if (Properties::enablePartialUpdates && Properties::useBufferAge) {
112         mSwapBehavior = SwapBehavior::BufferAge;
113     }
114 
115     mRenderThread.renderState().onVkContextCreated();
116 }
117 
118 // Returns the next BackbufferInfo to use for the next draw. The function will make sure all
119 // previous uses have finished before returning.
getAvailableBackbuffer(VulkanSurface * surface)120 VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
121     SkASSERT(surface->mBackbuffers);
122 
123     ++surface->mCurrentBackbufferIndex;
124     if (surface->mCurrentBackbufferIndex > surface->mImageCount) {
125         surface->mCurrentBackbufferIndex = 0;
126     }
127 
128     VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
129             surface->mCurrentBackbufferIndex;
130 
131     // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
132     // reuse its commands buffers.
133     VkResult res = mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences,
134             true, UINT64_MAX);
135     if (res != VK_SUCCESS) {
136         return nullptr;
137     }
138 
139     return backbuffer;
140 }
141 
142 
getBackbufferSurface(VulkanSurface * surface)143 SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
144     VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
145     SkASSERT(backbuffer);
146 
147     VkResult res;
148 
149     res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
150     SkASSERT(VK_SUCCESS == res);
151 
152     // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
153     // finished presenting and that it is safe to begin sending new commands to the returned image.
154     res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
155             backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
156 
157     if (VK_ERROR_SURFACE_LOST_KHR == res) {
158         // need to figure out how to create a new vkSurface without the platformData*
159         // maybe use attach somehow? but need a Window
160         return nullptr;
161     }
162     if (VK_ERROR_OUT_OF_DATE_KHR == res) {
163         // tear swapchain down and try again
164         if (!createSwapchain(surface)) {
165             return nullptr;
166         }
167         backbuffer = getAvailableBackbuffer(surface);
168         res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
169         SkASSERT(VK_SUCCESS == res);
170 
171         // acquire the image
172         res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
173                 backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
174 
175         if (VK_SUCCESS != res) {
176             return nullptr;
177         }
178     }
179 
180     // set up layout transfer from initial to color attachment
181     VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout;
182     SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
183     VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
184                                         VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
185                                         VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
186     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
187     VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
188                                   0 : VK_ACCESS_MEMORY_READ_BIT;
189     VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
190 
191     VkImageMemoryBarrier imageMemoryBarrier = {
192         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,    // sType
193         NULL,                                      // pNext
194         srcAccessMask,                             // outputMask
195         dstAccessMask,                             // inputMask
196         layout,                                    // oldLayout
197         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,  // newLayout
198         mPresentQueueIndex,                        // srcQueueFamilyIndex
199         mBackendContext->fGraphicsQueueIndex,      // dstQueueFamilyIndex
200         surface->mImages[backbuffer->mImageIndex], // image
201         { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }  // subresourceRange
202     };
203     mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
204 
205     VkCommandBufferBeginInfo info;
206     memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
207     info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
208     info.flags = 0;
209     mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
210 
211     mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0,
212             0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
213 
214     mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
215 
216     VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
217     // insert the layout transfer into the queue and wait on the acquire
218     VkSubmitInfo submitInfo;
219     memset(&submitInfo, 0, sizeof(VkSubmitInfo));
220     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
221     submitInfo.waitSemaphoreCount = 1;
222     // Wait to make sure aquire semaphore set above has signaled.
223     submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore;
224     submitInfo.pWaitDstStageMask = &waitDstStageFlags;
225     submitInfo.commandBufferCount = 1;
226     submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0];
227     submitInfo.signalSemaphoreCount = 0;
228 
229     // Attach first fence to submission here so we can track when the command buffer finishes.
230     mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
231 
232     // We need to notify Skia that we changed the layout of the wrapped VkImage
233     GrVkImageInfo* imageInfo;
234     sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
235     skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
236             SkSurface::kFlushRead_BackendHandleAccess);
237     imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
238 
239     surface->mBackbuffer = std::move(skSurface);
240     return surface->mBackbuffer.get();
241 }
242 
destroyBuffers(VulkanSurface * surface)243 void VulkanManager::destroyBuffers(VulkanSurface* surface) {
244     if (surface->mBackbuffers) {
245         for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
246             mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true,
247                     UINT64_MAX);
248             surface->mBackbuffers[i].mImageIndex = -1;
249             mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore,
250                     nullptr);
251             mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore,
252                     nullptr);
253             mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2,
254                     surface->mBackbuffers[i].mTransitionCmdBuffers);
255             mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
256             mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
257         }
258     }
259 
260     delete[] surface->mBackbuffers;
261     surface->mBackbuffers = nullptr;
262     delete[] surface->mImageInfos;
263     surface->mImageInfos = nullptr;
264     delete[] surface->mImages;
265     surface->mImages = nullptr;
266 }
267 
destroySurface(VulkanSurface * surface)268 void VulkanManager::destroySurface(VulkanSurface* surface) {
269     // Make sure all submit commands have finished before starting to destroy objects.
270     if (VK_NULL_HANDLE != mPresentQueue) {
271         mQueueWaitIdle(mPresentQueue);
272     }
273     mDeviceWaitIdle(mBackendContext->fDevice);
274 
275     destroyBuffers(surface);
276 
277     if (VK_NULL_HANDLE != surface->mSwapchain) {
278         mDestroySwapchainKHR(mBackendContext->fDevice, surface->mSwapchain, nullptr);
279         surface->mSwapchain = VK_NULL_HANDLE;
280     }
281 
282     if (VK_NULL_HANDLE != surface->mVkSurface) {
283         mDestroySurfaceKHR(mBackendContext->fInstance, surface->mVkSurface, nullptr);
284         surface->mVkSurface = VK_NULL_HANDLE;
285     }
286     delete surface;
287 }
288 
createBuffers(VulkanSurface * surface,VkFormat format,VkExtent2D extent)289 void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
290     mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
291             nullptr);
292     SkASSERT(surface->mImageCount);
293     surface->mImages = new VkImage[surface->mImageCount];
294     mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain,
295             &surface->mImageCount, surface->mImages);
296 
297     SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
298 
299     bool wantSRGB = VK_FORMAT_R8G8B8A8_SRGB == format;
300     GrPixelConfig config = wantSRGB ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
301 
302     // set up initial image layouts and create surfaces
303     surface->mImageInfos = new VulkanSurface::ImageInfo[surface->mImageCount];
304     for (uint32_t i = 0; i < surface->mImageCount; ++i) {
305         GrBackendRenderTargetDesc desc;
306         GrVkImageInfo info;
307         info.fImage = surface->mImages[i];
308         info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
309         info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
310         info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
311         info.fFormat = format;
312         info.fLevelCount = 1;
313 
314         desc.fWidth = extent.width;
315         desc.fHeight = extent.height;
316         desc.fConfig = config;
317         desc.fOrigin = kTopLeft_GrSurfaceOrigin;
318         desc.fSampleCnt = 0;
319         desc.fStencilBits = 0;
320         desc.fRenderTargetHandle = (GrBackendObject) &info;
321 
322         VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
323         imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(),
324                 desc, &props);
325     }
326 
327     SkASSERT(mCommandPool != VK_NULL_HANDLE);
328 
329     // set up the backbuffers
330     VkSemaphoreCreateInfo semaphoreInfo;
331     memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
332     semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
333     semaphoreInfo.pNext = nullptr;
334     semaphoreInfo.flags = 0;
335     VkCommandBufferAllocateInfo commandBuffersInfo;
336     memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
337     commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
338     commandBuffersInfo.pNext = nullptr;
339     commandBuffersInfo.commandPool = mCommandPool;
340     commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
341     commandBuffersInfo.commandBufferCount = 2;
342     VkFenceCreateInfo fenceInfo;
343     memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
344     fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
345     fenceInfo.pNext = nullptr;
346     fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
347 
348     // we create one additional backbuffer structure here, because we want to
349     // give the command buffers they contain a chance to finish before we cycle back
350     surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1];
351     for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
352         SkDEBUGCODE(VkResult res);
353         surface->mBackbuffers[i].mImageIndex = -1;
354         SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
355                 &surface->mBackbuffers[i].mAcquireSemaphore);
356         SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
357                 &surface->mBackbuffers[i].mRenderSemaphore);
358         SkDEBUGCODE(res = ) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo,
359                 surface->mBackbuffers[i].mTransitionCmdBuffers);
360         SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
361                 &surface->mBackbuffers[i].mUsageFences[0]);
362         SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
363                 &surface->mBackbuffers[i].mUsageFences[1]);
364         SkASSERT(VK_SUCCESS == res);
365     }
366     surface->mCurrentBackbufferIndex = surface->mImageCount;
367 }
368 
createSwapchain(VulkanSurface * surface)369 bool VulkanManager::createSwapchain(VulkanSurface* surface) {
370     // check for capabilities
371     VkSurfaceCapabilitiesKHR caps;
372     VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice,
373             surface->mVkSurface, &caps);
374     if (VK_SUCCESS != res) {
375         return false;
376     }
377 
378     uint32_t surfaceFormatCount;
379     res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
380             &surfaceFormatCount, nullptr);
381     if (VK_SUCCESS != res) {
382         return false;
383     }
384 
385     FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount);
386     res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
387             &surfaceFormatCount, surfaceFormats.data());
388     if (VK_SUCCESS != res) {
389         return false;
390     }
391 
392     uint32_t presentModeCount;
393     res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
394             surface->mVkSurface, &presentModeCount, nullptr);
395     if (VK_SUCCESS != res) {
396         return false;
397     }
398 
399     FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount);
400     res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
401             surface->mVkSurface, &presentModeCount, 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 & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
432                                              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 
createSurface(ANativeWindow * window)519 VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) {
520     initialize();
521 
522     if (!window) {
523         return nullptr;
524     }
525 
526     VulkanSurface* surface = new VulkanSurface();
527 
528     VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
529     memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
530     surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
531     surfaceCreateInfo.pNext = nullptr;
532     surfaceCreateInfo.flags = 0;
533     surfaceCreateInfo.window = window;
534 
535     VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo,
536             nullptr, &surface->mVkSurface);
537     if (VK_SUCCESS != res) {
538         delete surface;
539         return nullptr;
540     }
541 
542 SkDEBUGCODE(
543     VkBool32 supported;
544     res = mGetPhysicalDeviceSurfaceSupportKHR(mBackendContext->fPhysicalDevice,
545             mPresentQueueIndex, surface->mVkSurface, &supported);
546     // All physical devices and queue families on Android must be capable of presentation with any
547     // native window.
548     SkASSERT(VK_SUCCESS == res && supported);
549 );
550 
551     if (!createSwapchain(surface)) {
552         destroySurface(surface);
553         return nullptr;
554     }
555 
556     return surface;
557 }
558 
559 // Helper to know which src stage flags we need to set when transitioning to the present layout
layoutToPipelineStageFlags(const VkImageLayout layout)560 static VkPipelineStageFlags layoutToPipelineStageFlags(const VkImageLayout layout) {
561     if (VK_IMAGE_LAYOUT_GENERAL == layout) {
562         return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
563     } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
564                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
565         return VK_PIPELINE_STAGE_TRANSFER_BIT;
566     } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout ||
567                VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
568                VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout ||
569                VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
570         return VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
571     } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
572         return VK_PIPELINE_STAGE_HOST_BIT;
573     }
574 
575     SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
576     return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
577 }
578 
579 // Helper to know which src access mask we need to set when transitioning to the present layout
layoutToSrcAccessMask(const VkImageLayout layout)580 static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
581     VkAccessFlags flags = 0;
582     if (VK_IMAGE_LAYOUT_GENERAL == layout) {
583         flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
584                 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
585                 VK_ACCESS_TRANSFER_WRITE_BIT |
586                 VK_ACCESS_TRANSFER_READ_BIT |
587                 VK_ACCESS_SHADER_READ_BIT |
588                 VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
589     } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
590         flags = VK_ACCESS_HOST_WRITE_BIT;
591     } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
592         flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
593     } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
594         flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
595     } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
596         flags = VK_ACCESS_TRANSFER_WRITE_BIT;
597     } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
598         flags = VK_ACCESS_TRANSFER_READ_BIT;
599     } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
600         flags = VK_ACCESS_SHADER_READ_BIT;
601     }
602     return flags;
603 }
604 
swapBuffers(VulkanSurface * surface)605 void VulkanManager::swapBuffers(VulkanSurface* surface) {
606     if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
607         ATRACE_NAME("Finishing GPU work");
608         mDeviceWaitIdle(mBackendContext->fDevice);
609     }
610 
611     VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
612             surface->mCurrentBackbufferIndex;
613     GrVkImageInfo* imageInfo;
614     SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get();
615     skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
616             SkSurface::kFlushRead_BackendHandleAccess);
617     // Check to make sure we never change the actually wrapped image
618     SkASSERT(imageInfo->fImage == surface->mImages[backbuffer->mImageIndex]);
619 
620     // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all
621     // previous work is complete for before presenting. So we first add the necessary barrier here.
622     VkImageLayout layout = imageInfo->fImageLayout;
623     VkPipelineStageFlags srcStageMask = layoutToPipelineStageFlags(layout);
624     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
625     VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout);
626     VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
627 
628     VkImageMemoryBarrier imageMemoryBarrier = {
629         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,    // sType
630         NULL,                                      // pNext
631         srcAccessMask,                             // outputMask
632         dstAccessMask,                             // inputMask
633         layout,                                    // oldLayout
634         VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,           // newLayout
635         mBackendContext->fGraphicsQueueIndex,      // srcQueueFamilyIndex
636         mPresentQueueIndex,                        // dstQueueFamilyIndex
637         surface->mImages[backbuffer->mImageIndex], // image
638         { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }  // subresourceRange
639     };
640 
641     mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
642     VkCommandBufferBeginInfo info;
643     memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
644     info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
645     info.flags = 0;
646     mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
647     mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0,
648             0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
649     mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
650 
651     surface->mImageInfos[backbuffer->mImageIndex].mImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
652 
653     // insert the layout transfer into the queue and wait on the acquire
654     VkSubmitInfo submitInfo;
655     memset(&submitInfo, 0, sizeof(VkSubmitInfo));
656     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
657     submitInfo.waitSemaphoreCount = 0;
658     submitInfo.pWaitDstStageMask = 0;
659     submitInfo.commandBufferCount = 1;
660     submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1];
661     submitInfo.signalSemaphoreCount = 1;
662     // When this command buffer finishes we will signal this semaphore so that we know it is now
663     // safe to present the image to the screen.
664     submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore;
665 
666     // Attach second fence to submission here so we can track when the command buffer finishes.
667     mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
668 
669     // Submit present operation to present queue. We use a semaphore here to make sure all rendering
670     // to the image is complete and that the layout has been change to present on the graphics
671     // queue.
672     const VkPresentInfoKHR presentInfo =
673     {
674         VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
675         NULL, // pNext
676         1, // waitSemaphoreCount
677         &backbuffer->mRenderSemaphore, // pWaitSemaphores
678         1, // swapchainCount
679         &surface->mSwapchain, // pSwapchains
680         &backbuffer->mImageIndex, // pImageIndices
681         NULL // pResults
682     };
683 
684     mQueuePresentKHR(mPresentQueue, &presentInfo);
685 
686     surface->mBackbuffer.reset();
687     surface->mImageInfos[backbuffer->mImageIndex].mLastUsed = surface->mCurrentTime;
688     surface->mImageInfos[backbuffer->mImageIndex].mInvalid = false;
689     surface->mCurrentTime++;
690 }
691 
getAge(VulkanSurface * surface)692 int VulkanManager::getAge(VulkanSurface* surface) {
693     VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
694             surface->mCurrentBackbufferIndex;
695     if (mSwapBehavior == SwapBehavior::Discard
696             || surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
697         return 0;
698     }
699     uint16_t lastUsed = surface->mImageInfos[backbuffer->mImageIndex].mLastUsed;
700     return surface->mCurrentTime - lastUsed;
701 }
702 
703 } /* namespace renderthread */
704 } /* namespace uirenderer */
705 } /* namespace android */
706