summaryrefslogtreecommitdiff
path: root/libs/hwui/renderthread/VulkanManager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/renderthread/VulkanManager.cpp')
-rw-r--r--libs/hwui/renderthread/VulkanManager.cpp712
1 files changed, 86 insertions, 626 deletions
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index ce2dddc69049..6dacc7a0ea07 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -16,6 +16,7 @@
#include "VulkanManager.h"
+#include <android/sync.h>
#include <gui/Surface.h>
#include "Properties.h"
@@ -23,6 +24,7 @@
#include "renderstate/RenderState.h"
#include "utils/FatVector.h"
+#include <GrBackendSemaphore.h>
#include <GrBackendSurface.h>
#include <GrContext.h>
#include <GrTypes.h>
@@ -144,6 +146,7 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
GET_INST_PROC(GetPhysicalDeviceProperties);
GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties);
GET_INST_PROC(GetPhysicalDeviceFeatures2);
+ GET_INST_PROC(GetPhysicalDeviceImageFormatProperties2);
GET_INST_PROC(CreateDevice);
GET_INST_PROC(EnumerateDeviceExtensionProperties);
GET_INST_PROC(CreateAndroidSurfaceKHR);
@@ -320,11 +323,6 @@ void VulkanManager::setupDevice(GrVkExtensions& grExtensions, VkPhysicalDeviceFe
GET_DEV_PROC(GetDeviceQueue);
GET_DEV_PROC(DeviceWaitIdle);
GET_DEV_PROC(DestroyDevice);
- GET_DEV_PROC(CreateSwapchainKHR);
- GET_DEV_PROC(DestroySwapchainKHR);
- GET_DEV_PROC(GetSwapchainImagesKHR);
- GET_DEV_PROC(AcquireNextImageKHR);
- GET_DEV_PROC(QueuePresentKHR);
GET_DEV_PROC(CreateCommandPool);
GET_DEV_PROC(DestroyCommandPool);
GET_DEV_PROC(AllocateCommandBuffers);
@@ -428,201 +426,102 @@ VkFunctorInitParams VulkanManager::getVkFunctorInitParams() const {
};
}
-// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
-// previous uses have finished before returning.
-VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
- SkASSERT(surface->mBackbuffers);
+Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) {
- ++surface->mCurrentBackbufferIndex;
- if (surface->mCurrentBackbufferIndex > surface->mImageCount) {
- surface->mCurrentBackbufferIndex = 0;
- }
-
- VulkanSurface::BackbufferInfo* backbuffer =
- surface->mBackbuffers + surface->mCurrentBackbufferIndex;
+ VulkanSurface::NativeBufferInfo* bufferInfo = surface->dequeueNativeBuffer();
- // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
- // reuse its commands buffers.
- VkResult res = mWaitForFences(mDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX);
- if (res != VK_SUCCESS) {
- return nullptr;
+ if (bufferInfo == nullptr) {
+ ALOGE("VulkanSurface::dequeueNativeBuffer called with an invalid surface!");
+ return Frame(-1, -1, 0);
}
- return backbuffer;
-}
+ LOG_ALWAYS_FATAL_IF(!bufferInfo->dequeued);
-static SkMatrix getPreTransformMatrix(int width, int height,
- VkSurfaceTransformFlagBitsKHR transform) {
- switch (transform) {
- case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
- return SkMatrix::I();
- case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
- return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
- return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
- return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
- return SkMatrix::MakeAll(-1, 0, width, 0, 1, 0, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
- return SkMatrix::MakeAll(0, -1, height, -1, 0, width, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
- return SkMatrix::MakeAll(1, 0, 0, 0, -1, height, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
- return SkMatrix::MakeAll(0, 1, 0, 1, 0, 0, 0, 0, 1);
- default:
- LOG_ALWAYS_FATAL("Unsupported pre transform of swapchain.");
- }
- return SkMatrix::I();
-}
-
-
-SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface** surfaceOut) {
- // Recreate VulkanSurface, if ANativeWindow has been resized.
- VulkanSurface* surface = *surfaceOut;
- int windowWidth = 0, windowHeight = 0;
- ANativeWindow* window = surface->mNativeWindow;
- window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth);
- window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight);
- if (windowWidth != surface->mWindowWidth || windowHeight != surface->mWindowHeight) {
- ColorMode colorMode = surface->mColorMode;
- sk_sp<SkColorSpace> colorSpace = surface->mColorSpace;
- SkColorType colorType = surface->mColorType;
- GrContext* grContext = surface->mGrContext;
- destroySurface(surface);
- *surfaceOut = createSurface(window, colorMode, colorSpace, colorType, grContext);
- surface = *surfaceOut;
- if (!surface) {
- return nullptr;
+ if (bufferInfo->dequeue_fence != -1) {
+ int fence_clone = dup(bufferInfo->dequeue_fence);
+ if (fence_clone == -1) {
+ ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", strerror(errno), errno);
+ sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
+ } else {
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = nullptr;
+ semaphoreInfo.flags = 0;
+ VkSemaphore semaphore;
+ VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+ LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to create import semaphore, err: %d",
+ err);
+
+ VkImportSemaphoreFdInfoKHR importInfo;
+ importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+ importInfo.pNext = nullptr;
+ importInfo.semaphore = semaphore;
+ importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+ importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+ importInfo.fd = fence_clone;
+
+ err = mImportSemaphoreFdKHR(mDevice, &importInfo);
+ LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to import semaphore, err: %d", err);
+
+ GrBackendSemaphore backendSemaphore;
+ backendSemaphore.initVulkan(semaphore);
+ bufferInfo->skSurface->wait(1, &backendSemaphore);
}
}
- VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
- SkASSERT(backbuffer);
-
- VkResult res;
-
- res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
- SkASSERT(VK_SUCCESS == res);
-
- // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
- // finished presenting and that it is safe to begin sending new commands to the returned image.
- res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
- &backbuffer->mImageIndex);
-
- if (VK_ERROR_SURFACE_LOST_KHR == res) {
- // need to figure out how to create a new vkSurface without the platformData*
- // maybe use attach somehow? but need a Window
- return nullptr;
- }
- if (VK_ERROR_OUT_OF_DATE_KHR == res || VK_SUBOPTIMAL_KHR == res) {
- // tear swapchain down and try again
- if (!createSwapchain(surface)) {
- return nullptr;
- }
- backbuffer = getAvailableBackbuffer(surface);
- res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
- SkASSERT(VK_SUCCESS == res);
-
- // acquire the image
- res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
- &backbuffer->mImageIndex);
+ int bufferAge = (mSwapBehavior == SwapBehavior::Discard) ? 0 : surface->getCurrentBuffersAge();
+ return Frame(surface->logicalWidth(), surface->logicalHeight(), bufferAge);
+}
- if (VK_SUCCESS != res) {
- return nullptr;
- }
+void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
+ if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+ ATRACE_NAME("Finishing GPU work");
+ mDeviceWaitIdle(mDevice);
}
- // set up layout transfer from initial to color attachment
- VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout;
- SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
- VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- VkAccessFlags srcAccessMask = 0;
- VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
- VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
-
- VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
- mPresentQueueIndex, // srcQueueFamilyIndex
- mGraphicsQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
- };
- mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
-
- VkCommandBufferBeginInfo info;
- memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
- info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- info.flags = 0;
- mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
-
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, 0,
- nullptr, 0, nullptr, 1, &imageMemoryBarrier);
-
- mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
-
- VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- // insert the layout transfer into the queue and wait on the acquire
- VkSubmitInfo submitInfo;
- memset(&submitInfo, 0, sizeof(VkSubmitInfo));
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 1;
- // Wait to make sure aquire semaphore set above has signaled.
- submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore;
- submitInfo.pWaitDstStageMask = &waitDstStageFlags;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0];
- submitInfo.signalSemaphoreCount = 0;
-
- // Attach first fence to submission here so we can track when the command buffer finishes.
- mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
+ VkExportSemaphoreCreateInfo exportInfo;
+ exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
+ exportInfo.pNext = nullptr;
+ exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- // We need to notify Skia that we changed the layout of the wrapped VkImage
- sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
- GrBackendRenderTarget backendRT = skSurface->getBackendRenderTarget(
- SkSurface::kFlushRead_BackendHandleAccess);
- if (!backendRT.isValid()) {
- SkASSERT(backendRT.isValid());
- return nullptr;
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = &exportInfo;
+ semaphoreInfo.flags = 0;
+ VkSemaphore semaphore;
+ VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+ ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to create semaphore");
+
+ GrBackendSemaphore backendSemaphore;
+ backendSemaphore.initVulkan(semaphore);
+
+ VulkanSurface::NativeBufferInfo* bufferInfo = surface->getCurrentBufferInfo();
+
+ int fenceFd = -1;
+ GrSemaphoresSubmitted submitted =
+ bufferInfo->skSurface->flush(SkSurface::BackendSurfaceAccess::kPresent,
+ SkSurface::kNone_FlushFlags, 1, &backendSemaphore);
+ if (submitted == GrSemaphoresSubmitted::kYes) {
+ VkSemaphoreGetFdInfoKHR getFdInfo;
+ getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
+ getFdInfo.pNext = nullptr;
+ getFdInfo.semaphore = semaphore;
+ getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+
+ err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
+ ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
+ } else {
+ ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
+ mQueueWaitIdle(mGraphicsQueue);
}
- backendRT.setVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
- surface->mPreTransform = getPreTransformMatrix(surface->windowWidth(),
- surface->windowHeight(),
- surface->mTransform);
+ surface->presentCurrentBuffer(dirtyRect, fenceFd);
- surface->mBackbuffer = std::move(skSurface);
- return surface->mBackbuffer.get();
-}
-
-void VulkanManager::destroyBuffers(VulkanSurface* surface) {
- if (surface->mBackbuffers) {
- for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
- mWaitForFences(mDevice, 2, surface->mBackbuffers[i].mUsageFences, true, UINT64_MAX);
- surface->mBackbuffers[i].mImageIndex = -1;
- mDestroySemaphore(mDevice, surface->mBackbuffers[i].mAcquireSemaphore, nullptr);
- mDestroySemaphore(mDevice, surface->mBackbuffers[i].mRenderSemaphore, nullptr);
- mFreeCommandBuffers(mDevice, mCommandPool, 2,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
- mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
- mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
- }
- }
-
- delete[] surface->mBackbuffers;
- surface->mBackbuffers = nullptr;
- delete[] surface->mImageInfos;
- surface->mImageInfos = nullptr;
- delete[] surface->mImages;
- surface->mImages = nullptr;
+ // Exporting a semaphore with copy transference via vkGetSemaphoreFdKHR, has the same effect of
+ // destroying the semaphore and creating a new one with the same handle, and the payloads
+ // ownership is move to the Fd we created. Thus the semaphore is in a state that we can delete
+ // it and we don't need to wait on the command buffer we submitted to finish.
+ mDestroySemaphore(mDevice, semaphore, nullptr);
}
void VulkanManager::destroySurface(VulkanSurface* surface) {
@@ -632,271 +531,9 @@ void VulkanManager::destroySurface(VulkanSurface* surface) {
}
mDeviceWaitIdle(mDevice);
- destroyBuffers(surface);
-
- if (VK_NULL_HANDLE != surface->mSwapchain) {
- mDestroySwapchainKHR(mDevice, surface->mSwapchain, nullptr);
- surface->mSwapchain = VK_NULL_HANDLE;
- }
-
- if (VK_NULL_HANDLE != surface->mVkSurface) {
- mDestroySurfaceKHR(mInstance, surface->mVkSurface, nullptr);
- surface->mVkSurface = VK_NULL_HANDLE;
- }
delete surface;
}
-void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
- mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, nullptr);
- SkASSERT(surface->mImageCount);
- surface->mImages = new VkImage[surface->mImageCount];
- mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, surface->mImages);
-
- SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
-
- // set up initial image layouts and create surfaces
- surface->mImageInfos = new VulkanSurface::ImageInfo[surface->mImageCount];
- for (uint32_t i = 0; i < surface->mImageCount; ++i) {
- GrVkImageInfo info;
- info.fImage = surface->mImages[i];
- info.fAlloc = GrVkAlloc();
- info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
- info.fFormat = format;
- info.fLevelCount = 1;
-
- GrBackendRenderTarget backendRT(extent.width, extent.height, 0, 0, info);
-
- VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
- imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
- surface->mGrContext, backendRT, kTopLeft_GrSurfaceOrigin,
- surface->mColorType, surface->mColorSpace, &props);
- }
-
- SkASSERT(mCommandPool != VK_NULL_HANDLE);
-
- // set up the backbuffers
- VkSemaphoreCreateInfo semaphoreInfo;
- memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
- semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- semaphoreInfo.pNext = nullptr;
- semaphoreInfo.flags = 0;
- VkCommandBufferAllocateInfo commandBuffersInfo;
- memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
- commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- commandBuffersInfo.pNext = nullptr;
- commandBuffersInfo.commandPool = mCommandPool;
- commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- commandBuffersInfo.commandBufferCount = 2;
- VkFenceCreateInfo fenceInfo;
- memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
- fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- fenceInfo.pNext = nullptr;
- fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
-
- // we create one additional backbuffer structure here, because we want to
- // give the command buffers they contain a chance to finish before we cycle back
- surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1];
- for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
- SkDEBUGCODE(VkResult res);
- surface->mBackbuffers[i].mImageIndex = -1;
- SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mAcquireSemaphore);
- SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mRenderSemaphore);
- SkDEBUGCODE(res =) mAllocateCommandBuffers(mDevice, &commandBuffersInfo,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
- SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[0]);
- SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[1]);
- SkASSERT(VK_SUCCESS == res);
- }
- surface->mCurrentBackbufferIndex = surface->mImageCount;
-}
-
-bool VulkanManager::createSwapchain(VulkanSurface* surface) {
- // check for capabilities
- VkSurfaceCapabilitiesKHR caps;
- VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mPhysicalDevice,
- surface->mVkSurface, &caps);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- uint32_t surfaceFormatCount;
- res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, nullptr);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount);
- res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, surfaceFormats.data());
- if (VK_SUCCESS != res) {
- return false;
- }
-
- uint32_t presentModeCount;
- res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
- surface->mVkSurface, &presentModeCount, nullptr);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount);
- res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
- surface->mVkSurface, &presentModeCount,
- presentModes.data());
- if (VK_SUCCESS != res) {
- return false;
- }
-
- if (!SkToBool(caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) {
- return false;
- }
- VkSurfaceTransformFlagBitsKHR transform;
- if (SkToBool(caps.supportedTransforms & caps.currentTransform) &&
- !SkToBool(caps.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR)) {
- transform = caps.currentTransform;
- } else {
- transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- }
-
- VkExtent2D extent = caps.currentExtent;
- // clamp width; to handle currentExtent of -1 and protect us from broken hints
- if (extent.width < caps.minImageExtent.width) {
- extent.width = caps.minImageExtent.width;
- }
- SkASSERT(extent.width <= caps.maxImageExtent.width);
- // clamp height
- if (extent.height < caps.minImageExtent.height) {
- extent.height = caps.minImageExtent.height;
- }
- SkASSERT(extent.height <= caps.maxImageExtent.height);
-
- VkExtent2D swapExtent = extent;
- if (transform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
- transform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR ||
- transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR ||
- transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
- swapExtent.width = extent.height;
- swapExtent.height = extent.width;
- }
-
- surface->mWindowWidth = extent.width;
- surface->mWindowHeight = extent.height;
-
- uint32_t imageCount = std::max<uint32_t>(3, caps.minImageCount);
- if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
- // Application must settle for fewer images than desired:
- imageCount = caps.maxImageCount;
- }
-
- // Currently Skia requires the images to be color attchments and support all transfer
- // operations.
- VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
- VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
-
- SkASSERT(caps.supportedCompositeAlpha &
- (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
- VkCompositeAlphaFlagBitsKHR composite_alpha =
- (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
- ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
- : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
-
- VkFormat surfaceFormat = VK_FORMAT_R8G8B8A8_UNORM;
- VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
- if (surface->mColorType == SkColorType::kRGBA_F16_SkColorType) {
- surfaceFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
- }
-
- if (surface->mColorMode == ColorMode::WideColorGamut) {
- skcms_Matrix3x3 surfaceGamut;
- LOG_ALWAYS_FATAL_IF(!surface->mColorSpace->toXYZD50(&surfaceGamut),
- "Could not get gamut matrix from color space");
- if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
- colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
- } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
- colorSpace = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT;
- } else {
- LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
- }
- }
-
- bool foundSurfaceFormat = false;
- for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
- if (surfaceFormat == surfaceFormats[i].format
- && colorSpace == surfaceFormats[i].colorSpace) {
- foundSurfaceFormat = true;
- break;
- }
- }
-
- if (!foundSurfaceFormat) {
- return false;
- }
-
- // FIFO is always available and will match what we do on GL so just pick that here.
- VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
-
- VkSwapchainCreateInfoKHR swapchainCreateInfo;
- memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
- swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- swapchainCreateInfo.surface = surface->mVkSurface;
- swapchainCreateInfo.minImageCount = imageCount;
- swapchainCreateInfo.imageFormat = surfaceFormat;
- swapchainCreateInfo.imageColorSpace = colorSpace;
- swapchainCreateInfo.imageExtent = swapExtent;
- swapchainCreateInfo.imageArrayLayers = 1;
- swapchainCreateInfo.imageUsage = usageFlags;
-
- uint32_t queueFamilies[] = {mGraphicsQueueIndex, mPresentQueueIndex};
- if (mGraphicsQueueIndex != mPresentQueueIndex) {
- swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
- swapchainCreateInfo.queueFamilyIndexCount = 2;
- swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
- } else {
- swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- swapchainCreateInfo.queueFamilyIndexCount = 0;
- swapchainCreateInfo.pQueueFamilyIndices = nullptr;
- }
-
- swapchainCreateInfo.preTransform = transform;
- swapchainCreateInfo.compositeAlpha = composite_alpha;
- swapchainCreateInfo.presentMode = mode;
- swapchainCreateInfo.clipped = true;
- swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
-
- res = mCreateSwapchainKHR(mDevice, &swapchainCreateInfo, nullptr, &surface->mSwapchain);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- surface->mTransform = transform;
-
- // destroy the old swapchain
- if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
- mDeviceWaitIdle(mDevice);
-
- destroyBuffers(surface);
-
- mDestroySwapchainKHR(mDevice, swapchainCreateInfo.oldSwapchain, nullptr);
- }
-
- createBuffers(surface, surfaceFormat, swapExtent);
-
- // The window content is not updated (frozen) until a buffer of the window size is received.
- // This prevents temporary stretching of the window after it is resized, but before the first
- // buffer with new size is enqueued.
- native_window_set_scaling_mode(surface->mNativeWindow, NATIVE_WINDOW_SCALING_MODE_FREEZE);
-
- return true;
-}
-
VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
SkColorType surfaceColorType,
@@ -906,185 +543,8 @@ VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode col
return nullptr;
}
- VulkanSurface* surface = new VulkanSurface(colorMode, window, surfaceColorSpace,
- surfaceColorType, grContext);
-
- VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
- memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
- surfaceCreateInfo.pNext = nullptr;
- surfaceCreateInfo.flags = 0;
- surfaceCreateInfo.window = window;
-
- VkResult res = mCreateAndroidSurfaceKHR(mInstance, &surfaceCreateInfo, nullptr,
- &surface->mVkSurface);
- if (VK_SUCCESS != res) {
- delete surface;
- return nullptr;
- }
-
- SkDEBUGCODE(VkBool32 supported; res = mGetPhysicalDeviceSurfaceSupportKHR(
- mPhysicalDevice, mPresentQueueIndex, surface->mVkSurface, &supported);
- // All physical devices and queue families on Android must be capable of
- // presentation with any native window.
- SkASSERT(VK_SUCCESS == res && supported););
-
- if (!createSwapchain(surface)) {
- destroySurface(surface);
- return nullptr;
- }
-
- return surface;
-}
-
-// Helper to know which src stage flags we need to set when transitioning to the present layout
-static VkPipelineStageFlags layoutToPipelineSrcStageFlags(const VkImageLayout layout) {
- if (VK_IMAGE_LAYOUT_GENERAL == layout) {
- return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
- } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_TRANSFER_BIT;
- } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
- } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
- return VK_PIPELINE_STAGE_HOST_BIT;
- }
-
- SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
- return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-}
-
-// Helper to know which src access mask we need to set when transitioning to the present layout
-static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
- VkAccessFlags flags = 0;
- if (VK_IMAGE_LAYOUT_GENERAL == layout) {
- flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
- VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT |
- VK_ACCESS_HOST_READ_BIT;
- } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
- flags = VK_ACCESS_HOST_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
- flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
- flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
- flags = VK_ACCESS_TRANSFER_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
- flags = VK_ACCESS_TRANSFER_READ_BIT;
- } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
- flags = VK_ACCESS_SHADER_READ_BIT;
- }
- return flags;
-}
-
-void VulkanManager::swapBuffers(VulkanSurface* surface) {
- if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
- ATRACE_NAME("Finishing GPU work");
- mDeviceWaitIdle(mDevice);
- }
-
- SkASSERT(surface->mBackbuffers);
- VulkanSurface::BackbufferInfo* backbuffer =
- surface->mBackbuffers + surface->mCurrentBackbufferIndex;
-
- SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get();
- GrBackendRenderTarget backendRT = skSurface->getBackendRenderTarget(
- SkSurface::kFlushRead_BackendHandleAccess);
- SkASSERT(backendRT.isValid());
-
- GrVkImageInfo imageInfo;
- SkAssertResult(backendRT.getVkImageInfo(&imageInfo));
-
- // Check to make sure we never change the actually wrapped image
- SkASSERT(imageInfo.fImage == surface->mImages[backbuffer->mImageIndex]);
-
- // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all
- // previous work is complete for before presenting. So we first add the necessary barrier here.
- VkImageLayout layout = imageInfo.fImageLayout;
- VkPipelineStageFlags srcStageMask = layoutToPipelineSrcStageFlags(layout);
- VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
- VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout);
- VkAccessFlags dstAccessMask = 0;
-
- VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
- mGraphicsQueueIndex, // srcQueueFamilyIndex
- mPresentQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
- };
-
- mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
- VkCommandBufferBeginInfo info;
- memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
- info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- info.flags = 0;
- mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, 0,
- nullptr, 0, nullptr, 1, &imageMemoryBarrier);
- mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
-
- surface->mImageInfos[backbuffer->mImageIndex].mImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-
- // insert the layout transfer into the queue and wait on the acquire
- VkSubmitInfo submitInfo;
- memset(&submitInfo, 0, sizeof(VkSubmitInfo));
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 0;
- submitInfo.pWaitDstStageMask = 0;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1];
- submitInfo.signalSemaphoreCount = 1;
- // When this command buffer finishes we will signal this semaphore so that we know it is now
- // safe to present the image to the screen.
- submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore;
-
- // Attach second fence to submission here so we can track when the command buffer finishes.
- mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
-
- // Submit present operation to present queue. We use a semaphore here to make sure all rendering
- // to the image is complete and that the layout has been change to present on the graphics
- // queue.
- const VkPresentInfoKHR presentInfo = {
- VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
- NULL, // pNext
- 1, // waitSemaphoreCount
- &backbuffer->mRenderSemaphore, // pWaitSemaphores
- 1, // swapchainCount
- &surface->mSwapchain, // pSwapchains
- &backbuffer->mImageIndex, // pImageIndices
- NULL // pResults
- };
-
- mQueuePresentKHR(mPresentQueue, &presentInfo);
-
- surface->mBackbuffer.reset();
- surface->mImageInfos[backbuffer->mImageIndex].mLastUsed = surface->mCurrentTime;
- surface->mImageInfos[backbuffer->mImageIndex].mInvalid = false;
- surface->mCurrentTime++;
-}
-
-int VulkanManager::getAge(VulkanSurface* surface) {
- SkASSERT(surface->mBackbuffers);
- VulkanSurface::BackbufferInfo* backbuffer =
- surface->mBackbuffers + surface->mCurrentBackbufferIndex;
- if (mSwapBehavior == SwapBehavior::Discard ||
- surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
- return 0;
- }
- uint16_t lastUsed = surface->mImageInfos[backbuffer->mImageIndex].mLastUsed;
- return surface->mCurrentTime - lastUsed;
+ return VulkanSurface::Create(window, colorMode, surfaceColorType, surfaceColorSpace, grContext,
+ *this);
}
bool VulkanManager::setupDummyCommandBuffer() {