mirror of
https://github.com/fergalmoran/ladybird.git
synced 2026-01-02 22:55:23 +00:00
...by constructing ImmutableBitmap directly from SkImage. This is a huge optimization for the case when content of canvas is painted onto another canvas, as it allows pixels to remain in GPU memory throughout the process. Fixes performance regression on https://playbiolab.com/ introduced by switching to GPU-backend for canvas.
138 lines
4.6 KiB
C++
138 lines
4.6 KiB
C++
/*
|
|
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <LibGfx/Bitmap.h>
|
|
#include <LibGfx/ImmutableBitmap.h>
|
|
#include <LibGfx/PaintingSurface.h>
|
|
|
|
#include <core/SkColorSpace.h>
|
|
#include <core/SkSurface.h>
|
|
#include <gpu/GrBackendSurface.h>
|
|
#include <gpu/GrDirectContext.h>
|
|
#include <gpu/ganesh/SkSurfaceGanesh.h>
|
|
|
|
#ifdef AK_OS_MACOS
|
|
# include <gpu/ganesh/mtl/GrMtlBackendContext.h>
|
|
# include <gpu/ganesh/mtl/GrMtlBackendSurface.h>
|
|
# include <gpu/ganesh/mtl/GrMtlDirectContext.h>
|
|
#endif
|
|
|
|
namespace Gfx {
|
|
|
|
struct PaintingSurface::Impl {
|
|
IntSize size;
|
|
sk_sp<SkSurface> surface;
|
|
RefPtr<Bitmap> bitmap;
|
|
RefPtr<SkiaBackendContext> context;
|
|
};
|
|
|
|
static SkColorType to_skia_color_type(Gfx::BitmapFormat format)
|
|
{
|
|
switch (format) {
|
|
case Gfx::BitmapFormat::Invalid:
|
|
return kUnknown_SkColorType;
|
|
case Gfx::BitmapFormat::BGRA8888:
|
|
case Gfx::BitmapFormat::BGRx8888:
|
|
return kBGRA_8888_SkColorType;
|
|
case Gfx::BitmapFormat::RGBA8888:
|
|
return kRGBA_8888_SkColorType;
|
|
default:
|
|
return kUnknown_SkColorType;
|
|
}
|
|
}
|
|
|
|
NonnullRefPtr<PaintingSurface> PaintingSurface::create_with_size(RefPtr<SkiaBackendContext> context, Gfx::IntSize size, Gfx::BitmapFormat color_type, Gfx::AlphaType alpha_type)
|
|
{
|
|
auto sk_color_type = to_skia_color_type(color_type);
|
|
auto sk_alpha_type = alpha_type == Gfx::AlphaType::Premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
|
|
auto image_info = SkImageInfo::Make(size.width(), size.height(), sk_color_type, sk_alpha_type);
|
|
|
|
if (!context) {
|
|
auto bitmap = Gfx::Bitmap::create(color_type, alpha_type, size).value();
|
|
auto surface = SkSurfaces::WrapPixels(image_info, bitmap->begin(), bitmap->pitch());
|
|
VERIFY(surface);
|
|
return adopt_ref(*new PaintingSurface(make<Impl>(size, surface, bitmap, context)));
|
|
}
|
|
|
|
auto surface = SkSurfaces::RenderTarget(context->sk_context(), skgpu::Budgeted::kNo, image_info);
|
|
VERIFY(surface);
|
|
return adopt_ref(*new PaintingSurface(make<Impl>(size, surface, nullptr, context)));
|
|
}
|
|
|
|
NonnullRefPtr<PaintingSurface> PaintingSurface::wrap_bitmap(Bitmap& bitmap)
|
|
{
|
|
auto color_type = to_skia_color_type(bitmap.format());
|
|
auto alpha_type = bitmap.alpha_type() == Gfx::AlphaType::Premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
|
|
auto size = bitmap.size();
|
|
auto image_info = SkImageInfo::Make(bitmap.width(), bitmap.height(), color_type, alpha_type);
|
|
auto surface = SkSurfaces::WrapPixels(image_info, bitmap.begin(), bitmap.pitch());
|
|
return adopt_ref(*new PaintingSurface(make<Impl>(size, surface, bitmap, nullptr)));
|
|
}
|
|
|
|
#ifdef AK_OS_MACOS
|
|
NonnullRefPtr<PaintingSurface> PaintingSurface::wrap_metal_surface(Gfx::MetalTexture& metal_texture, RefPtr<SkiaBackendContext> context)
|
|
{
|
|
IntSize const size { metal_texture.width(), metal_texture.height() };
|
|
auto image_info = SkImageInfo::Make(size.width(), size.height(), kBGRA_8888_SkColorType, kPremul_SkAlphaType);
|
|
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);
|
|
return adopt_ref(*new PaintingSurface(make<Impl>(size, surface, nullptr, context)));
|
|
}
|
|
#endif
|
|
|
|
PaintingSurface::PaintingSurface(NonnullOwnPtr<Impl>&& impl)
|
|
: m_impl(move(impl))
|
|
{
|
|
}
|
|
|
|
PaintingSurface::~PaintingSurface() = default;
|
|
|
|
void PaintingSurface::read_into_bitmap(Gfx::Bitmap& bitmap)
|
|
{
|
|
auto color_type = to_skia_color_type(bitmap.format());
|
|
auto alpha_type = bitmap.alpha_type() == Gfx::AlphaType::Premultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
|
|
auto image_info = SkImageInfo::Make(bitmap.width(), bitmap.height(), color_type, alpha_type);
|
|
SkPixmap const pixmap(image_info, bitmap.begin(), bitmap.pitch());
|
|
m_impl->surface->readPixels(pixmap, 0, 0);
|
|
}
|
|
|
|
IntSize PaintingSurface::size() const
|
|
{
|
|
return m_impl->size;
|
|
}
|
|
|
|
IntRect PaintingSurface::rect() const
|
|
{
|
|
return { {}, m_impl->size };
|
|
}
|
|
|
|
SkCanvas& PaintingSurface::canvas() const
|
|
{
|
|
return *m_impl->surface->getCanvas();
|
|
}
|
|
|
|
SkSurface& PaintingSurface::sk_surface() const
|
|
{
|
|
return *m_impl->surface;
|
|
}
|
|
|
|
template<>
|
|
sk_sp<SkImage> PaintingSurface::sk_image_snapshot() const
|
|
{
|
|
return m_impl->surface->makeImageSnapshot();
|
|
}
|
|
|
|
void PaintingSurface::flush() const
|
|
{
|
|
if (auto context = m_impl->context) {
|
|
context->flush_and_submit(m_impl->surface.get());
|
|
}
|
|
}
|
|
|
|
}
|