ladybird/Libraries/LibGfx/PaintingSurface.h
Aliaksandr Kalenik a08734ecbc LibGfx+LibWeb+Compositor+WebContent: Commit 2D canvas flushes atomically
2D canvas contexts started publishing partial frames after canvas
rasterization moved into the Compositor. WebContent still splits large
recorded command lists after 64 commands, but every split batch was sent
through the same compositor path as the end-of-frame flush. The
compositor replayed each batch into the DrawCanvas source surface,
so a pending present could sample a canvas after clear and before the
rest of the next frame had been drawn. Canvas-heavy pages such as
slither.com then flickered between partial and complete frames.

Carry an explicit commit bit with 2D canvas command updates. Non-commit
batches now update a hidden working canvas in the Compositor, while the
display-list-visible surface keeps the last committed canvas contents.
The end-of-frame canvas preparation sends the commit boundary, including
the empty-commit case needed when the auto-flush consumed all recorded
commands before prepare_for_compositing() runs.
2026-06-19 00:01:26 +02:00

88 lines
2 KiB
C++

/*
* Copyright (c) 2024-2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/AtomicRefCounted.h>
#include <AK/Function.h>
#include <AK/NonnullOwnPtr.h>
#include <AK/RefPtr.h>
#include <LibGfx/Color.h>
#include <LibGfx/Size.h>
#include <LibGfx/SkiaBackendContext.h>
#ifdef USE_VULKAN_DMABUF_IMAGES
namespace Gfx {
struct VulkanImage;
}
#endif
#ifdef AK_OS_MACOS
# include <LibGfx/MetalContext.h>
#endif
class SkCanvas;
class SkSurface;
namespace Gfx {
class SharedImage;
class PaintingSurface : public AtomicRefCounted<PaintingSurface> {
public:
enum class Origin {
TopLeft,
BottomLeft,
};
Function<void(PaintingSurface&)> on_flush;
static NonnullRefPtr<PaintingSurface> create_with_size(IntSize size, BitmapFormat color_type, AlphaType alpha_type, RefPtr<SkiaBackendContext> = {});
static NonnullRefPtr<PaintingSurface> wrap_bitmap(Bitmap&);
#ifdef AK_OS_MACOS
static NonnullRefPtr<PaintingSurface> create_from_shared_image_buffer(SharedImageBuffer&, NonnullRefPtr<SkiaBackendContext>, Origin = Origin::TopLeft);
#endif
#ifdef USE_VULKAN_DMABUF_IMAGES
static NonnullRefPtr<PaintingSurface> create_from_vkimage(NonnullRefPtr<SkiaBackendContext> context, NonnullRefPtr<VulkanImage> vulkan_image, Origin origin);
#endif
NonnullRefPtr<Bitmap> snapshot_bitmap() const;
SharedImage snapshot_into_shared_image() const;
void read_into_bitmap(Bitmap&, IntPoint source_position = {}) const;
void write_from_bitmap(Bitmap const&);
void copy_from_surface(PaintingSurface&);
void notify_content_will_change();
IntSize size() const;
IntRect rect() const;
SkCanvas& canvas() const;
SkSurface& sk_surface() const;
template<typename T>
T sk_image_snapshot() const;
RefPtr<SkiaBackendContext> skia_backend_context() const;
void flush();
~PaintingSurface();
private:
struct Impl;
PaintingSurface(NonnullOwnPtr<Impl>&&);
NonnullOwnPtr<Impl> m_impl;
};
}