From aa99853a5c15283b2714a5f852c7ef2bd0b4300f Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Thu, 9 Jan 2025 17:20:59 +0000 Subject: [PATCH] LibWeb/WebGL: Track the shaders attached to a program This is required to return original references to the shaders attached to a program from getAttachedShaders. This is required for Figma (and likely all other Emscripten compiled applications that use WebGL) to get it's own generated shader IDs from the shaders returned from getAttachedShaders. --- Libraries/LibWeb/WebGL/WebGLProgram.cpp | 10 +++- Libraries/LibWeb/WebGL/WebGLProgram.h | 13 ++++- Libraries/LibWeb/WebGL/WebGLShader.cpp | 9 ++-- Libraries/LibWeb/WebGL/WebGLShader.h | 9 +++- .../LibWeb/GenerateWebGLRenderingContext.cpp | 54 ++++++++++++++++++- 5 files changed, 86 insertions(+), 9 deletions(-) diff --git a/Libraries/LibWeb/WebGL/WebGLProgram.cpp b/Libraries/LibWeb/WebGL/WebGLProgram.cpp index e755c1a0f93..542c5607191 100644 --- a/Libraries/LibWeb/WebGL/WebGLProgram.cpp +++ b/Libraries/LibWeb/WebGL/WebGLProgram.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, Jelle Raaijmakers * Copyright (c) 2024, Aliaksandr Kalenik - * Copyright (c) 2024, Luke Wilde + * Copyright (c) 2024-2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -10,6 +10,7 @@ #include #include #include +#include namespace Web::WebGL { @@ -33,4 +34,11 @@ void WebGLProgram::initialize(JS::Realm& realm) WEB_SET_PROTOTYPE_FOR_INTERFACE(WebGLProgram); } +void WebGLProgram::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_attached_vertex_shader); + visitor.visit(m_attached_fragment_shader); +} + } diff --git a/Libraries/LibWeb/WebGL/WebGLProgram.h b/Libraries/LibWeb/WebGL/WebGLProgram.h index 6d7b8df5e3c..81d56c1ee25 100644 --- a/Libraries/LibWeb/WebGL/WebGLProgram.h +++ b/Libraries/LibWeb/WebGL/WebGLProgram.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, Jelle Raaijmakers * Copyright (c) 2024, Aliaksandr Kalenik - * Copyright (c) 2024, Luke Wilde + * Copyright (c) 2024-2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -22,10 +22,21 @@ public: virtual ~WebGLProgram(); + GC::Ptr attached_vertex_shader() const { return m_attached_fragment_shader; } + void set_attached_vertex_shader(GC::Ptr shader) { m_attached_vertex_shader = shader; } + + GC::Ptr attached_fragment_shader() const { return m_attached_fragment_shader; } + void set_attached_fragment_shader(GC::Ptr shader) { m_attached_fragment_shader = shader; } + protected: explicit WebGLProgram(JS::Realm&, WebGLRenderingContextBase&, GLuint handle); virtual void initialize(JS::Realm&) override; + virtual void visit_edges(JS::Cell::Visitor&) override; + +private: + GC::Ptr m_attached_vertex_shader; + GC::Ptr m_attached_fragment_shader; }; } diff --git a/Libraries/LibWeb/WebGL/WebGLShader.cpp b/Libraries/LibWeb/WebGL/WebGLShader.cpp index de9b125b91a..1b9adb6568b 100644 --- a/Libraries/LibWeb/WebGL/WebGLShader.cpp +++ b/Libraries/LibWeb/WebGL/WebGLShader.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2024, Jelle Raaijmakers * Copyright (c) 2024, Aliaksandr Kalenik - * Copyright (c) 2024, Luke Wilde + * Copyright (c) 2024-2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -15,13 +15,14 @@ namespace Web::WebGL { GC_DEFINE_ALLOCATOR(WebGLShader); -GC::Ref WebGLShader::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle) +GC::Ref WebGLShader::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle, GLenum type) { - return realm.create(realm, context, handle); + return realm.create(realm, context, handle, type); } -WebGLShader::WebGLShader(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle) +WebGLShader::WebGLShader(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle, GLenum type) : WebGLObject(realm, context, handle) + , m_type(type) { } diff --git a/Libraries/LibWeb/WebGL/WebGLShader.h b/Libraries/LibWeb/WebGL/WebGLShader.h index 75071b699e2..98b45b004d3 100644 --- a/Libraries/LibWeb/WebGL/WebGLShader.h +++ b/Libraries/LibWeb/WebGL/WebGLShader.h @@ -18,14 +18,19 @@ class WebGLShader final : public WebGLObject { GC_DECLARE_ALLOCATOR(WebGLShader); public: - static GC::Ref create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle); + static GC::Ref create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle, GLenum type); virtual ~WebGLShader(); + GLenum type() const { return m_type; } + protected: - explicit WebGLShader(JS::Realm&, WebGLRenderingContextBase&, GLuint handle); + explicit WebGLShader(JS::Realm&, WebGLRenderingContextBase&, GLuint handle, GLenum type); virtual void initialize(JS::Realm&) override; + +private: + GLenum m_type { 0 }; }; } diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateWebGLRenderingContext.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateWebGLRenderingContext.cpp index 7aa31284d4e..2fa0165a502 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateWebGLRenderingContext.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateWebGLRenderingContext.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2024, Aliaksandr Kalenik - * Copyright (c) 2024, Luke Wilde + * Copyright (c) 2024-2025, Luke Wilde * * SPDX-License-Identifier: BSD-2-Clause */ @@ -605,6 +605,44 @@ public: function_impl_generator.append(" m_context->notify_content_will_change();\n"sv); } + if (function.name == "attachShader"sv) { + generate_webgl_object_handle_unwrap(function_impl_generator, "program"sv, ""sv); + generate_webgl_object_handle_unwrap(function_impl_generator, "shader"sv, ""sv); + function_impl_generator.append(R"~~~( + if (program->attached_vertex_shader() == shader || program->attached_fragment_shader() == shader) { + dbgln("WebGL: Shader is already attached to program"); + set_error(GL_INVALID_OPERATION); + return; + } + + if (shader->type() == GL_VERTEX_SHADER && program->attached_vertex_shader()) { + dbgln("WebGL: Not attaching vertex shader to program as it already has a vertex shader attached"); + set_error(GL_INVALID_OPERATION); + return; + } + + if (shader->type() == GL_FRAGMENT_SHADER && program->attached_fragment_shader()) { + dbgln("WebGL: Not attaching fragment shader to program as it already has a fragment shader attached"); + set_error(GL_INVALID_OPERATION); + return; + } + + glAttachShader(program_handle, shader_handle); + + switch (shader->type()) { + case GL_VERTEX_SHADER: + program->set_attached_vertex_shader(shader.ptr()); + break; + case GL_FRAGMENT_SHADER: + program->set_attached_fragment_shader(shader.ptr()); + break; + default: + VERIFY_NOT_REACHED(); + } +)~~~"); + continue; + } + if (function.name == "getUniformLocation"sv) { generate_webgl_object_handle_unwrap(function_impl_generator, "program"sv, "{}"sv); function_impl_generator.append(R"~~~( @@ -623,6 +661,20 @@ public: continue; } + if (function.name == "createShader"sv) { + function_impl_generator.append(R"~~~( + if (type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER) { + dbgln("Unknown WebGL shader type: 0x{:04x}", type); + set_error(GL_INVALID_ENUM); + return nullptr; + } + + GLuint handle = glCreateShader(type); + return WebGLShader::create(m_realm, *this, handle, type); +)~~~"); + continue; + } + if (function.name == "createTexture"sv) { function_impl_generator.append(R"~~~( GLuint handle = 0;