LibWeb+Compositor: Move OpenGLContext in Compositor namespace

This commit is contained in:
Aliaksandr Kalenik 2026-06-17 06:18:58 +02:00 committed by Alexander Kalenik
parent 7efdb8a900
commit 54a07a08b4
12 changed files with 114 additions and 88 deletions

View file

@ -1149,6 +1149,7 @@ set(SOURCES
WebGL/Extensions/WebGLDebugRendererInfo.cpp
WebGL/Extensions/WebGLDrawBuffers.cpp
WebGL/Extensions/WebGLVertexArrayObjectOES.cpp
WebGL/TextureUpload.cpp
WebGL/WebGL2RenderingContext.cpp
WebGL/WebGL2RenderingContextImpl.cpp
WebGL/WebGL2RenderingContextOverloads.cpp
@ -1256,12 +1257,12 @@ set(GENERATED_SOURCES
Worker/WebWorkerServerEndpoint.h
HTML/MediaControlsDOM.cpp
HTML/Parser/NamedCharacterReferences.cpp
WebGL/GLFunctions.cpp
WebGL/WebGLCommands.cpp
WebGL/WebGLContextProxy.cpp
)
ladybird_lib(LibWeb web EXPLICIT_SYMBOL_EXPORT)
add_dependencies(LibWeb generate_GLFunctions.cpp)
target_link_libraries(LibWeb PRIVATE LibCore LibCompress LibCrypto LibJS LibHTTP LibGfx LibIPC LibRegex LibSyntax LibTextCodec LibUnicode LibMedia LibWasm LibXML LibURL LibTLS LibRequests LibGC LibSync LibThreading skia ${ANGLE_TARGETS} SDL3::SDL3 LibXml2::LibXml2)

View file

@ -1311,7 +1311,6 @@ enum class AudioContextState;
namespace Web::WebGL {
class OpenGLContext;
class RemoteWebGLTransport;
class WebGLContextProxy;
class WebGL2RenderingContext;

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <GLES2/gl2.h>
#include <AK/Debug.h>
#include <LibWeb/WebGL/TextureUpload.h>
namespace Web::WebGL {
Optional<Gfx::ExportFormat> texture_export_format(GLenum format, GLenum type)
{
switch (format) {
case GL_RGB:
switch (type) {
case GL_UNSIGNED_BYTE:
return Gfx::ExportFormat::RGB888;
case GL_UNSIGNED_SHORT_5_6_5:
return Gfx::ExportFormat::RGB565;
default:
break;
}
break;
case GL_RGBA:
switch (type) {
case GL_UNSIGNED_BYTE:
return Gfx::ExportFormat::RGBA8888;
case GL_UNSIGNED_SHORT_4_4_4_4:
// FIXME: This is not exactly the same as RGBA.
return Gfx::ExportFormat::RGBA4444;
case GL_UNSIGNED_SHORT_5_5_5_1:
return Gfx::ExportFormat::RGBA5551;
default:
break;
}
break;
case GL_ALPHA:
switch (type) {
case GL_UNSIGNED_BYTE:
return Gfx::ExportFormat::Alpha8;
default:
break;
}
break;
case GL_LUMINANCE:
switch (type) {
case GL_UNSIGNED_BYTE:
return Gfx::ExportFormat::Gray8;
default:
break;
}
break;
default:
break;
}
dbgln("WebGL: Unsupported format and type combination. format: 0x{:04x}, type: 0x{:04x}", format, type);
return {};
}
}

View file

@ -0,0 +1,18 @@
/*
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Optional.h>
#include <LibGfx/BitmapExport.h>
#include <LibWeb/Export.h>
#include <LibWeb/WebGL/Types.h>
namespace Web::WebGL {
WEB_API Optional<Gfx::ExportFormat> texture_export_format(GLenum format, GLenum type);
}

View file

@ -11,7 +11,6 @@ extern "C" {
#include <GLES2/gl2ext_angle.h>
}
#include <Compositor/OpenGLContext.h>
#include <LibGfx/DecodedImageFrame.h>
#include <LibWeb/HTML/DecodedImageData.h>
#include <LibWeb/HTML/EventLoop/Task.h>
@ -37,6 +36,7 @@ extern "C" {
#include <LibWeb/WebGL/Extensions/WebGLCompressedTextureS3tcSrgb.h>
#include <LibWeb/WebGL/Extensions/WebGLDebugRendererInfo.h>
#include <LibWeb/WebGL/Extensions/WebGLDrawBuffers.h>
#include <LibWeb/WebGL/TextureUpload.h>
#include <LibWeb/WebGL/WebGLContextProxy.h>
#include <LibWeb/WebGL/WebGLRenderingContext.h>
#include <LibWeb/WebGL/WebGLRenderingContextBase.h>

View file

@ -152,7 +152,7 @@ def signature(function: dict, payload_used: bool) -> str:
objects = "WebGLObjectMap& objects" if uses_objects else "WebGLObjectMap&"
payload = "ReadonlyBytes payload" if payload_used else "ReadonlyBytes"
return (
f"ErrorOr<void> replay_webgl_command(Web::WebGL::OpenGLContext& gl, {objects}, "
f"ErrorOr<void> replay_webgl_command(OpenGLContext& gl, {objects}, "
f"Web::WebGL::Commands::{command_name(function)} {command}, {payload})"
)
@ -247,8 +247,7 @@ def sync_signature(function: dict, payload_used: bool, objects_used: bool) -> st
objects = "WebGLObjectMap& objects" if objects_used else "WebGLObjectMap&"
payload = "ReadonlyBytes payload" if payload_used else "ReadonlyBytes"
return (
f"static ByteBuffer handle_one(Web::WebGL::OpenGLContext& gl, {objects}, "
f"SyncCalls::{name}::Request {request}, {payload})"
f"static ByteBuffer handle_one(OpenGLContext& gl, {objects}, SyncCalls::{name}::Request {request}, {payload})"
)
@ -266,7 +265,7 @@ namespace Compositor {
if function["category"] not in ("command", "gen"):
continue
out.write(
f"ErrorOr<void> replay_webgl_command(Web::WebGL::OpenGLContext&, WebGLObjectMap&, "
f"ErrorOr<void> replay_webgl_command(OpenGLContext&, WebGLObjectMap&, "
f"Web::WebGL::Commands::{command_name(function)} const&, ReadonlyBytes);\n"
)
out.write("""
@ -277,17 +276,17 @@ namespace Compositor {
for function in functions:
if function["category"] == "custom" and is_wire_command(function):
out.write(
f"ErrorOr<void> replay_webgl_command(Web::WebGL::OpenGLContext&, WebGLObjectMap&, "
f"ErrorOr<void> replay_webgl_command(OpenGLContext&, WebGLObjectMap&, "
f"Web::WebGL::Commands::{command_name(function)} const&, ReadonlyBytes);\n"
)
for function in functions:
if is_wire_sync(function):
out.write(
f"ErrorOr<ByteBuffer> handle_one(Web::WebGL::OpenGLContext&, WebGLObjectMap&, "
f"ErrorOr<ByteBuffer> handle_one(OpenGLContext&, WebGLObjectMap&, "
f"Web::WebGL::SyncCalls::{command_name(function)}::Request const&, ReadonlyBytes);\n"
)
out.write("""
ErrorOr<ByteBuffer> handle_webgl_sync_call(Web::WebGL::OpenGLContext&, WebGLObjectMap&, ReadonlyBytes request);
ErrorOr<ByteBuffer> handle_webgl_sync_call(OpenGLContext&, WebGLObjectMap&, ReadonlyBytes request);
}
""")
@ -324,7 +323,7 @@ using namespace Web::WebGL;
out.write(body.getvalue())
out.write("}\n\n")
out.write("""ErrorOr<ByteBuffer> handle_webgl_sync_call(Web::WebGL::OpenGLContext& gl, WebGLObjectMap& objects, ReadonlyBytes request)
out.write("""ErrorOr<ByteBuffer> handle_webgl_sync_call(OpenGLContext& gl, WebGLObjectMap& objects, ReadonlyBytes request)
{
return WebGLSyncCall::dispatch_request(request, [&]<typename Call>(typename Call::Request const& call_request, ReadonlyBytes payload) -> ErrorOr<ByteBuffer> {
return handle_one(gl, objects, call_request, payload);

View file

@ -15,7 +15,7 @@ from libweb_webgl import method_signature
from libweb_webgl import run_generator
# Generates Web::WebGL::GLFunctions from GLFunctions.json: one member function per GL
# entry point used by the WebGL implementation. This is the only place in LibWeb that is
# entry point used by the host WebGL implementation. This is the only place that is
# allowed to call GL entry points directly; everything above it goes through the methods
# so the GL boundary stays in one generated, mechanically-verifiable layer.
@ -32,12 +32,11 @@ extern "C" {
}
#include <GLES3/gl3.h>
#include <LibWeb/Export.h>
#include <LibWeb/WebGL/Types.h>
namespace Web::WebGL {
class WEB_API GLFunctions {
class GLFunctions {
public:
""")

View file

@ -6,6 +6,7 @@ set(SOURCES
ConnectionFromClient.cpp
ConnectionFromWebContent.cpp
HostWebGLContext.cpp
OpenGLContext.cpp
VSyncScheduler.cpp
ViewportScrollbarController.cpp
WebGLObjectMap.cpp
@ -26,12 +27,10 @@ set(GENERATED_SOURCES
CompositorControlServerEndpoint.h
CompositorWebContentClientEndpoint.h
CompositorWebContentServerEndpoint.h
${CMAKE_BINARY_DIR}/Libraries/LibWeb/WebGL/GLFunctions.cpp
WebGLCommandReplayer.cpp
)
target_sources(LibWeb PRIVATE OpenGLContext.cpp)
target_include_directories(LibWeb PRIVATE ${LADYBIRD_SOURCE_DIR}/Services/)
add_library(compositorservice STATIC ${SOURCES} ${GENERATED_SOURCES})
ladybird_generated_sources(compositorservice)

View file

@ -13,6 +13,7 @@
#include <LibGfx/PaintingSurface.h>
#include <LibGfx/ShareableBitmap.h>
#include <LibGfx/SkiaBackendContext.h>
#include <LibWeb/WebGL/TextureUpload.h>
#include <LibWeb/WebGL/WebGLCommandList.h>
namespace Compositor {
@ -21,17 +22,17 @@ using namespace Web::WebGL;
static constexpr GLsizei max_webgl_string_list_entries = 16384;
HostWebGLContext::HostWebGLContext(NonnullOwnPtr<Web::WebGL::OpenGLContext> gl_context)
HostWebGLContext::HostWebGLContext(NonnullOwnPtr<OpenGLContext> gl_context)
: m_gl_context(move(gl_context))
{
}
OwnPtr<HostWebGLContext> HostWebGLContext::create(NonnullRefPtr<Gfx::SkiaBackendContext> skia_backend_context, Web::WebGL::OpenGLContext::WebGLVersion version, Web::WebGL::OpenGLContext::DrawingBufferOptions options, Gfx::IntSize initial_size)
OwnPtr<HostWebGLContext> HostWebGLContext::create(NonnullRefPtr<Gfx::SkiaBackendContext> skia_backend_context, OpenGLContext::WebGLVersion version, OpenGLContext::DrawingBufferOptions options, Gfx::IntSize initial_size)
{
if (initial_size.width() < 1 || initial_size.width() > max_webgl_drawing_buffer_dimension
|| initial_size.height() < 1 || initial_size.height() > max_webgl_drawing_buffer_dimension)
return {};
auto gl_context = Web::WebGL::OpenGLContext::create(skia_backend_context, version, options);
auto gl_context = OpenGLContext::create(skia_backend_context, version, options);
if (!gl_context)
return {};
gl_context->set_size(initial_size);
@ -207,7 +208,7 @@ ErrorOr<void> HostWebGLContext::set_drawing_buffer_size(int width, int height)
return {};
}
ErrorOr<void> replay_webgl_command(Web::WebGL::OpenGLContext& gl, WebGLObjectMap& objects, Commands::ShaderSource const& command, ReadonlyBytes payload)
ErrorOr<void> replay_webgl_command(OpenGLContext& gl, WebGLObjectMap& objects, Commands::ShaderSource const& command, ReadonlyBytes payload)
{
auto source_bytes = WebGLCommandList::resolve_string_span(payload, command.source);
auto shader = objects.lookup(command.shader);
@ -237,7 +238,7 @@ static ErrorOr<Vector<GLchar const*>> split_packed_strings(ReadonlyBytes bytes,
return strings;
}
ErrorOr<void> replay_webgl_command(Web::WebGL::OpenGLContext& gl, WebGLObjectMap& objects, Commands::TransformFeedbackVaryings const& command, ReadonlyBytes payload)
ErrorOr<void> replay_webgl_command(OpenGLContext& gl, WebGLObjectMap& objects, Commands::TransformFeedbackVaryings const& command, ReadonlyBytes payload)
{
auto varyings_bytes = WebGLCommandList::resolve_data_span(payload, command.varyings);
auto varyings = TRY(split_packed_strings(varyings_bytes, command.count));
@ -246,9 +247,7 @@ ErrorOr<void> replay_webgl_command(Web::WebGL::OpenGLContext& gl, WebGLObjectMap
return {};
}
// --- Wire-specified synchronous calls ------------------------------------------------
ErrorOr<ByteBuffer> handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap&, SyncCalls::GetString::Request const& request, ReadonlyBytes)
ErrorOr<ByteBuffer> handle_one(OpenGLContext& gl, WebGLObjectMap&, SyncCalls::GetString::Request const& request, ReadonlyBytes)
{
auto const* value = gl.get_string(request.name);
static constexpr u8 empty_string[] { 0 };
@ -261,7 +260,7 @@ ErrorOr<ByteBuffer> handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap&, S
return WebGLSyncCall::encode_reply(reply, value_bytes);
}
ErrorOr<ByteBuffer> handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap&, SyncCalls::GetVertexAttribPointervRobustANGLE::Request const& request, ReadonlyBytes)
ErrorOr<ByteBuffer> handle_one(OpenGLContext& gl, WebGLObjectMap&, SyncCalls::GetVertexAttribPointervRobustANGLE::Request const& request, ReadonlyBytes)
{
void* pointer = nullptr;
GLsizei length = 0;
@ -272,7 +271,7 @@ ErrorOr<ByteBuffer> handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap&, S
return WebGLSyncCall::encode_reply(reply);
}
ErrorOr<ByteBuffer> handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap& objects, SyncCalls::GetUniformIndices::Request const& request, ReadonlyBytes payload)
ErrorOr<ByteBuffer> handle_one(OpenGLContext& gl, WebGLObjectMap& objects, SyncCalls::GetUniformIndices::Request const& request, ReadonlyBytes payload)
{
auto names_bytes = WebGLCommandList::resolve_data_span(payload, request.uniform_names);
auto names = TRY(split_packed_strings(names_bytes, request.uniform_count));

View file

@ -30,7 +30,7 @@ namespace Compositor {
class HostWebGLContext {
public:
static OwnPtr<HostWebGLContext> create(NonnullRefPtr<Gfx::SkiaBackendContext>, Web::WebGL::OpenGLContext::WebGLVersion, Web::WebGL::OpenGLContext::DrawingBufferOptions, Gfx::IntSize initial_size);
static OwnPtr<HostWebGLContext> create(NonnullRefPtr<Gfx::SkiaBackendContext>, OpenGLContext::WebGLVersion, OpenGLContext::DrawingBufferOptions, Gfx::IntSize initial_size);
ErrorOr<void> execute_commands(ReadonlyBytes, Vector<Gfx::DecodedImageFrame> const& bitmaps);
ErrorOr<ByteBuffer> execute_sync_call(ReadonlyBytes request);
@ -40,16 +40,16 @@ public:
ErrorOr<NonnullRefPtr<Gfx::PaintingSurface>> prepare_for_compositing(bool preserve_drawing_buffer);
RefPtr<Gfx::PaintingSurface> surface();
Web::WebGL::OpenGLContext& gl_context() { return *m_gl_context; }
OpenGLContext& gl_context() { return *m_gl_context; }
private:
explicit HostWebGLContext(NonnullOwnPtr<Web::WebGL::OpenGLContext>);
explicit HostWebGLContext(NonnullOwnPtr<OpenGLContext>);
ErrorOr<void> set_drawing_buffer_size(int width, int height);
ErrorOr<void> tex_image2d_from_bitmap(Web::WebGL::Commands::TexImage2DFromBitmap const&, Vector<Gfx::DecodedImageFrame> const& bitmaps);
ErrorOr<void> tex_sub_image2d_from_bitmap(Web::WebGL::Commands::TexSubImage2DFromBitmap const&, Vector<Gfx::DecodedImageFrame> const& bitmaps);
NonnullOwnPtr<Web::WebGL::OpenGLContext> m_gl_context;
NonnullOwnPtr<OpenGLContext> m_gl_context;
WebGLObjectMap m_objects;
bool m_needs_clear_before_next_frame { false };
};

View file

@ -35,57 +35,9 @@ extern "C" {
# define ENABLE_WEBGL 1
#endif
namespace Web::WebGL {
namespace Compositor {
Optional<Gfx::ExportFormat> texture_export_format(GLenum format, GLenum type)
{
switch (format) {
case GL_RGB:
switch (type) {
case GL_UNSIGNED_BYTE:
return Gfx::ExportFormat::RGB888;
case GL_UNSIGNED_SHORT_5_6_5:
return Gfx::ExportFormat::RGB565;
default:
break;
}
break;
case GL_RGBA:
switch (type) {
case GL_UNSIGNED_BYTE:
return Gfx::ExportFormat::RGBA8888;
case GL_UNSIGNED_SHORT_4_4_4_4:
// FIXME: This is not exactly the same as RGBA.
return Gfx::ExportFormat::RGBA4444;
case GL_UNSIGNED_SHORT_5_5_5_1:
return Gfx::ExportFormat::RGBA5551;
default:
break;
}
break;
case GL_ALPHA:
switch (type) {
case GL_UNSIGNED_BYTE:
return Gfx::ExportFormat::Alpha8;
default:
break;
}
break;
case GL_LUMINANCE:
switch (type) {
case GL_UNSIGNED_BYTE:
return Gfx::ExportFormat::Gray8;
default:
break;
}
break;
default:
break;
}
dbgln("WebGL: Unsupported format and type combination. format: 0x{:04x}, type: 0x{:04x}", format, type);
return {};
}
using namespace Web::WebGL;
struct OpenGLContext::Impl {
EGLDisplay display { EGL_NO_DISPLAY };

View file

@ -11,19 +11,15 @@
#include <AK/OwnPtr.h>
#include <AK/RefPtr.h>
#include <AK/Vector.h>
#include <LibGfx/BitmapExport.h>
#include <LibGfx/Forward.h>
#include <LibGfx/Size.h>
#include <LibWeb/Export.h>
#include <LibWeb/WebGL/GLFunctions.h>
namespace Web::WebGL {
namespace Compositor {
WEB_API Optional<Gfx::ExportFormat> texture_export_format(GLenum format, GLenum type);
class WEB_API OpenGLContext : public GLFunctions {
class OpenGLContext : public Web::WebGL::GLFunctions {
public:
using WebGLVersion = WebGL::WebGLVersion;
using WebGLVersion = Web::WebGL::WebGLVersion;
struct DrawingBufferOptions {
bool depth;