diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 1d15e7c90d..5e27306da1 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -621,6 +621,7 @@ set(SOURCES WebDriver/Screenshot.cpp WebDriver/TimeoutsConfiguration.cpp WebGL/EventNames.cpp + WebGL/OpenGLContext.cpp WebGL/WebGLContextAttributes.cpp WebGL/WebGLContextEvent.cpp WebGL/WebGLRenderingContext.cpp @@ -679,12 +680,18 @@ set(GENERATED_SOURCES serenity_lib(LibWeb web) # NOTE: We link with LibSoftGPU here instead of lazy loading it via dlopen() so that we do not have to unveil the library and pledge prot_exec. -target_link_libraries(LibWeb PRIVATE LibCore LibCrypto LibJS LibMarkdown LibHTTP LibGemini LibGL LibGUI LibGfx LibIPC LibLocale LibRegex LibSoftGPU LibSyntax LibTextCodec LibUnicode LibAudio LibVideo LibWasm LibXML LibIDL) +target_link_libraries(LibWeb PRIVATE LibCore LibCrypto LibJS LibMarkdown LibHTTP LibGemini LibGUI LibGfx LibIPC LibLocale LibRegex LibSoftGPU LibSyntax LibTextCodec LibUnicode LibAudio LibVideo LibWasm LibXML LibIDL) link_with_locale_data(LibWeb) if (HAS_ACCELERATED_GRAPHICS) + target_link_libraries(LibWeb PRIVATE ${ACCEL_GFX_LIBS}) target_sources(LibWeb PRIVATE Painting/PaintingCommandExecutorGPU.cpp) target_link_libraries(LibWeb PRIVATE LibAccelGfx) + target_compile_definitions(LibWeb PRIVATE HAS_ACCELERATED_GRAPHICS) +endif() + +if (SERENITYOS) + target_link_libraries(LibWeb PRIVATE LibGL) endif() generate_js_bindings(LibWeb) diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.cpp b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.cpp index 2e587d2f05..283570ff5c 100644 --- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.cpp +++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPath.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include namespace Web::HTML { diff --git a/Userland/Libraries/LibWeb/WebGL/OpenGLContext.cpp b/Userland/Libraries/LibWeb/WebGL/OpenGLContext.cpp new file mode 100644 index 0000000000..1b458f2f8f --- /dev/null +++ b/Userland/Libraries/LibWeb/WebGL/OpenGLContext.cpp @@ -0,0 +1,360 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +#ifdef HAS_ACCELERATED_GRAPHICS +# include +# include +#elif defined(AK_OS_SERENITY) +# include +#endif + +namespace Web::WebGL { + +#ifdef HAS_ACCELERATED_GRAPHICS +class AccelGfxContext : public OpenGLContext { +public: + virtual void activate() override + { + m_context->activate(); + } + + virtual void present(Gfx::Bitmap& bitmap) override + { + VERIFY(bitmap.format() == Gfx::BitmapFormat::BGRA8888); + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glReadPixels(0, 0, bitmap.width(), bitmap.height(), GL_BGRA, GL_UNSIGNED_BYTE, bitmap.scanline(0)); + } + + virtual GLenum gl_get_error() override + { + activate(); + return glGetError(); + } + + virtual void gl_get_doublev(GLenum pname, GLdouble* params) override + { + activate(); + glGetDoublev(pname, params); + } + + virtual void gl_get_integerv(GLenum pname, GLint* params) override + { + activate(); + glGetIntegerv(pname, params); + } + + virtual void gl_clear(GLbitfield mask) override + { + activate(); + glClear(mask); + } + + virtual void gl_clear_color(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) override + { + activate(); + glClearColor(red, green, blue, alpha); + } + + virtual void gl_clear_depth(GLdouble depth) override + { + activate(); + glClearDepth(depth); + } + + virtual void gl_clear_stencil(GLint s) override + { + activate(); + glClearStencil(s); + } + + virtual void gl_active_texture(GLenum texture) override + { + activate(); + glActiveTexture(texture); + } + + virtual void gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height) override + { + activate(); + glViewport(x, y, width, height); + } + + virtual void gl_line_width(GLfloat width) override + { + activate(); + glLineWidth(width); + } + + virtual void gl_polygon_offset(GLfloat factor, GLfloat units) override + { + activate(); + glPolygonOffset(factor, units); + } + + virtual void gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height) override + { + activate(); + glScissor(x, y, width, height); + } + + virtual void gl_depth_mask(GLboolean mask) override + { + activate(); + glDepthMask(mask); + } + + virtual void gl_depth_func(GLenum func) override + { + activate(); + glDepthFunc(func); + } + + virtual void gl_depth_range(GLdouble z_near, GLdouble z_far) override + { + activate(); + glDepthRange(z_near, z_far); + } + + virtual void gl_cull_face(GLenum mode) override + { + activate(); + glCullFace(mode); + } + + virtual void gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) override + { + activate(); + glColorMask(red, green, blue, alpha); + } + + virtual void gl_front_face(GLenum mode) override + { + activate(); + glFrontFace(mode); + } + + virtual void gl_finish() override + { + activate(); + glFinish(); + } + + virtual void gl_flush() override + { + activate(); + glFlush(); + } + + virtual void gl_stencil_op_separate(GLenum, GLenum, GLenum, GLenum) override + { + TODO(); + } + + AccelGfxContext(OwnPtr context, NonnullRefPtr canvas) + : m_context(move(context)) + , m_canvas(move(canvas)) + { + } + +private: + OwnPtr m_context; + NonnullRefPtr m_canvas; +}; +#endif + +#ifdef AK_OS_SERENITY +class LibGLContext : public OpenGLContext { +public: + virtual void activate() override + { + GL::make_context_current(m_context); + } + + virtual void present(Gfx::Bitmap&) override + { + m_context->present(); + } + + virtual GLenum gl_get_error() override + { + return m_context->gl_get_error(); + } + + virtual void gl_get_doublev(GLenum pname, GLdouble* params) override + { + m_context->gl_get_doublev(pname, params); + } + + virtual void gl_get_integerv(GLenum pname, GLint* params) override + { + m_context->gl_get_integerv(pname, params); + } + + virtual void gl_clear(GLbitfield mask) override + { + m_context->gl_clear(mask); + } + + virtual void gl_clear_color(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) override + { + m_context->gl_clear_color(red, green, blue, alpha); + } + + virtual void gl_clear_depth(GLdouble depth) override + { + m_context->gl_clear_depth(depth); + } + + virtual void gl_clear_stencil(GLint s) override + { + m_context->gl_clear_stencil(s); + } + + virtual void gl_active_texture(GLenum texture) override + { + m_context->gl_active_texture(texture); + } + + virtual void gl_viewport(GLint x, GLint y, GLsizei width, GLsizei height) override + { + m_context->gl_viewport(x, y, width, height); + } + + virtual void gl_line_width(GLfloat width) override + { + m_context->gl_line_width(width); + } + + virtual void gl_polygon_offset(GLfloat factor, GLfloat units) override + { + m_context->gl_polygon_offset(factor, units); + } + + virtual void gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height) override + { + m_context->gl_scissor(x, y, width, height); + } + + virtual void gl_depth_mask(GLboolean flag) override + { + m_context->gl_depth_mask(flag); + } + + virtual void gl_depth_func(GLenum func) override + { + m_context->gl_depth_func(func); + } + + virtual void gl_depth_range(GLdouble z_near, GLdouble z_far) override + { + m_context->gl_depth_range(z_near, z_far); + } + + virtual void gl_cull_face(GLenum mode) override + { + m_context->gl_cull_face(mode); + } + + virtual void gl_color_mask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) override + { + m_context->gl_color_mask(red, green, blue, alpha); + } + + virtual void gl_front_face(GLenum mode) override + { + m_context->gl_front_face(mode); + } + + virtual void gl_finish() override + { + m_context->gl_finish(); + } + + virtual void gl_flush() override + { + m_context->gl_flush(); + } + + virtual void gl_stencil_op_separate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) override + { + m_context->gl_stencil_op_separate(face, sfail, dpfail, dppass); + } + + LibGLContext(OwnPtr context) + : m_context(move(context)) + { + } + +private: + OwnPtr m_context; +}; +#endif + +#ifdef HAS_ACCELERATED_GRAPHICS +static OwnPtr make_accelgfx_context(Gfx::Bitmap& bitmap) +{ + auto context = AccelGfx::Context::create(); + auto canvas = AccelGfx::Canvas::create(bitmap.size()); + canvas->bind(); + return make(move(context), move(canvas)); +} +#endif + +#ifdef AK_OS_SERENITY +static OwnPtr make_libgl_context(Gfx::Bitmap& bitmap) +{ + auto context_or_error = GL::create_context(bitmap); + return make(move(context_or_error.value())); +} +#endif + +OwnPtr OpenGLContext::create(Gfx::Bitmap& bitmap) +{ +#ifdef HAS_ACCELERATED_GRAPHICS + return make_accelgfx_context(bitmap); +#elif defined(AK_OS_SERENITY) + return make_libgl_context(bitmap); +#endif + + (void)bitmap; + return {}; +} + +void OpenGLContext::clear_buffer_to_default_values() +{ +#if defined(HAS_ACCELERATED_GRAPHICS) || defined(AK_OS_SERENITY) + Array current_clear_color; + gl_get_doublev(GL_COLOR_CLEAR_VALUE, current_clear_color.data()); + + GLdouble current_clear_depth; + gl_get_doublev(GL_DEPTH_CLEAR_VALUE, ¤t_clear_depth); + + GLint current_clear_stencil; + gl_get_integerv(GL_STENCIL_CLEAR_VALUE, ¤t_clear_stencil); + + // The implicit clear value for the color buffer is (0, 0, 0, 0) + gl_clear_color(0, 0, 0, 0); + + // The implicit clear value for the depth buffer is 1.0. + gl_clear_depth(1.0); + + // The implicit clear value for the stencil buffer is 0. + gl_clear_stencil(0); + + gl_clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + // Restore the clear values. + gl_clear_color(current_clear_color[0], current_clear_color[1], current_clear_color[2], current_clear_color[3]); + gl_clear_depth(current_clear_depth); + gl_clear_stencil(current_clear_stencil); +#endif +} + +} diff --git a/Userland/Libraries/LibWeb/WebGL/OpenGLContext.h b/Userland/Libraries/LibWeb/WebGL/OpenGLContext.h new file mode 100644 index 0000000000..e319657600 --- /dev/null +++ b/Userland/Libraries/LibWeb/WebGL/OpenGLContext.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, Aliaksandr Kalenik + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::WebGL { + +class OpenGLContext { +public: + static OwnPtr create(Gfx::Bitmap&); + + virtual void activate() = 0; + virtual void present(Gfx::Bitmap&) = 0; + void clear_buffer_to_default_values(); + + virtual GLenum gl_get_error() = 0; + virtual void gl_get_doublev(GLenum, GLdouble*) = 0; + virtual void gl_get_integerv(GLenum, GLint*) = 0; + virtual void gl_clear(GLbitfield) = 0; + virtual void gl_clear_color(GLfloat, GLfloat, GLfloat, GLfloat) = 0; + virtual void gl_clear_depth(GLdouble) = 0; + virtual void gl_clear_stencil(GLint) = 0; + virtual void gl_active_texture(GLenum) = 0; + virtual void gl_viewport(GLint, GLint, GLsizei, GLsizei) = 0; + virtual void gl_line_width(GLfloat) = 0; + virtual void gl_polygon_offset(GLfloat, GLfloat) = 0; + virtual void gl_scissor(GLint, GLint, GLsizei, GLsizei) = 0; + virtual void gl_depth_mask(GLboolean) = 0; + virtual void gl_depth_func(GLenum) = 0; + virtual void gl_depth_range(GLdouble, GLdouble) = 0; + virtual void gl_cull_face(GLenum) = 0; + virtual void gl_color_mask(GLboolean, GLboolean, GLboolean, GLboolean) = 0; + virtual void gl_front_face(GLenum) = 0; + virtual void gl_finish() = 0; + virtual void gl_flush() = 0; + virtual void gl_stencil_op_separate(GLenum, GLenum, GLenum, GLenum) = 0; + + virtual ~OpenGLContext() { } +}; + +} diff --git a/Userland/Libraries/LibWeb/WebGL/Types.h b/Userland/Libraries/LibWeb/WebGL/Types.h index 0d4df0e70f..36c8ae2f44 100644 --- a/Userland/Libraries/LibWeb/WebGL/Types.h +++ b/Userland/Libraries/LibWeb/WebGL/Types.h @@ -6,4 +6,11 @@ #pragma once -// FIXME: This header is here just to satisfy the IDL code generator. +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef int GLint; +typedef int GLsizei; +typedef float GLfloat; +typedef double GLdouble; +typedef GLfloat GLclampf; +typedef unsigned int GLbitfield; diff --git a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp index afeef838dd..a8d92f8741 100644 --- a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp +++ b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.cpp @@ -44,15 +44,18 @@ JS::ThrowCompletionOr> WebGLRenderingContext::c return JS::GCPtr { nullptr }; } - auto context_or_error = GL::create_context(*canvas_element.bitmap()); - if (context_or_error.is_error()) { + VERIFY(canvas_element.bitmap()); + auto context = OpenGLContext::create(*canvas_element.bitmap()); + + if (!context) { fire_webgl_context_creation_error(canvas_element); return JS::GCPtr { nullptr }; } - return realm.heap().allocate(realm, realm, canvas_element, context_or_error.release_value(), context_attributes, context_attributes); + + return realm.heap().allocate(realm, realm, canvas_element, context.release_nonnull(), context_attributes, context_attributes); } -WebGLRenderingContext::WebGLRenderingContext(JS::Realm& realm, HTML::HTMLCanvasElement& canvas_element, NonnullOwnPtr context, WebGLContextAttributes context_creation_parameters, WebGLContextAttributes actual_context_parameters) +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)) { } diff --git a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.h b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.h index 3312e453cc..d504382ada 100644 --- a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.h +++ b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContext.h @@ -1,11 +1,13 @@ /* * Copyright (c) 2022, Luke Wilde + * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once +#include #include #include #include @@ -24,7 +26,7 @@ public: private: virtual void initialize(JS::Realm&) override; - WebGLRenderingContext(JS::Realm&, HTML::HTMLCanvasElement&, NonnullOwnPtr context, WebGLContextAttributes context_creation_parameters, WebGLContextAttributes actual_context_parameters); + WebGLRenderingContext(JS::Realm&, HTML::HTMLCanvasElement&, NonnullOwnPtr context, WebGLContextAttributes context_creation_parameters, WebGLContextAttributes actual_context_parameters); }; } diff --git a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp index ea898634de..a2e59ad990 100644 --- a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp +++ b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.cpp @@ -1,11 +1,11 @@ /* * Copyright (c) 2022, Luke Wilde + * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #include -#include #include #include #include @@ -13,7 +13,12 @@ namespace Web::WebGL { -WebGLRenderingContextBase::WebGLRenderingContextBase(JS::Realm& realm, HTML::HTMLCanvasElement& canvas_element, NonnullOwnPtr context, WebGLContextAttributes context_creation_parameters, WebGLContextAttributes actual_context_parameters) +// 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)) @@ -48,36 +53,13 @@ void WebGLRenderingContextBase::present() // FIXME: Is this the operation it means? m_context->gl_flush(); - m_context->present(); + m_context->present(*canvas_element().bitmap()); // "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) { - Array current_clear_color; - m_context->gl_get_doublev(GL_COLOR_CLEAR_VALUE, current_clear_color.data()); - - GLdouble current_clear_depth; - m_context->gl_get_doublev(GL_DEPTH_CLEAR_VALUE, ¤t_clear_depth); - - GLint current_clear_stencil; - m_context->gl_get_integerv(GL_STENCIL_CLEAR_VALUE, ¤t_clear_stencil); - - // The implicit clear value for the color buffer is (0, 0, 0, 0) - m_context->gl_clear_color(0, 0, 0, 0); - - // The implicit clear value for the depth buffer is 1.0. - m_context->gl_clear_depth(1.0); - - // The implicit clear value for the stencil buffer is 0. - m_context->gl_clear_stencil(0); - - m_context->gl_clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - // Restore the clear values. - m_context->gl_clear_color(current_clear_color[0], current_clear_color[1], current_clear_color[2], current_clear_color[3]); - m_context->gl_clear_depth(current_clear_depth); - m_context->gl_clear_stencil(current_clear_stencil); + m_context->clear_buffer_to_default_values(); } } diff --git a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h index 1027923fd4..14e9b20d65 100644 --- a/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h +++ b/Userland/Libraries/LibWeb/WebGL/WebGLRenderingContextBase.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, Luke Wilde + * Copyright (c) 2024, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ @@ -9,14 +10,16 @@ #include #include #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); @@ -64,14 +67,14 @@ public: 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); + 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; JS::NonnullGCPtr m_canvas_element; - NonnullOwnPtr m_context; + 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.