[Libreoffice-commits] core.git: Branch 'feature/skia' - 7 commits - external/skia include/vcl vcl/inc vcl/qa vcl/skia vcl/source

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Tue Nov 19 11:19:23 UTC 2019


Rebased ref, commits from common ancestor:
commit 9a392b3452fff42ba13a1c1713addebde267f46f
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Mon Nov 18 16:40:25 2019 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Nov 19 12:18:27 2019 +0100

    solve the Skia lerp() conflict differently
    
    New versions of libstdc++ provide lerp() in the global namespace,
    older ones don't, but it depends on the libstdc++ version and not
    the c++ version. Since the function is local, just "rename" it.
    
    Change-Id: I37896190c620350739fba9b8ce6544f945519244

diff --git a/external/skia/lerp.patch b/external/skia/lerp.patch
index c87a965e7caf..2062c21f2df0 100644
--- a/external/skia/lerp.patch
+++ b/external/skia/lerp.patch
@@ -1,14 +1,12 @@
---- skia/src/shaders/SkPerlinNoiseShader.cpp.sav	2019-07-29 14:37:30.429563360 +0200
-+++ skia/src/shaders/SkPerlinNoiseShader.cpp	2019-07-29 16:45:29.736231751 +0200
-@@ -573,9 +573,11 @@ static SkScalar fade(SkScalar t) {
+diff --git a/src/shaders/SkPerlinNoiseShader.cpp b/src/shaders/SkPerlinNoiseShader.cpp
+index 812dc1694f..60b8d617c6 100644
+--- a/src/shaders/SkPerlinNoiseShader.cpp
++++ b/src/shaders/SkPerlinNoiseShader.cpp
+@@ -573,6 +573,7 @@ static SkScalar fade(SkScalar t) {
      return t * t * t * (t * (t * 6 - 15) + 10);
  }
  
-+#if __cplusplus <= 201703L
++#define lerp skia_lerp
  static SkScalar lerp(SkScalar t, SkScalar a, SkScalar b) {
      return a + t * (b - a);
  }
-+#endif
- 
- static SkScalar grad(int hash, SkScalar x, SkScalar y, SkScalar z) {
-     int h = hash & 15;
commit ea73f62947f4b5d06b07e16cce0fe6b2038febbc
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Mon Nov 18 13:52:09 2019 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Nov 19 12:18:26 2019 +0100

    avoid unused parameter warning in non-debug build
    
    Change-Id: I3ea06a872d5348f7681602a6d68ff69990f2cd7e

diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx
index 1090c33b73e0..0f253a797097 100644
--- a/vcl/qa/cppunit/BackendTest.cxx
+++ b/vcl/qa/cppunit/BackendTest.cxx
@@ -59,6 +59,7 @@ public:
     {
         // This ensures that all backends return a valid name.
         assert(!name.isEmpty());
+        (void)name;
         return false;
     }
 
commit 452713d0b06ced29111b7b82ce5b747fc3e22dc5
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Mon Nov 18 12:24:59 2019 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Nov 19 12:18:25 2019 +0100

    make about dialog differentiate between Skia with Vulkan or raster
    
    Since they are technically still two different rendering implementations.
    
    Change-Id: I83c324b384b7acfcc84e729271d00b995327eec6

diff --git a/vcl/inc/strings.hrc b/vcl/inc/strings.hrc
index 65e829648f23..6c86cec3e747 100644
--- a/vcl/inc/strings.hrc
+++ b/vcl/inc/strings.hrc
@@ -126,7 +126,8 @@
 #define SV_APP_OSVERSION                             NC_("SV_APP_OSVERSION", "OS: ")
 #define SV_APP_UIRENDER                              NC_("SV_APP_UIRENDER", "UI render: ")
 #define SV_APP_GL                                    NC_("SV_APP_GL", "GL")
-#define SV_APP_SKIA                                  NC_("SV_APP_SKIA", "Skia")
+#define SV_APP_SKIA_VULKAN                           NC_("SV_APP_SKIA_VULKAN", "Skia/Vulkan")
+#define SV_APP_SKIA_RASTER                           NC_("SV_APP_SKIA_RASTER", "Skia/Raster")
 #define SV_APP_DEFAULT                               NC_("SV_APP_DEFAULT", "default")
 
 #define SV_MSGBOX_INFO                               NC_("SV_MSGBOX_INFO", "Information")
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index 3de5548a274e..d3b78a989610 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -1155,7 +1155,17 @@ OUString Application::GetHWOSConfInfo()
     else
 #endif
     if ( SkiaHelper::isVCLSkiaEnabled() )
-        aDetails.append( VclResId(SV_APP_SKIA) );
+    {
+        switch(SkiaHelper::renderMethodToUse())
+        {
+            case SkiaHelper::RenderVulkan:
+                aDetails.append( VclResId(SV_APP_SKIA_VULKAN) );
+                break;
+            case SkiaHelper::RenderRaster:
+                aDetails.append( VclResId(SV_APP_SKIA_RASTER) );
+                break;
+        }
+    }
     else
         aDetails.append( VclResId(SV_APP_DEFAULT) );
     aDetails.append( "; " );
commit 5d0cf5c1dfe735ddf58acd5ac2595077013b5b5e
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Mon Nov 18 12:10:36 2019 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Nov 19 12:18:24 2019 +0100

    make sure Skia invert with TrackFrame doesn't paint outside
    
    According to Tomaž that's a requirement and that is what the test
    for it tests. This is easy to implement with additional clipping.
    
    Change-Id: Ia54489e20ce58ae0624183f2989036e6938cd44f

diff --git a/vcl/qa/cppunit/BackendTest.cxx b/vcl/qa/cppunit/BackendTest.cxx
index 6dfda5d02d35..1090c33b73e0 100644
--- a/vcl/qa/cppunit/BackendTest.cxx
+++ b/vcl/qa/cppunit/BackendTest.cxx
@@ -465,8 +465,7 @@ public:
 
     CPPUNIT_TEST(testDrawInvertWithRectangle);
     CPPUNIT_TEST(testDrawInvertN50WithRectangle);
-    // AFAIK this test (itself) is broken.
-    // CPPUNIT_TEST(testDrawInvertTrackFrameWithRectangle);
+    CPPUNIT_TEST(testDrawInvertTrackFrameWithRectangle);
 
     CPPUNIT_TEST(testDrawBezierWithPolylineB2D);
     CPPUNIT_TEST(testDrawBezierAAWithPolylineB2D);
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index 948c85df72e4..271f1a61321c 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -920,6 +920,11 @@ void SkiaSalGraphicsImpl::invert(basegfx::B2DPolygon const& rPoly, SalInvert eFl
         SkPath aPath;
         addPolygonToPath(rPoly, aPath);
         aPath.setFillType(SkPath::kEvenOdd_FillType);
+        // TrackFrame is not supposed to paint outside of the polygon (usually rectangle),
+        // but wider stoke width usually results in that, so ensure the requirement
+        // by clipping.
+        SkAutoCanvasRestore autoRestore(mSurface->getCanvas(), true);
+        mSurface->getCanvas()->clipRect(aPath.getBounds(), SkClipOp::kIntersect, false);
         SkPaint aPaint;
         aPaint.setStrokeWidth(2);
         float intervals[] = { 4.0f, 4.0f };
commit 53bb01c85c0126ef9f77bd8725de67fbe7588f7a
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 15 17:22:38 2019 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Nov 19 12:18:24 2019 +0100

    disable Skia resource leak checking on exit
    
    This is normally enabled in Skia debug builds and it asserts if there
    is a problem, which there is with a number of our unittests that leak
    something (usually a VirtualDevice). Those are non-trivial to find
    and don't matter in practice (or if they do they should be fixed
    for all VCL backends), so just disable the Skia check.
    
    Change-Id: I0a0721d8a3f0f961e14513574f4b3cc88ec1e62c

diff --git a/external/skia/UnpackedTarball_skia.mk b/external/skia/UnpackedTarball_skia.mk
index c3988042a012..1fab368cc34b 100644
--- a/external/skia/UnpackedTarball_skia.mk
+++ b/external/skia/UnpackedTarball_skia.mk
@@ -18,6 +18,7 @@ skia_patches := \
     fix-ddi.patch \
     make-api-visible.patch.1 \
     fix-shader-locale.patch.1 \
+    no-trace-resources-on-exit.patch.1 \
     share-grcontext.patch.1
 
 $(eval $(call gb_UnpackedTarball_set_patchlevel,skia,1))
diff --git a/external/skia/no-trace-resources-on-exit.patch.1 b/external/skia/no-trace-resources-on-exit.patch.1
new file mode 100644
index 000000000000..7a8567938eba
--- /dev/null
+++ b/external/skia/no-trace-resources-on-exit.patch.1
@@ -0,0 +1,26 @@
+diff --git a/src/gpu/vk/GrVkCommandPool.h b/src/gpu/vk/GrVkCommandPool.h
+index fd44d62e94..f9e90f185f 100644
+--- a/src/gpu/vk/GrVkCommandPool.h
++++ b/src/gpu/vk/GrVkCommandPool.h
+@@ -41,7 +41,7 @@ public:
+     // returns true if close() has not been called
+     bool isOpen() const { return fOpen; }
+ 
+-#ifdef SK_DEBUG
++#ifdef SK_TRACE_VK_RESOURCES
+     void dumpInfo() const override {
+         SkDebugf("GrVkCommandPool: %p (%d refs)\n", fCommandPool, this->getRefCnt());
+     }
+diff --git a/src/gpu/vk/GrVkResource.h b/src/gpu/vk/GrVkResource.h
+index 7b9949ba1b..4e8fb48c7c 100644
+--- a/src/gpu/vk/GrVkResource.h
++++ b/src/gpu/vk/GrVkResource.h
+@@ -17,7 +17,7 @@ class GrVkGpu;
+ 
+ // uncomment to enable tracing of resource refs
+ #ifdef SK_DEBUG
+-#define SK_TRACE_VK_RESOURCES
++//#define SK_TRACE_VK_RESOURCES
+ #endif
+ 
+ /** \class GrVkResource
commit 857c4899f88d3717d85c95ebde3c251267c44573
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 15 17:20:44 2019 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Nov 19 12:18:23 2019 +0100

    fix memory leak
    
    Change-Id: I6148159737edd4fe225d1140606064cdb77ef615

diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx
index fe24e50ad11f..879b39fe3114 100644
--- a/include/vcl/pdfwriter.hxx
+++ b/include/vcl/pdfwriter.hxx
@@ -74,7 +74,7 @@ class VCL_DLLPUBLIC PDFOutputStream
 
 class VCL_DLLPUBLIC PDFWriter
 {
-    VclPtr<PDFWriterImpl> xImplementation;
+    ScopedVclPtr<PDFWriterImpl> xImplementation;
 
     PDFWriter(const PDFWriter&) = delete;
     PDFWriter& operator=(const PDFWriter&) = delete;
commit a69c38275d16817d351ca3897a3d81ea44e1e446
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 15 14:42:05 2019 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Nov 19 12:18:15 2019 +0100

    make Skia GPU offscreen surfaces work with unittests
    
    Skia is now patched to be able to create also invalid
    sk_app::WindowContext that will just initialize the shared GrContext.
    And always use that GrContext, even for tests, because some tests
    first create a offscreen surfaces and only later create windows,
    which before this patch led to mixing GrContext instances.
    
    Change-Id: Ic79c0719f98f6ac48527c2ea2a9a9a69412adeff

diff --git a/external/skia/Library_skia.mk b/external/skia/Library_skia.mk
index 7d84762a621d..ed24d30fa93f 100644
--- a/external/skia/Library_skia.mk
+++ b/external/skia/Library_skia.mk
@@ -62,7 +62,6 @@ ifeq ($(OS),LINUX)
 $(eval $(call gb_Library_add_libs,skia,\
     -lm \
     -ldl \
-    -lGLU \
     -lGLX \
     -lGL \
     -lX11-xcb \
@@ -814,12 +813,6 @@ $(eval $(call gb_Library_add_generated_exception_objects,skia,\
 ))
 
 $(eval $(call gb_Library_add_generated_exception_objects,skia,\
-    UnpackedTarball/skia/tools/gpu/GrContextFactory \
-    UnpackedTarball/skia/tools/gpu/TestContext \
-    UnpackedTarball/skia/tools/gpu/gl/GLTestContext \
-    UnpackedTarball/skia/tools/gpu/gl/command_buffer/GLTestContext_command_buffer \
-    UnpackedTarball/skia/tools/gpu/mock/MockTestContext \
-    UnpackedTarball/skia/tools/gpu/vk/VkTestContext \
     UnpackedTarball/skia/tools/gpu/vk/VkTestUtils \
     UnpackedTarball/skia/tools/sk_app/GLWindowContext \
     UnpackedTarball/skia/tools/sk_app/VulkanWindowContext \
@@ -848,7 +841,6 @@ $(eval $(call gb_Library_add_generated_exception_objects,skia,\
 ))
 
 $(eval $(call gb_Library_add_generated_exception_objects,skia,\
-    UnpackedTarball/skia/tools/gpu/gl/win/CreatePlatformGLTestContext_win \
     UnpackedTarball/skia/tools/sk_app/win/GLWindowContext_win \
     UnpackedTarball/skia/tools/sk_app/win/RasterWindowContext_win \
     UnpackedTarball/skia/tools/sk_app/win/VulkanWindowContext_win \
@@ -871,7 +863,6 @@ $(eval $(call gb_Library_add_generated_exception_objects,skia,\
 ))
 
 $(eval $(call gb_Library_add_generated_exception_objects,skia,\
-    UnpackedTarball/skia/tools/gpu/gl/glx/CreatePlatformGLTestContext_glx \
     UnpackedTarball/skia/tools/sk_app/unix/GLWindowContext_unix \
     UnpackedTarball/skia/tools/sk_app/unix/RasterWindowContext_unix \
     UnpackedTarball/skia/tools/sk_app/unix/VulkanWindowContext_unix \
diff --git a/external/skia/make-api-visible.patch.1 b/external/skia/make-api-visible.patch.1
index 3c2ff873eabb..2bf3a0f3d73a 100644
--- a/external/skia/make-api-visible.patch.1
+++ b/external/skia/make-api-visible.patch.1
@@ -1,29 +1,3 @@
-diff --git a/tools/gpu/GrContextFactory.h b/tools/gpu/GrContextFactory.h
-index d1b7fd5fa0..1b0bc249d2 100644
---- a/tools/gpu/GrContextFactory.h
-+++ b/tools/gpu/GrContextFactory.h
-@@ -26,7 +26,7 @@ class ContextInfo;
-  * factory is destroyed (though the caller can always grab a ref on the returned
-  * Gr and GL contexts to make them outlive the factory).
-  */
--class GrContextFactory : SkNoncopyable {
-+class SK_API GrContextFactory : SkNoncopyable {
- public:
-     // The availability of context types is subject to platform and build configuration
-     // restrictions.
-diff --git a/tools/gpu/gl/GLTestContext.cpp b/tools/gpu/gl/GLTestContext.cpp
-index d4aa605188..5d246f9737 100644
---- a/tools/gpu/gl/GLTestContext.cpp
-+++ b/tools/gpu/gl/GLTestContext.cpp
-@@ -298,7 +298,7 @@ void GLTestContext::teardown() {
- void GLTestContext::testAbandon() {
-     INHERITED::testAbandon();
-     if (fGL) {
--        fGL->abandon();
-+//        fGL->abandon();
-     }
- }
- 
 diff --git a/tools/sk_app/unix/WindowContextFactory_unix.h b/tools/sk_app/unix/WindowContextFactory_unix.h
 index 47310970d5..e02e6eb5b7 100644
 --- a/tools/sk_app/unix/WindowContextFactory_unix.h
diff --git a/external/skia/share-grcontext.patch.1 b/external/skia/share-grcontext.patch.1
index 357c3a885880..ed81e772aa20 100644
--- a/external/skia/share-grcontext.patch.1
+++ b/external/skia/share-grcontext.patch.1
@@ -1,13 +1,168 @@
-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 @@
+--- ./tools/sk_app/VulkanWindowContext.h.sav	2019-11-14 16:46:31.218722399 +0100
++++ ./tools/sk_app/VulkanWindowContext.h	2019-11-15 11:58:46.656455921 +0100
+@@ -23,14 +23,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 fSurface != VK_NULL_HANDLE; }
+ 
+     void resize(int w, int h) override {
+         this->createSwapchain(w, h, fDisplayParams);
+@@ -53,6 +69,7 @@ public:
+ private:
+     void initializeContext();
+     void destroyContext();
++    static void checkDestroyShared();
+ 
+     struct BackbufferInfo {
+         uint32_t        fImageIndex;          // image this is associated with
+@@ -64,11 +81,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;
 -
- /*
-  * Copyright 2015 Google Inc.
-  *
-@@ -24,8 +23,10 @@
+     // Create functions
+     CreateVkSurfaceFn fCreateVkSurfaceFn;
+     CanPresentFn      fCanPresentFn;
+@@ -90,20 +102,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;
+--- ./tools/sk_app/unix/VulkanWindowContext_unix.cpp.sav	2019-10-21 12:03:51.753745188 +0200
++++ ./tools/sk_app/unix/VulkanWindowContext_unix.cpp	2019-11-15 12:08:01.605967642 +0100
+@@ -30,7 +30,7 @@ std::unique_ptr<WindowContext> MakeVulka
+         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> MakeVulka
+ 
+         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> MakeVulka
+     };
+     std::unique_ptr<WindowContext> ctx(
+             new VulkanWindowContext(displayParams, createVkSurface, canPresent, instProc, devProc));
+-    if (!ctx->isValid()) {
++    if (!ctx->isValid() && createVkSurface != nullptr) {
+         return nullptr;
+     }
+     return ctx;
+--- ./tools/sk_app/win/VulkanWindowContext_win.cpp.sav	2019-10-21 12:03:51.753745188 +0200
++++ ./tools/sk_app/win/VulkanWindowContext_win.cpp	2019-11-15 12:08:21.466022257 +0100
+@@ -30,7 +30,7 @@ std::unique_ptr<WindowContext> MakeVulka
+         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)
+@@ -54,6 +54,9 @@ std::unique_ptr<WindowContext> MakeVulka
+ 
+         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) {
+@@ -71,7 +74,7 @@ std::unique_ptr<WindowContext> MakeVulka
+ 
+     std::unique_ptr<WindowContext> ctx(
+             new VulkanWindowContext(params, createVkSurface, canPresent, instProc, devProc));
+-    if (!ctx->isValid()) {
++    if (!ctx->isValid() && createVkSurface != nullptr) {
+         return nullptr;
+     }
+     return ctx;
+--- ./tools/sk_app/VulkanWindowContext.cpp.sav	2019-11-14 16:46:31.218722399 +0100
++++ ./tools/sk_app/VulkanWindowContext.cpp	2019-11-15 11:58:46.656455921 +0100
+@@ -24,8 +24,10 @@
  #undef CreateSemaphore
  #endif
  
@@ -20,7 +175,7 @@ index 793c88c158..21164cac67 100644
  
  namespace sk_app {
  
-@@ -49,6 +50,14 @@ VulkanWindowContext::VulkanWindowContext(const DisplayParams& params,
+@@ -49,6 +51,14 @@ VulkanWindowContext::VulkanWindowContext
  }
  
  void VulkanWindowContext::initializeContext() {
@@ -35,7 +190,7 @@ index 793c88c158..21164cac67 100644
      // any config code here (particularly for msaa)?
  
      PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr;
-@@ -62,24 +71,25 @@ void VulkanWindowContext::initializeContext() {
+@@ -62,24 +72,25 @@ void VulkanWindowContext::initializeCont
      };
      GrVkBackendContext backendContext;
      GrVkExtensions extensions;
@@ -71,7 +226,7 @@ index 793c88c158..21164cac67 100644
  
      PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties =
              reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
-@@ -87,21 +97,31 @@ void VulkanWindowContext::initializeContext() {
+@@ -87,21 +98,31 @@ void VulkanWindowContext::initializeCont
                                              backendContext.fInstance,
                                              VK_NULL_HANDLE));
      if (!localGetPhysicalDeviceProperties) {
@@ -108,7 +263,7 @@ index 793c88c158..21164cac67 100644
      GET_PROC(DestroySurfaceKHR);
      GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
      GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
-@@ -109,7 +129,6 @@ void VulkanWindowContext::initializeContext() {
+@@ -109,7 +130,6 @@ void VulkanWindowContext::initializeCont
      GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
      GET_DEV_PROC(DeviceWaitIdle);
      GET_DEV_PROC(QueueWaitIdle);
@@ -116,12 +271,15 @@ index 793c88c158..21164cac67 100644
      GET_DEV_PROC(CreateSwapchainKHR);
      GET_DEV_PROC(DestroySwapchainKHR);
      GET_DEV_PROC(GetSwapchainImagesKHR);
-@@ -117,46 +136,40 @@ void VulkanWindowContext::initializeContext() {
+@@ -117,46 +137,44 @@ void VulkanWindowContext::initializeCont
      GET_DEV_PROC(QueuePresentKHR);
      GET_DEV_PROC(GetDeviceQueue);
  
 -    fContext = GrContext::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) {
@@ -130,6 +288,9 @@ index 793c88c158..21164cac67 100644
          return;
      }
  
++    // create presentQueue
++    fGetDeviceQueue(fShared->fDevice, fShared->fPresentQueueIndex, 0, &fPresentQueue);
++
      VkBool32 supported;
 -    VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex,
 +    VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fShared->fPhysicalDevice, fShared->fPresentQueueIndex,
@@ -145,11 +306,10 @@ index 793c88c158..21164cac67 100644
 -        sk_gpu_test::FreeVulkanFeaturesStructs(&features);
          return;
      }
- 
-     // create presentQueue
+-
+-    // 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,
@@ -168,7 +328,7 @@ index 793c88c158..21164cac67 100644
                                                nullptr);
      if (VK_SUCCESS != res) {
          return false;
-@@ -164,14 +177,14 @@ bool VulkanWindowContext::createSwapchain(int width, int height,
+@@ -164,14 +182,14 @@ bool VulkanWindowContext::createSwapchai
  
      SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
      VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
@@ -185,7 +345,7 @@ index 793c88c158..21164cac67 100644
                                                     nullptr);
      if (VK_SUCCESS != res) {
          return false;
-@@ -179,7 +192,7 @@ bool VulkanWindowContext::createSwapchain(int width, int height,
+@@ -179,7 +197,7 @@ bool VulkanWindowContext::createSwapchai
  
      SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
      VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
@@ -194,7 +354,7 @@ index 793c88c158..21164cac67 100644
                                                     presentModes);
      if (VK_SUCCESS != res) {
          return false;
-@@ -286,8 +299,8 @@ bool VulkanWindowContext::createSwapchain(int width, int height,
+@@ -286,8 +304,8 @@ bool VulkanWindowContext::createSwapchai
      swapchainCreateInfo.imageArrayLayers = 1;
      swapchainCreateInfo.imageUsage = usageFlags;
  
@@ -205,7 +365,7 @@ index 793c88c158..21164cac67 100644
          swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
          swapchainCreateInfo.queueFamilyIndexCount = 2;
          swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
-@@ -303,18 +316,18 @@ bool VulkanWindowContext::createSwapchain(int width, int height,
+@@ -303,18 +321,18 @@ bool VulkanWindowContext::createSwapchai
      swapchainCreateInfo.clipped = true;
      swapchainCreateInfo.oldSwapchain = fSwapchain;
  
@@ -227,7 +387,7 @@ index 793c88c158..21164cac67 100644
      }
  
      this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
-@@ -323,10 +336,10 @@ bool VulkanWindowContext::createSwapchain(int width, int height,
+@@ -323,10 +341,10 @@ bool VulkanWindowContext::createSwapchai
  }
  
  void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
@@ -240,7 +400,7 @@ index 793c88c158..21164cac67 100644
  
      // set up initial image layouts and create surfaces
      fImageLayouts = new VkImageLayout[fImageCount];
-@@ -341,7 +354,7 @@ void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType)
+@@ -341,7 +359,7 @@ void VulkanWindowContext::createBuffers(
          info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
          info.fFormat = format;
          info.fLevelCount = 1;
@@ -249,7 +409,7 @@ index 793c88c158..21164cac67 100644
  
          if (fSampleCount == 1) {
              GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
-@@ -372,8 +385,8 @@ void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType)
+@@ -372,8 +390,8 @@ void VulkanWindowContext::createBuffers(
      fBackbuffers = new BackbufferInfo[fImageCount + 1];
      for (uint32_t i = 0; i < fImageCount + 1; ++i) {
          fBackbuffers[i].fImageIndex = -1;
@@ -260,7 +420,7 @@ index 793c88c158..21164cac67 100644
                                              nullptr, &fBackbuffers[i].fRenderSemaphore));
      }
      fCurrentBackbufferIndex = fImageCount;
-@@ -384,8 +397,8 @@ void VulkanWindowContext::destroyBuffers() {
+@@ -384,8 +402,8 @@ void VulkanWindowContext::destroyBuffers
      if (fBackbuffers) {
          for (uint32_t i = 0; i < fImageCount + 1; ++i) {
              fBackbuffers[i].fImageIndex = -1;
@@ -271,7 +431,7 @@ index 793c88c158..21164cac67 100644
                                          fBackbuffers[i].fRenderSemaphore,
                                          nullptr));
          }
-@@ -410,41 +423,55 @@ VulkanWindowContext::~VulkanWindowContext() {
+@@ -410,41 +428,55 @@ VulkanWindowContext::~VulkanWindowContex
  void VulkanWindowContext::destroyContext() {
      if (this->isValid()) {
          fQueueWaitIdle(fPresentQueue);
@@ -340,7 +500,7 @@ index 793c88c158..21164cac67 100644
  }
  
  VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
-@@ -470,34 +497,34 @@ sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
+@@ -470,34 +502,34 @@ sk_sp<SkSurface> VulkanWindowContext::ge
      semaphoreInfo.pNext = nullptr;
      semaphoreInfo.flags = 0;
      VkSemaphore semaphore;
@@ -381,119 +541,10 @@ index 793c88c158..21164cac67 100644
              return nullptr;
          }
      }
-@@ -541,4 +568,6 @@ void VulkanWindowContext::swapBuffers() {
+@@ -541,4 +573,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 && 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/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
index 7c41e98a91b5..0036b2d89f7a 100644
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -211,6 +211,8 @@ protected:
     void destroySurface();
     // Reimplemented for X11.
     virtual bool avoidRecreateByResize() const { return false; }
+    void createWindowSurface();
+    virtual void createWindowContext() = 0;
     void createOffscreenSurface();
 
     void privateDrawAlphaRect(long nX, long nY, long nWidth, long nHeight, double nTransparency,
@@ -256,11 +258,12 @@ protected:
     SalGraphics& mParent;
     /// Pointer to the SalFrame or SalVirtualDevice
     SalGeometryProvider* mProvider;
+    std::unique_ptr<sk_app::WindowContext> mWindowContext;
+    sk_app::VulkanWindowContext::SharedGrContext mOffscreenGrContext;
     // 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/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx
index 321f35f24366..75531ae9a164 100644
--- a/vcl/inc/skia/win/gdiimpl.hxx
+++ b/vcl/inc/skia/win/gdiimpl.hxx
@@ -21,10 +21,6 @@
 #include <svdata.hxx>
 
 class ControlCacheKey;
-namespace sk_app
-{
-class WindowContext;
-}
 
 class SkiaCompatibleDC : public CompatibleDC
 {
@@ -79,11 +75,8 @@ public:
                                   const SalTwoRect& rPosAry) override;
 
 protected:
-    virtual void createSurface() override;
+    virtual void createWindowContext() override;
     virtual void performFlush() override;
-
-private:
-    std::unique_ptr<sk_app::WindowContext> mWindowContext;
 };
 
 typedef std::pair<ControlCacheKey, SkBitmap> SkiaControlCachePair;
diff --git a/vcl/inc/skia/x11/gdiimpl.hxx b/vcl/inc/skia/x11/gdiimpl.hxx
index 1dc5064e6667..4d88740b8ba9 100644
--- a/vcl/inc/skia/x11/gdiimpl.hxx
+++ b/vcl/inc/skia/x11/gdiimpl.hxx
@@ -16,11 +16,6 @@
 #include <unx/x11/x11gdiimpl.h>
 #include <skia/gdiimpl.hxx>
 
-namespace sk_app
-{
-class WindowContext;
-}
-
 class VCL_PLUGIN_PUBLIC X11SkiaSalGraphicsImpl : public SkiaSalGraphicsImpl, public X11GraphicsImpl
 {
 private:
@@ -35,12 +30,9 @@ public:
     virtual void freeResources() override;
 
 protected:
-    virtual void createSurface() override;
+    virtual void createWindowContext() override;
     virtual void performFlush() override;
     virtual bool avoidRecreateByResize() const override;
-
-private:
-    std::unique_ptr<sk_app::WindowContext> mWindowContext;
 };
 
 #endif // INCLUDED_VCL_INC_SKIA_X11_GDIIMPL_HXX
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index caed9fb33431..948c85df72e4 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -31,7 +31,6 @@
 #include <SkRegion.h>
 #include <SkDashPathEffect.h>
 #include <GrBackendSurface.h>
-#include <GrContextFactory.h>
 
 #include <basegfx/polygon/b2dpolygontools.hxx>
 
@@ -182,6 +181,7 @@ SkiaSalGraphicsImpl::SkiaSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvid
 SkiaSalGraphicsImpl::~SkiaSalGraphicsImpl()
 {
     assert(!mSurface);
+    assert(!mWindowContext);
     assert(!mOffscreenGrContext);
 }
 
@@ -191,6 +191,17 @@ void SkiaSalGraphicsImpl::recreateSurface()
 {
     destroySurface();
     createSurface();
+}
+
+void SkiaSalGraphicsImpl::createSurface()
+{
+    if (isOffscreen())
+        createOffscreenSurface();
+    else
+        createWindowSurface();
+#ifdef DBG_UTIL
+    prefillSurface();
+#endif
     mSurface->getCanvas()->save(); // see SetClipRegion()
     mClipRegion = vcl::Region(tools::Rectangle(0, 0, GetWidth(), GetHeight()));
 
@@ -199,20 +210,35 @@ void SkiaSalGraphicsImpl::recreateSurface()
     mFlush->SetPriority(TaskPriority::POST_PAINT);
 }
 
-void SkiaSalGraphicsImpl::createSurface()
+void SkiaSalGraphicsImpl::createWindowSurface()
 {
-    // Create raster surface. Subclasses will create GPU-backed surfaces as appropriate.
-    mSurface = SkSurface::MakeRasterN32Premul(GetWidth(), GetHeight());
-    mIsGPU = false;
-#ifdef DBG_UTIL
-    prefillSurface();
-#endif
+    assert(!isOffscreen());
+    assert(!mSurface);
+    assert(!mWindowContext);
+    createWindowContext();
+    if (mWindowContext)
+        mSurface = mWindowContext->getBackbufferSurface();
+    if (!mSurface)
+    {
+        switch (SkiaHelper::renderMethodToUse())
+        {
+            case SkiaHelper::RenderVulkan:
+                SAL_WARN("vcl.skia", "cannot create Vulkan GPU window surface, disabling Vulkan");
+                // fall back to raster
+                SkiaHelper::disableRenderMethod(SkiaHelper::RenderVulkan);
+                destroySurface(); // destroys also WindowContext
+                return createWindowSurface(); // try again
+            case SkiaHelper::RenderRaster:
+                abort(); // this should not really happen
+        }
+    }
 }
 
 void SkiaSalGraphicsImpl::createOffscreenSurface()
 {
     assert(isOffscreen());
-    destroySurface();
+    assert(!mSurface);
+    assert(!mWindowContext);
     switch (SkiaHelper::renderMethodToUse())
     {
         case SkiaHelper::RenderVulkan:
@@ -228,11 +254,16 @@ void SkiaSalGraphicsImpl::createOffscreenSurface()
                 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);
+                    // Create temporary WindowContext with no window. That will fail,
+                    // but it will initialize the shared GrContext.
+                    createWindowContext();
+                    // Keep a reference.
+                    sk_app::VulkanWindowContext::SharedGrContext context
+                        = sk_app::VulkanWindowContext::getSharedGrContext();
+                    // Destroy the temporary WindowContext.
+                    destroySurface();
+                    mOffscreenGrContext = context;
+                    grContext = mOffscreenGrContext.getGrContext();
                 }
             }
             if (grContext)
@@ -241,7 +272,7 @@ void SkiaSalGraphicsImpl::createOffscreenSurface()
                     grContext, SkBudgeted::kNo,
                     SkImageInfo::MakeN32Premul(GetWidth(), GetHeight()));
                 mIsGPU = true;
-                assert(mSurface.get());
+                assert(mSurface);
 #ifdef DBG_UTIL
                 prefillSurface();
 #endif
@@ -254,7 +285,10 @@ void SkiaSalGraphicsImpl::createOffscreenSurface()
         default:
             break;
     }
-    return SkiaSalGraphicsImpl::createSurface(); // create a raster one
+    // Create raster surface. Subclasses will create GPU-backed surfaces as appropriate.
+    mSurface = SkSurface::MakeRasterN32Premul(GetWidth(), GetHeight());
+    assert(mSurface);
+    mIsGPU = false;
 }
 
 void SkiaSalGraphicsImpl::destroySurface()
@@ -266,6 +300,7 @@ void SkiaSalGraphicsImpl::destroySurface()
         // if this fails, something forgot to use SkAutoCanvasRestore
         assert(mSurface->getCanvas()->getTotalMatrix().isIdentity());
     }
+    // TODO Is this still needed?
     // If we use e.g. Vulkan, we must destroy the surface before the context,
     // otherwise destroying the surface will reference the context. This is
     // handled by calling destroySurface() before destroying the context.
@@ -276,6 +311,7 @@ void SkiaSalGraphicsImpl::destroySurface()
     if (mSurface)
         mSurface->flush();
     mSurface.reset();
+    mWindowContext.reset();
     mIsGPU = false;
     mOffscreenGrContext.reset();
 }
diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx
index cba8bed29355..dd63f4d6121e 100644
--- a/vcl/skia/win/gdiimpl.cxx
+++ b/vcl/skia/win/gdiimpl.cxx
@@ -43,43 +43,26 @@ void WinSkiaSalGraphicsImpl::Init()
     SkiaSalGraphicsImpl::Init();
 }
 
-void WinSkiaSalGraphicsImpl::createSurface()
+void WinSkiaSalGraphicsImpl::createWindowContext()
 {
-    if (isOffscreen())
-        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.
-    assert(GetWidth() != 0 && GetHeight() != 0);
+    assert((GetWidth() != 0 && GetHeight() != 0) || isOffscreen());
     sk_app::DisplayParams displayParams;
     switch (SkiaHelper::renderMethodToUse())
     {
         case SkiaHelper::RenderRaster:
             mWindowContext = sk_app::window_context_factory::MakeRasterForWin(mWinParent.gethWnd(),
                                                                               displayParams);
-            assert(SkToBool(mWindowContext));
-            mSurface = mWindowContext->getBackbufferSurface();
-            assert(mSurface.get());
             mIsGPU = false;
             break;
         case SkiaHelper::RenderVulkan:
             mWindowContext = sk_app::window_context_factory::MakeVulkanForWin(mWinParent.gethWnd(),
                                                                               displayParams);
-            if (mWindowContext)
-                mSurface = mWindowContext->getBackbufferSurface();
-            if (!mSurface)
-            {
-                SAL_WARN("vcl.skia", "cannot create Vulkan GPU surface, disabling Vulkan");
-                SkiaHelper::disableRenderMethod(SkiaHelper::RenderVulkan);
-                return createSurface(); // try again
-            }
             mIsGPU = true;
             break;
     }
-#ifdef DBG_UTIL
-    prefillSurface();
-#endif
 }
 
 void WinSkiaSalGraphicsImpl::DeInit()
diff --git a/vcl/skia/x11/gdiimpl.cxx b/vcl/skia/x11/gdiimpl.cxx
index e679fa8dbb2d..3f706399f136 100644
--- a/vcl/skia/x11/gdiimpl.cxx
+++ b/vcl/skia/x11/gdiimpl.cxx
@@ -38,11 +38,8 @@ void X11SkiaSalGraphicsImpl::Init()
     SkiaSalGraphicsImpl::Init();
 }
 
-void X11SkiaSalGraphicsImpl::createSurface()
+void X11SkiaSalGraphicsImpl::createWindowContext()
 {
-    if (isOffscreen())
-        return createOffscreenSurface();
-    destroySurface();
     sk_app::DisplayParams displayParams;
     // Use a macro to hide an unreachable code warning.
     // TODO The Skia Xlib code actually requires the non-native color type to work properly.
@@ -53,7 +50,10 @@ void X11SkiaSalGraphicsImpl::createSurface()
     sk_app::window_context_factory::XlibWindowInfo winInfo;
     winInfo.fDisplay = mX11Parent.GetXDisplay();
     winInfo.fWindow = mX11Parent.GetDrawable();
-    assert(winInfo.fDisplay && winInfo.fWindow != None);
+    assert(winInfo.fDisplay);
+    // Allow window being None if offscreen, this is used to temporarily create GrContext
+    // for an offscreen surface.
+    assert(winInfo.fWindow != None || isOffscreen());
     winInfo.fFBConfig = nullptr; // not used
     winInfo.fVisualInfo = const_cast<SalVisual*>(&mX11Parent.GetVisual());
 #ifdef DBG_UTIL
@@ -70,28 +70,14 @@ void X11SkiaSalGraphicsImpl::createSurface()
         case SkiaHelper::RenderRaster:
             mWindowContext
                 = sk_app::window_context_factory::MakeRasterForXlib(winInfo, displayParams);
-            assert(SkToBool(mWindowContext));
-            mSurface = mWindowContext->getBackbufferSurface();
-            assert(mSurface.get());
             mIsGPU = false;
             break;
         case SkiaHelper::RenderVulkan:
             mWindowContext
                 = sk_app::window_context_factory::MakeVulkanForXlib(winInfo, displayParams);
-            if (mWindowContext)
-                mSurface = mWindowContext->getBackbufferSurface();
-            if (!mSurface)
-            {
-                SAL_WARN("vcl.skia", "cannot create Vulkan GPU surface, disabling Vulkan");
-                SkiaHelper::disableRenderMethod(SkiaHelper::RenderVulkan);
-                return createSurface(); // try again
-            }
             mIsGPU = true;
             break;
     }
-#ifdef DBG_UTIL
-    prefillSurface();
-#endif
 }
 
 bool X11SkiaSalGraphicsImpl::avoidRecreateByResize() const


More information about the Libreoffice-commits mailing list