1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 13:07:46 +00:00

LibWeb: Implement border radius corner clipping in GPU painter

It is implemented in the way identical to how it works in CPU painter:
1. SampleUnderCorners command saves pixels within corners into a
   texture.
2. BlitCornerClipping command uses the texture prepared earlier to
   restore pixels within corners.
This commit is contained in:
Aliaksandr Kalenik 2023-12-17 14:34:44 +01:00 committed by Andreas Kling
parent 177e7df1c5
commit bd08b1815f
6 changed files with 127 additions and 13 deletions

View file

@ -30,6 +30,8 @@ static GLenum to_gl_enum(BlendFactor factor)
return GL_SRC_ALPHA;
case BlendFactor::One:
return GL_ONE;
case BlendFactor::Zero:
return GL_ZERO;
case BlendFactor::OneMinusSrcAlpha:
return GL_ONE_MINUS_SRC_ALPHA;
}

View file

@ -61,6 +61,7 @@ struct Framebuffer {
void set_viewport(Gfx::IntRect);
enum class BlendFactor {
Zero,
One,
OneMinusSrcAlpha,
SrcAlpha,

View file

@ -168,6 +168,23 @@ void main() {
}
)";
static void set_blending_mode(Painter::BlendingMode blending_mode)
{
switch (blending_mode) {
case Painter::BlendingMode::AlphaAdd:
GL::enable_blending(GL::BlendFactor::SrcAlpha, GL::BlendFactor::OneMinusSrcAlpha, GL::BlendFactor::One, GL::BlendFactor::One);
break;
case Painter::BlendingMode::AlphaOverride:
GL::enable_blending(GL::BlendFactor::SrcAlpha, GL::BlendFactor::OneMinusSrcAlpha, GL::BlendFactor::One, GL::BlendFactor::Zero);
break;
case Painter::BlendingMode::AlphaPreserve:
GL::enable_blending(GL::BlendFactor::SrcAlpha, GL::BlendFactor::OneMinusSrcAlpha, GL::BlendFactor::Zero, GL::BlendFactor::One);
break;
default:
VERIFY_NOT_REACHED();
}
}
HashMap<u32, GL::Texture> s_immutable_bitmap_texture_cache;
NonnullOwnPtr<Painter> Painter::create(Context& context, NonnullRefPtr<Canvas> canvas)
@ -249,12 +266,12 @@ void Painter::fill_rect(Gfx::FloatRect rect, Gfx::Color color)
GL::delete_vertex_array(vao);
}
void Painter::fill_rect_with_rounded_corners(Gfx::IntRect 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)
void Painter::fill_rect_with_rounded_corners(Gfx::IntRect 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, BlendingMode blending_mode)
{
fill_rect_with_rounded_corners(rect.to_type<float>(), color, top_left_radius, top_right_radius, bottom_left_radius, bottom_right_radius);
fill_rect_with_rounded_corners(rect.to_type<float>(), color, top_left_radius, top_right_radius, bottom_left_radius, bottom_right_radius, blending_mode);
}
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)
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, BlendingMode blending_mode)
{
bind_target_canvas();
@ -291,7 +308,8 @@ void Painter::fill_rect_with_rounded_corners(Gfx::FloatRect const& rect, Color c
auto bottom_right_corner_radius_uniform = m_rounded_rectangle_program.get_uniform_location("uBottomRightRadius");
GL::set_uniform(bottom_right_corner_radius_uniform, bottom_right_radius.horizontal_radius, bottom_right_radius.vertical_radius);
GL::enable_blending(GL::BlendFactor::SrcAlpha, GL::BlendFactor::OneMinusSrcAlpha, GL::BlendFactor::One, GL::BlendFactor::One);
set_blending_mode(blending_mode);
GL::draw_arrays(GL::DrawPrimitive::TriangleFan, 4);
GL::delete_buffer(vbo);
@ -627,7 +645,13 @@ void Painter::blit_canvas(Gfx::FloatRect const& dst_rect, Canvas const& canvas,
blit_scaled_texture(dst_rect, texture, { { 0, 0 }, canvas.size() }, Painter::ScalingMode::NearestNeighbor, opacity, move(affine_transform));
}
void Painter::blit_scaled_texture(Gfx::FloatRect const& dst_rect, GL::Texture const& texture, Gfx::FloatRect const& src_rect, ScalingMode scaling_mode, float opacity, Optional<Gfx::AffineTransform> affine_transform)
void Painter::blit_canvas(Gfx::FloatRect const& dst_rect, Canvas const& canvas, Gfx::FloatRect const& src_rect, float opacity, Optional<Gfx::AffineTransform> affine_transform, BlendingMode blending_mode)
{
auto texture = GL::Texture(canvas.framebuffer().texture);
blit_scaled_texture(dst_rect, texture, src_rect, Painter::ScalingMode::NearestNeighbor, opacity, move(affine_transform), blending_mode);
}
void Painter::blit_scaled_texture(Gfx::FloatRect const& dst_rect, GL::Texture const& texture, Gfx::FloatRect const& src_rect, ScalingMode scaling_mode, float opacity, Optional<Gfx::AffineTransform> affine_transform, BlendingMode blending_mode)
{
bind_target_canvas();
@ -689,7 +713,7 @@ void Painter::blit_scaled_texture(Gfx::FloatRect const& dst_rect, GL::Texture co
auto scaling_mode_gl = to_gl_scaling_mode(scaling_mode);
GL::set_texture_scale_mode(scaling_mode_gl);
GL::enable_blending(GL::BlendFactor::SrcAlpha, GL::BlendFactor::OneMinusSrcAlpha, GL::BlendFactor::One, GL::BlendFactor::One);
set_blending_mode(blending_mode);
GL::draw_arrays(GL::DrawPrimitive::TriangleFan, 4);

View file

@ -34,6 +34,8 @@ public:
Painter(Context&, NonnullRefPtr<Canvas>);
~Painter();
Canvas const& canvas() { return *m_target_canvas; }
void clear(Gfx::Color);
void save();
@ -53,6 +55,12 @@ public:
Bilinear,
};
enum class BlendingMode {
AlphaAdd,
AlphaOverride,
AlphaPreserve,
};
void draw_line(Gfx::IntPoint a, Gfx::IntPoint b, float thickness, Gfx::Color color);
void draw_line(Gfx::FloatPoint a, Gfx::FloatPoint b, float thickness, Gfx::Color color);
@ -76,11 +84,12 @@ public:
float horizontal_radius;
float vertical_radius;
};
void fill_rect_with_rounded_corners(Gfx::IntRect 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);
void 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);
void fill_rect_with_rounded_corners(Gfx::IntRect 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, BlendingMode = BlendingMode::AlphaAdd);
void 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, BlendingMode = BlendingMode::AlphaAdd);
void blit_canvas(Gfx::IntRect const& dst_rect, Canvas const&, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {});
void blit_canvas(Gfx::FloatRect const& dst_rect, Canvas const&, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {});
void blit_canvas(Gfx::FloatRect const& dst_rect, Canvas const&, Gfx::FloatRect const& src_rect, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {}, BlendingMode = BlendingMode::AlphaAdd);
enum class BlurDirection {
Horizontal,
@ -101,7 +110,7 @@ private:
[[nodiscard]] State& state() { return m_state_stack.last(); }
[[nodiscard]] State const& state() const { return m_state_stack.last(); }
void blit_scaled_texture(Gfx::FloatRect const& dst_rect, GL::Texture const&, Gfx::FloatRect const& src_rect, ScalingMode, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {});
void blit_scaled_texture(Gfx::FloatRect const& dst_rect, GL::Texture const&, Gfx::FloatRect const& src_rect, ScalingMode, float opacity = 1.0f, Optional<Gfx::AffineTransform> affine_transform = {}, BlendingMode = BlendingMode::AlphaAdd);
void blit_blurred_texture(Gfx::FloatRect const& dst_rect, GL::Texture const&, Gfx::FloatRect const& src_rect, int radius, BlurDirection direction, ScalingMode = ScalingMode::NearestNeighbor);
void bind_target_canvas();