LibWeb: Save WebGL context pointer in WebGLObject

This way we could be sure that context object won't be deallocated
before any of the objects that belong to it.

Having a context pointer is also going to be used in upcoming changes
to generate an INVALID_OPERATION error if an object does not belong to
the context it's being used in.
This commit is contained in:
Aliaksandr Kalenik 2024-12-17 06:15:53 +01:00 committed by Alexander Kalenik
parent b909e3d587
commit cf730870c5
Notes: github-actions[bot] 2024-12-19 12:39:49 +00:00
28 changed files with 127 additions and 80 deletions

View file

@ -27,6 +27,10 @@ public:
virtual ~WebGL2RenderingContext() override;
// FIXME: This is a hack required to visit context from WebGLObject.
// It should be gone once WebGLRenderingContextBase inherits from PlatformObject.
GC::Cell const* gc_cell() const override { return this; }
void present() override;
void needs_to_present() override;

View file

@ -15,13 +15,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLBuffer);
GC::Ref<WebGLBuffer> WebGLBuffer::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLBuffer> WebGLBuffer::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLBuffer>(realm, handle);
return realm.create<WebGLBuffer>(realm, context, handle);
}
WebGLBuffer::WebGLBuffer(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLBuffer::WebGLBuffer(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -18,12 +18,12 @@ class WebGLBuffer final : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLBuffer);
public:
static GC::Ref<WebGLBuffer> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLBuffer> create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle);
virtual ~WebGLBuffer();
protected:
explicit WebGLBuffer(JS::Realm&, GLuint handle);
explicit WebGLBuffer(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -14,13 +14,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLFramebuffer);
GC::Ref<WebGLFramebuffer> WebGLFramebuffer::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLFramebuffer> WebGLFramebuffer::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLFramebuffer>(realm, handle);
return realm.create<WebGLFramebuffer>(realm, context, handle);
}
WebGLFramebuffer::WebGLFramebuffer(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLFramebuffer::WebGLFramebuffer(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -16,12 +16,12 @@ class WebGLFramebuffer final : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLFramebuffer);
public:
static GC::Ref<WebGLFramebuffer> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLFramebuffer> create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle);
virtual ~WebGLFramebuffer();
protected:
explicit WebGLFramebuffer(JS::Realm&, GLuint handle);
explicit WebGLFramebuffer(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -12,8 +12,9 @@
namespace Web::WebGL {
WebGLObject::WebGLObject(JS::Realm& realm, GLuint handle)
WebGLObject::WebGLObject(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: Bindings::PlatformObject(realm)
, m_context(&context)
, m_handle(handle)
{
}
@ -26,4 +27,10 @@ void WebGLObject::initialize(JS::Realm& realm)
WEB_SET_PROTOTYPE_FOR_INTERFACE(WebGLObject);
}
void WebGLObject::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_context->gc_cell());
}
}

View file

@ -10,6 +10,7 @@
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/WebGL/Types.h>
#include <LibWeb/WebGL/WebGLRenderingContextBase.h>
namespace Web::WebGL {
@ -25,16 +26,20 @@ public:
GLuint handle() const { return m_handle; }
protected:
explicit WebGLObject(JS::Realm&, GLuint handle);
explicit WebGLObject(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
void initialize(JS::Realm&) override;
void visit_edges(Visitor&) override;
bool invalidated() const { return m_invalidated; }
private:
// FIXME: It should be GC::Ptr instead of raw pointer, but we need to make WebGLRenderingContextBase inherit from PlatformObject first.
WebGLRenderingContextBase* m_context;
GLuint m_handle { 0 };
bool m_invalidated { false };
String m_label;
GLuint m_handle { 0 };
};
}

View file

