This commit is contained in:
Luke Wilde 2025-01-02 11:40:21 +00:00 committed by GitHub
commit 18c6840c0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 558 additions and 46 deletions

View file

@ -69,6 +69,7 @@ void WebGL2RenderingContext::initialize(JS::Realm& realm)
void WebGL2RenderingContext::visit_edges(Cell::Visitor& visitor) void WebGL2RenderingContext::visit_edges(Cell::Visitor& visitor)
{ {
Base::visit_edges(visitor); Base::visit_edges(visitor);
WebGL2RenderingContextImpl::visit_edges(visitor);
visitor.visit(m_canvas_element); visitor.visit(m_canvas_element);
} }
@ -128,7 +129,10 @@ Optional<WebGLContextAttributes> WebGL2RenderingContext::get_context_attributes(
void WebGL2RenderingContext::set_size(Gfx::IntSize const& size) void WebGL2RenderingContext::set_size(Gfx::IntSize const& size)
{ {
context().set_size(size); Gfx::IntSize final_size;
final_size.set_width(max(size.width(), 1));
final_size.set_height(max(size.height(), 1));
context().set_size(final_size);
} }
void WebGL2RenderingContext::reset_to_default_state() void WebGL2RenderingContext::reset_to_default_state()

View file

@ -298,7 +298,7 @@ interface mixin WebGL2RenderingContextBase {
// Framebuffer objects // Framebuffer objects
undefined blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); undefined blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
[FIXME] undefined framebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture? texture, GLint level, GLint layer); [FIXME] undefined framebufferTextureLayer(GLenum target, GLenum attachment, WebGLTexture? texture, GLint level, GLint layer);
[FIXME] undefined invalidateFramebuffer(GLenum target, sequence<GLenum> attachments); undefined invalidateFramebuffer(GLenum target, sequence<GLenum> attachments);
[FIXME] undefined invalidateSubFramebuffer(GLenum target, sequence<GLenum> attachments, GLint x, GLint y, GLsizei width, GLsizei height); [FIXME] undefined invalidateSubFramebuffer(GLenum target, sequence<GLenum> attachments, GLint x, GLint y, GLsizei width, GLsizei height);
undefined readBuffer(GLenum src); undefined readBuffer(GLenum src);
@ -360,22 +360,22 @@ interface mixin WebGL2RenderingContextBase {
[FIXME] undefined vertexAttribI4iv(GLuint index, Int32List values); [FIXME] undefined vertexAttribI4iv(GLuint index, Int32List values);
[FIXME] undefined vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); [FIXME] undefined vertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
[FIXME] undefined vertexAttribI4uiv(GLuint index, Uint32List values); [FIXME] undefined vertexAttribI4uiv(GLuint index, Uint32List values);
[FIXME] undefined vertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset); undefined vertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
// Writing to the drawing buffer // Writing to the drawing buffer
[FIXME] undefined vertexAttribDivisor(GLuint index, GLuint divisor); undefined vertexAttribDivisor(GLuint index, GLuint divisor);
[FIXME] undefined drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount); [FIXME] undefined drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
[FIXME] undefined drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei instanceCount); undefined drawElementsInstanced(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei instanceCount);
[FIXME] undefined drawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLintptr offset); [FIXME] undefined drawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, GLintptr offset);
// Multiple Render Targets // Multiple Render Targets
undefined drawBuffers(sequence<GLenum> buffers); undefined drawBuffers(sequence<GLenum> buffers);
[FIXME] undefined clearBufferfv(GLenum buffer, GLint drawbuffer, Float32List values, optional unsigned long long srcOffset = 0); undefined clearBufferfv(GLenum buffer, GLint drawbuffer, Float32List values, optional unsigned long long srcOffset = 0);
[FIXME] undefined clearBufferiv(GLenum buffer, GLint drawbuffer, Int32List values, optional unsigned long long srcOffset = 0); undefined clearBufferiv(GLenum buffer, GLint drawbuffer, Int32List values, optional unsigned long long srcOffset = 0);
[FIXME] undefined clearBufferuiv(GLenum buffer, GLint drawbuffer, Uint32List values, optional unsigned long long srcOffset = 0); undefined clearBufferuiv(GLenum buffer, GLint drawbuffer, Uint32List values, optional unsigned long long srcOffset = 0);
[FIXME] undefined clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); undefined clearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
// Query Objects // Query Objects
[FIXME] WebGLQuery createQuery(); [FIXME] WebGLQuery createQuery();
@ -388,11 +388,11 @@ interface mixin WebGL2RenderingContextBase {
// Sampler Objects // Sampler Objects
WebGLSampler createSampler(); WebGLSampler createSampler();
[FIXME] undefined deleteSampler(WebGLSampler? sampler); undefined deleteSampler(WebGLSampler? sampler);
[FIXME] GLboolean isSampler(WebGLSampler? sampler); // [WebGLHandlesContextLoss] [FIXME] GLboolean isSampler(WebGLSampler? sampler); // [WebGLHandlesContextLoss]
undefined bindSampler(GLuint unit, WebGLSampler? sampler); undefined bindSampler(GLuint unit, WebGLSampler? sampler);
[FIXME] undefined samplerParameteri(WebGLSampler sampler, GLenum pname, GLint param); undefined samplerParameteri(WebGLSampler sampler, GLenum pname, GLint param);
[FIXME] undefined samplerParameterf(WebGLSampler sampler, GLenum pname, GLfloat param); undefined samplerParameterf(WebGLSampler sampler, GLenum pname, GLfloat param);
[FIXME] any getSamplerParameter(WebGLSampler sampler, GLenum pname); [FIXME] any getSamplerParameter(WebGLSampler sampler, GLenum pname);
// Sync objects // Sync objects
@ -421,10 +421,10 @@ interface mixin WebGL2RenderingContextBase {
[FIXME] any getIndexedParameter(GLenum target, GLuint index); [FIXME] any getIndexedParameter(GLenum target, GLuint index);
[FIXME] sequence<GLuint>? getUniformIndices(WebGLProgram program, sequence<DOMString> uniformNames); [FIXME] sequence<GLuint>? getUniformIndices(WebGLProgram program, sequence<DOMString> uniformNames);
[FIXME] any getActiveUniforms(WebGLProgram program, sequence<GLuint> uniformIndices, GLenum pname); [FIXME] any getActiveUniforms(WebGLProgram program, sequence<GLuint> uniformIndices, GLenum pname);
[FIXME] GLuint getUniformBlockIndex(WebGLProgram program, DOMString uniformBlockName); GLuint getUniformBlockIndex(WebGLProgram program, DOMString uniformBlockName);
[FIXME] any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname); any getActiveUniformBlockParameter(WebGLProgram program, GLuint uniformBlockIndex, GLenum pname);
[FIXME] DOMString? getActiveUniformBlockName(WebGLProgram program, GLuint uniformBlockIndex); DOMString? getActiveUniformBlockName(WebGLProgram program, GLuint uniformBlockIndex);
[FIXME] undefined uniformBlockBinding(WebGLProgram program, GLuint uniformBlockIndex, GLuint uniformBlockBinding); undefined uniformBlockBinding(WebGLProgram program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
// Vertex Array Objects // Vertex Array Objects
WebGLVertexArrayObject createVertexArray(); WebGLVertexArrayObject createVertexArray();

View file

@ -10,8 +10,8 @@ interface mixin WebGL2RenderingContextOverloads {
undefined bufferData(GLenum target, BufferSource? srcData, GLenum usage); undefined bufferData(GLenum target, BufferSource? srcData, GLenum usage);
undefined bufferSubData(GLenum target, GLintptr dstByteOffset, BufferSource srcData); undefined bufferSubData(GLenum target, GLintptr dstByteOffset, BufferSource srcData);
// WebGL2: // WebGL2:
[FIXME] undefined bufferData(GLenum target, [AllowShared] ArrayBufferView srcData, GLenum usage, unsigned long long srcOffset, optional GLuint length = 0); undefined bufferData(GLenum target, [AllowShared] ArrayBufferView srcData, GLenum usage, unsigned long long srcOffset, optional GLuint length = 0);
[FIXME] undefined bufferSubData(GLenum target, GLintptr dstByteOffset, [AllowShared] ArrayBufferView srcData, unsigned long long srcOffset, optional GLuint length = 0); undefined bufferSubData(GLenum target, GLintptr dstByteOffset, [AllowShared] ArrayBufferView srcData, unsigned long long srcOffset, optional GLuint length = 0);
// WebGL1 legacy entrypoints: // WebGL1 legacy entrypoints:
undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView? pixels); undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView? pixels);
@ -22,20 +22,20 @@ interface mixin WebGL2RenderingContextOverloads {
undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView? pixels); undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView? pixels);
// May throw DOMException // May throw DOMException
[FIXME] undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, TexImageSource source); undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, TexImageSource source);
// WebGL2 entrypoints: // WebGL2 entrypoints:
[FIXME] undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLintptr pboOffset); [FIXME] undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLintptr pboOffset);
// May throw DOMException // May throw DOMException
[FIXME] undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, TexImageSource source); undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, TexImageSource source);
undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData, unsigned long long srcOffset); undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData, unsigned long long srcOffset);
[FIXME] undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLintptr pboOffset); [FIXME] undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLintptr pboOffset);
// May throw DOMException // May throw DOMException
[FIXME] undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, TexImageSource source); undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, TexImageSource source);
undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData, unsigned long long srcOffset); undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView srcData, unsigned long long srcOffset);
[FIXME] undefined compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLintptr offset); [FIXME] undefined compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, GLintptr offset);

