From 1688cbc991832164ee60d354beee1b70beb80c95 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Thu, 19 Sep 2024 22:34:53 +0200 Subject: [PATCH] LibWeb+LibGfx: Move class that represents Skia GPU context to LibGfx This is required to share GPU context creation code between display list player, which resides in LibWeb, and PainterSkia, which handles painting. --- Userland/Libraries/LibGfx/CMakeLists.txt | 2 + .../Libraries/LibGfx/SkiaBackendContext.cpp | 125 ++++++++++++++++++ .../Libraries/LibGfx/SkiaBackendContext.h | 43 ++++++ .../LibWeb/HTML/TraversableNavigable.cpp | 5 +- .../LibWeb/HTML/TraversableNavigable.h | 2 +- .../LibWeb/Painting/DisplayListPlayerSkia.cpp | 108 ++------------- .../LibWeb/Painting/DisplayListPlayerSkia.h | 27 +--- 7 files changed, 186 insertions(+), 126 deletions(-) create mode 100644 Userland/Libraries/LibGfx/SkiaBackendContext.cpp create mode 100644 Userland/Libraries/LibGfx/SkiaBackendContext.h diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt index 64dca64083f..6b1929e0d99 100644 --- a/Userland/Libraries/LibGfx/CMakeLists.txt +++ b/Userland/Libraries/LibGfx/CMakeLists.txt @@ -1,4 +1,5 @@ include(skia) +include(vulkan) set(SOURCES AffineTransform.cpp @@ -65,6 +66,7 @@ set(SOURCES TextLayout.cpp Triangle.cpp VectorGraphic.cpp + SkiaBackendContext.cpp ) serenity_lib(LibGfx gfx) diff --git a/Userland/Libraries/LibGfx/SkiaBackendContext.cpp b/Userland/Libraries/LibGfx/SkiaBackendContext.cpp new file mode 100644 index 00000000000..5fa8933cba0 --- /dev/null +++ b/Userland/Libraries/LibGfx/SkiaBackendContext.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +#include + +#ifdef USE_VULKAN +# include +# include +# include +#endif + +#ifdef AK_OS_MACOS +# include +# include +# include +# include +#endif + +namespace Gfx { + +#ifdef USE_VULKAN +class SkiaVulkanBackendContext final : public SkiaBackendContext { + AK_MAKE_NONCOPYABLE(SkiaVulkanBackendContext); + AK_MAKE_NONMOVABLE(SkiaVulkanBackendContext); + +public: + SkiaVulkanBackendContext(sk_sp context, NonnullOwnPtr extensions) + : m_context(move(context)) + , m_extensions(move(extensions)) + { + } + + ~SkiaVulkanBackendContext() override { } + + void flush_and_submit() override + { + m_context->flush(); + m_context->submit(GrSyncCpu::kYes); + } + + sk_sp create_surface(int width, int height) + { + auto image_info = SkImageInfo::Make(width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType); + return SkSurfaces::RenderTarget(m_context.get(), skgpu::Budgeted::kYes, image_info); + } + + skgpu::VulkanExtensions const* extensions() const { return m_extensions.ptr(); } + + GrDirectContext* sk_context() const override { return m_context.get(); } + +private: + sk_sp m_context; + NonnullOwnPtr m_extensions; +}; + +OwnPtr SkiaBackendContext::create_vulkan_context(Core::VulkanContext& vulkan_context) +{ + skgpu::VulkanBackendContext backend_context; + + backend_context.fInstance = vulkan_context.instance; + backend_context.fDevice = vulkan_context.logical_device; + backend_context.fQueue = vulkan_context.graphics_queue; + backend_context.fPhysicalDevice = vulkan_context.physical_device; + backend_context.fMaxAPIVersion = vulkan_context.api_version; + backend_context.fGetProc = [](char const* proc_name, VkInstance instance, VkDevice device) { + if (device != VK_NULL_HANDLE) { + return vkGetDeviceProcAddr(device, proc_name); + } + return vkGetInstanceProcAddr(instance, proc_name); + }; + + auto extensions = make(); + backend_context.fVkExtensions = extensions.ptr(); + + sk_sp ctx = GrDirectContexts::MakeVulkan(backend_context); + VERIFY(ctx); + return make(ctx, move(extensions)); +} +#endif + +#ifdef AK_OS_MACOS +class SkiaMetalBackendContext final : public SkiaBackendContext { + AK_MAKE_NONCOPYABLE(SkiaMetalBackendContext); + AK_MAKE_NONMOVABLE(SkiaMetalBackendContext); + +public: + SkiaMetalBackendContext(sk_sp context) + : m_context(move(context)) + { + } + + ~SkiaMetalBackendContext() override { } + + void flush_and_submit() override + { + m_context->flush(); + m_context->submit(GrSyncCpu::kYes); + } + + GrDirectContext* sk_context() const override { return m_context.get(); } + +private: + sk_sp m_context; +}; + +OwnPtr SkiaBackendContext::create_metal_context(Core::MetalContext const& metal_context) +{ + GrMtlBackendContext backend_context; + backend_context.fDevice.retain((GrMTLHandle)metal_context.device()); + backend_context.fQueue.retain((GrMTLHandle)metal_context.queue()); + sk_sp ctx = GrDirectContexts::MakeMetal(backend_context); + return make(ctx); +} + +#endif + +} diff --git a/Userland/Libraries/LibGfx/SkiaBackendContext.h b/Userland/Libraries/LibGfx/SkiaBackendContext.h new file mode 100644 index 00000000000..af3ecfd6038 --- /dev/null +++ b/Userland/Libraries/LibGfx/SkiaBackendContext.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include + +#ifdef AK_OS_MACOS +# include +#endif + +#ifdef USE_VULKAN +# include +#endif + +class GrDirectContext; + +namespace Gfx { + +class SkiaBackendContext { + AK_MAKE_NONCOPYABLE(SkiaBackendContext); + AK_MAKE_NONMOVABLE(SkiaBackendContext); + +public: +#ifdef USE_VULKAN + static OwnPtr create_vulkan_context(Core::VulkanContext&); +#endif + +#ifdef AK_OS_MACOS + static OwnPtr create_metal_context(Core::MetalContext const&); +#endif + + SkiaBackendContext() {}; + virtual ~SkiaBackendContext() {}; + + virtual void flush_and_submit() {}; + virtual GrDirectContext* sk_context() const = 0; +}; + +} diff --git a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp index 8c6fe3e90d3..0a3aeee7590 100644 --- a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp +++ b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -31,7 +32,7 @@ TraversableNavigable::TraversableNavigable(JS::NonnullGCPtr page) auto display_list_player_type = page->client().display_list_player_type(); if (display_list_player_type == DisplayListPlayerType::SkiaGPUIfAvailable) { m_metal_context = Core::get_metal_context(); - m_skia_backend_context = Painting::DisplayListPlayerSkia::create_metal_context(*m_metal_context); + m_skia_backend_context = Gfx::SkiaBackendContext::create_metal_context(*m_metal_context); } #endif @@ -41,7 +42,7 @@ TraversableNavigable::TraversableNavigable(JS::NonnullGCPtr page) auto maybe_vulkan_context = Core::create_vulkan_context(); if (!maybe_vulkan_context.is_error()) { auto vulkan_context = maybe_vulkan_context.release_value(); - m_skia_backend_context = Painting::DisplayListPlayerSkia::create_vulkan_context(vulkan_context); + m_skia_backend_context = Gfx::SkiaBackendContext::create_vulkan_context(vulkan_context); } else { dbgln("Vulkan context creation failed: {}", maybe_vulkan_context.error()); } diff --git a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h index c2cd076e8c0..64bafde80d5 100644 --- a/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h +++ b/Userland/Libraries/LibWeb/HTML/TraversableNavigable.h @@ -144,7 +144,7 @@ private: String m_window_handle; - OwnPtr m_skia_backend_context; + OwnPtr m_skia_backend_context; #ifdef AK_OS_MACOS OwnPtr m_metal_context; diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index de791f1b6dc..73e08fbf2ad 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -71,66 +71,11 @@ private: }; #ifdef USE_VULKAN -class SkiaVulkanBackendContext final : public SkiaBackendContext { - AK_MAKE_NONCOPYABLE(SkiaVulkanBackendContext); - AK_MAKE_NONMOVABLE(SkiaVulkanBackendContext); - -public: - SkiaVulkanBackendContext(sk_sp context, NonnullOwnPtr extensions) - : m_context(move(context)) - , m_extensions(move(extensions)) - { - } - - ~SkiaVulkanBackendContext() override {}; - - void flush_and_submit() override - { - m_context->flush(); - m_context->submit(GrSyncCpu::kYes); - } - - sk_sp create_surface(int width, int height) - { - auto image_info = SkImageInfo::Make(width, height, kBGRA_8888_SkColorType, kPremul_SkAlphaType); - return SkSurfaces::RenderTarget(m_context.get(), skgpu::Budgeted::kYes, image_info); - } - - skgpu::VulkanExtensions const* extensions() const { return m_extensions.ptr(); } - -private: - sk_sp m_context; - NonnullOwnPtr m_extensions; -}; - -OwnPtr DisplayListPlayerSkia::create_vulkan_context(Core::VulkanContext& vulkan_context) -{ - skgpu::VulkanBackendContext backend_context; - - backend_context.fInstance = vulkan_context.instance; - backend_context.fDevice = vulkan_context.logical_device; - backend_context.fQueue = vulkan_context.graphics_queue; - backend_context.fPhysicalDevice = vulkan_context.physical_device; - backend_context.fMaxAPIVersion = vulkan_context.api_version; - backend_context.fGetProc = [](char const* proc_name, VkInstance instance, VkDevice device) { - if (device != VK_NULL_HANDLE) { - return vkGetDeviceProcAddr(device, proc_name); - } - return vkGetInstanceProcAddr(instance, proc_name); - }; - - auto extensions = make(); - backend_context.fVkExtensions = extensions.ptr(); - - sk_sp ctx = GrDirectContexts::MakeVulkan(backend_context); - VERIFY(ctx); - return make(ctx, move(extensions)); -} - -DisplayListPlayerSkia::DisplayListPlayerSkia(SkiaBackendContext& context, Gfx::Bitmap& bitmap) +DisplayListPlayerSkia::DisplayListPlayerSkia(Gfx::SkiaBackendContext& context, Gfx::Bitmap& bitmap) { VERIFY(bitmap.format() == Gfx::BitmapFormat::BGRA8888); - auto surface = static_cast(context).create_surface(bitmap.width(), bitmap.height()); + auto image_info = SkImageInfo::Make(bitmap.width(), bitmap.height(), kBGRA_8888_SkColorType, kPremul_SkAlphaType); + auto surface = SkSurfaces::RenderTarget(context.sk_context(), skgpu::Budgeted::kYes, image_info); m_surface = make(surface); m_flush_context = [&bitmap, &surface = m_surface, &context] { context.flush_and_submit(); @@ -140,50 +85,13 @@ DisplayListPlayerSkia::DisplayListPlayerSkia(SkiaBackendContext& context, Gfx::B #endif #ifdef AK_OS_MACOS -class SkiaMetalBackendContext final : public SkiaBackendContext { - AK_MAKE_NONCOPYABLE(SkiaMetalBackendContext); - AK_MAKE_NONMOVABLE(SkiaMetalBackendContext); - -public: - SkiaMetalBackendContext(sk_sp context) - : m_context(move(context)) - { - } - - ~SkiaMetalBackendContext() override {}; - - sk_sp wrap_metal_texture(Core::MetalTexture& metal_texture) - { - GrMtlTextureInfo mtl_info; - mtl_info.fTexture = sk_ret_cfp(metal_texture.texture()); - auto backend_render_target = GrBackendRenderTargets::MakeMtl(metal_texture.width(), metal_texture.height(), mtl_info); - return SkSurfaces::WrapBackendRenderTarget(m_context.get(), backend_render_target, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType, nullptr, nullptr); - } - - void flush_and_submit() override - { - m_context->flush(); - m_context->submit(GrSyncCpu::kYes); - } - -private: - sk_sp m_context; -}; - -OwnPtr DisplayListPlayerSkia::create_metal_context(Core::MetalContext const& metal_context) -{ - GrMtlBackendContext backend_context; - backend_context.fDevice.retain((GrMTLHandle)metal_context.device()); - backend_context.fQueue.retain((GrMTLHandle)metal_context.queue()); - sk_sp ctx = GrDirectContexts::MakeMetal(backend_context); - return make(ctx); -} - -DisplayListPlayerSkia::DisplayListPlayerSkia(SkiaBackendContext& context, Core::MetalTexture& metal_texture) +DisplayListPlayerSkia::DisplayListPlayerSkia(Gfx::SkiaBackendContext& context, Core::MetalTexture& metal_texture) { auto image_info = SkImageInfo::Make(metal_texture.width(), metal_texture.height(), kBGRA_8888_SkColorType, kPremul_SkAlphaType); - VERIFY(is(context)); - auto surface = static_cast(context).wrap_metal_texture(metal_texture); + GrMtlTextureInfo mtl_info; + mtl_info.fTexture = sk_ret_cfp(metal_texture.texture()); + auto backend_render_target = GrBackendRenderTargets::MakeMtl(metal_texture.width(), metal_texture.height(), mtl_info); + auto surface = SkSurfaces::WrapBackendRenderTarget(context.sk_context(), backend_render_target, kTopLeft_GrSurfaceOrigin, kBGRA_8888_SkColorType, nullptr, nullptr); if (!surface) { dbgln("Failed to create Skia surface from Metal texture"); VERIFY_NOT_REACHED(); diff --git a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h index 598b94b2f35..8e5488a825c 100644 --- a/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h +++ b/Userland/Libraries/LibWeb/Painting/DisplayListPlayerSkia.h @@ -7,42 +7,23 @@ #pragma once #include +#include #include -#ifdef AK_OS_MACOS -# include -# include -#endif - -#ifdef USE_VULKAN -# include -#endif +class GrDirectContext; namespace Web::Painting { -class SkiaBackendContext { - AK_MAKE_NONCOPYABLE(SkiaBackendContext); - AK_MAKE_NONMOVABLE(SkiaBackendContext); - -public: - SkiaBackendContext() {}; - virtual ~SkiaBackendContext() {}; - - virtual void flush_and_submit() {}; -}; - class DisplayListPlayerSkia : public DisplayListPlayer { public: DisplayListPlayerSkia(Gfx::Bitmap&); #ifdef USE_VULKAN - static OwnPtr create_vulkan_context(Core::VulkanContext&); - DisplayListPlayerSkia(SkiaBackendContext&, Gfx::Bitmap&); + DisplayListPlayerSkia(Gfx::SkiaBackendContext&, Gfx::Bitmap&); #endif #ifdef AK_OS_MACOS - static OwnPtr create_metal_context(Core::MetalContext const&); - DisplayListPlayerSkia(SkiaBackendContext&, Core::MetalTexture&); + DisplayListPlayerSkia(Gfx::SkiaBackendContext&, Core::MetalTexture&); #endif virtual ~DisplayListPlayerSkia() override;