mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:02:46 +00:00 
			
		
		
		
	 21364711da
			
		
	
	
		21364711da
		
	
	
	
	
		
			
			Destructor of AccelGfxContext needs to make sure that correct OpenGL context is active so that destructors of its members could proceed destroying they resources (for example framebuffer owned by AccelGfx::Canvas). Fixes https://github.com/SerenityOS/serenity/issues/22879
		
			
				
	
	
		
			360 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			360 lines
		
	
	
	
		
			8.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  * 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:
 | |
|     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(OwnPtr<AccelGfx::Context> context, NonnullRefPtr<AccelGfx::Canvas> canvas)
 | |
|         : m_context(move(context))
 | |
|         , m_canvas(move(canvas))
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     ~AccelGfxContext()
 | |
|     {
 | |
|         activate();
 | |
|     }
 | |
| 
 | |
| private:
 | |
|     OwnPtr<AccelGfx::Context> m_context;
 | |
|     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();
 | |
|     auto canvas = AccelGfx::Canvas::create(bitmap.size());
 | |
|     canvas->bind();
 | |
|     return make<AccelGfxContext>(move(context), move(canvas));
 | |
| }
 | |
| #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
 | |
| }
 | |
| 
 | |
| }
 |