View file

@ -86,6 +86,7 @@ void WebGLRenderingContext::initialize(JS::Realm& realm)
void WebGLRenderingContext::visit_edges(Cell::Visitor& visitor) void WebGLRenderingContext::visit_edges(Cell::Visitor& visitor)
{ {
Base::visit_edges(visitor); Base::visit_edges(visitor);
WebGLRenderingContextImpl::visit_edges(visitor);
visitor.visit(m_canvas_element); visitor.visit(m_canvas_element);
} }
@ -145,7 +146,10 @@ Optional<WebGLContextAttributes> WebGLRenderingContext::get_context_attributes()
void WebGLRenderingContext::set_size(Gfx::IntSize const& size) void WebGLRenderingContext::set_size(Gfx::IntSize const& size)
{ {
context().set_size(size); Gfx::IntSize final_size;
final_size.set_width(max(size.width(), 1));
final_size.set_height(max(size.height(), 1));
context().set_size(final_size);
} }
void WebGLRenderingContext::reset_to_default_state() void WebGLRenderingContext::reset_to_default_state()

View file

@ -13,6 +13,7 @@ namespace Web::WebGL {
class WebGLRenderingContextBase { class WebGLRenderingContextBase {
public: public:
virtual GC::Cell const* gc_cell() const = 0; virtual GC::Cell const* gc_cell() const = 0;
virtual void visit_edges(JS::Cell::Visitor&) = 0;
}; };
} }

View file

