summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--external/skia/README6
-rw-r--r--external/skia/UnpackedTarball_skia.mk8
-rw-r--r--external/skia/share-grcontext.patch.1499
-rw-r--r--vcl/Library_vcl.mk3
-rw-r--r--vcl/inc/skia/gdiimpl.hxx4
-rw-r--r--vcl/inc/skia/vulkan.hxx29
-rw-r--r--vcl/skia/README16
-rw-r--r--vcl/skia/gdiimpl.cxx59
-rw-r--r--vcl/skia/vulkan.cxx39
-rw-r--r--vcl/skia/win/gdiimpl.cxx22
-rw-r--r--vcl/skia/x11/gdiimpl.cxx32
11 files changed, 601 insertions, 116 deletions
diff --git a/external/skia/README b/external/skia/README
index 767f12e91936..95be1561d4fb 100644
--- a/external/skia/README
+++ b/external/skia/README
@@ -17,3 +17,9 @@ tar cvJf skia-mXX-$id.tar.xz skia
(where XX refers to the branch version)
And review differences for BUILD.gn and relevant files in gn/ .
+
+
+GrContext sharing
+=================
+
+For details about the share-grcontext patch, see vcl/skia/README.
diff --git a/external/skia/UnpackedTarball_skia.mk b/external/skia/UnpackedTarball_skia.mk
index e9905f5abfa7..c3988042a012 100644
--- a/external/skia/UnpackedTarball_skia.mk
+++ b/external/skia/UnpackedTarball_skia.mk
@@ -12,7 +12,13 @@ $(eval $(call gb_UnpackedTarball_UnpackedTarball,skia))
$(eval $(call gb_UnpackedTarball_set_tarball,skia,$(SKIA_TARBALL)))
# TODO
-skia_patches := lerp.patch fix-pch.patch fix-ddi.patch make-api-visible.patch.1 fix-shader-locale.patch.1
+skia_patches := \
+ lerp.patch \
+ fix-pch.patch \
+ fix-ddi.patch \
+ make-api-visible.patch.1 \
+ fix-shader-locale.patch.1 \
+ share-grcontext.patch.1
$(eval $(call gb_UnpackedTarball_set_patchlevel,skia,1))
diff --git a/external/skia/share-grcontext.patch.1 b/external/skia/share-grcontext.patch.1
new file mode 100644
index 000000000000..0492bd948240
--- /dev/null
+++ b/external/skia/share-grcontext.patch.1
@@ -0,0 +1,499 @@
+diff --git a/tools/sk_app/VulkanWindowContext.cpp b/tools/sk_app/VulkanWindowContext.cpp
+index 793c88c158..21164cac67 100644
+--- a/tools/sk_app/VulkanWindowContext.cpp
++++ b/tools/sk_app/VulkanWindowContext.cpp
+@@ -1,4 +1,3 @@
+-
+ /*
+ * Copyright 2015 Google Inc.
+ *
+@@ -24,8 +23,10 @@
+ #undef CreateSemaphore
+ #endif
+
+-#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fInstance, "vk" #F)
+-#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fDevice, "vk" #F)
++#define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fShared->fInstance, "vk" #F)
++#define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fShared->fDevice, "vk" #F)
++#define GET_PROC_GLOBAL(F) fGlobalShared->f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fGlobalShared->fInstance, "vk" #F)
++#define GET_DEV_PROC_GLOBAL(F) fGlobalShared->f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fGlobalShared->fDevice, "vk" #F)
+
+ namespace sk_app {
+
+@@ -49,6 +50,14 @@ 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
++
+ // any config code here (particularly for msaa)?
+
+ PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr;
+@@ -62,24 +71,25 @@ void VulkanWindowContext::initializeContext() {
+ };
+ GrVkBackendContext backendContext;
+ GrVkExtensions extensions;
+- VkPhysicalDeviceFeatures2 features;
+- if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, &extensions, &features,
+- &fDebugCallback, &fPresentQueueIndex, fCanPresentFn)) {
+- sk_gpu_test::FreeVulkanFeaturesStructs(&features);
++ if (!sk_gpu_test::CreateVkBackendContext(getProc, &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>(
+@@ -87,21 +97,31 @@ 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;
+
+- 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 = GrContext::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);
+@@ -109,7 +129,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);
+@@ -117,46 +136,40 @@ void VulkanWindowContext::initializeContext() {
+ GET_DEV_PROC(QueuePresentKHR);
+ GET_DEV_PROC(GetDeviceQueue);
+
+- fContext = GrContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions);
+-
+- fSurface = fCreateVkSurfaceFn(fInstance);
++ fSurface = fCreateVkSurfaceFn(fShared->fInstance);
+ if (VK_NULL_HANDLE == fSurface) {
+ this->destroyContext();
+- sk_gpu_test::FreeVulkanFeaturesStructs(&features);
+ return;
+ }
+
+ 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);
++ fGetDeviceQueue(fShared->fDevice, fShared->fPresentQueueIndex, 0, &fPresentQueue);
+ }
+
+ 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;
+@@ -164,14 +177,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;
+@@ -179,7 +192,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 +299,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,18 +316,18 @@ 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);
+ }
+
+ this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
+@@ -323,10 +336,10 @@ bool VulkanWindowContext::createSwapchain(int width, int height,
+ }
+
+ void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
+- 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];
+@@ -341,7 +354,7 @@ void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType)
+ info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
+ info.fFormat = format;
+ info.fLevelCount = 1;
+- info.fCurrentQueueFamily = fPresentQueueIndex;
++ info.fCurrentQueueFamily = fShared->fPresentQueueIndex;
+
+ if (fSampleCount == 1) {
+ GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
+@@ -372,8 +385,8 @@ void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType)
+ fBackbuffers = new BackbufferInfo[fImageCount + 1];
+ for (uint32_t i = 0; i < fImageCount + 1; ++i) {
+ fBackbuffers[i].fImageIndex = -1;
+- GR_VK_CALL_ERRCHECK(fInterface,
+- CreateSemaphore(fDevice, &semaphoreInfo,
++ GR_VK_CALL_ERRCHECK(fShared->fInterface,
++ CreateSemaphore(fShared->fDevice, &semaphoreInfo,
+ nullptr, &fBackbuffers[i].fRenderSemaphore));
+ }
+ fCurrentBackbufferIndex = fImageCount;
+@@ -384,8 +397,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));
+ }
+@@ -410,41 +423,55 @@ 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;
+ }
+ }
+
+ fContext.reset();
+- fInterface.reset();
++ fShared.reset();
++
++ checkDestroyShared();
++}
+
+- if (VK_NULL_HANDLE != fDevice) {
+- fDestroyDevice(fDevice, nullptr);
+- fDevice = VK_NULL_HANDLE;
++void VulkanWindowContext::checkDestroyShared()
++{
++ if(!fGlobalShared || !fGlobalShared->unique()) // TODO mutex?
++ return;
++ SkASSERT(fGlobalShared->fContext->unique());
++ fGlobalShared->fContext.reset();
++ fGlobalShared->fInterface.reset();
++
++ 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() {
+@@ -470,34 +497,34 @@ sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
+ semaphoreInfo.pNext = nullptr;
+ semaphoreInfo.flags = 0;
+ VkSemaphore semaphore;
+- GR_VK_CALL_ERRCHECK(fInterface, CreateSemaphore(fDevice, &semaphoreInfo,
++ GR_VK_CALL_ERRCHECK(fShared->fInterface, CreateSemaphore(fShared->fDevice, &semaphoreInfo,
+ nullptr, &semaphore));
+
+ // 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;
+ }
+ }
+@@ -541,4 +568,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 2db9e79ae6..7950dc159b 100644
+--- a/tools/sk_app/VulkanWindowContext.h
++++ b/tools/sk_app/VulkanWindowContext.h
+@@ -1,4 +1,3 @@
+-
+ /*
+ * Copyright 2016 Google Inc.
+ *
+@@ -23,14 +22,30 @@ class GrRenderTarget;
+
+ namespace sk_app {
+
+-class VulkanWindowContext : public WindowContext {
++class SK_API VulkanWindowContext : public WindowContext {
++ struct Shared;
+ public:
+ ~VulkanWindowContext() override;
+
++ class SharedGrContext {
++ public:
++ SharedGrContext() {}
++ GrContext* getGrContext() { return shared ? shared->fContext.get() : nullptr; }
++ ~SharedGrContext() { shared.reset(); checkDestroyShared(); }
++ bool operator!() const { return !shared; }
++ void reset() { shared.reset(); }
++ private:
++ friend class VulkanWindowContext;
++ SharedGrContext(sk_sp<Shared>& sh ) : shared( sh ) {}
++ sk_sp<Shared> shared;
++ };
++
++ static SharedGrContext getSharedGrContext() { return SharedGrContext( fGlobalShared ); }
++
+ sk_sp<SkSurface> getBackbufferSurface() override;
+ void swapBuffers() override;
+
+- bool isValid() override { return fDevice != VK_NULL_HANDLE; }
++ bool isValid() override { return fShared->fDevice != VK_NULL_HANDLE; }
+
+ void resize(int w, int h) override {
+ this->createSwapchain(w, h, fDisplayParams);
+@@ -53,6 +68,7 @@ public:
+ private:
+ void initializeContext();
+ void destroyContext();
++ static void checkDestroyShared();
+
+ struct BackbufferInfo {
+ uint32_t fImageIndex; // image this is associated with
+@@ -64,11 +80,6 @@ private:
+ void createBuffers(VkFormat format, SkColorType colorType);
+ 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;
+@@ -90,20 +101,41 @@ 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 GrContext, 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;
++
+ uint32_t fGraphicsQueueIndex;
+ VkQueue fGraphicsQueue;
+ uint32_t fPresentQueueIndex;
++
++ sk_sp<GrContext> fContext;
++ };
++
++ sk_sp<Shared> fShared;
++
++ static sk_sp<Shared> fGlobalShared;
++
++ VkSurfaceKHR fSurface;
++ VkSwapchainKHR fSwapchain;
+ VkQueue fPresentQueue;
+
+ uint32_t fImageCount;
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 1f05f7aa9dd2..c054a2767a3c 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -586,8 +586,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/skia/SkiaHelper \
$(if $(filter SKIA,$(BUILD_TYPE)), \
vcl/skia/salbmp \
- vcl/skia/gdiimpl \
- vcl/skia/vulkan) \
+ vcl/skia/gdiimpl) \
))
# runtime dependency
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
index 04f96cb7bd11..195b5d877eed 100644
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -26,6 +26,7 @@
#include <salgeom.hxx>
#include <SkSurface.h>
+#include <tools/sk_app/VulkanWindowContext.h>
class SkiaFlushIdle;
@@ -210,6 +211,7 @@ protected:
void destroySurface();
// Reimplemented for X11.
virtual bool avoidRecreateByResize() const { return false; }
+ void createOffscreenSurface();
void privateDrawAlphaRect(long nX, long nY, long nWidth, long nHeight, double nTransparency,
bool blockAA = false);
@@ -265,6 +267,8 @@ protected:
// The Skia surface that is target of all the rendering.
sk_sp<SkSurface> mSurface;
bool mIsGPU; // whether the surface is GPU-backed
+ // Keep reference to shared GrContext.
+ sk_app::VulkanWindowContext::SharedGrContext mOffscreenGrContext;
vcl::Region mClipRegion;
Color mLineColor;
Color mFillColor;
diff --git a/vcl/inc/skia/vulkan.hxx b/vcl/inc/skia/vulkan.hxx
deleted file mode 100644
index 6c8e3c7bfa44..000000000000
--- a/vcl/inc/skia/vulkan.hxx
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-#ifndef INCLUDED_VCL_INC_SKIA_VULKAN_HXX
-#define INCLUDED_VCL_INC_SKIA_VULKAN_HXX
-
-#include <GrContext.h>
-
-#include <vcl/dllapi.h>
-
-// Create and handle GrContext for Vulkan drawing to offscreen surfaces.
-// Skia already provides WindowContext class that does this for surfaces
-// used for drawing to windows, but it does not seem to provide a simple
-// way to get GrContext without a window.
-class VCL_PLUGIN_PUBLIC SkiaVulkanGrContext
-{
-public:
- static GrContext* getGrContext();
-};
-
-#endif // INCLUDED_VCL_INC_SKIA_VULKAN_HXX
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/skia/README b/vcl/skia/README
index 793c16e8dd39..f1248d90c3ea 100644
--- a/vcl/skia/README
+++ b/vcl/skia/README
@@ -17,3 +17,19 @@ Skia supports several methods to draw:
- Vulkan - Vulkan-based GPU drawing, this is the default
There are more (OpenGL, Metal on Mac, etc.), but (as of now) they are not supported by VCL.
+
+GrContext sharing:
+==================
+
+We use Skia's sk_app::WindowContext class for creating surfaces for windows, that class
+takes care of the internals. But of offscreen drawing, we need an instance of class
+GrContext. There is sk_app::WindowContext::getGrContext(), but each instance creates
+its own GrContext, and apparently it does not work to mix them. Which means that
+for offscreen drawing we would need to know which window (and only that window)
+the contents will be eventually painted to, which is not possible (it may not even
+be known at the time).
+
+To solve this problem we patch sk_app::WindowContext to create just one GrContext object
+and share it between instances. Additionally, using sk_app::WindowContext::SharedGrContext
+it is possible to share it also for offscreen drawing, including keeping proper reference
+count.
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index 776e44216c45..ac47d254cc03 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -23,12 +23,14 @@
#include <skia/salbmp.hxx>
#include <vcl/idle.hxx>
#include <vcl/svapp.hxx>
+#include <vcl/lazydelete.hxx>
#include <SkCanvas.h>
#include <SkPath.h>
#include <SkRegion.h>
#include <SkDashPathEffect.h>
#include <GrBackendSurface.h>
+#include <GrContextFactory.h>
#include <basegfx/polygon/b2dpolygontools.hxx>
@@ -190,7 +192,11 @@ SkiaSalGraphicsImpl::SkiaSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvid
{
}
-SkiaSalGraphicsImpl::~SkiaSalGraphicsImpl() {}
+SkiaSalGraphicsImpl::~SkiaSalGraphicsImpl()
+{
+ assert(!mSurface);
+ assert(!mOffscreenGrContext);
+}
void SkiaSalGraphicsImpl::Init() {}
@@ -208,8 +214,7 @@ void SkiaSalGraphicsImpl::recreateSurface()
void SkiaSalGraphicsImpl::createSurface()
{
- // Create surface for offscreen graphics. Subclasses will create GPU-backed
- // surfaces as appropriate.
+ // Create raster surface. Subclasses will create GPU-backed surfaces as appropriate.
mSurface = SkSurface::MakeRasterN32Premul(GetWidth(), GetHeight());
mIsGPU = false;
#ifdef DBG_UTIL
@@ -217,6 +222,53 @@ void SkiaSalGraphicsImpl::createSurface()
#endif
}
+void SkiaSalGraphicsImpl::createOffscreenSurface()
+{
+ assert(isOffscreen());
+ destroySurface();
+ switch (renderMethodToUse())
+ {
+ case RenderVulkan:
+ {
+ mOffscreenGrContext = sk_app::VulkanWindowContext::getSharedGrContext();
+ GrContext* grContext = mOffscreenGrContext.getGrContext();
+ // We may not get a GrContext if called before any onscreen window is created,
+ // but that happens very early, so this should be rare and insignificant.
+ // Unittests are an exception, they usually do not create any windows,
+ // so in that case do create GrContext that has no window associated.
+ if (!grContext)
+ {
+ static bool isUnitTest = (getenv("LO_TESTNAME") != nullptr);
+ if (isUnitTest)
+ {
+ static vcl::DeleteOnDeinit<sk_gpu_test::GrContextFactory> factory(
+ new sk_gpu_test::GrContextFactory);
+ // The factory owns the context.
+ grContext
+ = factory.get()->get(sk_gpu_test::GrContextFactory::kVulkan_ContextType);
+ }
+ }
+ if (grContext)
+ {
+ mSurface = SkSurface::MakeRenderTarget(
+ grContext, SkBudgeted::kNo,
+ SkImageInfo::MakeN32Premul(GetWidth(), GetHeight()));
+ mIsGPU = true;
+ assert(mSurface.get());
+#ifdef DBG_UTIL
+ prefillSurface();
+#endif
+ return;
+ }
+ SAL_WARN("vcl.skia", "cannot create Vulkan GPU offscreen surface");
+ break;
+ }
+ default:
+ break;
+ }
+ return SkiaSalGraphicsImpl::createSurface(); // create a raster one
+}
+
void SkiaSalGraphicsImpl::destroySurface()
{
if (mSurface)
@@ -237,6 +289,7 @@ void SkiaSalGraphicsImpl::destroySurface()
mSurface->flush();
mSurface.reset();
mIsGPU = false;
+ mOffscreenGrContext.reset();
}
void SkiaSalGraphicsImpl::DeInit() { destroySurface(); }
diff --git a/vcl/skia/vulkan.cxx b/vcl/skia/vulkan.cxx
deleted file mode 100644
index c5c9093739fc..000000000000
--- a/vcl/skia/vulkan.cxx
+++ /dev/null
@@ -1,39 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * Some of this code is based on Skia source code, covered by the following
- * license notice (see readlicense_oo for the full license):
- *
- * Copyright 2016 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- */
-
-#include <skia/vulkan.hxx>
-
-#include <GrContextFactory.h>
-
-#include <vcl/lazydelete.hxx>
-
-static GrContext* createGrContext()
-{
- static vcl::DeleteOnDeinit<sk_gpu_test::GrContextFactory> factory(
- new sk_gpu_test::GrContextFactory);
- // The factory owns the context.
- return factory.get()->get(sk_gpu_test::GrContextFactory::kVulkan_ContextType);
-}
-
-GrContext* SkiaVulkanGrContext::getGrContext()
-{
- static GrContext* context = createGrContext();
- return context;
-}
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx
index e9db555c25c0..8f30c3486dac 100644
--- a/vcl/skia/win/gdiimpl.cxx
+++ b/vcl/skia/win/gdiimpl.cxx
@@ -12,7 +12,6 @@
#include <tools/sk_app/win/WindowContextFactory_win.h>
#include <tools/sk_app/WindowContext.h>
#include <win/saldata.hxx>
-#include <skia/vulkan.hxx>
#include <SkColorFilter.h>
#include <SkPixelRef.h>
@@ -45,26 +44,9 @@ void WinSkiaSalGraphicsImpl::Init()
void WinSkiaSalGraphicsImpl::createSurface()
{
- destroySurface();
if (isOffscreen())
- {
- switch (renderMethodToUse())
- {
- case RenderVulkan:
- mSurface = SkSurface::MakeRenderTarget(
- SkiaVulkanGrContext::getGrContext(), SkBudgeted::kNo,
- SkImageInfo::MakeN32Premul(GetWidth(), GetHeight()));
- mIsGPU = true;
- assert(mSurface.get());
-#ifdef DBG_UTIL
- prefillSurface();
-#endif
- return;
- default:
- break;
- }
- return SkiaSalGraphicsImpl::createSurface();
- }
+ return createOffscreenSurface();
+ destroySurface();
// When created, Init() gets called with size (0,0), which is invalid size
// for Skia. Creating the actual surface is delayed, so the size should be always
// valid here, but better check.
diff --git a/vcl/skia/x11/gdiimpl.cxx b/vcl/skia/x11/gdiimpl.cxx
index e349074e70e1..ef381c5e56d3 100644
--- a/vcl/skia/x11/gdiimpl.cxx
+++ b/vcl/skia/x11/gdiimpl.cxx
@@ -21,8 +21,6 @@
#include <tools/sk_app/unix/WindowContextFactory_unix.h>
#include <tools/sk_app/WindowContext.h>
-#include <skia/vulkan.hxx>
-
X11SkiaSalGraphicsImpl::X11SkiaSalGraphicsImpl(X11SalGraphics& rParent)
: SkiaSalGraphicsImpl(rParent, rParent.GetGeometryProvider())
, mX11Parent(rParent)
@@ -40,29 +38,12 @@ void X11SkiaSalGraphicsImpl::Init()
void X11SkiaSalGraphicsImpl::createSurface()
{
- destroySurface();
if (isOffscreen())
- {
- switch (renderMethodToUse())
- {
- case RenderVulkan:
- mSurface = SkSurface::MakeRenderTarget(
- SkiaVulkanGrContext::getGrContext(), SkBudgeted::kNo,
- SkImageInfo::MakeN32Premul(GetWidth(), GetHeight()));
- mIsGPU = true;
- assert(mSurface.get());
-#ifdef DBG_UTIL
- prefillSurface();
-#endif
- return;
- default:
- break;
- }
- return SkiaSalGraphicsImpl::createSurface();
- }
+ return createOffscreenSurface();
+ destroySurface();
sk_app::DisplayParams displayParams;
- // TODO The Skia Xlib code actually requires the non-native color type to work properly.
// Use a macro to hide an unreachable code warning.
+ // TODO The Skia Xlib code actually requires the non-native color type to work properly.
#define GET_FORMAT \
kN32_SkColorType == kBGRA_8888_SkColorType ? kRGBA_8888_SkColorType : kBGRA_8888_SkColorType
displayParams.fColorType = GET_FORMAT;
@@ -73,6 +54,13 @@ void X11SkiaSalGraphicsImpl::createSurface()
assert(winInfo.fDisplay && winInfo.fWindow != None);
winInfo.fFBConfig = nullptr; // not used
winInfo.fVisualInfo = const_cast<SalVisual*>(&mX11Parent.GetVisual());
+#ifdef DBG_UTIL
+ // Our patched Skia has VulkanWindowContext that shares GrContext, which requires
+ // that the X11 visual is always the same. Ensure it is so.
+ static VisualID checkVisualID = -1U;
+ assert(checkVisualID == -1U || winInfo.fVisualInfo->visualid == checkVisualID);
+ checkVisualID = winInfo.fVisualInfo->visualid;
+#endif
winInfo.fWidth = GetWidth();
winInfo.fHeight = GetHeight();
switch (renderMethodToUse())