mirror of
https://github.com/fergalmoran/ladybird.git
synced 2026-01-03 15:16:14 +00:00
LibWeb+LibGfx: Use GPU backend for <canvas>
This is implemented by using a GPU-accelerated surface for <canvas> when a GPU context is available. A side effect of this change is that all canvas modifications have to be performed through Gfx::Painter, and whenever its content has to be accessed, we need to take a snapshot of the corresponding GPU surface. A new DrawPaintingSurface display list command is introduced to allow cheap blitting of canvas content without having to read GPU surface content into RAM.
This commit is contained in:
committed by
Alexander Kalenik
parent
ab9ecbd79d
commit
a7cbc7a6b8
@@ -21,6 +21,7 @@
|
||||
#include <LibWeb/HTML/HTMLCanvasElement.h>
|
||||
#include <LibWeb/HTML/Numbers.h>
|
||||
#include <LibWeb/HTML/Scripting/ExceptionReporter.h>
|
||||
#include <LibWeb/HTML/TraversableNavigable.h>
|
||||
#include <LibWeb/Layout/CanvasBox.h>
|
||||
#include <LibWeb/Platform/EventLoopPlugin.h>
|
||||
#include <LibWeb/WebIDL/AbstractOperations.h>
|
||||
@@ -115,7 +116,7 @@ void HTMLCanvasElement::reset_context_to_default_state()
|
||||
WebIDL::ExceptionOr<void> HTMLCanvasElement::set_width(unsigned value)
|
||||
{
|
||||
TRY(set_attribute(HTML::AttributeNames::width, String::number(value)));
|
||||
m_bitmap = nullptr;
|
||||
m_surface = nullptr;
|
||||
reset_context_to_default_state();
|
||||
return {};
|
||||
}
|
||||
@@ -123,7 +124,7 @@ WebIDL::ExceptionOr<void> HTMLCanvasElement::set_width(unsigned value)
|
||||
WebIDL::ExceptionOr<void> HTMLCanvasElement::set_height(unsigned value)
|
||||
{
|
||||
TRY(set_attribute(HTML::AttributeNames::height, String::number(value)));
|
||||
m_bitmap = nullptr;
|
||||
m_surface = nullptr;
|
||||
reset_context_to_default_state();
|
||||
return {};
|
||||
}
|
||||
@@ -204,20 +205,23 @@ static Gfx::IntSize bitmap_size_for_canvas(HTMLCanvasElement const& canvas, size
|
||||
return Gfx::IntSize(width, height);
|
||||
}
|
||||
|
||||
bool HTMLCanvasElement::create_bitmap(size_t minimum_width, size_t minimum_height)
|
||||
bool HTMLCanvasElement::allocate_painting_surface(size_t minimum_width, size_t minimum_height)
|
||||
{
|
||||
if (m_surface)
|
||||
return true;
|
||||
|
||||
auto traversable = document().navigable()->traversable_navigable();
|
||||
VERIFY(traversable);
|
||||
|
||||
auto size = bitmap_size_for_canvas(*this, minimum_width, minimum_height);
|
||||
if (size.is_empty()) {
|
||||
m_bitmap = nullptr;
|
||||
m_surface = nullptr;
|
||||
return false;
|
||||
}
|
||||
if (!m_bitmap || m_bitmap->size() != size) {
|
||||
auto bitmap_or_error = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied, size);
|
||||
if (bitmap_or_error.is_error())
|
||||
return false;
|
||||
m_bitmap = bitmap_or_error.release_value_but_fixme_should_propagate_errors();
|
||||
if (!m_surface || m_surface->size() != size) {
|
||||
m_surface = Gfx::PaintingSurface::create_with_size(traversable->skia_backend_context(), size, Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied);
|
||||
}
|
||||
return m_bitmap;
|
||||
return m_surface;
|
||||
}
|
||||
|
||||
struct SerializeBitmapResult {
|
||||
@@ -252,18 +256,19 @@ static ErrorOr<SerializeBitmapResult> serialize_bitmap(Gfx::Bitmap const& bitmap
|
||||
String HTMLCanvasElement::to_data_url(StringView type, Optional<double> quality)
|
||||
{
|
||||
// It is possible the the canvas doesn't have a associated bitmap so create one
|
||||
if (!bitmap())
|
||||
create_bitmap();
|
||||
if (!m_surface) {
|
||||
allocate_painting_surface();
|
||||
}
|
||||
|
||||
// FIXME: 1. If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.
|
||||
|
||||
// 2. If this canvas element's bitmap has no pixels (i.e. either its horizontal dimension or its vertical dimension is zero)
|
||||
// then return the string "data:,". (This is the shortest data: URL; it represents the empty string in a text/plain resource.)
|
||||
if (!m_bitmap)
|
||||
if (!m_surface)
|
||||
return "data:,"_string;
|
||||
|
||||
// 3. Let file be a serialization of this canvas element's bitmap as a file, passing type and quality if given.
|
||||
auto file = serialize_bitmap(*m_bitmap, type, move(quality));
|
||||
auto file = serialize_bitmap(*m_surface->create_snapshot(), type, move(quality));
|
||||
|
||||
// 4. If file is null then return "data:,".
|
||||
if (file.is_error()) {
|
||||
@@ -283,8 +288,9 @@ String HTMLCanvasElement::to_data_url(StringView type, Optional<double> quality)
|
||||
WebIDL::ExceptionOr<void> HTMLCanvasElement::to_blob(JS::NonnullGCPtr<WebIDL::CallbackType> callback, StringView type, Optional<double> quality)
|
||||
{
|
||||
// It is possible the the canvas doesn't have a associated bitmap so create one
|
||||
if (!bitmap())
|
||||
create_bitmap();
|
||||
if (!m_surface) {
|
||||
allocate_painting_surface();
|
||||
}
|
||||
|
||||
// FIXME: 1. If this canvas element's bitmap's origin-clean flag is set to false, then throw a "SecurityError" DOMException.
|
||||
|
||||
@@ -293,8 +299,9 @@ WebIDL::ExceptionOr<void> HTMLCanvasElement::to_blob(JS::NonnullGCPtr<WebIDL::Ca
|
||||
|
||||
// 3. If this canvas element's bitmap has pixels (i.e., neither its horizontal dimension nor its vertical dimension is zero),
|
||||
// then set result to a copy of this canvas element's bitmap.
|
||||
if (m_bitmap)
|
||||
bitmap_result = TRY_OR_THROW_OOM(vm(), m_bitmap->clone());
|
||||
if (m_surface) {
|
||||
bitmap_result = m_surface->create_snapshot();
|
||||
}
|
||||
|
||||
// 4. Run these steps in parallel:
|
||||
Platform::EventLoopPlugin::the().deferred_invoke(JS::create_heap_function(heap(), [this, callback, bitmap_result, type, quality] {
|
||||
@@ -326,6 +333,10 @@ WebIDL::ExceptionOr<void> HTMLCanvasElement::to_blob(JS::NonnullGCPtr<WebIDL::Ca
|
||||
|
||||
void HTMLCanvasElement::present()
|
||||
{
|
||||
if (m_surface) {
|
||||
m_surface->flush();
|
||||
}
|
||||
|
||||
m_context.visit(
|
||||
[](JS::NonnullGCPtr<CanvasRenderingContext2D>&) {
|
||||
// Do nothing, CRC2D writes directly to the canvas bitmap.
|
||||
|
||||
Reference in New Issue
Block a user