diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /external/skia/share-grcontext.patch.1 | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | external/skia/share-grcontext.patch.1 | 872 |
1 files changed, 872 insertions, 0 deletions
diff --git a/external/skia/share-grcontext.patch.1 b/external/skia/share-grcontext.patch.1 new file mode 100644 index 000000000..2a957c284 --- /dev/null +++ b/external/skia/share-grcontext.patch.1 @@ -0,0 +1,872 @@ +diff --git a/tools/sk_app/MetalWindowContext.h b/tools/sk_app/MetalWindowContext.h +index 106d366415..08dc19b5c8 100644 +--- a/tools/sk_app/MetalWindowContext.h ++++ b/tools/sk_app/MetalWindowContext.h +@@ -14,13 +14,18 @@ + + #include "tools/sk_app/WindowContext.h" + ++#ifdef __OBJC__ + #import <Metal/Metal.h> + #import <QuartzCore/CAMetalLayer.h> ++#endif + + namespace sk_app { + ++#ifdef __OBJC__ + class MetalWindowContext : public WindowContext { + public: ++ static GrDirectContext* getSharedGrDirectContext() { return fGlobalShared ? fGlobalShared->fContext.get() : nullptr; } ++ + sk_sp<SkSurface> getBackbufferSurface() override; + + bool isValid() override { return fValid; } +@@ -46,16 +51,34 @@ protected: + void destroyContext(); + virtual void onDestroyContext() = 0; + ++ static void checkDestroyShared(); ++ + bool fValid; ++ ++ // We need to use just one GrDirectContext, so share all the relevant data. ++ struct Shared : public SkRefCnt ++ { + sk_cfp<id<MTLDevice>> fDevice; + sk_cfp<id<MTLCommandQueue>> fQueue; +- CAMetalLayer* fMetalLayer; +- GrMTLHandle fDrawableHandle; + #if GR_METAL_SDK_VERSION >= 230 + // wrapping this in sk_cfp throws up an availability warning, so we'll track lifetime manually + id<MTLBinaryArchive> fPipelineArchive SK_API_AVAILABLE(macos(11.0), ios(14.0)); + #endif ++ ++ sk_sp<GrDirectContext> fContext; ++ }; ++ ++ sk_sp<Shared> fShared; ++ ++ static sk_sp<Shared> fGlobalShared; ++ ++ CAMetalLayer* fMetalLayer; ++ GrMTLHandle fDrawableHandle; + }; ++#endif // __OBJC__ ++ ++// Access function when header is used from C++ code that wouldn't handle ObjC++ headers. ++extern "C" SK_API GrDirectContext* getMetalSharedGrDirectContext(); + + } // namespace sk_app + +diff --git a/tools/sk_app/MetalWindowContext.mm b/tools/sk_app/MetalWindowContext.mm +index d972e321a6..9f576944b7 100644 +--- a/tools/sk_app/MetalWindowContext.mm ++++ b/tools/sk_app/MetalWindowContext.mm +@@ -37,24 +37,30 @@ NSURL* MetalWindowContext::CacheURL() { + } + + void MetalWindowContext::initializeContext() { ++ fShared = fGlobalShared; ++ if( !fShared ) ++ { ++ // TODO do we need a mutex? ++ ++ fGlobalShared = sk_make_sp<Shared>(); ++ Shared* d = fGlobalShared.get(); // shorter variable name ++ + SkASSERT(!fContext); + +- fDevice.reset(MTLCreateSystemDefaultDevice()); +- fQueue.reset([*fDevice newCommandQueue]); ++ d->fDevice.reset(MTLCreateSystemDefaultDevice()); ++ d->fQueue.reset([*d->fDevice newCommandQueue]); + + if (fDisplayParams.fMSAASampleCount > 1) { + if (@available(macOS 10.11, iOS 9.0, *)) { +- if (![*fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) { ++ if (![*d->fDevice supportsTextureSampleCount:fDisplayParams.fMSAASampleCount]) { ++ fGlobalShared.reset(); + return; + } + } else { ++ fGlobalShared.reset(); + return; + } + } +- fSampleCount = fDisplayParams.fMSAASampleCount; +- fStencilBits = 8; +- +- fValid = this->onInitializeContext(); + + #if GR_METAL_SDK_VERSION >= 230 + if (fDisplayParams.fEnableBinaryArchive) { +@@ -62,11 +68,11 @@ void MetalWindowContext::initializeContext() { + sk_cfp<MTLBinaryArchiveDescriptor*> desc([MTLBinaryArchiveDescriptor new]); + (*desc).url = CacheURL(); // try to load + NSError* error; +- fPipelineArchive = [*fDevice newBinaryArchiveWithDescriptor:*desc error:&error]; +- if (!fPipelineArchive) { ++ d->fPipelineArchive = [*d->fDevice newBinaryArchiveWithDescriptor:*desc error:&error]; ++ if (!d->fPipelineArchive) { + (*desc).url = nil; // create new +- fPipelineArchive = [*fDevice newBinaryArchiveWithDescriptor:*desc error:&error]; +- if (!fPipelineArchive) { ++ d->fPipelineArchive = [*d->fDevice newBinaryArchiveWithDescriptor:*desc error:&error]; ++ if (!d->fPipelineArchive) { + SkDebugf("Error creating MTLBinaryArchive:\n%s\n", + error.debugDescription.UTF8String); + } +@@ -74,46 +80,75 @@ void MetalWindowContext::initializeContext() { + } + } else { + if (@available(macOS 11.0, iOS 14.0, *)) { +- fPipelineArchive = nil; ++ d->fPipelineArchive = nil; + } + } + #endif + + GrMtlBackendContext backendContext = {}; +- backendContext.fDevice.retain((GrMTLHandle)fDevice.get()); +- backendContext.fQueue.retain((GrMTLHandle)fQueue.get()); ++ backendContext.fDevice.retain((GrMTLHandle)d->fDevice.get()); ++ backendContext.fQueue.retain((GrMTLHandle)d->fQueue.get()); + #if GR_METAL_SDK_VERSION >= 230 + if (@available(macOS 11.0, iOS 14.0, *)) { +- backendContext.fBinaryArchive.retain((__bridge GrMTLHandle)fPipelineArchive); ++ backendContext.fBinaryArchive.retain((__bridge GrMTLHandle)d->fPipelineArchive); + } + #endif +- fContext = GrDirectContext::MakeMetal(backendContext, fDisplayParams.fGrContextOptions); +- if (!fContext && fDisplayParams.fMSAASampleCount > 1) { ++ d->fContext = GrDirectContext::MakeMetal(backendContext, fDisplayParams.fGrContextOptions); ++ if (!d->fContext && fDisplayParams.fMSAASampleCount > 1) { + fDisplayParams.fMSAASampleCount /= 2; ++ fGlobalShared.reset(); + this->initializeContext(); + return; + } ++ ++ fShared = fGlobalShared; ++ } // if( !fShared ) ++ ++ fContext = fShared->fContext; ++ ++ fSampleCount = fDisplayParams.fMSAASampleCount; ++ fStencilBits = 8; ++ ++ fValid = this->onInitializeContext(); + } + + void MetalWindowContext::destroyContext() { +- if (fContext) { +- // in case we have outstanding refs to this (lua?) +- fContext->abandonContext(); +- fContext.reset(); +- } +- + this->onDestroyContext(); + + fMetalLayer = nil; + fValid = false; + ++ fContext.reset(); ++ fShared.reset(); ++ ++ checkDestroyShared(); ++} ++ ++void MetalWindowContext::checkDestroyShared() ++{ ++ if(!fGlobalShared || !fGlobalShared->unique()) // TODO mutex? ++ return; ++#ifndef SK_TRACE_VK_RESOURCES ++ if(!fGlobalShared->fContext->unique()) ++ return; ++#endif ++ SkASSERT(fGlobalShared->fContext->unique()); ++ ++ if (fGlobalShared->fContext) { ++ // in case we have outstanding refs to this (lua?) ++ fGlobalShared->fContext->abandonContext(); ++ fGlobalShared->fContext.reset(); ++ } ++ + #if GR_METAL_SDK_VERSION >= 230 + if (@available(macOS 11.0, iOS 14.0, *)) { +- [fPipelineArchive release]; ++ [fGlobalShared->fPipelineArchive release]; + } + #endif +- fQueue.reset(); +- fDevice.reset(); ++ fGlobalShared->fQueue.reset(); ++ fGlobalShared->fDevice.reset(); ++ ++ fGlobalShared.reset(); + } + + sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() { +@@ -154,7 +189,7 @@ sk_sp<SkSurface> MetalWindowContext::getBackbufferSurface() { + void MetalWindowContext::swapBuffers() { + id<CAMetalDrawable> currentDrawable = (id<CAMetalDrawable>)fDrawableHandle; + +- id<MTLCommandBuffer> commandBuffer([*fQueue commandBuffer]); ++ id<MTLCommandBuffer> commandBuffer([*fShared->fQueue commandBuffer]); + commandBuffer.label = @"Present"; + + [commandBuffer presentDrawable:currentDrawable]; +@@ -175,9 +210,9 @@ void MetalWindowContext::activate(bool isActive) { + if (!isActive) { + #if GR_METAL_SDK_VERSION >= 230 + if (@available(macOS 11.0, iOS 14.0, *)) { +- if (fPipelineArchive) { ++ if (fShared->fPipelineArchive) { + NSError* error; +- [fPipelineArchive serializeToURL:CacheURL() error:&error]; ++ [fShared->fPipelineArchive serializeToURL:CacheURL() error:&error]; + if (error) { + SkDebugf("Error storing MTLBinaryArchive:\n%s\n", + error.debugDescription.UTF8String); +@@ -188,4 +223,11 @@ void MetalWindowContext::activate(bool isActive) { + } + } + ++SK_API sk_sp<MetalWindowContext::Shared> MetalWindowContext::fGlobalShared; ++ ++GrDirectContext* getMetalSharedGrDirectContext() ++{ ++ return MetalWindowContext::getSharedGrDirectContext(); ++} ++ + } //namespace sk_app +diff --git a/tools/sk_app/VulkanWindowContext.cpp b/tools/sk_app/VulkanWindowContext.cpp +index c9db528ca4..634034da5a 100644 +--- a/tools/sk_app/VulkanWindowContext.cpp ++++ b/tools/sk_app/VulkanWindowContext.cpp +@@ -25,9 +25,13 @@ + #endif + + #define GET_PROC(F) f ## F = \ +- (PFN_vk ## F) backendContext.fGetProc("vk" #F, fInstance, VK_NULL_HANDLE) ++ (PFN_vk ## F) fGlobalShared->backendContext.fGetProc("vk" #F, fShared->fInstance, VK_NULL_HANDLE) + #define GET_DEV_PROC(F) f ## F = \ +- (PFN_vk ## F) backendContext.fGetProc("vk" #F, VK_NULL_HANDLE, fDevice) ++ (PFN_vk ## F) fGlobalShared->backendContext.fGetProc("vk" #F, VK_NULL_HANDLE, fShared->fDevice) ++#define GET_PROC_GLOBAL(F) fGlobalShared->f ## F = \ ++ (PFN_vk ## F) fGlobalShared->backendContext.fGetProc("vk" #F, fGlobalShared->fInstance, VK_NULL_HANDLE) ++#define GET_DEV_PROC_GLOBAL(F) fGlobalShared->f ## F = \ ++ (PFN_vk ## F) fGlobalShared->backendContext.fGetProc("vk" #F, VK_NULL_HANDLE, fGlobalShared->fDevice) + + namespace sk_app { + +@@ -49,31 +53,39 @@ VulkanWindowContext::VulkanWindowContext(const DisplayParams& params, + } + + void VulkanWindowContext::initializeContext() { ++ fShared = fGlobalShared; ++ if( !fShared ) ++ { ++ // TODO do we need a mutex? ++ ++ fGlobalShared = sk_make_sp<Shared>(); ++ Shared* d = fGlobalShared.get(); // shorter variable name ++ + SkASSERT(!fContext); + // any config code here (particularly for msaa)? + + PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr; +- GrVkBackendContext backendContext; ++ GrVkBackendContext& backendContext = fGlobalShared->backendContext; + GrVkExtensions extensions; +- VkPhysicalDeviceFeatures2 features; +- if (!sk_gpu_test::CreateVkBackendContext(getInstanceProc, &backendContext, &extensions, +- &features, &fDebugCallback, &fPresentQueueIndex, +- fCanPresentFn)) { +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); ++ if (!sk_gpu_test::CreateVkBackendContext(getInstanceProc, &backendContext, &extensions, &d->features, ++ &d->fDebugCallback, &d->fPresentQueueIndex, fCanPresentFn)) { ++ sk_gpu_test::FreeVulkanFeaturesStructs(&d->features); ++ fGlobalShared.reset(); + return; + } + + if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) || + !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) { +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); ++ sk_gpu_test::FreeVulkanFeaturesStructs(&d->features); ++ fGlobalShared.reset(); + return; + } + +- fInstance = backendContext.fInstance; +- fPhysicalDevice = backendContext.fPhysicalDevice; +- fDevice = backendContext.fDevice; +- fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex; +- fGraphicsQueue = backendContext.fQueue; ++ d->fInstance = backendContext.fInstance; ++ d->fPhysicalDevice = backendContext.fPhysicalDevice; ++ d->fDevice = backendContext.fDevice; ++ d->fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex; ++ d->fGraphicsQueue = backendContext.fQueue; + + PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties = + reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>( +@@ -81,21 +93,30 @@ void VulkanWindowContext::initializeContext() { + backendContext.fInstance, + VK_NULL_HANDLE)); + if (!localGetPhysicalDeviceProperties) { +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); ++ sk_gpu_test::FreeVulkanFeaturesStructs(&d->features); ++ fGlobalShared.reset(); + return; + } +- VkPhysicalDeviceProperties physDeviceProperties; +- localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties); +- uint32_t physDevVersion = physDeviceProperties.apiVersion; ++ localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &d->physDeviceProperties); ++ uint32_t physDevVersion = d->physDeviceProperties.apiVersion; + +- fInterface.reset(new GrVkInterface(backendContext.fGetProc, fInstance, fDevice, ++ d->fInterface.reset(new GrVkInterface(backendContext.fGetProc, d->fInstance, d->fDevice, + backendContext.fInstanceVersion, physDevVersion, + &extensions)); + +- GET_PROC(DestroyInstance); +- if (fDebugCallback != VK_NULL_HANDLE) { +- GET_PROC(DestroyDebugReportCallbackEXT); ++ d->fContext = GrDirectContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions); ++ ++ GET_PROC_GLOBAL(DestroyInstance); ++ GET_DEV_PROC_GLOBAL(DestroyDevice); ++ if (fGlobalShared->fDebugCallback != VK_NULL_HANDLE) { ++ GET_PROC_GLOBAL(DestroyDebugReportCallbackEXT); + } ++ ++ fShared = fGlobalShared; ++ } // if( !fShared ) ++ ++ fContext = fShared->fContext; ++ + GET_PROC(DestroySurfaceKHR); + GET_PROC(GetPhysicalDeviceSurfaceSupportKHR); + GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR); +@@ -103,7 +124,6 @@ void VulkanWindowContext::initializeContext() { + 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); +@@ -111,46 +131,44 @@ void VulkanWindowContext::initializeContext() { + GET_DEV_PROC(QueuePresentKHR); + GET_DEV_PROC(GetDeviceQueue); + +- fContext = GrDirectContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions); ++ // No actual window, used just to create the shared GrContext. ++ if(fCreateVkSurfaceFn == nullptr) ++ return; + +- fSurface = fCreateVkSurfaceFn(fInstance); ++ fSurface = fCreateVkSurfaceFn(fShared->fInstance); + if (VK_NULL_HANDLE == fSurface) { + this->destroyContext(); +- sk_gpu_test::FreeVulkanFeaturesStructs(&features); + return; + } + ++ // create presentQueue ++ fGetDeviceQueue(fShared->fDevice, fShared->fPresentQueueIndex, 0, &fPresentQueue); ++ + VkBool32 supported; +- VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex, ++ VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fShared->fPhysicalDevice, fShared->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); ++ VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fShared->fPhysicalDevice, fSurface, &caps); + if (VK_SUCCESS != res) { + return false; + } + + uint32_t surfaceFormatCount; +- res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount, ++ res = fGetPhysicalDeviceSurfaceFormatsKHR(fShared->fPhysicalDevice, fSurface, &surfaceFormatCount, + nullptr); + if (VK_SUCCESS != res) { + return false; +@@ -158,14 +176,14 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + + SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR)); + VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get(); +- res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount, ++ res = fGetPhysicalDeviceSurfaceFormatsKHR(fShared->fPhysicalDevice, fSurface, &surfaceFormatCount, + surfaceFormats); + if (VK_SUCCESS != res) { + return false; + } + + uint32_t presentModeCount; +- res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount, ++ res = fGetPhysicalDeviceSurfacePresentModesKHR(fShared->fPhysicalDevice, fSurface, &presentModeCount, + nullptr); + if (VK_SUCCESS != res) { + return false; +@@ -173,7 +191,7 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + + SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR)); + VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get(); +- res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount, ++ res = fGetPhysicalDeviceSurfacePresentModesKHR(fShared->fPhysicalDevice, fSurface, &presentModeCount, + presentModes); + if (VK_SUCCESS != res) { + return false; +@@ -286,8 +304,8 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + swapchainCreateInfo.imageArrayLayers = 1; + swapchainCreateInfo.imageUsage = usageFlags; + +- uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex }; +- if (fGraphicsQueueIndex != fPresentQueueIndex) { ++ uint32_t queueFamilies[] = { fShared->fGraphicsQueueIndex, fShared->fPresentQueueIndex }; ++ if (fShared->fGraphicsQueueIndex != fShared->fPresentQueueIndex) { + swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchainCreateInfo.queueFamilyIndexCount = 2; + swapchainCreateInfo.pQueueFamilyIndices = queueFamilies; +@@ -303,27 +321,27 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + swapchainCreateInfo.clipped = true; + swapchainCreateInfo.oldSwapchain = fSwapchain; + +- res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain); ++ res = fCreateSwapchainKHR(fShared->fDevice, &swapchainCreateInfo, nullptr, &fSwapchain); + if (VK_SUCCESS != res) { + return false; + } + + // destroy the old swapchain + if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) { +- fDeviceWaitIdle(fDevice); ++ fDeviceWaitIdle(fShared->fDevice); + + this->destroyBuffers(); + +- fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr); ++ fDestroySwapchainKHR(fShared->fDevice, swapchainCreateInfo.oldSwapchain, nullptr); + } + + if (!this->createBuffers(swapchainCreateInfo.imageFormat, usageFlags, colorType, + swapchainCreateInfo.imageSharingMode)) { +- fDeviceWaitIdle(fDevice); ++ fDeviceWaitIdle(fShared->fDevice); + + this->destroyBuffers(); + +- fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr); ++ fDestroySwapchainKHR(fShared->fDevice, swapchainCreateInfo.oldSwapchain, nullptr); + } + + return true; +@@ -332,10 +350,10 @@ bool VulkanWindowContext::createSwapchain(int width, int height, + bool VulkanWindowContext::createBuffers(VkFormat format, VkImageUsageFlags usageFlags, + SkColorType colorType, + VkSharingMode sharingMode) { +- fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr); ++ fGetSwapchainImagesKHR(fShared->fDevice, fSwapchain, &fImageCount, nullptr); + SkASSERT(fImageCount); + fImages = new VkImage[fImageCount]; +- fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages); ++ fGetSwapchainImagesKHR(fShared->fDevice, fSwapchain, &fImageCount, fImages); + + // set up initial image layouts and create surfaces + fImageLayouts = new VkImageLayout[fImageCount]; +@@ -351,7 +369,7 @@ bool VulkanWindowContext::createBuffers(VkFormat format, VkImageUsageFlags usage + info.fFormat = format; + info.fImageUsageFlags = usageFlags; + info.fLevelCount = 1; +- info.fCurrentQueueFamily = fPresentQueueIndex; ++ info.fCurrentQueueFamily = fShared->fPresentQueueIndex; + info.fSharingMode = sharingMode; + + if (usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) { +@@ -387,8 +405,8 @@ bool VulkanWindowContext::createBuffers(VkFormat format, VkImageUsageFlags usage + fBackbuffers = new BackbufferInfo[fImageCount + 1]; + for (uint32_t i = 0; i < fImageCount + 1; ++i) { + fBackbuffers[i].fImageIndex = -1; +- SkDEBUGCODE(VkResult result = )GR_VK_CALL(fInterface, +- CreateSemaphore(fDevice, &semaphoreInfo, nullptr, ++ SkDEBUGCODE(VkResult result = )GR_VK_CALL(fShared->fInterface, ++ CreateSemaphore(fShared->fDevice, &semaphoreInfo, nullptr, + &fBackbuffers[i].fRenderSemaphore)); + SkASSERT(result == VK_SUCCESS); + } +@@ -401,8 +419,8 @@ void VulkanWindowContext::destroyBuffers() { + if (fBackbuffers) { + for (uint32_t i = 0; i < fImageCount + 1; ++i) { + fBackbuffers[i].fImageIndex = -1; +- GR_VK_CALL(fInterface, +- DestroySemaphore(fDevice, ++ GR_VK_CALL(fShared->fInterface, ++ DestroySemaphore(fShared->fDevice, + fBackbuffers[i].fRenderSemaphore, + nullptr)); + } +@@ -427,42 +445,59 @@ VulkanWindowContext::~VulkanWindowContext() { + void VulkanWindowContext::destroyContext() { + if (this->isValid()) { + fQueueWaitIdle(fPresentQueue); +- fDeviceWaitIdle(fDevice); ++ fDeviceWaitIdle(fShared->fDevice); + + this->destroyBuffers(); + + if (VK_NULL_HANDLE != fSwapchain) { +- fDestroySwapchainKHR(fDevice, fSwapchain, nullptr); ++ fDestroySwapchainKHR(fShared->fDevice, fSwapchain, nullptr); + fSwapchain = VK_NULL_HANDLE; + } + + if (VK_NULL_HANDLE != fSurface) { +- fDestroySurfaceKHR(fInstance, fSurface, nullptr); ++ fDestroySurfaceKHR(fShared->fInstance, fSurface, nullptr); + fSurface = VK_NULL_HANDLE; + } + } + +- SkASSERT(fContext->unique()); + fContext.reset(); +- fInterface.reset(); ++ fShared.reset(); ++ ++ checkDestroyShared(); ++} ++ ++void VulkanWindowContext::checkDestroyShared() ++{ ++ if(!fGlobalShared || !fGlobalShared->unique()) // TODO mutex? ++ return; ++#ifndef SK_TRACE_VK_RESOURCES ++ if(!fGlobalShared->fContext->unique()) ++ return; ++#endif ++ SkASSERT(fGlobalShared->fContext->unique()); ++ fGlobalShared->fContext.reset(); ++ fGlobalShared->fInterface.reset(); + +- if (VK_NULL_HANDLE != fDevice) { +- fDestroyDevice(fDevice, nullptr); +- fDevice = VK_NULL_HANDLE; ++ if (VK_NULL_HANDLE != fGlobalShared->fDevice) { ++ fGlobalShared->fDestroyDevice(fGlobalShared->fDevice, nullptr); ++ fGlobalShared->fDevice = VK_NULL_HANDLE; + } + + #ifdef SK_ENABLE_VK_LAYERS +- if (fDebugCallback != VK_NULL_HANDLE) { +- fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr); ++ if (fGlobalShared->fDebugCallback != VK_NULL_HANDLE) { ++ fGlobalShared->fDestroyDebugReportCallbackEXT(fGlobalShared->fInstance, fDebugCallback, nullptr); + } + #endif + +- fPhysicalDevice = VK_NULL_HANDLE; ++ fGlobalShared->fPhysicalDevice = VK_NULL_HANDLE; + +- if (VK_NULL_HANDLE != fInstance) { +- fDestroyInstance(fInstance, nullptr); +- fInstance = VK_NULL_HANDLE; ++ if (VK_NULL_HANDLE != fGlobalShared->fInstance) { ++ fGlobalShared->fDestroyInstance(fGlobalShared->fInstance, nullptr); ++ fGlobalShared->fInstance = VK_NULL_HANDLE; + } ++ ++ sk_gpu_test::FreeVulkanFeaturesStructs(&fGlobalShared->features); ++ fGlobalShared.reset(); + } + + VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() { +@@ -488,35 +523,35 @@ sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() { + semaphoreInfo.pNext = nullptr; + semaphoreInfo.flags = 0; + VkSemaphore semaphore; +- SkDEBUGCODE(VkResult result = )GR_VK_CALL(fInterface, CreateSemaphore(fDevice, &semaphoreInfo, ++ SkDEBUGCODE(VkResult result = )GR_VK_CALL(fShared->fInterface, CreateSemaphore(fShared->fDevice, &semaphoreInfo, + nullptr, &semaphore)); + SkASSERT(result == VK_SUCCESS); + + // acquire the image +- VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX, ++ VkResult res = fAcquireNextImageKHR(fShared->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)); ++ GR_VK_CALL(fShared->fInterface, DestroySemaphore(fShared->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)); ++ GR_VK_CALL(fShared->fInterface, DestroySemaphore(fShared->fDevice, semaphore, nullptr)); + return nullptr; + } + backbuffer = this->getAvailableBackbuffer(); + + // acquire the image +- res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX, ++ res = fAcquireNextImageKHR(fShared->fDevice, fSwapchain, UINT64_MAX, + semaphore, VK_NULL_HANDLE, + &backbuffer->fImageIndex); + + if (VK_SUCCESS != res) { +- GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr)); ++ GR_VK_CALL(fShared->fInterface, DestroySemaphore(fShared->fDevice, semaphore, nullptr)); + return nullptr; + } + } +@@ -542,7 +577,7 @@ void VulkanWindowContext::swapBuffers() { + GrFlushInfo info; + info.fNumSemaphores = 1; + info.fSignalSemaphores = &beSemaphore; +- GrBackendSurfaceMutableState presentState(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, fPresentQueueIndex); ++ GrBackendSurfaceMutableState presentState(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, fShared->fPresentQueueIndex); + surface->flush(info, &presentState); + surface->recordingContext()->asDirectContext()->submit(); + +@@ -562,4 +597,6 @@ void VulkanWindowContext::swapBuffers() { + fQueuePresentKHR(fPresentQueue, &presentInfo); + } + ++SK_API sk_sp<VulkanWindowContext::Shared> VulkanWindowContext::fGlobalShared; ++ + } //namespace sk_app +diff --git a/tools/sk_app/VulkanWindowContext.h b/tools/sk_app/VulkanWindowContext.h +index 7e1fdd9af5..946bca7522 100644 +--- a/tools/sk_app/VulkanWindowContext.h ++++ b/tools/sk_app/VulkanWindowContext.h +@@ -19,18 +19,22 @@ + #include "tools/gpu/vk/VkTestUtils.h" + #include "tools/sk_app/WindowContext.h" + ++#include <cassert> ++ + class GrRenderTarget; + + namespace sk_app { + +-class VulkanWindowContext : public WindowContext { ++class SK_API VulkanWindowContext : public WindowContext { + public: + ~VulkanWindowContext() override; + ++ static GrDirectContext* getSharedGrDirectContext() { return fGlobalShared ? fGlobalShared->fContext.get() : nullptr; } ++ + sk_sp<SkSurface> getBackbufferSurface() override; + void swapBuffers() override; + +- bool isValid() override { return fDevice != VK_NULL_HANDLE; } ++ bool isValid() override { return fSurface != VK_NULL_HANDLE; } + + void resize(int w, int h) override { + this->createSwapchain(w, h, fDisplayParams); +@@ -50,9 +54,15 @@ public: + VulkanWindowContext(const DisplayParams&, CreateVkSurfaceFn, CanPresentFn, + PFN_vkGetInstanceProcAddr); + ++ static const VkPhysicalDeviceProperties& getPhysDeviceProperties() { ++ assert( fGlobalShared != nullptr ); ++ return fGlobalShared->physDeviceProperties; ++ } ++ + private: + void initializeContext(); + void destroyContext(); ++ static void checkDestroyShared(); + + struct BackbufferInfo { + uint32_t fImageIndex; // image this is associated with +@@ -64,11 +74,6 @@ private: + bool createBuffers(VkFormat format, VkImageUsageFlags, SkColorType colorType, VkSharingMode); + void destroyBuffers(); + +- VkInstance fInstance = VK_NULL_HANDLE; +- VkPhysicalDevice fPhysicalDevice = VK_NULL_HANDLE; +- VkDevice fDevice = VK_NULL_HANDLE; +- VkDebugReportCallbackEXT fDebugCallback = VK_NULL_HANDLE; +- + // Create functions + CreateVkSurfaceFn fCreateVkSurfaceFn; + CanPresentFn fCanPresentFn; +@@ -88,20 +93,46 @@ private: + PFN_vkAcquireNextImageKHR fAcquireNextImageKHR = nullptr; + PFN_vkQueuePresentKHR fQueuePresentKHR = nullptr; + +- PFN_vkDestroyInstance fDestroyInstance = nullptr; + PFN_vkDeviceWaitIdle fDeviceWaitIdle = nullptr; +- PFN_vkDestroyDebugReportCallbackEXT fDestroyDebugReportCallbackEXT = nullptr; + PFN_vkQueueWaitIdle fQueueWaitIdle = nullptr; +- PFN_vkDestroyDevice fDestroyDevice = nullptr; + PFN_vkGetDeviceQueue fGetDeviceQueue = nullptr; + ++ // We need to use just one GrDirectContext, so share all the relevant data. ++ struct Shared : public SkRefCnt ++ { ++ PFN_vkDestroyInstance fDestroyInstance = nullptr; ++ PFN_vkDestroyDevice fDestroyDevice = nullptr; ++ PFN_vkDestroyDebugReportCallbackEXT fDestroyDebugReportCallbackEXT = nullptr; ++ ++ VkInstance fInstance = VK_NULL_HANDLE; ++ VkPhysicalDevice fPhysicalDevice = VK_NULL_HANDLE; ++ VkDevice fDevice = VK_NULL_HANDLE; ++ VkDebugReportCallbackEXT fDebugCallback = VK_NULL_HANDLE; ++ + sk_sp<const GrVkInterface> fInterface; + +- VkSurfaceKHR fSurface; +- VkSwapchainKHR fSwapchain; ++ // Original code had this as a function-local variable, but that seems wrong. ++ // It should exist as long as the context exists. ++ VkPhysicalDeviceFeatures2 features; ++ ++ // Store this to make it accessible. ++ VkPhysicalDeviceProperties physDeviceProperties; ++ ++ GrVkBackendContext backendContext; ++ + uint32_t fGraphicsQueueIndex; + VkQueue fGraphicsQueue; + uint32_t fPresentQueueIndex; ++ ++ sk_sp<GrDirectContext> fContext; ++ }; ++ ++ sk_sp<Shared> fShared; ++ ++ static sk_sp<Shared> fGlobalShared; ++ ++ VkSurfaceKHR fSurface; ++ VkSwapchainKHR fSwapchain; + VkQueue fPresentQueue; + + uint32_t fImageCount; +diff --git a/tools/sk_app/WindowContext.h b/tools/sk_app/WindowContext.h +index 65ab8b9aa4..2d222385a3 100644 +--- a/tools/sk_app/WindowContext.h ++++ b/tools/sk_app/WindowContext.h +@@ -10,9 +10,9 @@ + #include "include/core/SkRefCnt.h" + #include "include/core/SkSurfaceProps.h" + #include "include/gpu/GrTypes.h" ++#include "include/gpu/GrDirectContext.h" + #include "tools/sk_app/DisplayParams.h" + +-class GrDirectContext; + class SkSurface; + #ifdef SK_GRAPHITE_ENABLED + namespace skgpu::graphite { +diff --git a/tools/sk_app/mac/MetalWindowContext_mac.mm b/tools/sk_app/mac/MetalWindowContext_mac.mm +index 5bea8578fa..f7df061af0 100644 +--- a/tools/sk_app/mac/MetalWindowContext_mac.mm ++++ b/tools/sk_app/mac/MetalWindowContext_mac.mm +@@ -49,10 +49,14 @@ MetalWindowContext_mac::~MetalWindowContext_mac() { + } + + bool MetalWindowContext_mac::onInitializeContext() { ++ // Allow creating just the shared context, without an associated window. ++ if(fMainView == nil) ++ return true; ++ + SkASSERT(nil != fMainView); + + fMetalLayer = [CAMetalLayer layer]; +- fMetalLayer.device = fDevice.get(); ++ fMetalLayer.device = fShared->fDevice.get(); + fMetalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm; + + // resize ignores the passed values and uses the fMainView directly. +diff --git a/tools/sk_app/unix/VulkanWindowContext_unix.cpp b/tools/sk_app/unix/VulkanWindowContext_unix.cpp +index 2b31fedc19..0c05fbfc92 100644 +--- a/tools/sk_app/unix/VulkanWindowContext_unix.cpp ++++ b/tools/sk_app/unix/VulkanWindowContext_unix.cpp +@@ -30,7 +30,7 @@ std::unique_ptr<WindowContext> MakeVulkanForXlib(const XlibWindowInfo& info, + return nullptr; + } + +- auto createVkSurface = [&info, instProc](VkInstance instance) -> VkSurfaceKHR { ++ VulkanWindowContext::CreateVkSurfaceFn createVkSurface = [&info, instProc](VkInstance instance) -> VkSurfaceKHR { + static PFN_vkCreateXcbSurfaceKHR createXcbSurfaceKHR = nullptr; + if (!createXcbSurfaceKHR) { + createXcbSurfaceKHR = +@@ -54,6 +54,9 @@ std::unique_ptr<WindowContext> MakeVulkanForXlib(const XlibWindowInfo& info, + + return surface; + }; ++ // Allow creating just the shared context, without an associated window. ++ if(info.fWindow == None) ++ createVkSurface = nullptr; + + auto canPresent = [&info, instProc](VkInstance instance, VkPhysicalDevice physDev, + uint32_t queueFamilyIndex) { +@@ -76,7 +79,7 @@ std::unique_ptr<WindowContext> MakeVulkanForXlib(const XlibWindowInfo& info, + }; + std::unique_ptr<WindowContext> ctx( + new VulkanWindowContext(displayParams, createVkSurface, canPresent, instProc)); +- if (!ctx->isValid()) { ++ if (!ctx->isValid() && createVkSurface != nullptr) { + return nullptr; + } + return ctx; +diff --git a/tools/sk_app/win/VulkanWindowContext_win.cpp b/tools/sk_app/win/VulkanWindowContext_win.cpp +index 976c42556e..c8f6b162bf 100644 +--- a/tools/sk_app/win/VulkanWindowContext_win.cpp ++++ b/tools/sk_app/win/VulkanWindowContext_win.cpp +@@ -29,7 +29,7 @@ std::unique_ptr<WindowContext> MakeVulkanForWin(HWND hwnd, const DisplayParams& + return nullptr; + } + +- auto createVkSurface = [hwnd, instProc] (VkInstance instance) -> VkSurfaceKHR { ++ VulkanWindowContext::CreateVkSurfaceFn createVkSurface = [hwnd, instProc] (VkInstance instance) -> VkSurfaceKHR { + static PFN_vkCreateWin32SurfaceKHR createWin32SurfaceKHR = nullptr; + if (!createWin32SurfaceKHR) { + createWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) +@@ -53,6 +53,9 @@ std::unique_ptr<WindowContext> MakeVulkanForWin(HWND hwnd, const DisplayParams& + + return surface; + }; ++ // Allow creating just the shared context, without an associated window. ++ if(hwnd == nullptr) ++ createVkSurface = nullptr; + + auto canPresent = [instProc] (VkInstance instance, VkPhysicalDevice physDev, + uint32_t queueFamilyIndex) { +@@ -70,7 +73,7 @@ std::unique_ptr<WindowContext> MakeVulkanForWin(HWND hwnd, const DisplayParams& + + std::unique_ptr<WindowContext> ctx( + new VulkanWindowContext(params, createVkSurface, canPresent, instProc)); +- if (!ctx->isValid()) { ++ if (!ctx->isValid() && createVkSurface != nullptr) { + return nullptr; + } + return ctx; |