mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibGfx+LibWeb: Create PaintingSurface snapshot without GPU->RAM readback
...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.
This commit is contained in:
parent
1a01a71568
commit
4b93e27698
Notes:
github-actions[bot]
2024-11-09 20:20:52 +00:00
Author: https://github.com/kalenikaliaksandr Commit: https://github.com/LadybirdBrowser/ladybird/commit/4b93e276985 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2254
7 changed files with 29 additions and 21 deletions
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <LibGfx/ImmutableBitmap.h>
|
||||
#include <LibGfx/PaintingSurface.h>
|
||||
|
||||
#include <core/SkBitmap.h>
|
||||
#include <core/SkImage.h>
|
||||
|
@ -14,7 +15,7 @@ namespace Gfx {
|
|||
struct ImmutableBitmapImpl {
|
||||
sk_sp<SkImage> sk_image;
|
||||
SkBitmap sk_bitmap;
|
||||
RefPtr<Gfx::Bitmap> gfx_bitmap;
|
||||
Variant<NonnullRefPtr<Gfx::Bitmap>, NonnullRefPtr<Gfx::PaintingSurface>, Empty> source;
|
||||
};
|
||||
|
||||
int ImmutableBitmap::width() const
|
||||
|
@ -49,15 +50,14 @@ SkImage const* ImmutableBitmap::sk_image() const
|
|||
|
||||
RefPtr<Gfx::Bitmap const> ImmutableBitmap::bitmap() const
|
||||
{
|
||||
return m_impl->gfx_bitmap;
|
||||
// FIXME: Implement for PaintingSurface
|
||||
return m_impl->source.get<NonnullRefPtr<Gfx::Bitmap>>();
|
||||
}
|
||||
|
||||
Color ImmutableBitmap::get_pixel(int x, int y) const
|
||||
{
|
||||
if (m_impl->gfx_bitmap) {
|
||||
return m_impl->gfx_bitmap->get_pixel(x, y);
|
||||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
// FIXME: Implement for PaintingSurface
|
||||
return m_impl->source.get<NonnullRefPtr<Gfx::Bitmap>>()->get_pixel(x, y);
|
||||
}
|
||||
|
||||
static SkColorType to_skia_color_type(Gfx::BitmapFormat format)
|
||||
|
@ -96,7 +96,15 @@ NonnullRefPtr<ImmutableBitmap> ImmutableBitmap::create(NonnullRefPtr<Bitmap> bit
|
|||
impl.sk_bitmap.installPixels(info, const_cast<void*>(static_cast<void const*>(bitmap->scanline(0))), bitmap->pitch());
|
||||
impl.sk_bitmap.setImmutable();
|
||||
impl.sk_image = impl.sk_bitmap.asImage();
|
||||
impl.gfx_bitmap = bitmap;
|
||||
impl.source = bitmap;
|
||||
return adopt_ref(*new ImmutableBitmap(make<ImmutableBitmapImpl>(impl)));
|
||||
}
|
||||
|
||||
NonnullRefPtr<ImmutableBitmap> ImmutableBitmap::create_snapshot_from_painting_surface(NonnullRefPtr<PaintingSurface> painting_surface)
|
||||
{
|
||||
ImmutableBitmapImpl impl;
|
||||
impl.sk_image = painting_surface->sk_image_snapshot<sk_sp<SkImage>>();
|
||||
impl.source = painting_surface;
|
||||
return adopt_ref(*new ImmutableBitmap(make<ImmutableBitmapImpl>(impl)));
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ struct ImmutableBitmapImpl;
|
|||
class ImmutableBitmap final : public RefCounted<ImmutableBitmap> {
|
||||
public:
|
||||
static NonnullRefPtr<ImmutableBitmap> create(NonnullRefPtr<Bitmap> bitmap);
|
||||
static NonnullRefPtr<ImmutableBitmap> create_snapshot_from_painting_surface(NonnullRefPtr<PaintingSurface>);
|
||||
|
||||
~ImmutableBitmap();
|
||||
|
||||
|
|
|
@ -92,15 +92,6 @@ PaintingSurface::PaintingSurface(NonnullOwnPtr<Impl>&& impl)
|
|||
|
||||
PaintingSurface::~PaintingSurface() = default;
|
||||
|
||||
NonnullRefPtr<ImmutableBitmap> PaintingSurface::create_snapshot() const
|
||||
{
|
||||
auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied, size()).value();
|
||||
auto image_info = SkImageInfo::Make(bitmap->width(), bitmap->height(), kBGRA_8888_SkColorType, kPremul_SkAlphaType);
|
||||
SkPixmap const pixmap(image_info, bitmap->begin(), bitmap->pitch());
|
||||
sk_surface().readPixels(pixmap, 0, 0);
|
||||
return ImmutableBitmap::create(bitmap);
|
||||
}
|
||||
|
||||
void PaintingSurface::read_into_bitmap(Gfx::Bitmap& bitmap)
|
||||
{
|
||||
auto color_type = to_skia_color_type(bitmap.format());
|
||||
|
@ -130,6 +121,12 @@ 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) {
|
||||
|
|
|
@ -31,7 +31,6 @@ public:
|
|||
static NonnullRefPtr<PaintingSurface> wrap_metal_surface(Gfx::MetalTexture&, RefPtr<SkiaBackendContext>);
|
||||
#endif
|
||||
|
||||
NonnullRefPtr<ImmutableBitmap> create_snapshot() const;
|
||||
void read_into_bitmap(Bitmap&);
|
||||
|
||||
IntSize size() const;
|
||||
|
@ -40,6 +39,9 @@ public:
|
|||
SkCanvas& canvas() const;
|
||||
SkSurface& sk_surface() const;
|
||||
|
||||
template<typename T>
|
||||
T sk_image_snapshot() const;
|
||||
|
||||
void flush() const;
|
||||
|
||||
~PaintingSurface();
|
||||
|
|
|
@ -131,7 +131,7 @@ WebIDL::ExceptionOr<JS::GCPtr<CanvasPattern>> CanvasPattern::create(JS::Realm& r
|
|||
auto bitmap = image.visit(
|
||||
[](JS::Handle<HTMLImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->immutable_bitmap(); },
|
||||
[](JS::Handle<SVG::SVGImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->current_image_bitmap(); },
|
||||
[](JS::Handle<HTMLCanvasElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return source->surface()->create_snapshot(); },
|
||||
[](JS::Handle<HTMLCanvasElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create_snapshot_from_painting_surface(*source->surface()); },
|
||||
[](JS::Handle<HTMLVideoElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); },
|
||||
[](JS::Handle<ImageBitmap> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); });
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@ WebIDL::ExceptionOr<void> CanvasRenderingContext2D::draw_image_internal(CanvasIm
|
|||
auto surface = source->surface();
|
||||
if (!surface)
|
||||
return {};
|
||||
return source->surface()->create_snapshot();
|
||||
return Gfx::ImmutableBitmap::create_snapshot_from_painting_surface(*surface);
|
||||
},
|
||||
[](JS::Handle<HTMLVideoElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> { return Gfx::ImmutableBitmap::create(*source->bitmap()); },
|
||||
[](JS::Handle<ImageBitmap> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
|
||||
|
@ -401,7 +401,7 @@ WebIDL::ExceptionOr<JS::GCPtr<ImageData>> CanvasRenderingContext2D::get_image_da
|
|||
// NOTE: We don't attempt to create the underlying bitmap here; if it doesn't exist, it's like copying only transparent black pixels (which is a no-op).
|
||||
if (!canvas_element().surface())
|
||||
return image_data;
|
||||
auto const snapshot = canvas_element().surface()->create_snapshot();
|
||||
auto const snapshot = Gfx::ImmutableBitmap::create_snapshot_from_painting_surface(*canvas_element().surface());
|
||||
|
||||
// 5. Let the source rectangle be the rectangle whose corners are the four points (sx, sy), (sx+sw, sy), (sx+sw, sy+sh), (sx, sy+sh).
|
||||
auto source_rect = Gfx::Rect { x, y, abs_width, abs_height };
|
||||
|
|
|
@ -268,7 +268,7 @@ String HTMLCanvasElement::to_data_url(StringView type, Optional<double> quality)
|
|||
return "data:,"_string;
|
||||
|
||||
// 3. Let file be a serialization of this canvas element's bitmap as a file, passing type and quality if given.
|
||||
auto snapshot = m_surface->create_snapshot();
|
||||
auto snapshot = Gfx::ImmutableBitmap::create_snapshot_from_painting_surface(*m_surface);
|
||||
auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied, m_surface->size()));
|
||||
m_surface->read_into_bitmap(*bitmap);
|
||||
auto file = serialize_bitmap(bitmap, type, move(quality));
|
||||
|
|
Loading…
Reference in a new issue