@ -81,7 +81,7 @@ interface mixin WebGLRenderingContextBase {
undefined deleteBuffer(WebGLBuffer? buffer); undefined deleteBuffer(WebGLBuffer? buffer);
undefined deleteFramebuffer(WebGLFramebuffer? framebuffer); undefined deleteFramebuffer(WebGLFramebuffer? framebuffer);
undefined deleteProgram(WebGLProgram? program); undefined deleteProgram(WebGLProgram? program);
[FIXME] undefined deleteRenderbuffer(WebGLRenderbuffer? renderbuffer); undefined deleteRenderbuffer(WebGLRenderbuffer? renderbuffer);
undefined deleteShader(WebGLShader? shader); undefined deleteShader(WebGLShader? shader);
undefined deleteTexture(WebGLTexture? texture); undefined deleteTexture(WebGLTexture? texture);

View file

@ -28,7 +28,7 @@ interface mixin WebGLRenderingContextOverloads {
undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, TexImageSource source); // May throw DOMException undefined texImage2D(GLenum target, GLint level, GLint internalformat, GLenum format, GLenum type, TexImageSource source); // May throw DOMException
undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView? pixels); undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, [AllowShared] ArrayBufferView? pixels);
[FIXME] undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, TexImageSource source); // May throw DOMException undefined texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLenum format, GLenum type, TexImageSource source); // May throw DOMException
undefined uniform1fv(WebGLUniformLocation? location, Float32List v); undefined uniform1fv(WebGLUniformLocation? location, Float32List v);
undefined uniform2fv(WebGLUniformLocation? location, Float32List v); undefined uniform2fv(WebGLUniformLocation? location, Float32List v);

View file

