mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 11:12:45 +00:00 
			
		
		
		
	LibGL: Implement glScissor()
				
					
				
			This commit is contained in:
		
							parent
							
								
									6dd2ebfe8e
								
							
						
					
					
						commit
						bb58f6ccab
					
				
					 9 changed files with 83 additions and 10 deletions
				
			
		|  | @ -33,4 +33,12 @@ void DepthBuffer::clear(float depth) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void DepthBuffer::clear(Gfx::IntRect bounds, float depth) | ||||||
|  | { | ||||||
|  |     bounds.intersect({ 0, 0, m_size.width(), m_size.height() }); | ||||||
|  |     for (int y = bounds.top(); y <= bounds.bottom(); ++y) | ||||||
|  |         for (int x = bounds.left(); x <= bounds.right(); ++x) | ||||||
|  |             m_data[y * m_size.width() + x] = depth; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <LibGfx/Rect.h> | ||||||
| #include <LibGfx/Size.h> | #include <LibGfx/Size.h> | ||||||
| 
 | 
 | ||||||
| namespace GL { | namespace GL { | ||||||
|  | @ -18,6 +19,7 @@ public: | ||||||
|     float* scanline(int y); |     float* scanline(int y); | ||||||
| 
 | 
 | ||||||
|     void clear(float depth); |     void clear(float depth); | ||||||
|  |     void clear(Gfx::IntRect bounds, float depth); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     Gfx::IntSize m_size; |     Gfx::IntSize m_size; | ||||||
|  |  | ||||||
|  | @ -290,6 +290,10 @@ extern "C" { | ||||||
| #define GL_FOG_COLOR 0x0B66 | #define GL_FOG_COLOR 0x0B66 | ||||||
| #define GL_FOG_DENSITY 0x0B62 | #define GL_FOG_DENSITY 0x0B62 | ||||||
| 
 | 
 | ||||||
|  | // Scissor enums
 | ||||||
|  | #define GL_SCISSOR_BOX 0x0C10 | ||||||
|  | #define GL_SCISSOR_TEST 0x0C11 | ||||||
|  | 
 | ||||||
| // OpenGL State & GLGet
 | // OpenGL State & GLGet
 | ||||||
| #define GL_MODELVIEW_MATRIX 0x0BA6 | #define GL_MODELVIEW_MATRIX 0x0BA6 | ||||||
| 
 | 
 | ||||||
|  | @ -416,6 +420,7 @@ GLAPI void glFogfv(GLenum mode, GLfloat* params); | ||||||
| GLAPI void glFogf(GLenum pname, GLfloat param); | GLAPI void glFogf(GLenum pname, GLfloat param); | ||||||
| GLAPI void glFogi(GLenum pname, GLint param); | GLAPI void glFogi(GLenum pname, GLint param); | ||||||
| GLAPI void glPixelStorei(GLenum pname, GLint param); | GLAPI void glPixelStorei(GLenum pname, GLint param); | ||||||
|  | GLAPI void glScissor(GLint x, GLint y, GLsizei width, GLsizei height); | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -86,6 +86,7 @@ public: | ||||||
|     virtual void gl_fogf(GLenum pname, GLfloat params) = 0; |     virtual void gl_fogf(GLenum pname, GLfloat params) = 0; | ||||||
|     virtual void gl_fogi(GLenum pname, GLint param) = 0; |     virtual void gl_fogi(GLenum pname, GLint param) = 0; | ||||||
|     virtual void gl_pixel_store(GLenum pname, GLfloat param) = 0; |     virtual void gl_pixel_store(GLenum pname, GLfloat param) = 0; | ||||||
|  |     virtual void gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height) = 0; | ||||||
| 
 | 
 | ||||||
|     virtual void present() = 0; |     virtual void present() = 0; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -154,3 +154,8 @@ void glPixelStorei(GLenum pname, GLint param) | ||||||
| { | { | ||||||
|     g_gl_context->gl_pixel_store(pname, param); |     g_gl_context->gl_pixel_store(pname, param); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void glScissor(GLint x, GLint y, GLsizei width, GLsizei height) | ||||||
|  | { | ||||||
|  |     g_gl_context->gl_scissor(x, y, width, height); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -549,6 +549,10 @@ void SoftwareGLContext::gl_enable(GLenum capability) | ||||||
|         rasterizer_options.fog_enabled = true; |         rasterizer_options.fog_enabled = true; | ||||||
|         update_rasterizer_options = true; |         update_rasterizer_options = true; | ||||||
|         break; |         break; | ||||||
|  |     case GL_SCISSOR_TEST: | ||||||
|  |         rasterizer_options.scissor_enabled = true; | ||||||
|  |         update_rasterizer_options = true; | ||||||
|  |         break; | ||||||
|     default: |     default: | ||||||
|         RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); |         RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); | ||||||
|     } |     } | ||||||
|  | @ -589,6 +593,10 @@ void SoftwareGLContext::gl_disable(GLenum capability) | ||||||
|         rasterizer_options.fog_enabled = false; |         rasterizer_options.fog_enabled = false; | ||||||
|         update_rasterizer_options = true; |         update_rasterizer_options = true; | ||||||
|         break; |         break; | ||||||
|  |     case GL_SCISSOR_TEST: | ||||||
|  |         rasterizer_options.scissor_enabled = false; | ||||||
|  |         update_rasterizer_options = true; | ||||||
|  |         break; | ||||||
|     default: |     default: | ||||||
|         RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); |         RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); | ||||||
|     } |     } | ||||||
|  | @ -614,6 +622,8 @@ GLboolean SoftwareGLContext::gl_is_enabled(GLenum capability) | ||||||
|         return m_alpha_test_enabled; |         return m_alpha_test_enabled; | ||||||
|     case GL_FOG: |     case GL_FOG: | ||||||
|         return rasterizer_options.fog_enabled; |         return rasterizer_options.fog_enabled; | ||||||
|  |     case GL_SCISSOR_TEST: | ||||||
|  |         return rasterizer_options.scissor_enabled; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     RETURN_VALUE_WITH_ERROR_IF(true, GL_INVALID_ENUM, 0); |     RETURN_VALUE_WITH_ERROR_IF(true, GL_INVALID_ENUM, 0); | ||||||
|  | @ -1472,6 +1482,14 @@ void SoftwareGLContext::gl_get_integerv(GLenum pname, GLint* data) | ||||||
|     case GL_MAX_TEXTURE_SIZE: |     case GL_MAX_TEXTURE_SIZE: | ||||||
|         *data = 4096; |         *data = 4096; | ||||||
|         break; |         break; | ||||||
|  |     case GL_SCISSOR_BOX: { | ||||||
|  |         auto scissor_box = m_rasterizer.options().scissor_box; | ||||||
|  |         *(data + 0) = scissor_box.x(); | ||||||
|  |         *(data + 1) = scissor_box.y(); | ||||||
|  |         *(data + 2) = scissor_box.width(); | ||||||
|  |         *(data + 3) = scissor_box.height(); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|     default: |     default: | ||||||
|         // According to the Khronos docs, we always return GL_INVALID_ENUM if we encounter a non-accepted value
 |         // According to the Khronos docs, we always return GL_INVALID_ENUM if we encounter a non-accepted value
 | ||||||
|         // for `pname`
 |         // for `pname`
 | ||||||
|  | @ -1966,6 +1984,16 @@ void SoftwareGLContext::gl_pixel_store(GLenum pname, GLfloat param) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void SoftwareGLContext::gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height) | ||||||
|  | { | ||||||
|  |     APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_scissor, x, y, width, height); | ||||||
|  |     RETURN_WITH_ERROR_IF(width < 0 || height < 0, GL_INVALID_VALUE); | ||||||
|  | 
 | ||||||
