/* * 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: void activate() { 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(NonnullOwnPtr context, NonnullRefPtr canvas) : m_context(move(context)) , m_canvas(move(canvas)) { } ~AccelGfxContext() { activate(); } private: NonnullOwnPtr m_context; NonnullRefPtr m_canvas; }; #endif #ifdef AK_OS_SERENITY class LibGLContext : public OpenGLContext { public: 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(); if (context.is_error()) { dbgln("Failed to create AccelGfx context: {}", context.error().string_literal()); return {}; } auto canvas = AccelGfx::Canvas::create(bitmap.size()); canvas->bind(); return make(context.release_value(), 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 } }