ladybird/Libraries/LibWeb/WebGL/Extensions/OESVertexArrayObject.cpp
Aliaksandr Kalenik 5b856595b3 Meta+LibWeb/WebGL: Route all GL calls through generated GLFunctions
LibWeb's WebGL implementation currently reaches ANGLE by calling glFoo()
throughout the WebGL context and extension code. That ties the WebGL
spec layer to the concrete GL executor. A future backend that records
operations, sends them to another process, or executes them from the
Compositor would otherwise need to duplicate the WebGL logic or edit
every call site again.

Introduce GLFunctions as an explicit boundary between WebGL semantics
and GL execution. GLFunctions.json lists the GL entry points used by the
implementation, and the generator emits one forwarding method per entry
point. OpenGLContext implements those methods today, so the current
in-process ANGLE path keeps the same behavior while all callers go
through a single replaceable interface.

That boundary is needed before canvas/WebGL rendering can move to the
Compositor: the WebGL context code can keep doing validation, state
tracking, and spec-visible error handling in LibWeb, while a later
implementation can record the same GL calls and replay them where the
canvas surface is produced. The JSON source also gives the recorder and
replayer one shared description of argument shapes, avoiding two
hand-written views of the GL API drifting apart.
2026-06-13 01:58:43 +02:00

104 lines
3 KiB
C++

/*
* Copyright (c) 2025, Luke Wilde <luke@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/OESVertexArrayObject.h>
#include <LibWeb/WebGL/Extensions/OESVertexArrayObject.h>
#include <LibWeb/WebGL/Extensions/WebGLVertexArrayObjectOES.h>
#include <LibWeb/WebGL/OpenGLContext.h>
#include <LibWeb/WebGL/WebGLRenderingContextBase.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(OESVertexArrayObject);
JS::ThrowCompletionOr<GC::Ref<JS::Object>> OESVertexArrayObject::create(JS::Realm& realm, GC::Ref<WebGLRenderingContextBase> context)
{
return realm.create<OESVertexArrayObject>(realm, context);
}
OESVertexArrayObject::OESVertexArrayObject(JS::Realm& realm, GC::Ref<WebGLRenderingContextBase> context)
: PlatformObject(realm)
, m_context(context)
{
}
GC::Ref<WebGLVertexArrayObjectOES> OESVertexArrayObject::create_vertex_array_oes()
{
m_context->context().make_current();
GLuint handle = 0;
m_context->context().gen_vertex_arrays_oes(1, &handle);
return WebGLVertexArrayObjectOES::create(realm(), m_context, handle);
}
void OESVertexArrayObject::delete_vertex_array_oes(GC::Ptr<WebGLVertexArrayObjectOES> array_object)
{
m_context->context().make_current();
GLuint vertex_array_handle = 0;
if (array_object) {
auto handle_or_error = array_object->handle(m_context.ptr());
if (handle_or_error.is_error()) {
// FIXME: m_context->set_error(GL_INVALID_OPERATION);
return;
}
vertex_array_handle = handle_or_error.release_value();
}
m_context->context().delete_vertex_arrays_oes(1, &vertex_array_handle);
}
bool OESVertexArrayObject::is_vertex_array_oes(GC::Ptr<WebGLVertexArrayObjectOES> array_object)
{
m_context->context().make_current();
GLuint vertex_array_handle = 0;
if (array_object) {
auto handle_or_error = array_object->handle(m_context.ptr());
if (handle_or_error.is_error()) {
return false;
}
vertex_array_handle = handle_or_error.release_value();
}
return m_context->context().is_vertex_array_oes(vertex_array_handle) == GL_TRUE;
}
void OESVertexArrayObject::bind_vertex_array_oes(GC::Ptr<WebGLVertexArrayObjectOES> array_object)
{
m_context->context().make_current();
GLuint vertex_array_handle = 0;
if (array_object) {
auto handle_or_error = array_object->handle(m_context.ptr());
if (handle_or_error.is_error()) {
// FIXME: m_context->set_error(GL_INVALID_OPERATION);
return;
}
vertex_array_handle = handle_or_error.release_value();
}
m_context->context().bind_vertex_array_oes(vertex_array_handle);
}
void OESVertexArrayObject::initialize(JS::Realm& realm)
{
WEB_SET_PROTOTYPE_FOR_INTERFACE(OESVertexArrayObject);
Base::initialize(realm);
}
void OESVertexArrayObject::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_context);
}
}