9c9a711ac5
(*) Remove patches already upstream (*) Remove the skia_sk_cpu_sse_level_0_by_default.patch.1 patch and rather set that define via -D parameter, because that is how the skia BUILD.gn seems to do it. (*) I hand edited the PCH file, because running the update_pch script failed for me. Change-Id: I1fd175b9f63f8d2792a1876e4ece03fe92fb5374 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146251 Tested-by: Jenkins Tested-by: Noel Grandin <noel.grandin@collabora.co.uk> Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
874 lines
35 KiB
Groff
874 lines
35 KiB
Groff
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;
|
|
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<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 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<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;
|
|
- skgpu::MutableTextureState presentState(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, fPresentQueueIndex);
|
|
+ skgpu::MutableTextureState 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,20 +19,24 @@
|
|
#include "tools/gpu/vk/VkTestUtils.h"
|
|
#include "tools/sk_app/WindowContext.h"
|
|
|
|
+#include <cassert>
|
|
+
|
|
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<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 skgpu::VulkanInterface> 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;
|