|  |     auto options = m_rasterizer.options(); | ||||||
|  |     options.scissor_box = { x, y, width, height }; | ||||||
|  |     m_rasterizer.set_options(options); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void SoftwareGLContext::present() | void SoftwareGLContext::present() | ||||||
| { | { | ||||||
|     m_rasterizer.blit_to(*m_frontbuffer); |     m_rasterizer.blit_to(*m_frontbuffer); | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
| #include <AK/Vector.h> | #include <AK/Vector.h> | ||||||
| #include <LibGfx/Bitmap.h> | #include <LibGfx/Bitmap.h> | ||||||
| #include <LibGfx/Matrix4x4.h> | #include <LibGfx/Matrix4x4.h> | ||||||
|  | #include <LibGfx/Rect.h> | ||||||
| #include <LibGfx/Vector3.h> | #include <LibGfx/Vector3.h> | ||||||
| 
 | 
 | ||||||
| namespace GL { | namespace GL { | ||||||
|  | @ -96,6 +97,7 @@ public: | ||||||
|     virtual void gl_fogf(GLenum pname, GLfloat param) override; |     virtual void gl_fogf(GLenum pname, GLfloat param) override; | ||||||
|     virtual void gl_fogi(GLenum pname, GLint param) override; |     virtual void gl_fogi(GLenum pname, GLint param) override; | ||||||
|     virtual void gl_pixel_store(GLenum pname, GLfloat param) override; |     virtual void gl_pixel_store(GLenum pname, GLfloat param) override; | ||||||
|  |     virtual void gl_scissor(GLint x, GLint y, GLsizei width, GLsizei height); | ||||||
|     virtual void present() override; |     virtual void present() override; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  | @ -231,7 +233,8 @@ private: | ||||||
|             decltype(&SoftwareGLContext::gl_draw_arrays), |             decltype(&SoftwareGLContext::gl_draw_arrays), | ||||||
|             decltype(&SoftwareGLContext::gl_draw_elements), |             decltype(&SoftwareGLContext::gl_draw_elements), | ||||||
|             decltype(&SoftwareGLContext::gl_depth_range), |             decltype(&SoftwareGLContext::gl_depth_range), | ||||||
|             decltype(&SoftwareGLContext::gl_polygon_offset)>; |             decltype(&SoftwareGLContext::gl_polygon_offset), | ||||||
|  |             decltype(&SoftwareGLContext::gl_scissor)>; | ||||||
| 
 | 
 | ||||||
|         using ExtraSavedArguments = Variant< |         using ExtraSavedArguments = Variant< | ||||||
|             FloatMatrix4x4>; |             FloatMatrix4x4>; | ||||||
|  |  | ||||||
|  | @ -183,11 +183,15 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // Calculate block-based bounds
 |     // Calculate block-based bounds
 | ||||||
|  |     auto render_bounds = render_target.rect(); | ||||||
|  |     if (options.scissor_enabled) | ||||||
|  |         render_bounds.intersect(options.scissor_box); | ||||||
|  |     int const block_padding = RASTERIZER_BLOCK_SIZE - 1; | ||||||
|     // clang-format off
 |     // clang-format off
 | ||||||
|     const int bx0 = max(0,                      min(min(v0.x(), v1.x()), v2.x())                            ) / RASTERIZER_BLOCK_SIZE; |     int const bx0 =  max(render_bounds.left(),   min(min(v0.x(), v1.x()), v2.x()))                  / RASTERIZER_BLOCK_SIZE; | ||||||
|     const int bx1 = min(render_target.width(),  max(max(v0.x(), v1.x()), v2.x()) + RASTERIZER_BLOCK_SIZE - 1) / RASTERIZER_BLOCK_SIZE; |     int const bx1 = (min(render_bounds.right(),  max(max(v0.x(), v1.x()), v2.x())) + block_padding) / RASTERIZER_BLOCK_SIZE; | ||||||
|     const int by0 = max(0,                      min(min(v0.y(), v1.y()), v2.y())                            ) / RASTERIZER_BLOCK_SIZE; |     int const by0 =  max(render_bounds.top(),    min(min(v0.y(), v1.y()), v2.y()))                  / RASTERIZER_BLOCK_SIZE; | ||||||
|     const int by1 = min(render_target.height(), max(max(v0.y(), v1.y()), v2.y()) + RASTERIZER_BLOCK_SIZE - 1) / RASTERIZER_BLOCK_SIZE; |     int const by1 = (min(render_bounds.bottom(), max(max(v0.y(), v1.y()), v2.y())) + block_padding) / RASTERIZER_BLOCK_SIZE; | ||||||
|     // clang-format on
 |     // clang-format on
 | ||||||
| 
 | 
 | ||||||
|     static_assert(RASTERIZER_BLOCK_SIZE < sizeof(int) * 8, "RASTERIZER_BLOCK_SIZE must be smaller than the pixel_mask's width in bits"); |     static_assert(RASTERIZER_BLOCK_SIZE < sizeof(int) * 8, "RASTERIZER_BLOCK_SIZE must be smaller than the pixel_mask's width in bits"); | ||||||
|  | @ -229,11 +233,10 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re | ||||||
|             int y0 = by * RASTERIZER_BLOCK_SIZE; |             int y0 = by * RASTERIZER_BLOCK_SIZE; | ||||||
| 
 | 
 | ||||||
|             // Generate the coverage mask
 |             // Generate the coverage mask
 | ||||||
|             if (test_point(b0) && test_point(b1) && test_point(b2) && test_point(b3)) { |             if (!options.scissor_enabled && test_point(b0) && test_point(b1) && test_point(b2) && test_point(b3)) { | ||||||
|                 // The block is fully contained within the triangle. Fill the mask with all 1s
 |                 // The block is fully contained within the triangle. Fill the mask with all 1s
 | ||||||
|                 for (int y = 0; y < RASTERIZER_BLOCK_SIZE; y++) { |                 for (int y = 0; y < RASTERIZER_BLOCK_SIZE; y++) | ||||||
|                     pixel_mask[y] = -1; |                     pixel_mask[y] = -1; | ||||||
|                 } |  | ||||||
|             } else { |             } else { | ||||||
|                 // The block overlaps at least one triangle edge.
 |                 // The block overlaps at least one triangle edge.
 | ||||||
|                 // We need to test coverage of every pixel within the block.
 |                 // We need to test coverage of every pixel within the block.
 | ||||||
|  | @ -242,7 +245,7 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re | ||||||
|                     pixel_mask[y] = 0; |                     pixel_mask[y] = 0; | ||||||
| 
 | 
 | ||||||
|                     for (int x = 0; x < RASTERIZER_BLOCK_SIZE; x++, coords += dbdx) { |                     for (int x = 0; x < RASTERIZER_BLOCK_SIZE; x++, coords += dbdx) { | ||||||
|                         if (test_point(coords)) |                         if (test_point(coords) && (!options.scissor_enabled || render_bounds.contains(x0 + x, y0 + y))) | ||||||
|                             pixel_mask[y] |= 1 << x; |                             pixel_mask[y] |= 1 << x; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|  | @ -481,6 +484,7 @@ SoftwareRasterizer::SoftwareRasterizer(const Gfx::IntSize& min_size) | ||||||
|     : m_render_target { Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, closest_multiple(min_size, RASTERIZER_BLOCK_SIZE)).release_value_but_fixme_should_propagate_errors() } |     : m_render_target { Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, closest_multiple(min_size, RASTERIZER_BLOCK_SIZE)).release_value_but_fixme_should_propagate_errors() } | ||||||
|     , m_depth_buffer { adopt_own(*new DepthBuffer(closest_multiple(min_size, RASTERIZER_BLOCK_SIZE))) } |     , m_depth_buffer { adopt_own(*new DepthBuffer(closest_multiple(min_size, RASTERIZER_BLOCK_SIZE))) } | ||||||
| { | { | ||||||
|  |     m_options.scissor_box = m_render_target->rect(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SoftwareRasterizer::submit_triangle(const GLTriangle& triangle, const Array<TextureUnit, 32>& texture_units) | void SoftwareRasterizer::submit_triangle(const GLTriangle& triangle, const Array<TextureUnit, 32>& texture_units) | ||||||
|  | @ -559,14 +563,28 @@ void SoftwareRasterizer::clear_color(const FloatVector4& color) | ||||||
|     uint8_t g = static_cast<uint8_t>(clamp(color.y(), 0.0f, 1.0f) * 255); |     uint8_t g = static_cast<uint8_t>(clamp(color.y(), 0.0f, 1.0f) * 255); | ||||||
|     uint8_t b = static_cast<uint8_t>(clamp(color.z(), 0.0f, 1.0f) * 255); |     uint8_t b = static_cast<uint8_t>(clamp(color.z(), 0.0f, 1.0f) * 255); | ||||||
|     uint8_t a = static_cast<uint8_t>(clamp(color.w(), 0.0f, 1.0f) * 255); |     uint8_t a = static_cast<uint8_t>(clamp(color.w(), 0.0f, 1.0f) * 255); | ||||||
|  |     auto const fill_color = Gfx::Color(r, g, b, a); | ||||||
| 
 | 
 | ||||||
|     m_render_target->fill(Gfx::Color(r, g, b, a)); |     if (m_options.scissor_enabled) { | ||||||
|  |         auto fill_rect = m_render_target->rect(); | ||||||
|  |         fill_rect.intersect(m_options.scissor_box); | ||||||
|  |         Gfx::Painter painter { *m_render_target }; | ||||||
|  |         painter.fill_rect(fill_rect, fill_color); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     m_render_target->fill(fill_color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SoftwareRasterizer::clear_depth(float depth) | void SoftwareRasterizer::clear_depth(float depth) | ||||||
| { | { | ||||||
|     wait_for_all_threads(); |     wait_for_all_threads(); | ||||||
| 
 | 
 | ||||||
|  |     if (m_options.scissor_enabled) { | ||||||
|  |         m_depth_buffer->clear(m_options.scissor_box, depth); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     m_depth_buffer->clear(depth); |     m_depth_buffer->clear(depth); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ | ||||||
| #include <AK/Array.h> | #include <AK/Array.h> | ||||||
| #include <AK/OwnPtr.h> | #include <AK/OwnPtr.h> | ||||||
| #include <LibGfx/Bitmap.h> | #include <LibGfx/Bitmap.h> | ||||||
|  | #include <LibGfx/Rect.h> | ||||||
| #include <LibGfx/Vector4.h> | #include <LibGfx/Vector4.h> | ||||||
| 
 | 
 | ||||||
| namespace GL { | namespace GL { | ||||||
|  | @ -44,6 +45,8 @@ struct RasterizerOptions { | ||||||
|     GLboolean fog_enabled { false }; |     GLboolean fog_enabled { false }; | ||||||
|     GLfloat fog_start { 0.0f }; |     GLfloat fog_start { 0.0f }; | ||||||
|     GLfloat fog_end { 1.0f }; |     GLfloat fog_end { 1.0f }; | ||||||
|  |     bool scissor_enabled { false }; | ||||||
|  |     Gfx::IntRect scissor_box {}; | ||||||
|     GLenum draw_buffer { GL_BACK }; |     GLenum draw_buffer { GL_BACK }; | ||||||
|     GLfloat depth_offset_factor { 0 }; |     GLfloat depth_offset_factor { 0 }; | ||||||
|     GLfloat depth_offset_constant { 0 }; |     GLfloat depth_offset_constant { 0 }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jelle Raaijmakers
						Jelle Raaijmakers