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 <canvas>
painting.
This commit is contained in:
Aliaksandr Kalenik 2024-09-19 22:34:53 +02:00 committed by Alexander Kalenik
parent 29f419d637
commit 1688cbc991
Notes: github-actions[bot] 2024-11-07 12:49:46 +00:00
7 changed files with 186 additions and 126 deletions

View file

@ -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)

View file

@ -0,0 +1,125 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/NonnullOwnPtr.h>
#include <AK/OwnPtr.h>
#include <AK/Platform.h>
#include <LibGfx/SkiaBackendContext.h>
#include <gpu/GrDirectContext.h>
#ifdef USE_VULKAN
# include <gpu/ganesh/vk/GrVkDirectContext.h>
# include <gpu/vk/VulkanBackendContext.h>
# include <gpu/vk/VulkanExtensions.h>
#endif
#ifdef AK_OS_MACOS
# include <gpu/GrBackendSurface.h>
# include <gpu/ganesh/mtl/GrMtlBackendContext.h>
# include <gpu/ganesh/mtl/GrMtlBackendSurface.h>
# include <gpu/ganesh/mtl/GrMtlDirectContext.h>
#endif
namespace Gfx {
#ifdef USE_VULKAN
class SkiaVulkanBackendContext final : public SkiaBackendContext {
AK_MAKE_NONCOPYABLE(SkiaVulkanBackendContext);
AK_MAKE_NONMOVABLE(SkiaVulkanBackendContext);
public:
SkiaVulkanBackendContext(sk_sp<GrDirectContext> context, NonnullOwnPtr<skgpu::VulkanExtensions> 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<SkSurface> 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<GrDirectContext> m_context;
NonnullOwnPtr<skgpu::VulkanExtensions> m_extensions;
};
OwnPtr<SkiaBackendContext> 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<skgpu::VulkanExtensions>();
backend_context.fVkExtensions = extensions.ptr();
sk_sp<GrDirectContext> ctx = GrDirectContexts::MakeVulkan(backend_context);
VERIFY(ctx);
return make<SkiaVulkanBackendContext>(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<GrDirectContext> 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<GrDirectContext> m_context;
};
OwnPtr<SkiaBackendContext> 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<GrDirectContext> ctx = GrDirectContexts::MakeMetal(backend_context);
return make<SkiaMetalBackendContext>(ctx);
}
#endif
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Noncopyable.h>
#ifdef AK_OS_MACOS
# include <LibCore/MetalContext.h>
#endif
#ifdef USE_VULKAN
# include <LibCore/VulkanContext.h>
#endif
class GrDirectContext;
namespace Gfx {
class SkiaBackendContext {
AK_MAKE_NONCOPYABLE(SkiaBackendContext);
AK_MAKE_NONMOVABLE(SkiaBackendContext);
public:
#ifdef USE_VULKAN
static OwnPtr<SkiaBackendContext> create_vulkan_context(Core::VulkanContext&);
#endif
#ifdef AK_OS_MACOS
static OwnPtr<Gfx::SkiaBackendContext> create_metal_context(Core::MetalContext const&);
#endif
SkiaBackendContext() {};
virtual ~SkiaBackendContext() {};
virtual void flush_and_submit() {};
virtual GrDirectContext* sk_context() const = 0;
};
}

View file

@ -5,6 +5,7 @@
*/
#include <AK/QuickSort.h>
#include <LibGfx/SkiaBackendContext.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/HTML/BrowsingContextGroup.h>
@ -31,7 +32,7 @@ TraversableNavigable::TraversableNavigable(JS::NonnullGCPtr<Page> 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> 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());
}

View file

@ -144,7 +144,7 @@ private:
String m_window_handle;
OwnPtr<Web::Painting::SkiaBackendContext> m_skia_backend_context;
OwnPtr<Gfx::SkiaBackendContext> m_skia_backend_context;
#ifdef AK_OS_MACOS
OwnPtr<Core::MetalContext> m_metal_context;

View file

@ -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<GrDirectContext> context, NonnullOwnPtr<skgpu::VulkanExtensions> 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<SkSurface> 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<GrDirectContext> m_context;
NonnullOwnPtr<skgpu::VulkanExtensions> m_extensions;
};
OwnPtr<SkiaBackendContext> 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<skgpu::VulkanExtensions>();
backend_context.fVkExtensions = extensions.ptr();
sk_sp<GrDirectContext> ctx = GrDirectContexts::MakeVulkan(backend_context);
VERIFY(ctx);
return make<SkiaVulkanBackendContext>(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<SkiaVulkanBackendContext&>(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<SkiaSurface>(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<GrDirectContext> context)
: m_context(move(context))
{
}
~SkiaMetalBackendContext() override {};
sk_sp<SkSurface> 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<GrDirectContext> m_context;
};
OwnPtr<SkiaBackendContext> 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<GrDirectContext> ctx = GrDirectContexts::MakeMetal(backend_context);
return make<SkiaMetalBackendContext>(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<SkiaMetalBackendContext>(context));
auto surface = static_cast<SkiaMetalBackendContext&>(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();

View file

@ -7,42 +7,23 @@
#pragma once
#include <LibGfx/Bitmap.h>
#include <LibGfx/SkiaBackendContext.h>
#include <LibWeb/Painting/DisplayListRecorder.h>
#ifdef AK_OS_MACOS
# include <LibCore/IOSurface.h>
# include <LibCore/MetalContext.h>
#endif
#ifdef USE_VULKAN
# include <LibCore/VulkanContext.h>
#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<SkiaBackendContext> create_vulkan_context(Core::VulkanContext&);
DisplayListPlayerSkia(SkiaBackendContext&, Gfx::Bitmap&);
DisplayListPlayerSkia(Gfx::SkiaBackendContext&, Gfx::Bitmap&);
#endif
#ifdef AK_OS_MACOS
static OwnPtr<SkiaBackendContext> create_metal_context(Core::MetalContext const&);
DisplayListPlayerSkia(SkiaBackendContext&, Core::MetalTexture&);
DisplayListPlayerSkia(Gfx::SkiaBackendContext&, Core::MetalTexture&);
#endif
virtual ~DisplayListPlayerSkia() override;