mirror of
https://github.com/fergalmoran/ladybird.git
synced 2026-01-04 15:45:25 +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:
@@ -116,6 +116,8 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
|||||||
arguments.append("--use-lagom-networking"sv);
|
arguments.append("--use-lagom-networking"sv);
|
||||||
if (web_content_options.enable_gpu_painting == Ladybird::EnableGPUPainting::Yes)
|
if (web_content_options.enable_gpu_painting == Ladybird::EnableGPUPainting::Yes)
|
||||||
arguments.append("--use-gpu-painting"sv);
|
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)
|
if (web_content_options.wait_for_debugger == Ladybird::WaitForDebugger::Yes)
|
||||||
arguments.append("--wait-for-debugger"sv);
|
arguments.append("--wait-for-debugger"sv);
|
||||||
if (web_content_options.log_all_js_exceptions == Ladybird::LogAllJSExceptions::Yes)
|
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 enable_qt_networking = false;
|
||||||
bool expose_internals_object = false;
|
bool expose_internals_object = false;
|
||||||
bool use_gpu_painting = false;
|
bool use_gpu_painting = false;
|
||||||
|
bool use_experimental_cpu_transform_support = false;
|
||||||
bool debug_web_content = false;
|
bool debug_web_content = false;
|
||||||
bool log_all_js_exceptions = false;
|
bool log_all_js_exceptions = false;
|
||||||
bool enable_idl_tracing = 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(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(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_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(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(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");
|
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()))),
|
.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_callgrind_profiling = enable_callgrind_profiling ? Ladybird::EnableCallgrindProfiling::Yes : Ladybird::EnableCallgrindProfiling::No,
|
||||||
.enable_gpu_painting = use_gpu_painting ? Ladybird::EnableGPUPainting::Yes : Ladybird::EnableGPUPainting::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,
|
.use_lagom_networking = enable_qt_networking ? Ladybird::UseLagomNetworking::No : Ladybird::UseLagomNetworking::Yes,
|
||||||
.wait_for_debugger = debug_web_content ? Ladybird::WaitForDebugger::Yes : Ladybird::WaitForDebugger::No,
|
.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,
|
.log_all_js_exceptions = log_all_js_exceptions ? Ladybird::LogAllJSExceptions::Yes : Ladybird::LogAllJSExceptions::No,
|
||||||
|
|||||||
@@ -20,6 +20,11 @@ enum class EnableGPUPainting {
|
|||||||
Yes
|
Yes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class EnableExperimentalCPUTransforms {
|
||||||
|
No,
|
||||||
|
Yes
|
||||||
|
};
|
||||||
|
|
||||||
enum class IsLayoutTestMode {
|
enum class IsLayoutTestMode {
|
||||||
No,
|
No,
|
||||||
Yes
|
Yes
|
||||||
@@ -55,6 +60,7 @@ struct WebContentOptions {
|
|||||||
String executable_path;
|
String executable_path;
|
||||||
EnableCallgrindProfiling enable_callgrind_profiling { EnableCallgrindProfiling::No };
|
EnableCallgrindProfiling enable_callgrind_profiling { EnableCallgrindProfiling::No };
|
||||||
EnableGPUPainting enable_gpu_painting { EnableGPUPainting::No };
|
EnableGPUPainting enable_gpu_painting { EnableGPUPainting::No };
|
||||||
|
EnableExperimentalCPUTransforms enable_experimental_cpu_transforms { EnableExperimentalCPUTransforms::No };
|
||||||
IsLayoutTestMode is_layout_test_mode { IsLayoutTestMode::No };
|
IsLayoutTestMode is_layout_test_mode { IsLayoutTestMode::No };
|
||||||
UseLagomNetworking use_lagom_networking { UseLagomNetworking::Yes };
|
UseLagomNetworking use_lagom_networking { UseLagomNetworking::Yes };
|
||||||
WaitForDebugger wait_for_debugger { WaitForDebugger::No };
|
WaitForDebugger wait_for_debugger { WaitForDebugger::No };
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||||||
bool expose_internals_object = false;
|
bool expose_internals_object = false;
|
||||||
bool use_lagom_networking = false;
|
bool use_lagom_networking = false;
|
||||||
bool use_gpu_painting = false;
|
bool use_gpu_painting = false;
|
||||||
|
bool use_experimental_cpu_transform_support = false;
|
||||||
bool wait_for_debugger = false;
|
bool wait_for_debugger = false;
|
||||||
bool log_all_js_exceptions = false;
|
bool log_all_js_exceptions = false;
|
||||||
bool enable_idl_tracing = 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(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_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_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(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(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");
|
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();
|
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 defined(AK_OS_MACOS)
|
||||||
if (!mach_server_name.is_empty()) {
|
if (!mach_server_name.is_empty()) {
|
||||||
Core::Platform::register_with_mach_server(mach_server_name);
|
Core::Platform::register_with_mach_server(mach_server_name);
|
||||||
|
|||||||
@@ -524,6 +524,7 @@ set(SOURCES
|
|||||||
Page/EventHandler.cpp
|
Page/EventHandler.cpp
|
||||||
Page/InputEvent.cpp
|
Page/InputEvent.cpp
|
||||||
Page/Page.cpp
|
Page/Page.cpp
|
||||||
|
Painting/AffineCommandExecutorCPU.cpp
|
||||||
Painting/AudioPaintable.cpp
|
Painting/AudioPaintable.cpp
|
||||||
Painting/BackgroundPainting.cpp
|
Painting/BackgroundPainting.cpp
|
||||||
Painting/BorderRadiiData.cpp
|
Painting/BorderRadiiData.cpp
|
||||||
|
|||||||
@@ -15,8 +15,9 @@
|
|||||||
|
|
||||||
namespace Web::Painting {
|
namespace Web::Painting {
|
||||||
|
|
||||||
CommandExecutorCPU::CommandExecutorCPU(Gfx::Bitmap& bitmap)
|
CommandExecutorCPU::CommandExecutorCPU(Gfx::Bitmap& bitmap, bool enable_affine_command_executor)
|
||||||
: m_target_bitmap(bitmap)
|
: m_target_bitmap(bitmap)
|
||||||
|
, m_enable_affine_command_executor(enable_affine_command_executor)
|
||||||
{
|
{
|
||||||
stacking_contexts.append({ .painter = AK::make<Gfx::Painter>(bitmap),
|
stacking_contexts.append({ .painter = AK::make<Gfx::Painter>(bitmap),
|
||||||
.opacity = 1.0f,
|
.opacity = 1.0f,
|
||||||
@@ -127,6 +128,21 @@ CommandResult CommandExecutorCPU::clear_clip_rect(ClearClipRect const&)
|
|||||||
|
|
||||||
CommandResult CommandExecutorCPU::push_stacking_context(PushStackingContext const& command)
|
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();
|
painter().save();
|
||||||
if (command.is_fixed_position)
|
if (command.is_fixed_position)
|
||||||
painter().translate(-painter().translation());
|
painter().translate(-painter().translation());
|
||||||
@@ -148,10 +164,6 @@ CommandResult CommandExecutorCPU::push_stacking_context(PushStackingContext cons
|
|||||||
return CommandResult::Continue;
|
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()) {
|
if (command.opacity == 1.0f && affine_transform.is_identity_or_translation()) {
|
||||||
// OPTIMIZATION: This is a simple translation use previous stacking context's painter.
|
// OPTIMIZATION: This is a simple translation use previous stacking context's painter.
|
||||||
painter().translate(affine_transform.translation().to_rounded<int>() + command.post_transform_translation);
|
painter().translate(affine_transform.translation().to_rounded<int>() + command.post_transform_translation);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/MaybeOwned.h>
|
#include <AK/MaybeOwned.h>
|
||||||
|
#include <LibWeb/Painting/AffineCommandExecutorCPU.h>
|
||||||
#include <LibWeb/Painting/RecordingPainter.h>
|
#include <LibWeb/Painting/RecordingPainter.h>
|
||||||
|
|
||||||
namespace Web::Painting {
|
namespace Web::Painting {
|
||||||
@@ -53,10 +54,17 @@ public:
|
|||||||
bool needs_update_immutable_bitmap_texture_cache() const override { return false; }
|
bool needs_update_immutable_bitmap_texture_cache() const override { return false; }
|
||||||
void update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>&) override {};
|
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:
|
private:
|
||||||
Gfx::Bitmap& m_target_bitmap;
|
Gfx::Bitmap& m_target_bitmap;
|
||||||
|
bool m_enable_affine_command_executor { false };
|
||||||
|
|
||||||
Vector<RefPtr<BorderRadiusCornerClipper>> m_corner_clippers_stack;
|
Vector<RefPtr<BorderRadiusCornerClipper>> m_corner_clippers_stack;
|
||||||
|
|
||||||
struct StackingContext {
|
struct StackingContext {
|
||||||
@@ -71,6 +79,7 @@ private:
|
|||||||
[[nodiscard]] Gfx::Painter& painter() { return *stacking_contexts.last().painter; }
|
[[nodiscard]] Gfx::Painter& painter() { return *stacking_contexts.last().painter; }
|
||||||
|
|
||||||
Vector<StackingContext> stacking_contexts;
|
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);
|
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);
|
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(),
|
.bottom = box_model().border.bottom == 0 ? CSS::BorderData() : computed_values().border_bottom(),
|
||||||
.left = box_model().border.left == 0 ? CSS::BorderData() : computed_values().border_left(),
|
.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
|
void PaintableBox::paint_backdrop_filter(PaintContext& context) const
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
namespace WebContent {
|
namespace WebContent {
|
||||||
|
|
||||||
static bool s_use_gpu_painter = false;
|
static bool s_use_gpu_painter = false;
|
||||||
|
static bool s_use_experimental_cpu_transform_support = false;
|
||||||
|
|
||||||
JS_DEFINE_ALLOCATOR(PageClient);
|
JS_DEFINE_ALLOCATOR(PageClient);
|
||||||
|
|
||||||
@@ -45,6 +46,11 @@ void PageClient::set_use_gpu_painter()
|
|||||||
s_use_gpu_painter = true;
|
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)
|
JS::NonnullGCPtr<PageClient> PageClient::create(JS::VM& vm, PageHost& page_host, u64 id)
|
||||||
{
|
{
|
||||||
return vm.heap().allocate_without_realm<PageClient>(page_host, 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
|
#endif
|
||||||
} else {
|
} 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);
|
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 JS::NonnullGCPtr<PageClient> create(JS::VM& vm, PageHost& page_host, u64 id);
|
||||||
|
|
||||||
static void set_use_gpu_painter();
|
static void set_use_gpu_painter();
|
||||||
|
static void set_use_experimental_cpu_transform_support();
|
||||||
|
|
||||||
virtual void schedule_repaint() override;
|
virtual void schedule_repaint() override;
|
||||||
virtual bool is_ready_to_paint() const override;
|
virtual bool is_ready_to_paint() const override;
|
||||||
|
|||||||
Reference in New Issue
Block a user