mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 16:52:43 +00:00 
			
		
		
		
	 980b61470c
			
		
	
	
		980b61470c
		
	
	
	
	
		
			
			Now, if OpenGL context fails, an error will be returned and a message printed, instead of crashing.
		
			
				
	
	
		
			364 lines
		
	
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			364 lines
		
	
	
	
		
			8.6 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(NonnullOwnPtr<AccelGfx::Context> context, NonnullRefPtr<AccelGfx::Canvas> canvas)
 | |
|         : m_context(move(context))
 | |
|         , m_canvas(move(canvas))
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     ~AccelGfxContext()
 | |
|     {
 | |
|         activate();
 | |
|     }
 | |
| 
 | |
| private:
 | |
|     NonnullOwnPtr<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();
 | |
|     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<AccelGfxContext>(context.release_value(), 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
 | |
| }
 | |
| 
 | |
| }
 |