@ -15,13 +15,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLProgram);
GC::Ref<WebGLProgram> WebGLProgram::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLProgram> WebGLProgram::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLProgram>(realm, handle);
return realm.create<WebGLProgram>(realm, context, handle);
}
WebGLProgram::WebGLProgram(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLProgram::WebGLProgram(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -18,12 +18,12 @@ class WebGLProgram final : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLProgram);
public:
static GC::Ref<WebGLProgram> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLProgram> create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle);
virtual ~WebGLProgram();
protected:
explicit WebGLProgram(JS::Realm&, GLuint handle);
explicit WebGLProgram(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -13,13 +13,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLQuery);
GC::Ref<WebGLQuery> WebGLQuery::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLQuery> WebGLQuery::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLQuery>(realm, handle);
return realm.create<WebGLQuery>(realm, context, handle);
}
WebGLQuery::WebGLQuery(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLQuery::WebGLQuery(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -16,12 +16,12 @@ class WebGLQuery : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLQuery);
public:
static GC::Ref<WebGLQuery> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLQuery> create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle);
virtual ~WebGLQuery() override;
protected:
explicit WebGLQuery(JS::Realm&, GLuint handle);
explicit WebGLQuery(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -14,13 +14,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLRenderbuffer);
GC::Ref<WebGLRenderbuffer> WebGLRenderbuffer::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLRenderbuffer> WebGLRenderbuffer::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLRenderbuffer>(realm, handle);
return realm.create<WebGLRenderbuffer>(realm, context, handle);
}
WebGLRenderbuffer::WebGLRenderbuffer(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLRenderbuffer::WebGLRenderbuffer(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -16,12 +16,12 @@ class WebGLRenderbuffer final : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLRenderbuffer);
public:
static GC::Ref<WebGLRenderbuffer> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLRenderbuffer> create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle);
virtual ~WebGLRenderbuffer();
protected:
explicit WebGLRenderbuffer(JS::Realm&, GLuint handle);
explicit WebGLRenderbuffer(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -26,6 +26,10 @@ public:
virtual ~WebGLRenderingContext() override;
// FIXME: This is a hack required to visit context from WebGLObject.
// It should be gone once WebGLRenderingContextBase inherits from PlatformObject.
GC::Cell const* gc_cell() const override { return this; }
void present() override;
void needs_to_present() override;

View file

@ -0,0 +1,18 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
namespace Web::WebGL {
// FIXME: This object should inherit from Bindings::PlatformObject and implement the WebGLRenderingContextBase IDL interface.
// We should make WebGL code generator to produce implementation for this interface.
class WebGLRenderingContextBase {
public:
virtual GC::Cell const* gc_cell() const = 0;
};
}

View file

@ -13,13 +13,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLSampler);
GC::Ref<WebGLSampler> WebGLSampler::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLSampler> WebGLSampler::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLSampler>(realm, handle);
return realm.create<WebGLSampler>(realm, context, handle);
}
WebGLSampler::WebGLSampler(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLSampler::WebGLSampler(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -16,12 +16,12 @@ class WebGLSampler : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLSampler);
public:
static GC::Ref<WebGLSampler> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLSampler> create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle);
virtual ~WebGLSampler() override;
protected:
explicit WebGLSampler(JS::Realm&, GLuint handle);
explicit WebGLSampler(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -15,13 +15,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLShader);
GC::Ref<WebGLShader> WebGLShader::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLShader> WebGLShader::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLShader>(realm, handle);
return realm.create<WebGLShader>(realm, context, handle);
}
WebGLShader::WebGLShader(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLShader::WebGLShader(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -18,12 +18,12 @@ class WebGLShader final : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLShader);
public:
static GC::Ref<WebGLShader> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLShader> create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle);
virtual ~WebGLShader();
protected:
explicit WebGLShader(JS::Realm&, GLuint handle);
explicit WebGLShader(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -13,13 +13,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLSync);
GC::Ref<WebGLSync> WebGLSync::create(JS::Realm& realm, GLsyncInternal handle)
GC::Ref<WebGLSync> WebGLSync::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLsyncInternal handle)
{
return realm.create<WebGLSync>(realm, handle);
return realm.create<WebGLSync>(realm, context, handle);
}
WebGLSync::WebGLSync(JS::Realm& realm, GLsyncInternal handle)
: WebGLObject(realm, 0)
WebGLSync::WebGLSync(JS::Realm& realm, WebGLRenderingContextBase& context, GLsyncInternal handle)
: WebGLObject(realm, context, 0)
, m_sync_handle(handle)
{
}

