Pārlūkot izejas kodu

LibAccelGfx+WebContent: Introduce Canvas that represents framebuffer

Aliaksandr Kalenik 1 gadu atpakaļ
vecāks
revīzija
d5630fedf1

+ 46 - 0
Userland/Libraries/LibAccelGfx/Canvas.h

@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#pragma once
+
+#include <AK/RefCounted.h>
+#include <LibAccelGfx/GL.h>
+#include <LibGfx/Rect.h>
+
+namespace AccelGfx {
+
+class Canvas : public RefCounted<Canvas> {
+public:
+    static NonnullRefPtr<Canvas> create(Gfx::IntSize const& size)
+    {
+        return adopt_ref(*new Canvas(size));
+    }
+
+    Gfx::IntSize const& size() const { return m_size; }
+    GL::Framebuffer const& framebuffer() const { return m_framebuffer; }
+
+    void bind()
+    {
+        GL::bind_framebuffer(m_framebuffer);
+    }
+
+    virtual ~Canvas()
+    {
+        GL::delete_framebuffer(m_framebuffer);
+    }
+
+private:
+    Canvas(Gfx::IntSize const& size)
+        : m_size(size)
+        , m_framebuffer(GL::create_framebuffer(size))
+    {
+    }
+
+    Gfx::IntSize m_size;
+    GL::Framebuffer m_framebuffer;
+};
+
+}

+ 28 - 18
Userland/Libraries/LibAccelGfx/Painter.cpp

@@ -32,11 +32,11 @@ static ColorComponents gfx_color_to_opengl_color(Gfx::Color color)
 
 Gfx::FloatRect Painter::to_clip_space(Gfx::FloatRect const& screen_rect) const
 {
-    float x = 2.0f * screen_rect.x() / m_target_bitmap->width() - 1.0f;
-    float y = -1.0f + 2.0f * screen_rect.y() / m_target_bitmap->height();
+    float x = 2.0f * screen_rect.x() / m_target_canvas->size().width() - 1.0f;
+    float y = -1.0f + 2.0f * screen_rect.y() / m_target_canvas->size().height();
 
-    float width = 2.0f * screen_rect.width() / m_target_bitmap->width();
-    float height = 2.0f * screen_rect.height() / m_target_bitmap->height();
+    float width = 2.0f * screen_rect.width() / m_target_canvas->size().width();
+    float height = 2.0f * screen_rect.height() / m_target_canvas->size().height();
 
     return { x, y, width, height };
 }
@@ -155,7 +155,6 @@ Painter::Painter(Context& context)
 
 Painter::~Painter()
 {
-    flush();
 }
 
 void Painter::clear(Gfx::Color color)
