mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-29 08:11:13 +00:00
LibWeb+Ladybird: Add option to enable the AffineCommandExecutorCPU
This adds a `--experimental-cpu-transforms` option to Ladybird and WebContent (which defaults to false/off). When enabled the AffineCommandExecutorCPU will be used to handle painting transformed stacking contexts (i.e. stacking contexts where the transform is something other than a simple translation). The regular command executor will still handle the non-transformed cases. This is hidden under a flag as the `AffineCommandExecutorCPU` is very incomplete now. It missing support for clipping, text, and other basic commands. Once most common commands have been implemented this flag will be removed.
This commit is contained in:
parent
b9db9013f5
commit
9c711bc868
Notes:
sideshowbarker
2024-07-16 20:12:13 +09:00
Author: https://github.com/MacDue Commit: https://github.com/SerenityOS/serenity/commit/9c711bc868 Pull-request: https://github.com/SerenityOS/serenity/pull/24465 Issue: https://github.com/SerenityOS/serenity/issues/24252 Reviewed-by: https://github.com/kalenikaliaksandr ✅
|
@ -116,6 +116,8 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
|||
arguments.append("--use-lagom-networking"sv);
|
||||
if (web_content_options.enable_gpu_painting == Ladybird::EnableGPUPainting::Yes)
|
||||
arguments.append("--use-gpu-painting"sv);
|
||||
if (web_content_options.enable_experimental_cpu_transforms == Ladybird::EnableExperimentalCPUTransforms::Yes)
|
||||
arguments.append("--experimental-cpu-transforms"sv);
|
||||
if (web_content_options.wait_for_debugger == Ladybird::WaitForDebugger::Yes)
|
||||
arguments.append("--wait-for-debugger"sv);
|
||||
if (web_content_options.log_all_js_exceptions == Ladybird::LogAllJSExceptions::Yes)
|
||||
|
|
|
@ -100,6 +100,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
bool enable_qt_networking = false;
|
||||
bool expose_internals_object = false;
|
||||
bool use_gpu_painting = false;
|
||||
bool use_experimental_cpu_transform_support = false;
|
||||
bool debug_web_content = false;
|
||||
bool log_all_js_exceptions = false;
|
||||
bool enable_idl_tracing = false;
|
||||
|
@ -113,6 +114,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
args_parser.add_option(disable_sql_database, "Disable SQL database", "disable-sql-database");
|
||||
args_parser.add_option(enable_qt_networking, "Enable Qt as the backend networking service", "enable-qt-networking");
|
||||
args_parser.add_option(use_gpu_painting, "Enable GPU painting", "enable-gpu-painting");
|
||||
args_parser.add_option(use_experimental_cpu_transform_support, "Enable experimental CPU transform support", "experimental-cpu-transforms");
|
||||
args_parser.add_option(debug_web_content, "Wait for debugger to attach to WebContent", "debug-web-content");
|
||||
args_parser.add_option(certificates, "Path to a certificate file", "certificate", 'C', "certificate");
|
||||
args_parser.add_option(log_all_js_exceptions, "Log all JavaScript exceptions", "log-all-js-exceptions");
|
||||
|
@ -177,6 +179,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
.executable_path = MUST(String::from_byte_string(MUST(Core::System::current_executable_path()))),
|
||||
.enable_callgrind_profiling = enable_callgrind_profiling ? Ladybird::EnableCallgrindProfiling::Yes : Ladybird::EnableCallgrindProfiling::No,
|
||||
.enable_gpu_painting = use_gpu_painting ? Ladybird::EnableGPUPainting::Yes : Ladybird::EnableGPUPainting::No,
|
||||
.enable_experimental_cpu_transforms = use_experimental_cpu_transform_support ? Ladybird::EnableExperimentalCPUTransforms::Yes : Ladybird::EnableExperimentalCPUTransforms::No,
|
||||
.use_lagom_networking = enable_qt_networking ? Ladybird::UseLagomNetworking::No : Ladybird::UseLagomNetworking::Yes,
|
||||
.wait_for_debugger = debug_web_content ? Ladybird::WaitForDebugger::Yes : Ladybird::WaitForDebugger::No,
|
||||
.log_all_js_exceptions = log_all_js_exceptions ? Ladybird::LogAllJSExceptions::Yes : Ladybird::LogAllJSExceptions::No,
|
||||
|
|
|
@ -20,6 +20,11 @@ enum class EnableGPUPainting {
|
|||
Yes
|
||||
};
|
||||
|
||||
enum class EnableExperimentalCPUTransforms {
|
||||
No,
|
||||
Yes
|
||||
};
|
||||
|
||||
enum class IsLayoutTestMode {
|
||||
No,
|
||||
Yes
|
||||
|
@ -55,6 +60,7 @@ struct WebContentOptions {
|
|||
String executable_path;
|
||||
EnableCallgrindProfiling enable_callgrind_profiling { EnableCallgrindProfiling::No };
|
||||
EnableGPUPainting enable_gpu_painting { EnableGPUPainting::No };
|
||||
EnableExperimentalCPUTransforms enable_experimental_cpu_transforms { EnableExperimentalCPUTransforms::No };
|
||||
IsLayoutTestMode is_layout_test_mode { IsLayoutTestMode::No };
|
||||
UseLagomNetworking use_lagom_networking { UseLagomNetworking::Yes };
|
||||
WaitForDebugger wait_for_debugger { WaitForDebugger::No };
|
||||
|
|
|
@ -97,6 +97,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
bool expose_internals_object = false;
|
||||
bool use_lagom_networking = false;
|
||||
bool use_gpu_painting = false;
|
||||
bool use_experimental_cpu_transform_support = false;
|
||||
bool wait_for_debugger = false;
|
||||
bool log_all_js_exceptions = false;
|
||||
bool enable_idl_tracing = false;
|
||||
|
@ -109,6 +110,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
args_parser.add_option(expose_internals_object, "Expose internals object", "expose-internals-object");
|
||||
args_parser.add_option(use_lagom_networking, "Enable Lagom servers for networking", "use-lagom-networking");
|
||||
args_parser.add_option(use_gpu_painting, "Enable GPU painting", "use-gpu-painting");
|
||||
args_parser.add_option(use_experimental_cpu_transform_support, "Enable experimental CPU transform support", "experimental-cpu-transforms");
|
||||
args_parser.add_option(wait_for_debugger, "Wait for debugger", "wait-for-debugger");
|
||||
args_parser.add_option(mach_server_name, "Mach server name", "mach-server-name", 0, "mach_server_name");
|
||||
args_parser.add_option(log_all_js_exceptions, "Log all JavaScript exceptions", "log-all-js-exceptions");
|
||||
|
@ -130,6 +132,10 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
WebContent::PageClient::set_use_gpu_painter();
|
||||
}
|
||||
|
||||
if (use_experimental_cpu_transform_support) {
|
||||
WebContent::PageClient::set_use_experimental_cpu_transform_support();
|
||||
}
|
||||
|
||||
#if defined(AK_OS_MACOS)
|
||||
if (!mach_server_name.is_empty()) {
|
||||
Core::Platform::register_with_mach_server(mach_server_name);
|
||||
|
|
|
@ -524,6 +524,7 @@ set(SOURCES
|
|||
Page/EventHandler.cpp
|
||||
Page/InputEvent.cpp
|
||||
Page/Page.cpp
|
||||
Painting/AffineCommandExecutorCPU.cpp
|
||||
Painting/AudioPaintable.cpp
|
||||
Painting/BackgroundPainting.cpp
|
||||
Painting/BorderRadiiData.cpp
|
||||
|
|
|
@ -15,8 +15,9 @@
|
|||
|
||||
namespace Web::Painting {
|
||||
|
||||
CommandExecutorCPU::CommandExecutorCPU(Gfx::Bitmap& bitmap)
|
||||
CommandExecutorCPU::CommandExecutorCPU(Gfx::Bitmap& bitmap, bool enable_affine_command_executor)
|
||||
: m_target_bitmap(bitmap)
|
||||
, m_enable_affine_command_executor(enable_affine_command_executor)
|
||||
{
|
||||
stacking_contexts.append({ .painter = AK::make<Gfx::Painter>(bitmap),
|
||||
.opacity = 1.0f,
|
||||
|
@ -127,6 +128,21 @@ CommandResult CommandExecutorCPU::clear_clip_rect(ClearClipRect const&)
|
|||
|
||||
CommandResult CommandExecutorCPU::push_stacking_context(PushStackingContext const& command)
|
||||
{
|
||||
// FIXME: This extracts the affine 2D part of the full transformation matrix.
|
||||
// Use the whole matrix when we get better transformation support in LibGfx or use LibGL for drawing the bitmap
|
||||
auto affine_transform = Gfx::extract_2d_affine_transform(command.transform.matrix);
|
||||
|
||||
if (m_enable_affine_command_executor && command.opacity == 1.0f && !affine_transform.is_identity_or_translation()) {
|
||||
auto offset = command.is_fixed_position ? Gfx::IntPoint {} : painter().translation();
|
||||
auto full_transform = Gfx::AffineTransform {}
|
||||
.set_translation((command.post_transform_translation + offset).to_type<float>())
|
||||
.translate(command.transform.origin)
|
||||
.multiply(affine_transform)
|
||||
.translate(-command.transform.origin);
|
||||
m_affine_command_executor = AffineCommandExecutorCPU(m_target_bitmap, full_transform, painter().clip_rect());
|
||||
return CommandResult::ContinueWithNestedExecutor;
|
||||
}
|
||||
|
||||
painter().save();
|
||||
if (command.is_fixed_position)
|
||||
painter().translate(-painter().translation());
|
||||
|
@ -148,10 +164,6 @@ CommandResult CommandExecutorCPU::push_stacking_context(PushStackingContext cons
|
|||
return CommandResult::Continue;
|
||||
}
|
||||
|
||||
// FIXME: This extracts the affine 2D part of the full transformation matrix.
|
||||
// Use the whole matrix when we get better transformation support in LibGfx or use LibGL for drawing the bitmap
|
||||
auto affine_transform = Gfx::extract_2d_affine_transform(command.transform.matrix);
|
||||
|
||||
if (command.opacity == 1.0f && affine_transform.is_identity_or_translation()) {
|
||||
// OPTIMIZATION: This is a simple translation use previous stacking context's painter.
|
||||
painter().translate(affine_transform.translation().to_rounded<int>() + command.post_transform_translation);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/MaybeOwned.h>
|
||||
#include <LibWeb/Painting/AffineCommandExecutorCPU.h>
|
||||
#include <LibWeb/Painting/RecordingPainter.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
@ -53,10 +54,17 @@ public:
|
|||
bool needs_update_immutable_bitmap_texture_cache() const override { return false; }
|
||||
void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&) override {};
|
||||
|
||||
CommandExecutorCPU(Gfx::Bitmap& bitmap);
|
||||
CommandExecutorCPU(Gfx::Bitmap& bitmap, bool enable_affine_command_executor = false);
|
||||
|
||||
CommandExecutor& nested_executor() override
|
||||
{
|
||||
return *m_affine_command_executor;
|
||||
}
|
||||
|
||||
private:
|
||||
Gfx::Bitmap& m_target_bitmap;
|
||||
bool m_enable_affine_command_executor { false };
|
||||
|
||||
Vector<RefPtr<BorderRadiusCornerClipper>> m_corner_clippers_stack;
|
||||
|
||||
struct StackingContext {
|
||||
|
@ -71,6 +79,7 @@ private:
|
|||
[[nodiscard]] Gfx::Painter& painter() { return *stacking_contexts.last().painter; }
|
||||
|
||||
Vector<StackingContext> stacking_contexts;
|
||||
Optional<AffineCommandExecutorCPU> m_affine_command_executor;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -309,7 +309,7 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
|
|||
border_radius_data.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x);
|
||||
borders_rect.inflate(outline_data->top.width + outline_offset_y, outline_data->right.width + outline_offset_x, outline_data->bottom.width + outline_offset_y, outline_data->left.width + outline_offset_x);
|
||||
|
||||
context.recording_painter().paint_borders(context.rounded_device_rect(borders_rect), border_radius_data.as_corners(context), outline_data->to_device_pixels(context));
|
||||
paint_all_borders(context.recording_painter(), context.rounded_device_rect(borders_rect), border_radius_data.as_corners(context), outline_data->to_device_pixels(context));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,7 +390,7 @@ void PaintableBox::paint_border(PaintContext& context) const
|
|||
.bottom = box_model().border.bottom == 0 ? CSS::BorderData() : computed_values().border_bottom(),
|
||||
.left = box_model().border.left == 0 ? CSS::BorderData() : computed_values().border_left(),
|
||||
};
|
||||
context.recording_painter().paint_borders(context.rounded_device_rect(absolute_border_box_rect()), normalized_border_radii_data().as_corners(context), borders_data.to_device_pixels(context));
|
||||
paint_all_borders(context.recording_painter(), context.rounded_device_rect(absolute_border_box_rect()), normalized_border_radii_data().as_corners(context), borders_data.to_device_pixels(context));
|
||||
}
|
||||
|
||||
void PaintableBox::paint_backdrop_filter(PaintContext& context) const
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
namespace WebContent {
|
||||
|
||||
static bool s_use_gpu_painter = false;
|
||||
static bool s_use_experimental_cpu_transform_support = false;
|
||||
|
||||
JS_DEFINE_ALLOCATOR(PageClient);
|
||||
|
||||
|
@ -45,6 +46,11 @@ void PageClient::set_use_gpu_painter()
|
|||
s_use_gpu_painter = true;
|
||||
}
|
||||
|
||||
void PageClient::set_use_experimental_cpu_transform_support()
|
||||
{
|
||||
s_use_experimental_cpu_transform_support = true;
|
||||
}
|
||||
|
||||
JS::NonnullGCPtr<PageClient> PageClient::create(JS::VM& vm, PageHost& page_host, u64 id)
|
||||
{
|
||||
return vm.heap().allocate_without_realm<PageClient>(page_host, id);
|
||||
|
@ -222,7 +228,7 @@ void PageClient::paint(Web::DevicePixelRect const& content_rect, Gfx::Bitmap& ta
|
|||
}
|
||||
#endif
|
||||
} else {
|
||||
Web::Painting::CommandExecutorCPU painting_command_executor(target);
|
||||
Web::Painting::CommandExecutorCPU painting_command_executor(target, s_use_experimental_cpu_transform_support);
|
||||
painting_commands.execute(painting_command_executor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
static JS::NonnullGCPtr<PageClient> create(JS::VM& vm, PageHost& page_host, u64 id);
|
||||
|
||||
static void set_use_gpu_painter();
|
||||
static void set_use_experimental_cpu_transform_support();
|
||||
|
||||
virtual void schedule_repaint() override;
|
||||
virtual bool is_ready_to_paint() const override;
|
||||
|
|
Loading…
Reference in a new issue