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 #import +#endif namespace sk_app { +#ifdef __OBJC__ class MetalWindowContext : public WindowContext { public: + static GrDirectContext* getSharedGrDirectContext() { return fGlobalShared ? fGlobalShared->fContext.get() : nullptr; } + sk_sp getBackbufferSurface() override; bool isValid() override { return fValid; } @@ -44,18 +49,36 @@ void destroyContext(); virtual void onDestroyContext() = 0; + static void checkDestroyShared(); + void onSwapBuffers() override; bool fValid; + + // We need to use just one GrDirectContext, so share all the relevant data. + struct Shared : public SkRefCnt + { sk_cfp> fDevice; sk_cfp> fQueue; - CAMetalLayer* fMetalLayer; - GrMTLHandle fDrawableHandle; #if SKGPU_GRAPHITE_METAL_SDK_VERSION >= 230 // wrapping this in sk_cfp throws up an availability warning, so we'll track lifetime manually id fPipelineArchive SK_API_AVAILABLE(macos(11.0), ios(14.0)); #endif + + sk_sp fContext; + }; + + sk_sp fShared; + + static sk_sp 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 @@ -40,24 +40,30 @@ NSURL* MetalWindowContext::CacheURL() { } void MetalWindowContext::initializeContext() { + fShared = fGlobalShared; + if( !fShared ) + { + // TODO do we need a mutex? + + fGlobalShared = sk_make_sp(); + 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 SKGPU_GRAPHITE_METAL_SDK_VERSION >= 230 if (fDisplayParams.fEnableBinaryArchive) { @@ -62,11 +68,11 @@ void MetalWindowContext::initializeContext() { sk_cfp 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); } @@ -77,46 +83,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 SKGPU_GRAPHITE_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 SKGPU_GRAPHITE_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 MetalWindowContext::getBackbufferSurface() { @@ -159,7 +194,7 @@ sk_sp MetalWindowContext::getBackbufferSurface() { void MetalWindowContext::onSwapBuffers() { id currentDrawable = (id)fDrawableHandle; - id commandBuffer([*fQueue commandBuffer]); + id commandBuffer([*fShared->fQueue commandBuffer]); commandBuffer.label = @"Present"; [commandBuffer presentDrawable:currentDrawable]; @@ -180,9 +215,9 @@ void MetalWindowContext::activate(bool isActive) { if (!isActive) { #if SKGPU_GRAPHITE_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::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* 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; skgpu::VulkanExtensions 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( @@ -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 skgpu::VulkanInterface(backendContext.fGetProc, fInstance, fDevice, + d->fInterface.reset(new skgpu::VulkanInterface(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 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; } } @@ -547,7 +582,7 @@ void VulkanWindowContext::swapBuffers() { GrFlushInfo info; info.fNumSemaphores = 1; info.fSignalSemaphores = &beSemaphore; - skgpu::MutableTextureState presentState(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, fPresentQueueIndex); + skgpu::MutableTextureState presentState(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, fShared->fPresentQueueIndex); auto dContext = surface->recordingContext()->asDirectContext(); dContext->flush(surface, info, &presentState); dContext->submit(); @@ -562,4 +597,6 @@ void VulkanWindowContext::swapBuffers() { fQueuePresentKHR(fPresentQueue, &presentInfo); } +SK_API sk_sp 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 @@ -16,19 +16,23 @@ #include "tools/gpu/vk/VkTestUtils.h" #include "tools/sk_app/WindowContext.h" +#include + class GrRenderTarget; namespace skgpu { struct VulkanInterface; } 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 getBackbufferSurface() 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: void destroyBuffers(); void onSwapBuffers() override; - 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 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 fContext; + }; + + sk_sp fShared; + + static sk_sp 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; #if defined(SK_GRAPHITE) 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 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 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 MakeVulkanForXlib(const XlibWindowInfo& info, }; std::unique_ptr 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 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 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 MakeVulkanForWin(HWND hwnd, const DisplayParams& std::unique_ptr ctx( new VulkanWindowContext(params, createVkSurface, canPresent, instProc)); - if (!ctx->isValid()) { + if (!ctx->isValid() && createVkSurface != nullptr) { return nullptr; } return ctx;