2024-01-18 22:29:09 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <AK/OwnPtr.h>
|
|
|
|
#include <LibGfx/Bitmap.h>
|
|
|
|
#include <LibWeb/WebGL/OpenGLContext.h>
|
|
|
|
|
|
|
|
#ifdef HAS_ACCELERATED_GRAPHICS
|
|
|
|
# include <LibAccelGfx/Canvas.h>
|
|
|
|
# include <LibAccelGfx/Context.h>
|
|
|
|
#elif defined(AK_OS_SERENITY)
|
|
|
|
# include <LibGL/GLContext.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
namespace Web::WebGL {
|
|
|
|
|
|
|
|
#ifdef HAS_ACCELERATED_GRAPHICS
|
|
|
|
class AccelGfxContext : public OpenGLContext {
|
|
|
|
public:
|
2024-01-21 15:44:08 +03:00
|
|
|
void activate()
|
2024-01-18 22:29:09 +03:00
|
|
|
{
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2024-01-24 17:27:03 +03:00
|
|
|
AccelGfxContext(NonnullOwnPtr<AccelGfx::Context> context, NonnullRefPtr<AccelGfx::Canvas> canvas)
|
2024-01-18 22:29:09 +03:00
|
|
|
: m_context(move(context))
|
|
|
|
, m_canvas(move(canvas))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-01-21 15:45:30 +03:00
|
|
|
~AccelGfxContext()
|
|
|
|
{
|
|
|
|
activate();
|
|
|
|
}
|
|
|
|
|
2024-01-18 22:29:09 +03:00
|
|
|
private:
|
2024-01-24 17:27:03 +03:00
|
|
|
NonnullOwnPtr<AccelGfx::Context> m_context;
|
2024-01-18 22:29:09 +03:00
|
|
|
NonnullRefPtr<AccelGfx::Canvas> 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<GL::GLContext> context)
|
|
|
|
: m_context(move(context))
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
OwnPtr<GL::GLContext> m_context;
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAS_ACCELERATED_GRAPHICS
|
|
|
|
static OwnPtr<AccelGfxContext> make_accelgfx_context(Gfx::Bitmap& bitmap)
|
|
|
|
{
|
|
|
|
auto context = AccelGfx::Context::create();
|
2024-01-24 17:27:03 +03:00
|
|
|
if (context.is_error()) {
|
|
|
|
dbgln("Failed to create AccelGfx context: {}", context.error().string_literal());
|
|
|
|
return {};
|
|
|
|
}
|
2024-01-18 22:29:09 +03:00
|
|
|
auto canvas = AccelGfx::Canvas::create(bitmap.size());
|
|
|
|
canvas->bind();
|
2024-01-24 17:27:03 +03:00
|
|
|
return make<AccelGfxContext>(context.release_value(), move(canvas));
|
2024-01-18 22:29:09 +03:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef AK_OS_SERENITY
|
|
|
|
static OwnPtr<LibGLContext> make_libgl_context(Gfx::Bitmap& bitmap)
|
|
|
|
{
|
|
|
|
auto context_or_error = GL::create_context(bitmap);
|
|
|
|
return make<LibGLContext>(move(context_or_error.value()));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
OwnPtr<OpenGLContext> 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<GLdouble, 4> 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
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|