@ -29,6 +29,21 @@ u32 BufferableObjectBase::byte_length() const
[](GC::Ref<JS::ArrayBuffer> array_buffer) { return static_cast<u32>(array_buffer->byte_length()); }); [](GC::Ref<JS::ArrayBuffer> array_buffer) { return static_cast<u32>(array_buffer->byte_length()); });
} }
u32 BufferableObjectBase::element_size() const
{
return m_bufferable_object.visit(
[](GC::Ref<JS::TypedArrayBase> typed_array) -> u32 {
auto typed_array_record = JS::make_typed_array_with_buffer_witness_record(typed_array, JS::ArrayBuffer::Order::SeqCst);
return typed_array_record.object->element_size();
},
[](GC::Ref<JS::DataView>) -> u32 {
return 1;
},
[](GC::Ref<JS::ArrayBuffer>) -> u32 {
return 1;
});
}
GC::Ref<JS::Object> BufferableObjectBase::raw_object() GC::Ref<JS::Object> BufferableObjectBase::raw_object()
{ {
return m_bufferable_object.visit([](auto const& obj) -> GC::Ref<JS::Object> { return obj; }); return m_bufferable_object.visit([](auto const& obj) -> GC::Ref<JS::Object> { return obj; });

View file

@ -27,6 +27,7 @@ public:
virtual ~BufferableObjectBase() override = default; virtual ~BufferableObjectBase() override = default;
u32 byte_length() const; u32 byte_length() const;
u32 element_size() const;
GC::Ref<JS::Object> raw_object(); GC::Ref<JS::Object> raw_object();
GC::Ref<JS::Object const> raw_object() const { return const_cast<BufferableObjectBase&>(*this).raw_object(); } GC::Ref<JS::Object const> raw_object() const { return const_cast<BufferableObjectBase&>(*this).raw_object(); }

View file

@ -210,7 +210,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
// then remove from S all other entries. // then remove from S all other entries.
else if (value.is_object() && is<JS::DataView>(value.as_object()) else if (value.is_object() && is<JS::DataView>(value.as_object())
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) { && has_overload_with_argument_type_or_subtype_matching(overloads, i, [](IDL::Type const& type) {
if (type.is_plain() && (type.name() == "DataView" || type.name() == "BufferSource")) if (type.is_plain() && (type.name() == "DataView" || type.name() == "BufferSource" || type.name() == "ArrayBufferView"))
return true; return true;
if (type.is_object()) if (type.is_object())
return true; return true;
@ -228,7 +228,7 @@ JS::ThrowCompletionOr<ResolvedOverload> resolve_overload(JS::VM& vm, IDL::Effect
// then remove from S all other entries. // then remove from S all other entries.
else if (value.is_object() && value.as_object().is_typed_array() else if (value.is_object() && value.as_object().is_typed_array()
&& has_overload_with_argument_type_or_subtype_matching(overloads, i, [&](IDL::Type const& type) { && has_overload_with_argument_type_or_subtype_matching(overloads, i, [&](IDL::Type const& type) {
if (type.is_plain() && (type.name() == static_cast<JS::TypedArrayBase const&>(value.as_object()).element_name() || type.name() == "BufferSource")) if (type.is_plain() && (type.name() == static_cast<JS::TypedArrayBase const&>(value.as_object()).element_name() || type.name() == "BufferSource" || type.name() == "ArrayBufferView"))
return true; return true;
if (type.is_object()) if (type.is_object())
return true; return true;

View file

@ -29,7 +29,16 @@ static bool is_webgl_object_type(StringView type_name)
static bool gl_function_modifies_framebuffer(StringView function_name) static bool gl_function_modifies_framebuffer(StringView function_name)
{ {
return function_name == "clearColor"sv || function_name == "drawArrays"sv || function_name == "drawElements"sv; return function_name == "clear"sv
|| function_name == "clearBufferfv"sv
|| function_name == "clearBufferiv"sv
|| function_name == "clearBufferuiv"sv
|| function_name == "clearBufferfi"sv
|| function_name == "drawArrays"sv
|| function_name == "drawElements"sv
|| function_name == "drawElementsInstanced"sv
|| function_name == "blitFramebuffer"sv
|| function_name == "invalidateFramebuffer"sv;
} }
static ByteString to_cpp_type(const IDL::Type& type, const IDL::Interface& interface) static ByteString to_cpp_type(const IDL::Type& type, const IDL::Interface& interface)
@ -180,6 +189,13 @@ static void generate_get_parameter(SourceGenerator& generator, int webgl_version
{ "MAX_VERTEX_UNIFORM_BLOCKS"sv, { "GLint"sv }, 2 }, { "MAX_VERTEX_UNIFORM_BLOCKS"sv, { "GLint"sv }, 2 },
{ "MAX_FRAGMENT_INPUT_COMPONENTS"sv, { "GLint"sv }, 2 }, { "MAX_FRAGMENT_INPUT_COMPONENTS"sv, { "GLint"sv }, 2 },
{ "MAX_COMBINED_UNIFORM_BLOCKS"sv, { "GLint"sv }, 2 }, { "MAX_COMBINED_UNIFORM_BLOCKS"sv, { "GLint"sv }, 2 },
{ "UNIFORM_BUFFER_BINDING"sv, { "WebGLBuffer"sv }, 2 },
{ "TEXTURE_BINDING_2D_ARRAY"sv, { "WebGLTexture"sv }, 2 },
{ "COPY_READ_BUFFER_BINDING"sv, { "WebGLBuffer"sv }, 2 },
{ "COPY_WRITE_BUFFER_BINDING"sv, { "WebGLBuffer"sv }, 2 },
{ "MAX_ELEMENT_INDEX"sv, { "GLint64"sv }, 2 },
{ "MAX_FRAGMENT_UNIFORM_BLOCKS"sv, { "GLint"sv }, 2 },
{ "MAX_VARYING_COMPONENTS"sv, { "GLint"sv }, 2 },
}; };
auto is_primitive_type = [](StringView type) { auto is_primitive_type = [](StringView type) {
@ -236,12 +252,11 @@ static void generate_get_parameter(SourceGenerator& generator, int webgl_version
return JS::@type_name@::create(m_realm, @element_count@, array_buffer); return JS::@type_name@::create(m_realm, @element_count@, array_buffer);
)~~~"); )~~~");
} else if (type_name == "WebGLProgram"sv || type_name == "WebGLBuffer"sv || type_name == "WebGLTexture"sv || type_name == "WebGLFramebuffer"sv || type_name == "WebGLRenderbuffer"sv) { } else if (type_name == "WebGLProgram"sv || type_name == "WebGLBuffer"sv || type_name == "WebGLTexture"sv || type_name == "WebGLFramebuffer"sv || type_name == "WebGLRenderbuffer"sv) {
impl_generator.set("stored_name", name_and_type.name.to_lowercase_string());
impl_generator.append(R"~~~( impl_generator.append(R"~~~(
GLint result; if (!m_@stored_name@)
glGetIntegerv(GL_@parameter_name@, &result);
if (!result)
return JS::js_null(); return JS::js_null();
return @type_name@::create(m_realm, *this, result); return JS::Value(m_@stored_name@);
)~~~"); )~~~");
} else { } else {
VERIFY_NOT_REACHED(); VERIFY_NOT_REACHED();
@ -337,6 +352,40 @@ static void generate_webgl_object_handle_unwrap(SourceGenerator& generator, Stri
generator.append(unwrap_generator.as_string_view()); generator.append(unwrap_generator.as_string_view());
} }
static void generate_get_active_uniform_block_parameter(SourceGenerator& generator)
{
generate_webgl_object_handle_unwrap(generator, "program"sv, "JS::js_null()"sv);
generator.append(R"~~~(
switch (pname) {
case GL_UNIFORM_BLOCK_BINDING:
case GL_UNIFORM_BLOCK_DATA_SIZE:
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: {
GLint result = 0;
glGetActiveUniformBlockiv(program_handle, uniform_block_index, pname, &result);
return JS::Value(result);
}
case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES: {
GLint num_active_uniforms = 0;
glGetActiveUniformBlockiv(program_handle, uniform_block_index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &num_active_uniforms);
auto active_uniform_indices_buffer = MUST(ByteBuffer::create_zeroed(num_active_uniforms * sizeof(GLint)));
glGetActiveUniformBlockiv(program_handle, uniform_block_index, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, reinterpret_cast<GLint*>(active_uniform_indices_buffer.data()));
auto array_buffer = JS::ArrayBuffer::create(m_realm, move(active_uniform_indices_buffer));
return JS::Uint32Array::create(m_realm, num_active_uniforms, array_buffer);
}
case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER: {
GLint result = 0;
glGetActiveUniformBlockiv(program_handle, uniform_block_index, pname, &result);
return JS::Value(result == GL_TRUE);
}
default:
dbgln("Unknown WebGL active uniform block parameter name: {:x}", pname);
set_error(GL_INVALID_ENUM);
return JS::js_null();
}
)~~~");
}
ErrorOr<int> serenity_main(Main::Arguments arguments) ErrorOr<int> serenity_main(Main::Arguments arguments)
{ {
StringView generated_header_path; StringView generated_header_path;
@ -576,6 +625,14 @@ public:
continue; continue;
} }
if (function.name == "invalidateFramebuffer"sv) {
function_impl_generator.append(R"~~~(
glInvalidateFramebuffer(target, attachments.size(), attachments.data());
needs_to_present();
)~~~");
continue;
}
if (function.name == "createVertexArray"sv) { if (function.name == "createVertexArray"sv) {
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
GLuint handle = 0; GLuint handle = 0;
@ -680,7 +737,7 @@ public:
continue; continue;
} }
if (function.name == "texImage2D"sv && function.overload_index == 1) { if (function.name == "texImage2D"sv && (function.overload_index == 1 || (webgl_version == 2 && function.overload_index == 2))) {
// FIXME: If this function is called with an ImageData whose data attribute has been neutered, // FIXME: If this function is called with an ImageData whose data attribute has been neutered,
// an INVALID_VALUE error is generated. // an INVALID_VALUE error is generated.
// FIXME: If this function is called with an ImageBitmap that has been neutered, an INVALID_VALUE // FIXME: If this function is called with an ImageBitmap that has been neutered, an INVALID_VALUE
@ -716,14 +773,23 @@ public:
return; return;
void const* pixels_ptr = bitmap->bitmap()->begin(); void const* pixels_ptr = bitmap->bitmap()->begin();
)~~~");
if (webgl_version == 2 && function.overload_index == 2) {
function_impl_generator.append(R"~~~(
glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels_ptr);
)~~~");
} else {
function_impl_generator.append(R"~~~(
int width = bitmap->width(); int width = bitmap->width();
int height = bitmap->height(); int height = bitmap->height();
glTexImage2D(target, level, internalformat, width, height, 0, format, type, pixels_ptr); glTexImage2D(target, level, internalformat, width, height, 0, format, type, pixels_ptr);
)~~~"); )~~~");
}
continue; continue;
} }
if (webgl_version == 2 && function.name == "texImage2D"sv && function.overload_index == 2) { if (webgl_version == 2 && function.name == "texImage2D"sv && function.overload_index == 3) {
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
void const* pixels_ptr = nullptr; void const* pixels_ptr = nullptr;
if (src_data) { if (src_data) {
@ -749,7 +815,58 @@ public:
continue; continue;
} }
if (webgl_version == 2 && function.name == "texSubImage2D"sv && function.overload_index == 1) { if (function.name == "texSubImage2D" && (function.overload_index == 1 || (webgl_version == 2 && function.overload_index == 2))) {
// FIXME: If this function is called with an ImageData whose data attribute has been neutered,
// an INVALID_VALUE error is generated.
// FIXME: If this function is called with an ImageBitmap that has been neutered, an INVALID_VALUE
// error is generated.
// FIXME: If this function is called with an HTMLImageElement or HTMLVideoElement whose origin
// differs from the origin of the containing Document, or with an HTMLCanvasElement,
// ImageBitmap or OffscreenCanvas whose bitmap's origin-clean flag is set to false,
// a SECURITY_ERR exception must be thrown. See Origin Restrictions.
// FIXME: If source is null then an INVALID_VALUE error is generated.
function_impl_generator.append(R"~~~(
auto bitmap = source.visit(
[](GC::Root<HTMLImageElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
return source->immutable_bitmap();
},
[](GC::Root<HTMLCanvasElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
auto surface = source->surface();
if (!surface)
return {};
auto bitmap = MUST(Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA8888, Gfx::AlphaType::Premultiplied, surface->size()));
surface->read_into_bitmap(*bitmap);
return Gfx::ImmutableBitmap::create(*bitmap);
},
[](GC::Root<HTMLVideoElement> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
return Gfx::ImmutableBitmap::create(*source->bitmap());
},
[](GC::Root<ImageBitmap> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
return Gfx::ImmutableBitmap::create(*source->bitmap());
},
[](GC::Root<ImageData> const& source) -> RefPtr<Gfx::ImmutableBitmap> {
return Gfx::ImmutableBitmap::create(source->bitmap());
});
if (!bitmap)
return;
void const* pixels_ptr = bitmap->bitmap()->begin();
)~~~");
if (webgl_version == 2 && function.overload_index == 2) {
function_impl_generator.append(R"~~~(
glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels_ptr);
)~~~");
} else {
function_impl_generator.append(R"~~~(
int width = bitmap->width();
int height = bitmap->height();
glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels_ptr);
)~~~");
}
continue;
}
if (webgl_version == 2 && function.name == "texSubImage2D"sv && function.overload_index == 3) {
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
void const* pixels_ptr = nullptr; void const* pixels_ptr = nullptr;
if (src_data) { if (src_data) {
@ -795,6 +912,11 @@ public:
continue; continue;
} }
if (function.name == "getActiveUniformBlockParameter"sv) {
generate_get_active_uniform_block_parameter(function_impl_generator);
continue;
}
if (function.name == "bufferData"sv && function.overload_index == 0) { if (function.name == "bufferData"sv && function.overload_index == 0) {
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
glBufferData(target, size, 0, usage); glBufferData(target, size, 0, usage);
@ -802,6 +924,62 @@ public:
continue; continue;
} }
if (webgl_version == 2 && function.name == "bufferData"sv && function.overload_index == 2) {
function_impl_generator.append(R"~~~(
VERIFY(src_data);
auto const& viewed_array_buffer = src_data->viewed_array_buffer();
auto const& byte_buffer = viewed_array_buffer->buffer();
auto src_data_length = src_data->byte_length();
auto src_data_element_size = src_data->element_size();
u8 const* buffer_ptr = byte_buffer.data();
u64 copy_length = length == 0 ? src_data_length - src_offset : length;
copy_length *= src_data_element_size;
if (src_offset > src_data_length) {
set_error(GL_INVALID_VALUE);
return;
}
if (src_offset + copy_length > src_data_length) {
set_error(GL_INVALID_VALUE);
return;
}
buffer_ptr += src_offset * src_data_element_size;
glBufferData(target, copy_length, buffer_ptr, usage);
)~~~");
continue;
}
if (webgl_version == 2 && function.name == "bufferSubData"sv && function.overload_index == 1) {
function_impl_generator.append(R"~~~(
VERIFY(src_data);
auto const& viewed_array_buffer = src_data->viewed_array_buffer();
auto const& byte_buffer = viewed_array_buffer->buffer();
auto src_data_length = src_data->byte_length();
auto src_data_element_size = src_data->element_size();
u8 const* buffer_ptr = byte_buffer.data();
u64 copy_length = length == 0 ? src_data_length - src_offset : length;
copy_length *= src_data_element_size;
if (src_offset > src_data_length) {
set_error(GL_INVALID_VALUE);
return;
}
if (src_offset + copy_length > src_data_length) {
set_error(GL_INVALID_VALUE);
return;
}
buffer_ptr += src_offset * src_data_element_size;
glBufferSubData(target, dst_byte_offset, copy_length, buffer_ptr);
)~~~");
continue;
}
if (function.name == "readPixels"sv) { if (function.name == "readPixels"sv) {
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
if (!pixels) { if (!pixels) {
@ -832,6 +1010,14 @@ public:
continue; continue;
} }
if (function.name == "drawElementsInstanced"sv) {
function_impl_generator.append(R"~~~(
glDrawElementsInstanced(mode, count, type, reinterpret_cast<void*>(offset), instance_count);
needs_to_present();
)~~~");
continue;
}
if (function.name == "drawBuffers"sv) { if (function.name == "drawBuffers"sv) {
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
glDrawBuffers(buffers.size(), buffers.data()); glDrawBuffers(buffers.size(), buffers.data());
@ -867,14 +1053,16 @@ public:
if (webgl_version == 2) { if (webgl_version == 2) {
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
if (src_offset + src_length > (count * matrix_size)) {
set_error(GL_INVALID_VALUE);
return;
}
raw_data += src_offset; raw_data += src_offset;
if (src_length == 0) { if (src_length == 0) {
count -= src_offset; count -= src_offset;
} } else {
count = src_length;
if (src_offset + src_length <= count) {
set_error(GL_INVALID_VALUE);
return;
} }
)~~~"); )~~~");
} }
@ -919,14 +1107,16 @@ public:
if (webgl_version == 2) { if (webgl_version == 2) {
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
if (src_offset + src_length > count) {
set_error(GL_INVALID_VALUE);
return;
}
data += src_offset; data += src_offset;
if (src_length == 0) { if (src_length == 0) {
count -= src_offset; count -= src_offset;
} } else {
count = src_length;
if (src_offset + src_length <= count) {
set_error(GL_INVALID_VALUE);
return;
} }
)~~~"); )~~~");
} }
@ -955,6 +1145,13 @@ public:
continue; continue;
} }
if (function.name == "vertexAttribIPointer"sv) {
function_impl_generator.append(R"~~~(
glVertexAttribIPointer(index, size, type, stride, reinterpret_cast<void*>(offset));
)~~~");
continue;
}
if (function.name == "getParameter"sv) { if (function.name == "getParameter"sv) {
generate_get_parameter(function_impl_generator, webgl_version); generate_get_parameter(function_impl_generator, webgl_version);
continue; continue;
@ -1040,6 +1237,21 @@ public:
continue; continue;
} }
if (function.name == "getActiveUniformBlockName"sv) {
generate_webgl_object_handle_unwrap(function_impl_generator, "program"sv, "OptionalNone {}"sv);
function_impl_generator.append(R"~~~(
GLint uniform_block_name_length = 0;
glGetActiveUniformBlockiv(program_handle, uniform_block_index, GL_UNIFORM_BLOCK_NAME_LENGTH, &uniform_block_name_length);
Vector<GLchar> uniform_block_name;
uniform_block_name.resize(uniform_block_name_length);
if (!uniform_block_name_length)
return String {};
glGetActiveUniformBlockName(program_handle, uniform_block_index, uniform_block_name_length, nullptr, uniform_block_name.data());
return String::from_utf8_without_validation(ReadonlyBytes { uniform_block_name.data(), static_cast<size_t>(uniform_block_name_length - 1) });
)~~~");
continue;
}
if (function.name == "deleteBuffer"sv) { if (function.name == "deleteBuffer"sv) {
generate_webgl_object_handle_unwrap(function_impl_generator, "buffer"sv, ""sv); generate_webgl_object_handle_unwrap(function_impl_generator, "buffer"sv, ""sv);
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
@ -1056,6 +1268,14 @@ public:
continue; continue;
} }
if (function.name == "deleteRenderbuffer"sv) {
generate_webgl_object_handle_unwrap(function_impl_generator, "renderbuffer"sv, ""sv);
function_impl_generator.append(R"~~~(
glDeleteRenderbuffers(1, &renderbuffer_handle);
)~~~");
continue;
}
if (function.name == "deleteTexture"sv) { if (function.name == "deleteTexture"sv) {
generate_webgl_object_handle_unwrap(function_impl_generator, "texture"sv, ""sv); generate_webgl_object_handle_unwrap(function_impl_generator, "texture"sv, ""sv);
function_impl_generator.append(R"~~~( function_impl_generator.append(R"~~~(
@ -1072,6 +1292,225 @@ public:
continue; continue;
} }
if (function.name == "deleteSampler"sv) {
generate_webgl_object_handle_unwrap(function_impl_generator, "sampler"sv, ""sv);
function_impl_generator.append(R"~~~(
glDeleteSamplers(1, &sampler_handle);
)~~~");
continue;
}
if (function.name == "bindBuffer"sv) {
// FIXME: Implement Buffer Object Binding restrictions.
generate_webgl_object_handle_unwrap(function_impl_generator, "buffer"sv, ""sv);
function_impl_generator.append(R"~~~(
switch (target) {
case GL_ELEMENT_ARRAY_BUFFER:
m_element_array_buffer_binding = buffer;
break;
case GL_ARRAY_BUFFER:
m_array_buffer_binding = buffer;
break;
)~~~");
if (webgl_version == 2) {
function_impl_generator.append(R"~~~(
case GL_UNIFORM_BUFFER:
m_uniform_buffer_binding = buffer;
break;
case GL_COPY_READ_BUFFER:
m_copy_read_buffer_binding = buffer;
break;
case GL_COPY_WRITE_BUFFER:
m_copy_write_buffer_binding = buffer;
break;
)~~~");
}
function_impl_generator.append(R"~~~(
default:
dbgln("Unknown WebGL buffer object binding target for storing current binding: 0x{:04x}", target);
break;
}
glBindBuffer(target, buffer_handle);
)~~~");
continue;
}
if (function.name == "useProgram"sv) {
generate_webgl_object_handle_unwrap(function_impl_generator, "program"sv, ""sv);
function_impl_generator.append(R"~~~(
glUseProgram(program_handle);
m_current_program = program;
)~~~");
continue;
}
if (function.name == "bindFramebuffer"sv) {
generate_webgl_object_handle_unwrap(function_impl_generator, "framebuffer"sv, ""sv);
function_impl_generator.append(R"~~~(
glBindFramebuffer(target, framebuffer_handle);
m_framebuffer_binding = framebuffer;
)~~~");
continue;
}
if (function.name == "bindRenderbuffer"sv) {
generate_webgl_object_handle_unwrap(function_impl_generator, "renderbuffer"sv, ""sv);
function_impl_generator.append(R"~~~(
glBindRenderbuffer(target, renderbuffer_handle);
m_renderbuffer_binding = renderbuffer;
)~~~");
continue;
}
if (function.name == "bindTexture"sv) {
generate_webgl_object_handle_unwrap(function_impl_generator, "texture"sv, ""sv);
function_impl_generator.append(R"~~~(
switch (target) {
case GL_TEXTURE_2D:
m_texture_binding_2d = texture;
break;
case GL_TEXTURE_CUBE_MAP:
m_texture_binding_cube_map = texture;
break;
)~~~");
if (webgl_version == 2) {
function_impl_generator.append(R"~~~(
case GL_TEXTURE_2D_ARRAY:
m_texture_binding_2d_array = texture;
break;
case GL_TEXTURE_3D:
m_texture_binding_3d = texture;
break;
)~~~");
}
function_impl_generator.append(R"~~~(
default:
dbgln("Unknown WebGL texture target for storing current binding: 0x{:04x}", target);
break;
}
glBindTexture(target, texture_handle);
)~~~");
continue;
}
if (function.name == "renderbufferStorage"sv) {
// To be backward compatible with WebGL 1, also accepts internal format DEPTH_STENCIL, which should be
// mapped to DEPTH24_STENCIL8 by implementations.
if (webgl_version == 2) {
function_impl_generator.append(R"~~~(
if (internalformat == GL_DEPTH_STENCIL)
internalformat = GL_DEPTH24_STENCIL8;
)~~~");
}
function_impl_generator.append(R"~~~(
glRenderbufferStorage(target, internalformat, width, height);
)~~~");
continue;
}
if (function.name.starts_with("samplerParameter"sv)) {
generate_webgl_object_handle_unwrap(function_impl_generator, "sampler"sv, ""sv);
function_impl_generator.set("param_type", function.name.substring_view(16, 1));
// pname is given in the following table:
// - TEXTURE_COMPARE_FUNC
// - TEXTURE_COMPARE_MODE
// - TEXTURE_MAG_FILTER
// - TEXTURE_MAX_LOD
// - TEXTURE_MIN_FILTER
// - TEXTURE_MIN_LOD
// - TEXTURE_WRAP_R
// - TEXTURE_WRAP_S
// - TEXTURE_WRAP_T
// If pname is not in the table above, generates an INVALID_ENUM error.
// NOTE: We have to do this ourselves, as OpenGL does not.
function_impl_generator.append(R"~~~(
switch (pname) {
case GL_TEXTURE_COMPARE_FUNC:
case GL_TEXTURE_COMPARE_MODE:
case GL_TEXTURE_MAG_FILTER:
case GL_TEXTURE_MAX_LOD:
case GL_TEXTURE_MIN_FILTER:
case GL_TEXTURE_MIN_LOD:
case GL_TEXTURE_WRAP_R:
case GL_TEXTURE_WRAP_S:
case GL_TEXTURE_WRAP_T:
break;
default:
dbgln("Unknown WebGL sampler parameter name: 0x{:04x}", pname);
set_error(GL_INVALID_ENUM);
return;
}
glSamplerParameter@param_type@(sampler_handle, pname, param);
)~~~");
continue;
}
if (function.name.starts_with("clearBuffer"sv) && function.name.ends_with('v')) {
auto element_type = function.name.substring_view(11, 2);
if (element_type == "fv"sv) {
function_impl_generator.set("cpp_element_type", "float"sv);
function_impl_generator.set("typed_array_type", "Float32Array"sv);
function_impl_generator.set("gl_postfix", "f"sv);
} else if (element_type == "iv"sv) {
function_impl_generator.set("cpp_element_type", "int"sv);
function_impl_generator.set("typed_array_type", "Int32Array"sv);
function_impl_generator.set("gl_postfix", "i"sv);
} else if (element_type == "ui"sv) {
function_impl_generator.set("cpp_element_type", "u32"sv);
function_impl_generator.set("typed_array_type", "Uint32Array"sv);
function_impl_generator.set("gl_postfix", "ui"sv);
} else {
VERIFY_NOT_REACHED();
}
function_impl_generator.append(R"~~~(
@cpp_element_type@ const* data = nullptr;
size_t count = 0;
if (values.has<Vector<@cpp_element_type@>>()) {
auto& vector = values.get<Vector<@cpp_element_type@>>();
data = vector.data();
count = vector.size();
} else if (values.has<GC::Root<WebIDL::BufferSource>>()) {
auto& typed_array_base = static_cast<JS::TypedArrayBase&>(*values.get<GC::Root<WebIDL::BufferSource>>()->raw_object());
auto& typed_array = verify_cast<JS::@typed_array_type@>(typed_array_base);
data = typed_array.data().data();
count = typed_array.array_length().length();
} else {
VERIFY_NOT_REACHED();
}
switch (buffer) {
case GL_COLOR:
if (src_offset + 4 > count) {
set_error(GL_INVALID_VALUE);
return;
}
break;
case GL_DEPTH:
case GL_STENCIL:
if (src_offset + 1 > count) {
set_error(GL_INVALID_VALUE);
return;
}
break;
default:
dbgln("Unknown WebGL buffer target for buffer clearing: 0x{:04x}", buffer);
set_error(GL_INVALID_ENUM);
return;
}
data += src_offset;
glClearBuffer@gl_postfix@v(buffer, drawbuffer, data);
needs_to_present();
)~~~");
continue;
}
Vector<ByteString> gl_call_arguments; Vector<ByteString> gl_call_arguments;
for (size_t i = 0; i < function.parameters.size(); ++i) { for (size_t i = 0; i < function.parameters.size(); ++i) {
auto const& parameter = function.parameters[i]; auto const& parameter = function.parameters[i];
@ -1129,8 +1568,8 @@ public:
size_t byte_size = 0; size_t byte_size = 0;
if (@buffer_source_name@->is_typed_array_base()) { if (@buffer_source_name@->is_typed_array_base()) {
auto& typed_array_base = static_cast<JS::TypedArrayBase&>(*@buffer_source_name@->raw_object()); auto& typed_array_base = static_cast<JS::TypedArrayBase&>(*@buffer_source_name@->raw_object());
ptr = typed_array_base.viewed_array_buffer()->buffer().data(); ptr = typed_array_base.viewed_array_buffer()->buffer().data() + typed_array_base.byte_offset();
byte_size = typed_array_base.viewed_array_buffer()->byte_length(); byte_size = @buffer_source_name@->byte_length();
} else if (@buffer_source_name@->is_data_view()) { } else if (@buffer_source_name@->is_data_view()) {
auto& data_view = static_cast<JS::DataView&>(*@buffer_source_name@->raw_object()); auto& data_view = static_cast<JS::DataView&>(*@buffer_source_name@->raw_object());
ptr = data_view.viewed_array_buffer()->buffer().data(); ptr = data_view.viewed_array_buffer()->buffer().data();
@ -1175,8 +1614,31 @@ public:
} }
header_file_generator.append(R"~~~( header_file_generator.append(R"~~~(
protected:
virtual void visit_edges(JS::Cell::Visitor&) override;
private: private:
GC::Ref<JS::Realm> m_realm; GC::Ref<JS::Realm> m_realm;
GC::Ptr<WebGLBuffer> m_array_buffer_binding;
GC::Ptr<WebGLBuffer> m_element_array_buffer_binding;
GC::Ptr<WebGLProgram> m_current_program;
GC::Ptr<WebGLFramebuffer> m_framebuffer_binding;
GC::Ptr<WebGLRenderbuffer> m_renderbuffer_binding;
GC::Ptr<WebGLTexture> m_texture_binding_2d;
GC::Ptr<WebGLTexture> m_texture_binding_cube_map;
)~~~");
if (webgl_version == 2) {
header_file_generator.append(R"~~~(
GC::Ptr<WebGLBuffer> m_uniform_buffer_binding;
GC::Ptr<WebGLBuffer> m_copy_read_buffer_binding;
GC::Ptr<WebGLBuffer> m_copy_write_buffer_binding;
GC::Ptr<WebGLTexture> m_texture_binding_2d_array;
GC::Ptr<WebGLTexture> m_texture_binding_3d;
)~~~");
}
header_file_generator.append(R"~~~(
NonnullOwnPtr<OpenGLContext> m_context; NonnullOwnPtr<OpenGLContext> m_context;
}; };
@ -1184,6 +1646,31 @@ private:
)~~~"); )~~~");
implementation_file_generator.append(R"~~~( implementation_file_generator.append(R"~~~(
void @class_name@::visit_edges(JS::Cell::Visitor& visitor)
{
visitor.visit(m_realm);
visitor.visit(m_array_buffer_binding);
visitor.visit(m_element_array_buffer_binding);
visitor.visit(m_current_program);
visitor.visit(m_framebuffer_binding);
visitor.visit(m_renderbuffer_binding);
visitor.visit(m_texture_binding_2d);
visitor.visit(m_texture_binding_cube_map);
)~~~");
if (webgl_version == 2) {
implementation_file_generator.append(R"~~~(
visitor.visit(m_uniform_buffer_binding);
visitor.visit(m_copy_read_buffer_binding);
visitor.visit(m_copy_write_buffer_binding);
visitor.visit(m_texture_binding_2d_array);
visitor.visit(m_texture_binding_3d);
)~~~");
}
implementation_file_generator.append(R"~~~(
}
} }
)~~~"); )~~~");