@@ -184,6 +183,8 @@ static Array<GLfloat, 8> rect_to_vertices(Gfx::FloatRect const& rect)
 
 void Painter::fill_rect(Gfx::FloatRect rect, Gfx::Color color)
 {
+    bind_target_canvas();
+
     // Draw a filled rect (with `color`) using OpenGL after mapping it through the current transform.
 
     auto vertices = rect_to_vertices(to_clip_space(transform().map(rect)));
@@ -218,6 +219,8 @@ void Painter::fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color con
 
 void Painter::fill_rect_with_rounded_corners(Gfx::FloatRect const& rect, Color const& color, CornerRadius const& top_left_radius, CornerRadius const& top_right_radius, CornerRadius const& bottom_left_radius, CornerRadius const& bottom_right_radius)
 {
+    bind_target_canvas();
+
     auto transformed_rect = transform().map(rect);
     auto vertices = rect_to_vertices(to_clip_space(transformed_rect));
 
@@ -265,6 +268,8 @@ void Painter::draw_line(Gfx::IntPoint a, Gfx::IntPoint b, float thickness, Gfx::
 
 void Painter::draw_line(Gfx::FloatPoint a, Gfx::FloatPoint b, float thickness, Color color)
 {
+    bind_target_canvas();
+
     auto midpoint = (a + b) / 2.0f;
     auto length = a.distance_from(b);
     auto angle = AK::atan2(b.y() - a.y(), b.x() - a.x());
@@ -328,6 +333,8 @@ static GL::ScalingMode to_gl_scaling_mode(Painter::ScalingMode scaling_mode)
 
 void Painter::draw_scaled_bitmap(Gfx::FloatRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::FloatRect const& src_rect, ScalingMode scaling_mode)
 {
+    bind_target_canvas();
+
     m_blit_program.use();
 
     // FIXME: We should reuse textures across repaints if possible.
@@ -434,6 +441,8 @@ void Painter::prepare_glyph_texture(HashMap<Gfx::Font const*, HashTable<u32>> co
 
 void Painter::draw_glyph_run(Vector<Gfx::DrawGlyphOrEmoji> const& glyph_run, Color const& color)
 {
+    bind_target_canvas();
+
     Vector<GLfloat> vertices;
     vertices.ensure_capacity(glyph_run.size() * 24);
 
@@ -527,6 +536,8 @@ void Painter::fill_rect_with_linear_gradient(Gfx::IntRect const& rect, ReadonlyS
 
 void Painter::fill_rect_with_linear_gradient(Gfx::FloatRect const& rect, ReadonlySpan<Gfx::ColorStop> stops, float angle, Optional<float> repeat_length)
 {
+    bind_target_canvas();
+
     // FIXME: Implement support for angle and repeat_length
     (void)angle;
     (void)repeat_length;
@@ -632,24 +643,23 @@ void Painter::clear_clip_rect()
     GL::disable_scissor_test();
 }
 
-void Painter::set_target_bitmap(Gfx::Bitmap& bitmap)
+void Painter::bind_target_canvas()
 {
-    if (m_target_framebuffer.has_value()) {
-        GL::delete_framebuffer(*m_target_framebuffer);
-        m_target_framebuffer = {};
-    }
+    m_target_canvas->bind();
+    GL::set_viewport({ 0, 0, m_target_canvas->size().width(), m_target_canvas->size().height() });
+}
 
-    m_target_framebuffer = GL::create_framebuffer(bitmap.size());
-    GL::bind_framebuffer(*m_target_framebuffer);
-    GL::set_viewport({ 0, 0, bitmap.width(), bitmap.height() });
-    m_target_bitmap = bitmap;
+void Painter::set_target_canvas(NonnullRefPtr<Canvas> canvas)
+{
+    m_target_canvas = canvas;
+    canvas->bind();
+    GL::set_viewport({ 0, 0, canvas->size().width(), canvas->size().height() });
 }
 
-void Painter::flush()
+void Painter::flush(Gfx::Bitmap& bitmap)
 {
-    VERIFY(m_target_bitmap.has_value());
-    GL::bind_framebuffer(*m_target_framebuffer);
-    GL::read_pixels({ 0, 0, m_target_bitmap->width(), m_target_bitmap->height() }, *m_target_bitmap);
+    m_target_canvas->bind();
+    GL::read_pixels({ 0, 0, bitmap.width(), bitmap.height() }, bitmap);
 }
 
 }

+ 7 - 5
Userland/Libraries/LibAccelGfx/Painter.h

@@ -10,6 +10,7 @@
 #include <AK/HashMap.h>
 #include <AK/Noncopyable.h>
 #include <AK/Vector.h>
+#include <LibAccelGfx/Canvas.h>
 #include <LibAccelGfx/Context.h>
 #include <LibAccelGfx/Forward.h>
 #include <LibAccelGfx/GL.h>
@@ -72,8 +73,8 @@ public:
     void set_clip_rect(Gfx::IntRect);
     void clear_clip_rect();
 
-    void set_target_bitmap(Gfx::Bitmap&);
-    void flush();
+    void set_target_canvas(NonnullRefPtr<Canvas>);
+    void flush(Gfx::Bitmap&);
 
     void fill_rect_with_linear_gradient(Gfx::IntRect const&, ReadonlySpan<Gfx::ColorStop>, float angle, Optional<float> repeat_length = {});
     void fill_rect_with_linear_gradient(Gfx::FloatRect const&, ReadonlySpan<Gfx::ColorStop>, float angle, Optional<float> repeat_length = {});
@@ -95,10 +96,14 @@ private:
     [[nodiscard]] State& state() { return m_state_stack.last(); }
     [[nodiscard]] State const& state() const { return m_state_stack.last(); }
 
+    void bind_target_canvas();
+
     [[nodiscard]] Gfx::FloatRect to_clip_space(Gfx::FloatRect const& screen_rect) const;
 
     Vector<State, 1> m_state_stack;
 
+    RefPtr<Canvas> m_target_canvas;
+
     Program m_rectangle_program;
     Program m_rounded_rectangle_program;
     Program m_blit_program;
@@ -107,9 +112,6 @@ private:
     HashMap<GlyphsTextureKey, Gfx::IntRect> m_glyphs_texture_map;
     Gfx::IntSize m_glyphs_texture_size;
     GL::Texture m_glyphs_texture;
-
-    Optional<Gfx::Bitmap&> m_target_bitmap;
-    Optional<GL::Framebuffer> m_target_framebuffer;
 };
 
 }

+ 2 - 2
Userland/Services/WebContent/PageHost.cpp

@@ -164,10 +164,10 @@ void PageHost::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& targ
 
     if (s_use_gpu_painter) {
 #ifdef HAS_ACCELERATED_GRAPHICS
-        m_accelerated_painter->set_target_bitmap(target);
+        m_accelerated_painter->set_target_canvas(AccelGfx::Canvas::create(target.size()));
         Web::Painting::PaintingCommandExecutorGPU painting_command_executor(*m_accelerated_painter);
         recording_painter.execute(painting_command_executor);
-        m_accelerated_painter->flush();
+        m_accelerated_painter->flush(target);
 #endif
     } else {
         Web::Painting::PaintingCommandExecutorCPU painting_command_executor(target);