LibCore+LibWeb: Use Metal backend for Skia painter on macOS

If Metal context and IOSurface are available, Skia painter will use
Ganesh GPU backend on macOS, which is noticeably faster than the default
CPU backend.

Painting pipeline:
1. (WebContent) Allocate IOSurface for backing store
2. (WebContent) Allocate MTLTexture that wraps IOSurface
3. (WebContent) Paint into MTLTexture using Skia
4. (Browser) Wrap IOSurface into Gfx::Painter and use
   QPainter/CoreGraphics to blit backing store into viewport.

Things we should improve in the future:
1. Upload textures for images in advance instead of doing that before
   every repaint.
2. Teach AppKit client to read directly from IOSurface instead of
   copying.
This commit is contained in:
Aliaksandr Kalenik 2024-06-26 17:56:55 +02:00 committed by Alexander Kalenik
commit 79acb998e1
Notes: sideshowbarker 2024-07-16 20:05:14 +09:00
10 changed files with 288 additions and 21 deletions

View file

@ -18,7 +18,6 @@
#include <LibWeb/HTML/Window.h>
#include <LibWeb/Page/Page.h>
#include <LibWeb/Painting/DisplayListPlayerCPU.h>
#include <LibWeb/Painting/DisplayListPlayerSkia.h>
#include <LibWeb/Platform/EventLoopPlugin.h>
#ifdef HAS_ACCELERATED_GRAPHICS
@ -33,6 +32,10 @@ TraversableNavigable::TraversableNavigable(JS::NonnullGCPtr<Page> page)
: Navigable(page)
, m_session_history_traversal_queue(vm().heap().allocate_without_realm<SessionHistoryTraversalQueue>())
{
#ifdef AK_OS_MACOS
m_metal_context = Core::get_metal_context();
m_skia_backend_context = Web::Painting::DisplayListPlayerSkia::create_metal_context(*m_metal_context);
#endif
}
TraversableNavigable::~TraversableNavigable() = default;
@ -1174,10 +1177,8 @@ JS::GCPtr<DOM::Node> TraversableNavigable::currently_focused_area()
return candidate;
}
void TraversableNavigable::paint(Web::DevicePixelRect const& content_rect, Painting::BackingStore& backing_store, Web::PaintOptions paint_options)
void TraversableNavigable::paint(Web::DevicePixelRect const& content_rect, Painting::BackingStore& target, Web::PaintOptions paint_options)
{
auto& target = backing_store.bitmap();
Painting::DisplayList display_list;
Painting::DisplayListRecorder display_list_recorder(display_list);
@ -1193,7 +1194,7 @@ void TraversableNavigable::paint(Web::DevicePixelRect const& content_rect, Paint
auto display_list_player_type = page().client().display_list_player_type();
if (display_list_player_type == DisplayListPlayerType::GPU) {
#ifdef HAS_ACCELERATED_GRAPHICS
Web::Painting::DisplayListPlayerGPU player(*paint_options.accelerated_graphics_context, target);
Web::Painting::DisplayListPlayerGPU player(*paint_options.accelerated_graphics_context, target.bitmap());
display_list.execute(player);
#else
static bool has_warned_about_configuration = false;
@ -1204,10 +1205,19 @@ void TraversableNavigable::paint(Web::DevicePixelRect const& content_rect, Paint
}
#endif
} else if (display_list_player_type == DisplayListPlayerType::Skia) {
Painting::DisplayListPlayerSkia player(target);
#ifdef AK_OS_MACOS
if (m_metal_context && m_skia_backend_context && is<Painting::IOSurfaceBackingStore>(target)) {
auto& iosurface_backing_store = static_cast<Painting::IOSurfaceBackingStore&>(target);
auto texture = m_metal_context->create_texture_from_iosurface(iosurface_backing_store.iosurface_handle());
Painting::DisplayListPlayerSkia player(*m_skia_backend_context, *texture);
display_list.execute(player);
return;
}
#endif
Web::Painting::DisplayListPlayerSkia player(target.bitmap());
display_list.execute(player);
} else {
Web::Painting::DisplayListPlayerCPU player(target);
Web::Painting::DisplayListPlayerCPU player(target.bitmap());
display_list.execute(player);
}
}