View file

@ -16,14 +16,14 @@ class WebGLSync : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLSync);
public:
static GC::Ref<WebGLSync> create(JS::Realm& realm, GLsyncInternal handle);
static GC::Ref<WebGLSync> create(JS::Realm& realm, WebGLRenderingContextBase&, GLsyncInternal handle);
virtual ~WebGLSync() override;
GLsyncInternal sync_handle() const { return m_sync_handle; }
protected:
explicit WebGLSync(JS::Realm&, GLsyncInternal handle);
explicit WebGLSync(JS::Realm&, WebGLRenderingContextBase&, GLsyncInternal handle);
virtual void initialize(JS::Realm&) override;

View file

@ -15,13 +15,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLTexture);
GC::Ref<WebGLTexture> WebGLTexture::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLTexture> WebGLTexture::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLTexture>(realm, handle);
return realm.create<WebGLTexture>(realm, context, handle);
}
WebGLTexture::WebGLTexture(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLTexture::WebGLTexture(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -18,12 +18,12 @@ class WebGLTexture final : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLTexture);
public:
static GC::Ref<WebGLTexture> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLTexture> create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle);
virtual ~WebGLTexture();
protected:
explicit WebGLTexture(JS::Realm&, GLuint handle);
explicit WebGLTexture(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -13,13 +13,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLTransformFeedback);
GC::Ref<WebGLTransformFeedback> WebGLTransformFeedback::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLTransformFeedback> WebGLTransformFeedback::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLTransformFeedback>(realm, handle);
return realm.create<WebGLTransformFeedback>(realm, context, handle);
}
WebGLTransformFeedback::WebGLTransformFeedback(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLTransformFeedback::WebGLTransformFeedback(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -16,12 +16,12 @@ class WebGLTransformFeedback : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLTransformFeedback);
public:
static GC::Ref<WebGLTransformFeedback> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLTransformFeedback> create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle);
virtual ~WebGLTransformFeedback() override;
protected:
explicit WebGLTransformFeedback(JS::Realm&, GLuint handle);
explicit WebGLTransformFeedback(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -13,13 +13,13 @@ namespace Web::WebGL {
GC_DEFINE_ALLOCATOR(WebGLVertexArrayObject);
GC::Ref<WebGLVertexArrayObject> WebGLVertexArrayObject::create(JS::Realm& realm, GLuint handle)
GC::Ref<WebGLVertexArrayObject> WebGLVertexArrayObject::create(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
{
return realm.create<WebGLVertexArrayObject>(realm, handle);
return realm.create<WebGLVertexArrayObject>(realm, context, handle);
}
WebGLVertexArrayObject::WebGLVertexArrayObject(JS::Realm& realm, GLuint handle)
: WebGLObject(realm, handle)
WebGLVertexArrayObject::WebGLVertexArrayObject(JS::Realm& realm, WebGLRenderingContextBase& context, GLuint handle)
: WebGLObject(realm, context, handle)
{
}

View file

@ -16,12 +16,12 @@ class WebGLVertexArrayObject : public WebGLObject {
GC_DECLARE_ALLOCATOR(WebGLVertexArrayObject);
public:
static GC::Ref<WebGLVertexArrayObject> create(JS::Realm& realm, GLuint handle);
static GC::Ref<WebGLVertexArrayObject> create(JS::Realm& realm, WebGLRenderingContextBase&, GLuint handle);
virtual ~WebGLVertexArrayObject() override;
protected:
explicit WebGLVertexArrayObject(JS::Realm&, GLuint handle);
explicit WebGLVertexArrayObject(JS::Realm&, WebGLRenderingContextBase&, GLuint handle);
virtual void initialize(JS::Realm&) override;
};

View file

@ -242,7 +242,7 @@ static void generate_get_parameter(SourceGenerator& generator, int webgl_version
glGetIntegerv(GL_@parameter_name@, &result);
if (!result)
return JS::js_null();
return @type_name@::create(m_realm, result);
return @type_name@::create(m_realm, *this, result);
)~~~");
} else {
VERIFY_NOT_REACHED();
@ -435,13 +435,14 @@ static Vector<GLchar> null_terminated_string(StringView string)
#include <LibGfx/Bitmap.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
#include <LibWeb/WebGL/WebGLRenderingContextBase.h>
#include <LibWeb/WebIDL/Types.h>
namespace Web::WebGL {
using namespace Web::HTML;
class @class_name@ {
class @class_name@ : public WebGLRenderingContextBase {
public:
@class_name@(JS::Realm&, NonnullOwnPtr<OpenGLContext>);
@ -510,11 +511,19 @@ public:
function_impl_generator.append(" m_context->notify_content_will_change();\n"sv);
}
if (function.name == "getUniformLocation"sv) {
function_impl_generator.append(R"~~~(
auto name_null_terminated = null_terminated_string(name);
return WebGLUniformLocation::create(m_realm, glGetUniformLocation(program ? program->handle() : 0, name_null_terminated.data()));
)~~~");
continue;
}
if (function.name == "createBuffer"sv) {
function_impl_generator.append(R"~~~(
GLuint handle = 0;
glGenBuffers(1, &handle);
return WebGLBuffer::create(m_realm, handle);
return WebGLBuffer::create(m_realm, *this, handle);
)~~~");
continue;
}
@ -523,7 +532,7 @@ public:
function_impl_generator.append(R"~~~(
GLuint handle = 0;
glGenTextures(1, &handle);
return WebGLTexture::create(m_realm, handle);
return WebGLTexture::create(m_realm, *this, handle);
)~~~");
continue;
}
@ -532,7 +541,7 @@ public:
function_impl_generator.append(R"~~~(
GLuint handle = 0;
glGenFramebuffers(1, &handle);
return WebGLFramebuffer::create(m_realm, handle);
return WebGLFramebuffer::create(m_realm, *this, handle);
)~~~");
continue;
}
@ -541,7 +550,7 @@ public:
function_impl_generator.append(R"~~~(
GLuint handle = 0;
glGenRenderbuffers(1, &handle);
return WebGLRenderbuffer::create(m_realm, handle);
return WebGLRenderbuffer::create(m_realm, *this, handle);
)~~~");
continue;
}
@ -550,7 +559,7 @@ public:
function_impl_generator.append(R"~~~(
GLuint handle = 0;
glGenVertexArrays(1, &handle);
return WebGLVertexArrayObject::create(m_realm, handle);
return WebGLVertexArrayObject::create(m_realm, *this, handle);
)~~~");
continue;
}
@ -559,7 +568,7 @@ public:
function_impl_generator.append(R"~~~(
GLuint handle = 0;
glGenSamplers(1, &handle);
return WebGLSampler::create(m_realm, handle);
return WebGLSampler::create(m_realm, *this, handle);
)~~~");
continue;
}
@ -567,7 +576,7 @@ public:
if (function.name == "fenceSync"sv) {
function_impl_generator.append(R"~~~(
GLsync handle = glFenceSync(condition, flags);
return WebGLSync::create(m_realm, handle);
return WebGLSync::create(m_realm, *this, handle);
)~~~");
continue;
}
@ -1104,7 +1113,7 @@ public:
function_impl_generator.append(" return @call_string@;"sv);
} else if (is_webgl_object_type(function.return_type->name())) {
function_impl_generator.set("return_type_name", function.return_type->name());
function_impl_generator.append(" return @return_type_name@::create(m_realm, @call_string@);"sv);
function_impl_generator.append(" return @return_type_name@::create(m_realm, *this, @call_string@);"sv);
} else {
VERIFY_NOT_REACHED();
}