123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- /*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "tools/sk_app/VulkanWindowContext.h"
- #include "include/core/SkSurface.h"
- #include "include/gpu/GrBackendSemaphore.h"
- #include "include/gpu/GrBackendSurface.h"
- #include "include/gpu/GrContext.h"
- #include "src/core/SkAutoMalloc.h"
- #include "include/gpu/vk/GrVkExtensions.h"
- #include "include/gpu/vk/GrVkTypes.h"
- #include "src/gpu/vk/GrVkImage.h"
- #include "src/gpu/vk/GrVkUtil.h"
- #ifdef VK_USE_PLATFORM_WIN32_KHR
- // windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
- #undef CreateSemaphore
- #endif
- #define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fInstance, "vk" #F)
- #define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fDevice, "vk" #F)
- namespace sk_app {
- VulkanWindowContext::VulkanWindowContext(const DisplayParams& params,
- CreateVkSurfaceFn createVkSurface,
- CanPresentFn canPresent,
- PFN_vkGetInstanceProcAddr instProc,
- PFN_vkGetDeviceProcAddr devProc)
- : WindowContext(params)
- , fCreateVkSurfaceFn(createVkSurface)
- , fCanPresentFn(canPresent)
- , fSurface(VK_NULL_HANDLE)
- , fSwapchain(VK_NULL_HANDLE)
- , fImages(nullptr)
- , fImageLayouts(nullptr)
- , fSurfaces(nullptr)
- , fBackbuffers(nullptr) {
- fGetInstanceProcAddr = instProc;
- fGetDeviceProcAddr = devProc;
- this->initializeContext();
- }
- void VulkanWindowContext::initializeContext() {
- // any config code here (particularly for msaa)?
- PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr;
- PFN_vkGetDeviceProcAddr getDeviceProc = fGetDeviceProcAddr;
- auto getProc = [getInstanceProc, getDeviceProc](const char* proc_name,
- VkInstance instance, VkDevice device) {
- if (device != VK_NULL_HANDLE) {
- return getDeviceProc(device, proc_name);
- }
- return getInstanceProc(instance, proc_name);
- };
- GrVkBackendContext backendContext;
- GrVkExtensions extensions;
- VkPhysicalDeviceFeatures2 features;
- if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, &extensions, &features,
- &fDebugCallback, &fPresentQueueIndex, fCanPresentFn)) {
- sk_gpu_test::FreeVulkanFeaturesStructs(&features);
- return;
- }
- if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) ||
- !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) {
- sk_gpu_test::FreeVulkanFeaturesStructs(&features);
- return;
- }
- fInstance = backendContext.fInstance;
- fPhysicalDevice = backendContext.fPhysicalDevice;
- fDevice = backendContext.fDevice;
- fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex;
- fGraphicsQueue = backendContext.fQueue;
- PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties =
- reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
- backendContext.fGetProc("vkGetPhysicalDeviceProperties",
- backendContext.fInstance,
- VK_NULL_HANDLE));
- if (!localGetPhysicalDeviceProperties) {
- sk_gpu_test::FreeVulkanFeaturesStructs(&features);
- return;
- }
- VkPhysicalDeviceProperties physDeviceProperties;
- localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties);
- uint32_t physDevVersion = physDeviceProperties.apiVersion;
- fInterface.reset(new GrVkInterface(backendContext.fGetProc, fInstance, fDevice,
- backendContext.fInstanceVersion, physDevVersion,
- &extensions));
- GET_PROC(DestroyInstance);
- if (fDebugCallback != VK_NULL_HANDLE) {
- GET_PROC(DestroyDebugReportCallbackEXT);
- }
- GET_PROC(DestroySurfaceKHR);
- GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
- GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
- GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
- GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
- GET_DEV_PROC(DeviceWaitIdle);
- GET_DEV_PROC(QueueWaitIdle);
- 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(GetDeviceQueue);
- fContext = GrContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions);
- fSurface = fCreateVkSurfaceFn(fInstance);
- if (VK_NULL_HANDLE == fSurface) {
- this->destroyContext();
- sk_gpu_test::FreeVulkanFeaturesStructs(&features);
- return;
- }
- VkBool32 supported;
- VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex,
- fSurface, &supported);
- if (VK_SUCCESS != res) {
- this->destroyContext();
- sk_gpu_test::FreeVulkanFeaturesStructs(&features);
- return;
- }
- if (!this->createSwapchain(-1, -1, fDisplayParams)) {
- this->destroyContext();
- sk_gpu_test::FreeVulkanFeaturesStructs(&features);
- return;
- }
- // create presentQueue
- fGetDeviceQueue(fDevice, fPresentQueueIndex, 0, &fPresentQueue);
- sk_gpu_test::FreeVulkanFeaturesStructs(&features);
- }
- bool VulkanWindowContext::createSwapchain(int width, int height,
- const DisplayParams& params) {
- // check for capabilities
- VkSurfaceCapabilitiesKHR caps;
- VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fPhysicalDevice, fSurface, &caps);
- if (VK_SUCCESS != res) {
- return false;
- }
- uint32_t surfaceFormatCount;
- res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
- nullptr);
- if (VK_SUCCESS != res) {
- return false;
- }
- SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
- VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
- res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
- surfaceFormats);
- if (VK_SUCCESS != res) {
- return false;
- }
- uint32_t presentModeCount;
- res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
- nullptr);
- if (VK_SUCCESS != res) {
- return false;
- }
- SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
- VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
- res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
- presentModes);
- if (VK_SUCCESS != res) {
- return false;
- }
- VkExtent2D extent = caps.currentExtent;
- // use the hints
- if (extent.width == (uint32_t)-1) {
- extent.width = width;
- extent.height = height;
- }
- // clamp width; to protect us from broken hints
- if (extent.width < caps.minImageExtent.width) {
- extent.width = caps.minImageExtent.width;
- } else if (extent.width > caps.maxImageExtent.width) {
- extent.width = caps.maxImageExtent.width;
- }
- // clamp height
- if (extent.height < caps.minImageExtent.height) {
- extent.height = caps.minImageExtent.height;
- } else if (extent.height > caps.maxImageExtent.height) {
- extent.height = caps.maxImageExtent.height;
- }
- fWidth = (int)extent.width;
- fHeight = (int)extent.height;
- uint32_t imageCount = caps.minImageCount + 2;
- if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
- // Application must settle for fewer images than desired:
- imageCount = caps.maxImageCount;
- }
- 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.supportedTransforms & caps.currentTransform);
- 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;
- // Pick our surface format.
- VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
- VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
- for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
- VkFormat localFormat = surfaceFormats[i].format;
- if (GrVkFormatIsSupported(localFormat)) {
- surfaceFormat = localFormat;
- colorSpace = surfaceFormats[i].colorSpace;
- break;
- }
- }
- fDisplayParams = params;
- fSampleCount = params.fMSAASampleCount;
- fStencilBits = 8;
- if (VK_FORMAT_UNDEFINED == surfaceFormat) {
- return false;
- }
- SkColorType colorType;
- switch (surfaceFormat) {
- case VK_FORMAT_R8G8B8A8_UNORM: // fall through
- case VK_FORMAT_R8G8B8A8_SRGB:
- colorType = kRGBA_8888_SkColorType;
- break;
- case VK_FORMAT_B8G8R8A8_UNORM: // fall through
- colorType = kBGRA_8888_SkColorType;
- break;
- default:
- return false;
- }
- // If mailbox mode is available, use it, as it is the lowest-latency non-
- // tearing mode. If not, fall back to FIFO which is always available.
- VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
- bool hasImmediate = false;
- for (uint32_t i = 0; i < presentModeCount; ++i) {
- // use mailbox
- if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
- mode = VK_PRESENT_MODE_MAILBOX_KHR;
- }
- if (VK_PRESENT_MODE_IMMEDIATE_KHR == presentModes[i]) {
- hasImmediate = true;
- }
- }
- if (params.fDisableVsync && hasImmediate) {
- mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
- }
- VkSwapchainCreateInfoKHR swapchainCreateInfo;
- memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
- swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- swapchainCreateInfo.surface = fSurface;
- swapchainCreateInfo.minImageCount = imageCount;
- swapchainCreateInfo.imageFormat = surfaceFormat;
- swapchainCreateInfo.imageColorSpace = colorSpace;
- swapchainCreateInfo.imageExtent = extent;
- swapchainCreateInfo.imageArrayLayers = 1;
- swapchainCreateInfo.imageUsage = usageFlags;
- uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex };
- if (fGraphicsQueueIndex != fPresentQueueIndex) {
- 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 = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- swapchainCreateInfo.compositeAlpha = composite_alpha;
- swapchainCreateInfo.presentMode = mode;
- swapchainCreateInfo.clipped = true;
- swapchainCreateInfo.oldSwapchain = fSwapchain;
- res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
- if (VK_SUCCESS != res) {
- return false;
- }
- // destroy the old swapchain
- if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
- fDeviceWaitIdle(fDevice);
- this->destroyBuffers();
- fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
- }
- this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
- return true;
- }
- void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
- fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr);
- SkASSERT(fImageCount);
- fImages = new VkImage[fImageCount];
- fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages);
- // set up initial image layouts and create surfaces
- fImageLayouts = new VkImageLayout[fImageCount];
- fSurfaces = new sk_sp<SkSurface>[fImageCount];
- for (uint32_t i = 0; i < fImageCount; ++i) {
- fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
- GrVkImageInfo info;
- info.fImage = fImages[i];
- info.fAlloc = GrVkAlloc();
- info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
- info.fFormat = format;
- info.fLevelCount = 1;
- info.fCurrentQueueFamily = fPresentQueueIndex;
- if (fSampleCount == 1) {
- GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
- fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(
- fContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, colorType,
- fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps);
- } else {
- GrBackendTexture backendTexture(fWidth, fHeight, info);
- fSurfaces[i] = SkSurface::MakeFromBackendTexture(
- fContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin, fSampleCount,
- colorType, fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps);
- }
- }
- // 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;
- // 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
- fBackbuffers = new BackbufferInfo[fImageCount + 1];
- for (uint32_t i = 0; i < fImageCount + 1; ++i) {
- fBackbuffers[i].fImageIndex = -1;
- GR_VK_CALL_ERRCHECK(fInterface,
- CreateSemaphore(fDevice, &semaphoreInfo,
- nullptr, &fBackbuffers[i].fRenderSemaphore));
- }
- fCurrentBackbufferIndex = fImageCount;
- }
- void VulkanWindowContext::destroyBuffers() {
- if (fBackbuffers) {
- for (uint32_t i = 0; i < fImageCount + 1; ++i) {
- fBackbuffers[i].fImageIndex = -1;
- GR_VK_CALL(fInterface,
- DestroySemaphore(fDevice,
- fBackbuffers[i].fRenderSemaphore,
- nullptr));
- }
- }
- delete[] fBackbuffers;
- fBackbuffers = nullptr;
- // Does this actually free the surfaces?
- delete[] fSurfaces;
- fSurfaces = nullptr;
- delete[] fImageLayouts;
- fImageLayouts = nullptr;
- delete[] fImages;
- fImages = nullptr;
- }
- VulkanWindowContext::~VulkanWindowContext() {
- this->destroyContext();
- }
- void VulkanWindowContext::destroyContext() {
- if (this->isValid()) {
- fQueueWaitIdle(fPresentQueue);
- fDeviceWaitIdle(fDevice);
- this->destroyBuffers();
- if (VK_NULL_HANDLE != fSwapchain) {
- fDestroySwapchainKHR(fDevice, fSwapchain, nullptr);
- fSwapchain = VK_NULL_HANDLE;
- }
- if (VK_NULL_HANDLE != fSurface) {
- fDestroySurfaceKHR(fInstance, fSurface, nullptr);
- fSurface = VK_NULL_HANDLE;
- }
- }
- fContext.reset();
- fInterface.reset();
- if (VK_NULL_HANDLE != fDevice) {
- fDestroyDevice(fDevice, nullptr);
- fDevice = VK_NULL_HANDLE;
- }
- #ifdef SK_ENABLE_VK_LAYERS
- if (fDebugCallback != VK_NULL_HANDLE) {
- fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr);
- }
- #endif
- fPhysicalDevice = VK_NULL_HANDLE;
- if (VK_NULL_HANDLE != fInstance) {
- fDestroyInstance(fInstance, nullptr);
- fInstance = VK_NULL_HANDLE;
- }
- }
- VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
- SkASSERT(fBackbuffers);
- ++fCurrentBackbufferIndex;
- if (fCurrentBackbufferIndex > fImageCount) {
- fCurrentBackbufferIndex = 0;
- }
- BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
- return backbuffer;
- }
- sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
- BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
- SkASSERT(backbuffer);
- // semaphores should be in unsignaled state
- VkSemaphoreCreateInfo semaphoreInfo;
- memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
- semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- semaphoreInfo.pNext = nullptr;
- semaphoreInfo.flags = 0;
- VkSemaphore semaphore;
- GR_VK_CALL_ERRCHECK(fInterface, CreateSemaphore(fDevice, &semaphoreInfo,
- nullptr, &semaphore));
- // acquire the image
- VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
- semaphore, VK_NULL_HANDLE,
- &backbuffer->fImageIndex);
- 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
- GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
- return nullptr;
- }
- if (VK_ERROR_OUT_OF_DATE_KHR == res) {
- // tear swapchain down and try again
- if (!this->createSwapchain(-1, -1, fDisplayParams)) {
- GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
- return nullptr;
- }
- backbuffer = this->getAvailableBackbuffer();
- // acquire the image
- res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
- semaphore, VK_NULL_HANDLE,
- &backbuffer->fImageIndex);
- if (VK_SUCCESS != res) {
- GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
- return nullptr;
- }
- }
- SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
- GrBackendSemaphore beSemaphore;
- beSemaphore.initVulkan(semaphore);
- surface->wait(1, &beSemaphore);
- return sk_ref_sp(surface);
- }
- void VulkanWindowContext::swapBuffers() {
- BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
- SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
- GrBackendSemaphore beSemaphore;
- beSemaphore.initVulkan(backbuffer->fRenderSemaphore);
- GrFlushInfo info;
- info.fNumSemaphores = 1;
- info.fSignalSemaphores = &beSemaphore;
- surface->flush(SkSurface::BackendSurfaceAccess::kPresent, info);
- // Submit present operation to present queue
- const VkPresentInfoKHR presentInfo =
- {
- VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
- NULL, // pNext
- 1, // waitSemaphoreCount
- &backbuffer->fRenderSemaphore, // pWaitSemaphores
- 1, // swapchainCount
- &fSwapchain, // pSwapchains
- &backbuffer->fImageIndex, // pImageIndices
- NULL // pResults
- };
- fQueuePresentKHR(fPresentQueue, &presentInfo);
- }
- } //namespace sk_app
|