diff --git a/Libraries/LibWeb/CMakeLists.txt b/Libraries/LibWeb/CMakeLists.txt index 525ca311170..1622ccd06f6 100644 --- a/Libraries/LibWeb/CMakeLists.txt +++ b/Libraries/LibWeb/CMakeLists.txt @@ -812,7 +812,6 @@ set(SOURCES WebGL/WebGLProgram.cpp WebGL/WebGLRenderbuffer.cpp WebGL/WebGLRenderingContext.cpp - WebGL/WebGLRenderingContextBase.cpp WebGL/WebGLShader.cpp WebGL/WebGLShaderPrecisionFormat.cpp WebGL/WebGLTexture.cpp diff --git a/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp b/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp index 4c304c259ec..4a9e2c0cdf3 100644 --- a/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp +++ b/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp @@ -1,21 +1,39 @@ /* * Copyright (c) 2022, Luke Wilde + * Copyright (c) 2023, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ +#include +#include #include #include -#include #include +#include +#include #include +#include #include +#include #include +#include +#include + +#include +#include namespace Web::WebGL { GC_DEFINE_ALLOCATOR(WebGLRenderingContext); +#define RETURN_WITH_WEBGL_ERROR_IF(condition, error) \ + if (condition) { \ + dbgln_if(WEBGL_CONTEXT_DEBUG, "{}(): error {:#x}", __func__, error); \ + set_error(error); \ + return; \ + } + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#fire-a-webgl-context-event static void fire_webgl_context_event(HTML::HTMLCanvasElement& canvas_element, FlyString const& type) { @@ -50,7 +68,11 @@ JS::ThrowCompletionOr> WebGLRenderingContext::cre } WebGLRenderingContext::WebGLRenderingContext(JS::Realm& realm, HTML::HTMLCanvasElement& canvas_element, NonnullOwnPtr context, WebGLContextAttributes context_creation_parameters, WebGLContextAttributes actual_context_parameters) - : WebGLRenderingContextBase(realm, canvas_element, move(context), move(context_creation_parameters), move(actual_context_parameters)) + : PlatformObject(realm) + , m_context(move(context)) + , m_canvas_element(canvas_element) + , m_context_creation_parameters(context_creation_parameters) + , m_actual_context_parameters(actual_context_parameters) { } @@ -62,4 +84,291 @@ void WebGLRenderingContext::initialize(JS::Realm& realm) WEB_SET_PROTOTYPE_FOR_INTERFACE(WebGLRenderingContext); } +void WebGLRenderingContext::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(m_canvas_element); +} + +void WebGLRenderingContext::present() +{ + if (!m_should_present) + return; + + m_should_present = false; + + // "Before the drawing buffer is presented for compositing the implementation shall ensure that all rendering operations have been flushed to the drawing buffer." + glFlush(); + + // "By default, after compositing the contents of the drawing buffer shall be cleared to their default values, as shown in the table above. + // This default behavior can be changed by setting the preserveDrawingBuffer attribute of the WebGLContextAttributes object. + // If this flag is true, the contents of the drawing buffer shall be preserved until the author either clears or overwrites them." + if (!m_context_creation_parameters.preserve_drawing_buffer) { + m_context->clear_buffer_to_default_values(); + } +} + +GC::Ref WebGLRenderingContext::canvas_for_binding() const +{ + return *m_canvas_element; +} + +void WebGLRenderingContext::needs_to_present() +{ + m_should_present = true; + + if (!m_canvas_element->paintable()) + return; + m_canvas_element->paintable()->set_needs_display(); +} + +void WebGLRenderingContext::set_error(GLenum error) +{ + auto context_error = glGetError(); + if (context_error != GL_NO_ERROR) + m_error = context_error; + else + m_error = error; +} + +bool WebGLRenderingContext::is_context_lost() const +{ + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::is_context_lost()"); + return m_context_lost; +} + +void WebGLRenderingContext::set_size(Gfx::IntSize const&) +{ + TODO(); +} + +void WebGLRenderingContext::reset_to_default_state() +{ +} + +RefPtr WebGLRenderingContext::surface() +{ + TODO(); +} + +Optional> WebGLRenderingContext::get_supported_extensions() const +{ + if (m_context_lost) + return Optional> {}; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::get_supported_extensions()"); + + // FIXME: We don't currently support any extensions. + return Vector {}; +} + +JS::Object* WebGLRenderingContext::get_extension(String const& name) const +{ + if (m_context_lost) + return nullptr; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::get_extension(name='{}')", name); + + // FIXME: We don't currently support any extensions. + return nullptr; +} + +void WebGLRenderingContext::active_texture(GLenum texture) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::active_texture(texture={:#08x})", texture); + m_context->gl_active_texture(texture); +} + +void WebGLRenderingContext::clear(GLbitfield mask) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::clear(mask={:#08x})", mask); + m_context->gl_clear(mask); + + // FIXME: This should only be done if this is targeting the front buffer. + needs_to_present(); +} + +void WebGLRenderingContext::clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::clear_color(red={}, green={}, blue={}, alpha={})", red, green, blue, alpha); + m_context->gl_clear_color(red, green, blue, alpha); +} + +void WebGLRenderingContext::clear_depth(GLclampf depth) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::clear_depth(depth={})", depth); + m_context->gl_clear_depth(depth); +} + +void WebGLRenderingContext::clear_stencil(GLint s) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::clear_stencil(s={:#08x})", s); + m_context->gl_clear_stencil(s); +} + +void WebGLRenderingContext::color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::color_mask(red={}, green={}, blue={}, alpha={})", red, green, blue, alpha); + m_context->gl_color_mask(red, green, blue, alpha); +} + +void WebGLRenderingContext::cull_face(GLenum mode) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::cull_face(mode={:#08x})", mode); + m_context->gl_cull_face(mode); +} + +void WebGLRenderingContext::depth_func(GLenum func) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::depth_func(func={:#08x})", func); + m_context->gl_depth_func(func); +} + +void WebGLRenderingContext::depth_mask(GLboolean mask) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::depth_mask(mask={})", mask); + m_context->gl_depth_mask(mask); +} + +void WebGLRenderingContext::depth_range(GLclampf z_near, GLclampf z_far) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::depth_range(z_near={}, z_far={})", z_near, z_far); + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#VIEWPORT_DEPTH_RANGE + // "The WebGL API does not support depth ranges with where the near plane is mapped to a value greater than that of the far plane. A call to depthRange will generate an INVALID_OPERATION error if zNear is greater than zFar." + RETURN_WITH_WEBGL_ERROR_IF(z_near > z_far, GL_INVALID_OPERATION); + m_context->gl_depth_range(z_near, z_far); +} + +void WebGLRenderingContext::finish() +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::finish()"); + m_context->gl_finish(); +} + +void WebGLRenderingContext::flush() +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::flush()"); + m_context->gl_flush(); +} + +void WebGLRenderingContext::front_face(GLenum mode) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::front_face(mode={:#08x})", mode); + m_context->gl_front_face(mode); +} + +GLenum WebGLRenderingContext::get_error() +{ + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::get_error()"); + + // "If the context's webgl context lost flag is set, returns CONTEXT_LOST_WEBGL the first time this method is called. Afterward, returns NO_ERROR until the context has been restored." + // FIXME: The plan here is to make the context lost handler unconditionally set m_error to CONTEXT_LOST_WEBGL, which we currently do not have. + // The idea for the unconditional set is that any potentially error generating functions will not execute when the context is lost. + if (m_error != GL_NO_ERROR || m_context_lost) { + auto last_error = m_error; + m_error = GL_NO_ERROR; + return last_error; + } + + return m_context->gl_get_error(); +} + +void WebGLRenderingContext::line_width(GLfloat width) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::line_width(width={})", width); + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#NAN_LINE_WIDTH + // "In the WebGL API, if the width parameter passed to lineWidth is set to NaN, an INVALID_VALUE error is generated and the line width is not changed." + RETURN_WITH_WEBGL_ERROR_IF(isnan(width), GL_INVALID_VALUE); + m_context->gl_line_width(width); +} + +void WebGLRenderingContext::polygon_offset(GLfloat factor, GLfloat units) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::polygon_offset(factor={}, units={})", factor, units); + m_context->gl_polygon_offset(factor, units); +} + +void WebGLRenderingContext::scissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::scissor(x={}, y={}, width={}, height={})", x, y, width, height); + m_context->gl_scissor(x, y, width, height); +} + +void WebGLRenderingContext::stencil_op(GLenum fail, GLenum zfail, GLenum zpass) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::stencil_op(fail={:#08x}, zfail={:#08x}, zpass={:#08x})", fail, zfail, zpass); + m_context->gl_stencil_op_separate(GL_FRONT_AND_BACK, fail, zfail, zpass); +} + +void WebGLRenderingContext::stencil_op_separate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::stencil_op_separate(face={:#08x}, fail={:#08x}, zfail={:#08x}, zpass={:#08x})", face, fail, zfail, zpass); + m_context->gl_stencil_op_separate(face, fail, zfail, zpass); +} + +void WebGLRenderingContext::viewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + if (m_context_lost) + return; + + dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContext::viewport(x={}, y={}, width={}, height={})", x, y, width, height); + m_context->gl_viewport(x, y, width, height); +} + } diff --git a/Libraries/LibWeb/WebGL/WebGLRenderingContext.h b/Libraries/LibWeb/WebGL/WebGLRenderingContext.h index f2d3f613118..a1c48fd373f 100644 --- a/Libraries/LibWeb/WebGL/WebGLRenderingContext.h +++ b/Libraries/LibWeb/WebGL/WebGLRenderingContext.h @@ -7,15 +7,17 @@ #pragma once -#include #include #include -#include +#include +#include +#include +#include namespace Web::WebGL { -class WebGLRenderingContext final : public WebGLRenderingContextBase { - WEB_PLATFORM_OBJECT(WebGLRenderingContext, WebGLRenderingContextBase); +class WebGLRenderingContext : public Bindings::PlatformObject { + WEB_PLATFORM_OBJECT(WebGLRenderingContext, Bindings::PlatformObject); GC_DECLARE_ALLOCATOR(WebGLRenderingContext); public: @@ -23,10 +25,84 @@ public: virtual ~WebGLRenderingContext() override; + void present(); + void needs_to_present(); + + GC::Ref canvas_for_binding() const; + + bool is_context_lost() const; + + RefPtr surface(); + + void set_size(Gfx::IntSize const&); + void reset_to_default_state(); + + Optional> get_supported_extensions() const; + JS::Object* get_extension(String const& name) const; + + void active_texture(GLenum texture); + + void clear(GLbitfield mask); + void clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); + void clear_depth(GLclampf depth); + void clear_stencil(GLint s); + void color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); + + void cull_face(GLenum mode); + + void depth_func(GLenum func); + void depth_mask(GLboolean mask); + void depth_range(GLclampf z_near, GLclampf z_far); + + void finish(); + void flush(); + + void front_face(GLenum mode); + + GLenum get_error(); + + void line_width(GLfloat width); + void polygon_offset(GLfloat factor, GLfloat units); + + void scissor(GLint x, GLint y, GLsizei width, GLsizei height); + + void stencil_op(GLenum fail, GLenum zfail, GLenum zpass); + void stencil_op_separate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); + + void viewport(GLint x, GLint y, GLsizei width, GLsizei height); + private: virtual void initialize(JS::Realm&) override; WebGLRenderingContext(JS::Realm&, HTML::HTMLCanvasElement&, NonnullOwnPtr context, WebGLContextAttributes context_creation_parameters, WebGLContextAttributes actual_context_parameters); + + virtual void visit_edges(Cell::Visitor&) override; + + OwnPtr m_context; + + GC::Ref m_canvas_element; + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#context-creation-parameters + // Each WebGLRenderingContext has context creation parameters, set upon creation, in a WebGLContextAttributes object. + WebGLContextAttributes m_context_creation_parameters {}; + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#actual-context-parameters + // Each WebGLRenderingContext has actual context parameters, set each time the drawing buffer is created, in a WebGLContextAttributes object. + WebGLContextAttributes m_actual_context_parameters {}; + + // https://www.khronos.org/registry/webgl/specs/latest/1.0/#webgl-context-lost-flag + // Each WebGLRenderingContext has a webgl context lost flag, which is initially unset. + bool m_context_lost { false }; + + // WebGL presents its drawing buffer to the HTML page compositor immediately before a compositing operation, but only if at least one of the following has occurred since the previous compositing operation: + // - Context creation + // - Canvas resize + // - clear, drawArrays, or drawElements has been called while the drawing buffer is the currently bound framebuffer + bool m_should_present { true }; + + GLenum m_error { 0 }; + + void set_error(GLenum error); }; } diff --git a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp b/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp deleted file mode 100644 index 3848c3e0d18..00000000000 --- a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2022, Luke Wilde - * Copyright (c) 2024, Aliaksandr Kalenik - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include - -namespace Web::WebGL { - -// FIXME: Replace with constants defined in WebGL spec. -#define GL_INVALID_OPERATION 0x0502 -#define GL_INVALID_VALUE 0x0501 -#define GL_FRONT_AND_BACK 0x0408 - -WebGLRenderingContextBase::WebGLRenderingContextBase(JS::Realm& realm, HTML::HTMLCanvasElement& canvas_element, NonnullOwnPtr context, WebGLContextAttributes context_creation_parameters, WebGLContextAttributes actual_context_parameters) - : PlatformObject(realm) - , m_canvas_element(canvas_element) - , m_context(move(context)) - , m_context_creation_parameters(move(context_creation_parameters)) - , m_actual_context_parameters(move(actual_context_parameters)) -{ -} - -WebGLRenderingContextBase::~WebGLRenderingContextBase() = default; - -void WebGLRenderingContextBase::visit_edges(Cell::Visitor& visitor) -{ - Base::visit_edges(visitor); - visitor.visit(m_canvas_element); -} - -#define RETURN_WITH_WEBGL_ERROR_IF(condition, error) \ - if (condition) { \ - dbgln_if(WEBGL_CONTEXT_DEBUG, "{}(): error {:#x}", __func__, error); \ - set_error(error); \ - return; \ - } - -void WebGLRenderingContextBase::present() -{ - if (!m_should_present) - return; - - m_should_present = false; - - // "Before the drawing buffer is presented for compositing the implementation shall ensure that all rendering operations have been flushed to the drawing buffer." - // FIXME: Is this the operation it means? - m_context->gl_flush(); - - m_context->present(); - - // "By default, after compositing the contents of the drawing buffer shall be cleared to their default values, as shown in the table above. - // This default behavior can be changed by setting the preserveDrawingBuffer attribute of the WebGLContextAttributes object. - // If this flag is true, the contents of the drawing buffer shall be preserved until the author either clears or overwrites them." - if (!m_context_creation_parameters.preserve_drawing_buffer) { - m_context->clear_buffer_to_default_values(); - } -} - -HTML::HTMLCanvasElement& WebGLRenderingContextBase::canvas_element() -{ - return *m_canvas_element; -} - -HTML::HTMLCanvasElement const& WebGLRenderingContextBase::canvas_element() const -{ - return *m_canvas_element; -} - -GC::Ref WebGLRenderingContextBase::canvas_for_binding() const -{ - return *m_canvas_element; -} - -void WebGLRenderingContextBase::needs_to_present() -{ - m_should_present = true; - - if (!canvas_element().paintable()) - return; - canvas_element().paintable()->set_needs_display(); -} - -void WebGLRenderingContextBase::set_error(GLenum error) -{ - auto context_error = m_context->gl_get_error(); - if (context_error != GL_NO_ERROR) - m_error = context_error; - else - m_error = error; -} - -bool WebGLRenderingContextBase::is_context_lost() const -{ - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::is_context_lost()"); - return m_context_lost; -} - -Optional> WebGLRenderingContextBase::get_supported_extensions() const -{ - if (m_context_lost) - return Optional> {}; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::get_supported_extensions()"); - - // FIXME: We don't currently support any extensions. - return Vector {}; -} - -JS::Object* WebGLRenderingContextBase::get_extension(String const& name) const -{ - if (m_context_lost) - return nullptr; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::get_extension(name='{}')", name); - - // FIXME: We don't currently support any extensions. - return nullptr; -} - -void WebGLRenderingContextBase::active_texture(GLenum texture) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::active_texture(texture={:#08x})", texture); - m_context->gl_active_texture(texture); -} - -void WebGLRenderingContextBase::clear(GLbitfield mask) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::clear(mask={:#08x})", mask); - m_context->gl_clear(mask); - - // FIXME: This should only be done if this is targeting the front buffer. - needs_to_present(); -} - -void WebGLRenderingContextBase::clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::clear_color(red={}, green={}, blue={}, alpha={})", red, green, blue, alpha); - m_context->gl_clear_color(red, green, blue, alpha); -} - -void WebGLRenderingContextBase::clear_depth(GLclampf depth) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::clear_depth(depth={})", depth); - m_context->gl_clear_depth(depth); -} - -void WebGLRenderingContextBase::clear_stencil(GLint s) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::clear_stencil(s={:#08x})", s); - m_context->gl_clear_stencil(s); -} - -void WebGLRenderingContextBase::color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::color_mask(red={}, green={}, blue={}, alpha={})", red, green, blue, alpha); - m_context->gl_color_mask(red, green, blue, alpha); -} - -void WebGLRenderingContextBase::cull_face(GLenum mode) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::cull_face(mode={:#08x})", mode); - m_context->gl_cull_face(mode); -} - -void WebGLRenderingContextBase::depth_func(GLenum func) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::depth_func(func={:#08x})", func); - m_context->gl_depth_func(func); -} - -void WebGLRenderingContextBase::depth_mask(GLboolean mask) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::depth_mask(mask={})", mask); - m_context->gl_depth_mask(mask); -} - -void WebGLRenderingContextBase::depth_range(GLclampf z_near, GLclampf z_far) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::depth_range(z_near={}, z_far={})", z_near, z_far); - - // https://www.khronos.org/registry/webgl/specs/latest/1.0/#VIEWPORT_DEPTH_RANGE - // "The WebGL API does not support depth ranges with where the near plane is mapped to a value greater than that of the far plane. A call to depthRange will generate an INVALID_OPERATION error if zNear is greater than zFar." - RETURN_WITH_WEBGL_ERROR_IF(z_near > z_far, GL_INVALID_OPERATION); - m_context->gl_depth_range(z_near, z_far); -} - -void WebGLRenderingContextBase::finish() -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::finish()"); - m_context->gl_finish(); -} - -void WebGLRenderingContextBase::flush() -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::flush()"); - m_context->gl_flush(); -} - -void WebGLRenderingContextBase::front_face(GLenum mode) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::front_face(mode={:#08x})", mode); - m_context->gl_front_face(mode); -} - -GLenum WebGLRenderingContextBase::get_error() -{ - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::get_error()"); - - // "If the context's webgl context lost flag is set, returns CONTEXT_LOST_WEBGL the first time this method is called. Afterward, returns NO_ERROR until the context has been restored." - // FIXME: The plan here is to make the context lost handler unconditionally set m_error to CONTEXT_LOST_WEBGL, which we currently do not have. - // The idea for the unconditional set is that any potentially error generating functions will not execute when the context is lost. - if (m_error != GL_NO_ERROR || m_context_lost) { - auto last_error = m_error; - m_error = GL_NO_ERROR; - return last_error; - } - - return m_context->gl_get_error(); -} - -void WebGLRenderingContextBase::line_width(GLfloat width) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::line_width(width={})", width); - - // https://www.khronos.org/registry/webgl/specs/latest/1.0/#NAN_LINE_WIDTH - // "In the WebGL API, if the width parameter passed to lineWidth is set to NaN, an INVALID_VALUE error is generated and the line width is not changed." - RETURN_WITH_WEBGL_ERROR_IF(isnan(width), GL_INVALID_VALUE); - m_context->gl_line_width(width); -} - -void WebGLRenderingContextBase::polygon_offset(GLfloat factor, GLfloat units) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::polygon_offset(factor={}, units={})", factor, units); - m_context->gl_polygon_offset(factor, units); -} - -void WebGLRenderingContextBase::scissor(GLint x, GLint y, GLsizei width, GLsizei height) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::scissor(x={}, y={}, width={}, height={})", x, y, width, height); - m_context->gl_scissor(x, y, width, height); -} - -void WebGLRenderingContextBase::stencil_op(GLenum fail, GLenum zfail, GLenum zpass) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::stencil_op(fail={:#08x}, zfail={:#08x}, zpass={:#08x})", fail, zfail, zpass); - m_context->gl_stencil_op_separate(GL_FRONT_AND_BACK, fail, zfail, zpass); -} - -void WebGLRenderingContextBase::stencil_op_separate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::stencil_op_separate(face={:#08x}, fail={:#08x}, zfail={:#08x}, zpass={:#08x})", face, fail, zfail, zpass); - m_context->gl_stencil_op_separate(face, fail, zfail, zpass); -} - -void WebGLRenderingContextBase::viewport(GLint x, GLint y, GLsizei width, GLsizei height) -{ - if (m_context_lost) - return; - - dbgln_if(WEBGL_CONTEXT_DEBUG, "WebGLRenderingContextBase::viewport(x={}, y={}, width={}, height={})", x, y, width, height); - m_context->gl_viewport(x, y, width, height); -} - -} diff --git a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h b/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h deleted file mode 100644 index f87af49a11b..00000000000 --- a/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2022, Luke Wilde - * Copyright (c) 2024, Aliaksandr Kalenik - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace Web::WebGL { - -#define GL_NO_ERROR 0 - -class WebGLRenderingContextBase : public Bindings::PlatformObject { - WEB_PLATFORM_OBJECT(WebGLRenderingContextBase, Bindings::PlatformObject); - -public: - virtual ~WebGLRenderingContextBase(); - - void present(); - - GC::Ref canvas_for_binding() const; - - bool is_context_lost() const; - - Optional> get_supported_extensions() const; - JS::Object* get_extension(String const& name) const; - - void active_texture(GLenum texture); - - void clear(GLbitfield mask); - void clear_color(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); - void clear_depth(GLclampf depth); - void clear_stencil(GLint s); - void color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); - - void cull_face(GLenum mode); - - void depth_func(GLenum func); - void depth_mask(GLboolean mask); - void depth_range(GLclampf z_near, GLclampf z_far); - - void finish(); - void flush(); - - void front_face(GLenum mode); - - GLenum get_error(); - - void line_width(GLfloat width); - void polygon_offset(GLfloat factor, GLfloat units); - - void scissor(GLint x, GLint y, GLsizei width, GLsizei height); - - void stencil_op(GLenum fail, GLenum zfail, GLenum zpass); - void stencil_op_separate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass); - - void viewport(GLint x, GLint y, GLsizei width, GLsizei height); - -protected: - WebGLRenderingContextBase(JS::Realm&, HTML::HTMLCanvasElement& canvas_element, NonnullOwnPtr context, WebGLContextAttributes context_creation_parameters, WebGLContextAttributes actual_context_parameters); - -private: - virtual void visit_edges(Cell::Visitor&) override; - - GC::Ref m_canvas_element; - - NonnullOwnPtr m_context; - - // https://www.khronos.org/registry/webgl/specs/latest/1.0/#context-creation-parameters - // Each WebGLRenderingContext has context creation parameters, set upon creation, in a WebGLContextAttributes object. - WebGLContextAttributes m_context_creation_parameters {}; - - // https://www.khronos.org/registry/webgl/specs/latest/1.0/#actual-context-parameters - // Each WebGLRenderingContext has actual context parameters, set each time the drawing buffer is created, in a WebGLContextAttributes object. - WebGLContextAttributes m_actual_context_parameters {}; - - // https://www.khronos.org/registry/webgl/specs/latest/1.0/#webgl-context-lost-flag - // Each WebGLRenderingContext has a webgl context lost flag, which is initially unset. - bool m_context_lost { false }; - - // WebGL presents its drawing buffer to the HTML page compositor immediately before a compositing operation, but only if at least one of the following has occurred since the previous compositing operation: - // - Context creation - // - Canvas resize - // - clear, drawArrays, or drawElements has been called while the drawing buffer is the currently bound framebuffer - bool m_should_present { true }; - - GLenum m_error { GL_NO_ERROR }; - - HTML::HTMLCanvasElement& canvas_element(); - HTML::HTMLCanvasElement const& canvas_element() const; - - void needs_to_present(); - void set_error(GLenum error); -}; - -}