diff --git a/Libraries/LibGfx/PainterSkia.cpp b/Libraries/LibGfx/PainterSkia.cpp index 473fe325904..a7fd0d9b203 100644 --- a/Libraries/LibGfx/PainterSkia.cpp +++ b/Libraries/LibGfx/PainterSkia.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2024, Andreas Kling - * Copyright (c) 2024, Aliaksandr Kalenik + * Copyright (c) 2024-2025, Aliaksandr Kalenik * Copyright (c) 2024, Lucien Fiorini * * SPDX-License-Identifier: BSD-2-Clause @@ -33,9 +33,13 @@ struct PainterSkia::Impl { { } - SkCanvas* canvas() const + template + void with_canvas(Callback&& callback) { - return &painting_surface->canvas(); + painting_surface->lock_context(); + auto& canvas = painting_surface->canvas(); + callback(canvas); + painting_surface->unlock_context(); } }; @@ -122,14 +126,18 @@ void PainterSkia::clear_rect(Gfx::FloatRect const& rect, Gfx::Color color) SkPaint paint; paint.setColor(to_skia_color(color)); paint.setBlendMode(SkBlendMode::kClear); - impl().canvas()->drawRect(to_skia_rect(rect), paint); + impl().with_canvas([&](auto& canvas) { + canvas.drawRect(to_skia_rect(rect), paint); + }); } void PainterSkia::fill_rect(Gfx::FloatRect const& rect, Color color) { SkPaint paint; paint.setColor(to_skia_color(color)); - impl().canvas()->drawRect(to_skia_rect(rect), paint); + impl().with_canvas([&](auto& canvas) { + canvas.drawRect(to_skia_rect(rect), paint); + }); } void PainterSkia::draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitmap const& src_bitmap, Gfx::IntRect const& src_rect, Gfx::ScalingMode scaling_mode, ReadonlySpan filters, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) @@ -139,13 +147,15 @@ void PainterSkia::draw_bitmap(Gfx::FloatRect const& dst_rect, Gfx::ImmutableBitm paint.setAlpha(static_cast(global_alpha * 255)); paint.setBlender(to_skia_blender(compositing_and_blending_operator)); - impl().canvas()->drawImageRect( - src_bitmap.sk_image(), - to_skia_rect(src_rect), - to_skia_rect(dst_rect), - to_skia_sampling_options(scaling_mode), - &paint, - SkCanvas::kStrict_SrcRectConstraint); + impl().with_canvas([&](auto& canvas) { + canvas.drawImageRect( + src_bitmap.sk_image(), + to_skia_rect(src_rect), + to_skia_rect(dst_rect), + to_skia_sampling_options(scaling_mode), + &paint, + SkCanvas::kStrict_SrcRectConstraint); + }); } void PainterSkia::set_transform(Gfx::AffineTransform const& transform) @@ -155,7 +165,9 @@ void PainterSkia::set_transform(Gfx::AffineTransform const& transform) transform.b(), transform.d(), transform.f(), 0, 0, 1); - impl().canvas()->setMatrix(matrix); + impl().with_canvas([&](auto& canvas) { + canvas.setMatrix(matrix); + }); } void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::Color color, float thickness) @@ -170,7 +182,9 @@ void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::Color color, float thi paint.setStrokeWidth(thickness); paint.setColor(to_skia_color(color)); auto sk_path = to_skia_path(path); - impl().canvas()->drawPath(sk_path, paint); + impl().with_canvas([&](auto& canvas) { + canvas.drawPath(sk_path, paint); + }); } void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::Color color, float thickness, float blur_radius, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) @@ -187,7 +201,9 @@ void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::Color color, float thi paint.setColor(to_skia_color(color)); paint.setBlender(to_skia_blender(compositing_and_blending_operator)); auto sk_path = to_skia_path(path); - impl().canvas()->drawPath(sk_path, paint); + impl().with_canvas([&](auto& canvas) { + canvas.drawPath(sk_path, paint); + }); } void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, ReadonlySpan filters, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) @@ -204,7 +220,9 @@ void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& pain paint.setStyle(SkPaint::Style::kStroke_Style); paint.setStrokeWidth(thickness); paint.setBlender(to_skia_blender(compositing_and_blending_operator)); - impl().canvas()->drawPath(sk_path, paint); + impl().with_canvas([&](auto& canvas) { + canvas.drawPath(sk_path, paint); + }); } void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, ReadonlySpan filters, float thickness, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::Path::CapStyle const& cap_style, Gfx::Path::JoinStyle const& join_style) @@ -223,7 +241,9 @@ void PainterSkia::stroke_path(Gfx::Path const& path, Gfx::PaintStyle const& pain paint.setStrokeCap(to_skia_cap(cap_style)); paint.setStrokeJoin(to_skia_join(join_style)); paint.setBlender(to_skia_blender(compositing_and_blending_operator)); - impl().canvas()->drawPath(sk_path, paint); + impl().with_canvas([&](auto& canvas) { + canvas.drawPath(sk_path, paint); + }); } void PainterSkia::fill_path(Gfx::Path const& path, Gfx::Color color, Gfx::WindingRule winding_rule) @@ -233,7 +253,9 @@ void PainterSkia::fill_path(Gfx::Path const& path, Gfx::Color color, Gfx::Windin paint.setColor(to_skia_color(color)); auto sk_path = to_skia_path(path); sk_path.setFillType(to_skia_path_fill_type(winding_rule)); - impl().canvas()->drawPath(sk_path, paint); + impl().with_canvas([&](auto& canvas) { + canvas.drawPath(sk_path, paint); + }); } void PainterSkia::fill_path(Gfx::Path const& path, Gfx::Color color, Gfx::WindingRule winding_rule, float blur_radius, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator) @@ -245,7 +267,9 @@ void PainterSkia::fill_path(Gfx::Path const& path, Gfx::Color color, Gfx::Windin paint.setBlender(to_skia_blender(compositing_and_blending_operator)); auto sk_path = to_skia_path(path); sk_path.setFillType(to_skia_path_fill_type(winding_rule)); - impl().canvas()->drawPath(sk_path, paint); + impl().with_canvas([&](auto& canvas) { + canvas.drawPath(sk_path, paint); + }); } void PainterSkia::fill_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_style, ReadonlySpan filters, float global_alpha, Gfx::CompositingAndBlendingOperator compositing_and_blending_operator, Gfx::WindingRule winding_rule) @@ -257,24 +281,32 @@ void PainterSkia::fill_path(Gfx::Path const& path, Gfx::PaintStyle const& paint_ float alpha = paint.getAlphaf(); paint.setAlphaf(alpha * global_alpha); paint.setBlender(to_skia_blender(compositing_and_blending_operator)); - impl().canvas()->drawPath(sk_path, paint); + impl().with_canvas([&](auto& canvas) { + canvas.drawPath(sk_path, paint); + }); } void PainterSkia::save() { - impl().canvas()->save(); + impl().with_canvas([&](auto& canvas) { + canvas.save(); + }); } void PainterSkia::restore() { - impl().canvas()->restore(); + impl().with_canvas([&](auto& canvas) { + canvas.restore(); + }); } void PainterSkia::clip(Gfx::Path const& path, Gfx::WindingRule winding_rule) { auto sk_path = to_skia_path(path); sk_path.setFillType(to_skia_path_fill_type(winding_rule)); - impl().canvas()->clipPath(sk_path, SkClipOp::kIntersect, true); + impl().with_canvas([&](auto& canvas) { + canvas.clipPath(sk_path, SkClipOp::kIntersect, true); + }); } } diff --git a/Libraries/LibGfx/PaintingSurface.cpp b/Libraries/LibGfx/PaintingSurface.cpp index 163c911e45a..ab8f7d0399d 100644 --- a/Libraries/LibGfx/PaintingSurface.cpp +++ b/Libraries/LibGfx/PaintingSurface.cpp @@ -21,6 +21,7 @@ namespace Gfx { struct PaintingSurface::Impl { + RefPtr context; IntSize size; sk_sp surface; RefPtr bitmap; @@ -36,12 +37,12 @@ NonnullRefPtr PaintingSurface::create_with_size(RefPtrbegin(), bitmap->pitch()); VERIFY(surface); - return adopt_ref(*new PaintingSurface(make(size, surface, bitmap))); + return adopt_ref(*new PaintingSurface(make(context, size, surface, bitmap))); } auto surface = SkSurfaces::RenderTarget(context->sk_context(), skgpu::Budgeted::kNo, image_info); VERIFY(surface); - return adopt_ref(*new PaintingSurface(make(size, surface, nullptr))); + return adopt_ref(*new PaintingSurface(make(context, size, surface, nullptr))); } NonnullRefPtr PaintingSurface::wrap_bitmap(Bitmap& bitmap) @@ -51,7 +52,7 @@ NonnullRefPtr PaintingSurface::wrap_bitmap(Bitmap& bitmap) auto size = bitmap.size(); auto image_info = SkImageInfo::Make(bitmap.width(), bitmap.height(), color_type, alpha_type, SkColorSpace::MakeSRGB()); auto surface = SkSurfaces::WrapPixels(image_info, bitmap.begin(), bitmap.pitch()); - return adopt_ref(*new PaintingSurface(make(size, surface, bitmap))); + return adopt_ref(*new PaintingSurface(make(RefPtr {}, size, surface, bitmap))); } #ifdef AK_OS_MACOS @@ -75,7 +76,7 @@ NonnullRefPtr PaintingSurface::wrap_iosurface(Core::IOSurfaceHa VERIFY_NOT_REACHED(); } auto surface = SkSurfaces::WrapBackendRenderTarget(context->sk_context(), backend_render_target, sk_origin, kBGRA_8888_SkColorType, nullptr, nullptr); - return adopt_ref(*new PaintingSurface(make(size, surface, nullptr))); + return adopt_ref(*new PaintingSurface(make(context, size, surface, nullptr))); } #endif @@ -141,4 +142,18 @@ void PaintingSurface::flush() on_flush(*this); } +void PaintingSurface::lock_context() const +{ + auto& context = m_impl->context; + if (context) + context->lock(); +} + +void PaintingSurface::unlock_context() const +{ + auto& context = m_impl->context; + if (context) + context->unlock(); +} + } diff --git a/Libraries/LibGfx/PaintingSurface.h b/Libraries/LibGfx/PaintingSurface.h index 0760ad076af..fab6f6f65ed 100644 --- a/Libraries/LibGfx/PaintingSurface.h +++ b/Libraries/LibGfx/PaintingSurface.h @@ -57,6 +57,9 @@ public: ~PaintingSurface(); + void lock_context() const; + void unlock_context() const; + private: struct Impl; diff --git a/Libraries/LibGfx/SkiaBackendContext.h b/Libraries/LibGfx/SkiaBackendContext.h index 91fcef4b5cf..50ddf8ad647 100644 --- a/Libraries/LibGfx/SkiaBackendContext.h +++ b/Libraries/LibGfx/SkiaBackendContext.h @@ -8,6 +8,7 @@ #include #include +#include #ifdef USE_VULKAN # include @@ -44,6 +45,12 @@ public: virtual GrDirectContext* sk_context() const = 0; virtual MetalContext& metal_context() = 0; + + void lock() { m_mutex.lock(); } + void unlock() { m_mutex.unlock(); } + +private: + Threading::Mutex m_mutex; }; } diff --git a/Libraries/LibWeb/Painting/DisplayList.cpp b/Libraries/LibWeb/Painting/DisplayList.cpp index bbde8c16520..06c21688a77 100644 --- a/Libraries/LibWeb/Painting/DisplayList.cpp +++ b/Libraries/LibWeb/Painting/DisplayList.cpp @@ -36,6 +36,17 @@ static bool command_is_clip_or_mask(Command const& command) } void DisplayListPlayer::execute(DisplayList& display_list, RefPtr surface) +{ + if (surface) { + surface->lock_context(); + } + execute_impl(display_list, surface); + if (surface) { + surface->unlock_context(); + } +} + +void DisplayListPlayer::execute_impl(DisplayList& display_list, RefPtr surface) { if (surface) m_surfaces.append(*surface); diff --git a/Libraries/LibWeb/Painting/DisplayList.h b/Libraries/LibWeb/Painting/DisplayList.h index 6ab27a39bfd..387c62a5c2e 100644 --- a/Libraries/LibWeb/Painting/DisplayList.h +++ b/Libraries/LibWeb/Painting/DisplayList.h @@ -30,6 +30,7 @@ public: protected: Gfx::PaintingSurface& surface() const { return m_surfaces.last(); } + void execute_impl(DisplayList&, RefPtr); private: virtual void flush() = 0; diff --git a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp index dc8a4e458d5..89e96654024 100644 --- a/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp +++ b/Libraries/LibWeb/Painting/DisplayListPlayerSkia.cpp @@ -972,7 +972,7 @@ void DisplayListPlayerSkia::add_mask(AddMask const& command) auto mask_surface = Gfx::PaintingSurface::create_with_size(m_context, rect.size(), Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied); - execute(*command.display_list, mask_surface); + execute_impl(*command.display_list, mask_surface); SkMatrix mask_matrix; mask_matrix.setTranslate(rect.x(), rect.y()); @@ -985,7 +985,7 @@ void DisplayListPlayerSkia::paint_nested_display_list(PaintNestedDisplayList con { auto& canvas = surface().canvas(); canvas.translate(command.rect.x(), command.rect.y()); - execute(*command.display_list, {}); + execute_impl(*command.display_list, {}); } void DisplayListPlayerSkia::paint_scrollbar(PaintScrollBar const& command)