From 54be644c092eebb8be57a251556fe3f0e5f99e57 Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Wed, 6 Nov 2019 16:14:50 +0100 Subject: make SkiaSalGraphicsImpl use GPU-backed SkSurface also for offscreen Skia's sk_app::WindowContext can create GPU-backed SkSurface only for windows, but we also use virtual devices that are not windows. Fortunately, SkSurface can be created GPU-backed from GrContext* and sk_gpu_test::GrContextFactory seems to provide it easily. It is not completely clear to me what the rules are on mixing SkSurface's with different GrContext* (see the comment in SkiaSalGraphicsImpl::copyBits()), but it seems to work fine. Change-Id: I8110b67c41ab092e0c4b6a0973d6bed8a408c4c1 --- RepositoryExternal.mk | 1 + external/skia/Library_skia.mk | 9 ++++++++ external/skia/make-api-visible.patch.1 | 26 +++++++++++++++++++++++ vcl/Library_vcl.mk | 3 ++- vcl/inc/skia/vulkan.hxx | 29 +++++++++++++++++++++++++ vcl/skia/gdiimpl.cxx | 14 ++++++++---- vcl/skia/vulkan.cxx | 39 ++++++++++++++++++++++++++++++++++ vcl/skia/win/gdiimpl.cxx | 19 ++++++++++++++++- vcl/skia/x11/gdiimpl.cxx | 20 ++++++++++++++++- 9 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 vcl/inc/skia/vulkan.hxx create mode 100644 vcl/skia/vulkan.cxx diff --git a/RepositoryExternal.mk b/RepositoryExternal.mk index 91be30307dd7..6cf31f5c17ab 100644 --- a/RepositoryExternal.mk +++ b/RepositoryExternal.mk @@ -119,6 +119,7 @@ $(call gb_LinkTarget_set_include,$(1),\ -I$(call gb_UnpackedTarball_get_dir,skia)/include/gpu \ -I$(call gb_UnpackedTarball_get_dir,skia)/include/config \ -I$(call gb_UnpackedTarball_get_dir,skia)/include/third_party/vulkan \ + -I$(call gb_UnpackedTarball_get_dir,skia)/tools/gpu \ -I$(call gb_UnpackedTarball_get_dir,skia) \ $$(INCLUDE) \ ) diff --git a/external/skia/Library_skia.mk b/external/skia/Library_skia.mk index ed24d30fa93f..7d84762a621d 100644 --- a/external/skia/Library_skia.mk +++ b/external/skia/Library_skia.mk @@ -62,6 +62,7 @@ ifeq ($(OS),LINUX) $(eval $(call gb_Library_add_libs,skia,\ -lm \ -ldl \ + -lGLU \ -lGLX \ -lGL \ -lX11-xcb \ @@ -813,6 +814,12 @@ $(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 \ @@ -841,6 +848,7 @@ $(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 \ @@ -863,6 +871,7 @@ $(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 2bf3a0f3d73a..3c2ff873eabb 100644 --- a/external/skia/make-api-visible.patch.1 +++ b/external/skia/make-api-visible.patch.1 @@ -1,3 +1,29 @@ +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/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index c054a2767a3c..1f05f7aa9dd2 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -586,7 +586,8 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/skia/SkiaHelper \ $(if $(filter SKIA,$(BUILD_TYPE)), \ vcl/skia/salbmp \ - vcl/skia/gdiimpl) \ + vcl/skia/gdiimpl \ + vcl/skia/vulkan) \ )) # runtime dependency diff --git a/vcl/inc/skia/vulkan.hxx b/vcl/inc/skia/vulkan.hxx new file mode 100644 index 000000000000..6c8e3c7bfa44 --- /dev/null +++ b/vcl/inc/skia/vulkan.hxx @@ -0,0 +1,29 @@ +/* -*- 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 + +#include + +// 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/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index f505e7778d64..612e097b6e12 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -407,6 +407,8 @@ void SkiaSalGraphicsImpl::drawPixel(long nX, long nY, Color nColor) paint.setColor(toSkColor(nColor)); // Apparently drawPixel() is actually expected to set the pixel and not draw it. paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + if (isGPU()) // TODO this may need caching? + ++nX; // https://bugs.chromium.org/p/skia/issues/detail?id=9611 canvas->drawPoint(nX, nY, paint); postDraw(); } @@ -677,7 +679,6 @@ void SkiaSalGraphicsImpl::copyArea(long nDestX, long nDestY, long nSrcX, long nS << Size(nSrcWidth, nSrcHeight)); sk_sp image = mSurface->makeImageSnapshot(SkIRect::MakeXYWH(nSrcX, nSrcY, nSrcWidth, nSrcHeight)); - // TODO makeNonTextureImage() ? mSurface->getCanvas()->drawImage(image, nDestX, nDestY); postDraw(); } @@ -690,14 +691,18 @@ void SkiaSalGraphicsImpl::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcG { assert(dynamic_cast(pSrcGraphics->GetImpl())); src = static_cast(pSrcGraphics->GetImpl()); + src->checkSurface(); + // TODO Without this flush() Skia asserts if both src and destination are + // GPU-backed SkSurface that come from different GrContext (e.g. when + // src comes from SkiaVulkanGrContext and target is a window). I don't + // know if it's a Skia bug or our GrContext usage is incorrect. + src->mSurface->flush(); } else src = this; - src->checkSurface(); SAL_INFO("vcl.skia", "copybits(" << this << "): (" << src << "):" << rPosAry); sk_sp image = src->mSurface->makeImageSnapshot( SkIRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight)); - // TODO makeNonTextureImage() ? mSurface->getCanvas()->drawImageRect(image, SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, @@ -1055,7 +1060,8 @@ bool SkiaSalGraphicsImpl::supportsOperation(OutDevSupportType eType) const bool SkiaSalGraphicsImpl::isGPU() const { return mSurface.get() - && mSurface->getBackendRenderTarget(SkSurface::kFlushRead_BackendHandleAccess).isValid(); + && mSurface->getBackendRenderTarget(SkSurface::kFlushWrite_BackendHandleAccess) + .isValid(); } #ifdef DBG_UTIL diff --git a/vcl/skia/vulkan.cxx b/vcl/skia/vulkan.cxx new file mode 100644 index 000000000000..c5c9093739fc --- /dev/null +++ b/vcl/skia/vulkan.cxx @@ -0,0 +1,39 @@ +/* -*- 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 + +#include + +#include + +static GrContext* createGrContext() +{ + static vcl::DeleteOnDeinit 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 d54120d5ffce..f908ace261a3 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -44,14 +45,30 @@ void WinSkiaSalGraphicsImpl::Init() void WinSkiaSalGraphicsImpl::createSurface() { + destroySurface(); if (isOffscreen()) + { + switch (renderMethodToUse()) + { + case RenderVulkan: + mSurface = SkSurface::MakeRenderTarget( + SkiaVulkanGrContext::getGrContext(), SkBudgeted::kNo, + SkImageInfo::MakeN32Premul(GetWidth(), GetHeight())); + assert(mSurface.get()); +#ifdef DBG_UTIL + prefillSurface(); +#endif + return; + default: + break; + } return SkiaSalGraphicsImpl::createSurface(); + } // 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); sk_app::DisplayParams displayParams; - destroySurface(); switch (renderMethodToUse()) { case RenderRaster: diff --git a/vcl/skia/x11/gdiimpl.cxx b/vcl/skia/x11/gdiimpl.cxx index fff94936a33d..af602d35bede 100644 --- a/vcl/skia/x11/gdiimpl.cxx +++ b/vcl/skia/x11/gdiimpl.cxx @@ -21,6 +21,8 @@ #include #include +#include + X11SkiaSalGraphicsImpl::X11SkiaSalGraphicsImpl(X11SalGraphics& rParent) : SkiaSalGraphicsImpl(rParent, rParent.GetGeometryProvider()) , mX11Parent(rParent) @@ -38,8 +40,25 @@ void X11SkiaSalGraphicsImpl::Init() void X11SkiaSalGraphicsImpl::createSurface() { + destroySurface(); if (isOffscreen()) + { + switch (renderMethodToUse()) + { + case RenderVulkan: + mSurface = SkSurface::MakeRenderTarget( + SkiaVulkanGrContext::getGrContext(), SkBudgeted::kNo, + SkImageInfo::MakeN32Premul(GetWidth(), GetHeight())); + assert(mSurface.get()); +#ifdef DBG_UTIL + prefillSurface(); +#endif + return; + default: + break; + } return SkiaSalGraphicsImpl::createSurface(); + } 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. @@ -59,7 +78,6 @@ void X11SkiaSalGraphicsImpl::createSurface() // Avoid this somehow. winInfo.fWidth = GetWidth(); winInfo.fHeight = GetHeight(); - destroySurface(); switch (renderMethodToUse()) { case RenderRaster: -- cgit