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
30namespace android {
31namespace uirenderer {
32namespace 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
37VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
38
39void 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
52void 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.
128VulkanSurface::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
150SkSurface* 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
252void 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
277void 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
298void 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
368bool 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
518VulkanSurface* 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
558static 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
578static 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
601void 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
688int 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