diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 31347e2ef5..566bee608b 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -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) diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 5c27a7c761..a905b5fc7b 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -1311,7 +1311,6 @@ enum class AudioContextState; namespace Web::WebGL { -class OpenGLContext; class RemoteWebGLTransport; class WebGLContextProxy; class WebGL2RenderingContext; diff --git a/Libraries/LibWeb/WebGL/TextureUpload.cpp b/Libraries/LibWeb/WebGL/TextureUpload.cpp new file mode 100644 index 0000000000..4fab28002c --- /dev/null +++ b/Libraries/LibWeb/WebGL/TextureUpload.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2026, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +#include +#include + +namespace Web::WebGL { + +Optional 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 {}; +} + +} diff --git a/Libraries/LibWeb/WebGL/TextureUpload.h b/Libraries/LibWeb/WebGL/TextureUpload.h new file mode 100644 index 0000000000..689ce398c2 --- /dev/null +++ b/Libraries/LibWeb/WebGL/TextureUpload.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2026, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Web::WebGL { + +WEB_API Optional texture_export_format(GLenum format, GLenum type); + +} diff --git a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp b/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp index 0c96b922e4..2c629a0a3e 100644 --- a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp +++ b/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp @@ -11,7 +11,6 @@ extern "C" { #include } -#include #include #include #include @@ -37,6 +36,7 @@ extern "C" { #include #include #include +#include #include #include #include diff --git a/Meta/Generators/generate_compositor_webgl_replayer.py b/Meta/Generators/generate_compositor_webgl_replayer.py index f473ad83db..87bd1aa96e 100644 --- a/Meta/Generators/generate_compositor_webgl_replayer.py +++ b/Meta/Generators/generate_compositor_webgl_replayer.py @@ -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 replay_webgl_command(Web::WebGL::OpenGLContext& gl, {objects}, " + f"ErrorOr 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 replay_webgl_command(Web::WebGL::OpenGLContext&, WebGLObjectMap&, " + f"ErrorOr 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 replay_webgl_command(Web::WebGL::OpenGLContext&, WebGLObjectMap&, " + f"ErrorOr 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 handle_one(Web::WebGL::OpenGLContext&, WebGLObjectMap&, " + f"ErrorOr handle_one(OpenGLContext&, WebGLObjectMap&, " f"Web::WebGL::SyncCalls::{command_name(function)}::Request const&, ReadonlyBytes);\n" ) out.write(""" -ErrorOr handle_webgl_sync_call(Web::WebGL::OpenGLContext&, WebGLObjectMap&, ReadonlyBytes request); +ErrorOr 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 handle_webgl_sync_call(Web::WebGL::OpenGLContext& gl, WebGLObjectMap& objects, ReadonlyBytes request) + out.write("""ErrorOr handle_webgl_sync_call(OpenGLContext& gl, WebGLObjectMap& objects, ReadonlyBytes request) { return WebGLSyncCall::dispatch_request(request, [&](typename Call::Request const& call_request, ReadonlyBytes payload) -> ErrorOr { return handle_one(gl, objects, call_request, payload); diff --git a/Meta/Generators/generate_libweb_webgl_functions.py b/Meta/Generators/generate_libweb_webgl_functions.py index c2dba35909..e8d17dbe41 100644 --- a/Meta/Generators/generate_libweb_webgl_functions.py +++ b/Meta/Generators/generate_libweb_webgl_functions.py @@ -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 -#include #include namespace Web::WebGL { -class WEB_API GLFunctions { +class GLFunctions { public: """) diff --git a/Services/Compositor/CMakeLists.txt b/Services/Compositor/CMakeLists.txt index 7d739f652e..84bbe13232 100644 --- a/Services/Compositor/CMakeLists.txt +++ b/Services/Compositor/CMakeLists.txt @@ -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) diff --git a/Services/Compositor/HostWebGLContext.cpp b/Services/Compositor/HostWebGLContext.cpp index 028569f408..f19dbcc755 100644 --- a/Services/Compositor/HostWebGLContext.cpp +++ b/Services/Compositor/HostWebGLContext.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace Compositor { @@ -21,17 +22,17 @@ using namespace Web::WebGL; static constexpr GLsizei max_webgl_string_list_entries = 16384; -HostWebGLContext::HostWebGLContext(NonnullOwnPtr gl_context) +HostWebGLContext::HostWebGLContext(NonnullOwnPtr gl_context) : m_gl_context(move(gl_context)) { } -OwnPtr HostWebGLContext::create(NonnullRefPtr skia_backend_context, Web::WebGL::OpenGLContext::WebGLVersion version, Web::WebGL::OpenGLContext::DrawingBufferOptions options, Gfx::IntSize initial_size) +OwnPtr HostWebGLContext::create(NonnullRefPtr 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 HostWebGLContext::set_drawing_buffer_size(int width, int height) return {}; } -ErrorOr replay_webgl_command(Web::WebGL::OpenGLContext& gl, WebGLObjectMap& objects, Commands::ShaderSource const& command, ReadonlyBytes payload) +ErrorOr 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> split_packed_strings(ReadonlyBytes bytes, return strings; } -ErrorOr replay_webgl_command(Web::WebGL::OpenGLContext& gl, WebGLObjectMap& objects, Commands::TransformFeedbackVaryings const& command, ReadonlyBytes payload) +ErrorOr 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 replay_webgl_command(Web::WebGL::OpenGLContext& gl, WebGLObjectMap return {}; } -// --- Wire-specified synchronous calls ------------------------------------------------ - -ErrorOr handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap&, SyncCalls::GetString::Request const& request, ReadonlyBytes) +ErrorOr 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 handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap&, S return WebGLSyncCall::encode_reply(reply, value_bytes); } -ErrorOr handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap&, SyncCalls::GetVertexAttribPointervRobustANGLE::Request const& request, ReadonlyBytes) +ErrorOr handle_one(OpenGLContext& gl, WebGLObjectMap&, SyncCalls::GetVertexAttribPointervRobustANGLE::Request const& request, ReadonlyBytes) { void* pointer = nullptr; GLsizei length = 0; @@ -272,7 +271,7 @@ ErrorOr handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap&, S return WebGLSyncCall::encode_reply(reply); } -ErrorOr handle_one(Web::WebGL::OpenGLContext& gl, WebGLObjectMap& objects, SyncCalls::GetUniformIndices::Request const& request, ReadonlyBytes payload) +ErrorOr 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)); diff --git a/Services/Compositor/HostWebGLContext.h b/Services/Compositor/HostWebGLContext.h index 6acf73bf9a..dec0209bf8 100644 --- a/Services/Compositor/HostWebGLContext.h +++ b/Services/Compositor/HostWebGLContext.h @@ -30,7 +30,7 @@ namespace Compositor { class HostWebGLContext { public: - static OwnPtr create(NonnullRefPtr, Web::WebGL::OpenGLContext::WebGLVersion, Web::WebGL::OpenGLContext::DrawingBufferOptions, Gfx::IntSize initial_size); + static OwnPtr create(NonnullRefPtr, OpenGLContext::WebGLVersion, OpenGLContext::DrawingBufferOptions, Gfx::IntSize initial_size); ErrorOr execute_commands(ReadonlyBytes, Vector const& bitmaps); ErrorOr execute_sync_call(ReadonlyBytes request); @@ -40,16 +40,16 @@ public: ErrorOr> prepare_for_compositing(bool preserve_drawing_buffer); RefPtr surface(); - Web::WebGL::OpenGLContext& gl_context() { return *m_gl_context; } + OpenGLContext& gl_context() { return *m_gl_context; } private: - explicit HostWebGLContext(NonnullOwnPtr); + explicit HostWebGLContext(NonnullOwnPtr); ErrorOr set_drawing_buffer_size(int width, int height); ErrorOr tex_image2d_from_bitmap(Web::WebGL::Commands::TexImage2DFromBitmap const&, Vector const& bitmaps); ErrorOr tex_sub_image2d_from_bitmap(Web::WebGL::Commands::TexSubImage2DFromBitmap const&, Vector const& bitmaps); - NonnullOwnPtr m_gl_context; + NonnullOwnPtr m_gl_context; WebGLObjectMap m_objects; bool m_needs_clear_before_next_frame { false }; }; diff --git a/Services/Compositor/OpenGLContext.cpp b/Services/Compositor/OpenGLContext.cpp index 8cdeda8f60..d0918d87c3 100644 --- a/Services/Compositor/OpenGLContext.cpp +++ b/Services/Compositor/OpenGLContext.cpp @@ -35,57 +35,9 @@ extern "C" { # define ENABLE_WEBGL 1 #endif -namespace Web::WebGL { +namespace Compositor { -Optional 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 }; diff --git a/Services/Compositor/OpenGLContext.h b/Services/Compositor/OpenGLContext.h index a18f4fefb2..81b37b5001 100644 --- a/Services/Compositor/OpenGLContext.h +++ b/Services/Compositor/OpenGLContext.h @@ -11,19 +11,15 @@ #include #include #include -#include #include #include -#include #include -namespace Web::WebGL { +namespace Compositor { -WEB_API Optional 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;