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 | ||||
| 
 | ||||
| #include <LibGfx/Rect.h> | ||||
| #include <LibGfx/Size.h> | ||||
| 
 | ||||
| namespace GL { | ||||
|  | @ -18,6 +19,7 @@ public: | |||
|     float* scanline(int y); | ||||
| 
 | ||||
|     void clear(float depth); | ||||
|     void clear(Gfx::IntRect bounds, float depth); | ||||
| 
 | ||||
| private: | ||||
|     Gfx::IntSize m_size; | ||||
|  |  | |||
|  | @ -290,6 +290,10 @@ extern "C" { | |||
| #define GL_FOG_COLOR 0x0B66 | ||||
| #define GL_FOG_DENSITY 0x0B62 | ||||
| 
 | ||||
| // Scissor enums
 | ||||
| #define GL_SCISSOR_BOX 0x0C10 | ||||
| #define GL_SCISSOR_TEST 0x0C11 | ||||
| 
 | ||||
| // OpenGL State & GLGet
 | ||||
| #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 glFogi(GLenum pname, GLint param); | ||||
| GLAPI void glPixelStorei(GLenum pname, GLint param); | ||||
| GLAPI void glScissor(GLint x, GLint y, GLsizei width, GLsizei height); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
|  |  | |||
|  | @ -86,6 +86,7 @@ public: | |||
|     virtual void gl_fogf(GLenum pname, GLfloat params) = 0; | ||||
|     virtual void gl_fogi(GLenum pname, GLint 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; | ||||
| }; | ||||
|  |  | |||
|  | @ -154,3 +154,8 @@ void glPixelStorei(GLenum pname, GLint 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; | ||||
|         update_rasterizer_options = true; | ||||
|         break; | ||||
|     case GL_SCISSOR_TEST: | ||||
|         rasterizer_options.scissor_enabled = true; | ||||
|         update_rasterizer_options = true; | ||||
|         break; | ||||
|     default: | ||||
|         RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); | ||||
|     } | ||||
|  | @ -589,6 +593,10 @@ void SoftwareGLContext::gl_disable(GLenum capability) | |||
|         rasterizer_options.fog_enabled = false; | ||||
|         update_rasterizer_options = true; | ||||
|         break; | ||||
|     case GL_SCISSOR_TEST: | ||||
|         rasterizer_options.scissor_enabled = false; | ||||
|         update_rasterizer_options = true; | ||||
|         break; | ||||
|     default: | ||||
|         RETURN_WITH_ERROR_IF(true, GL_INVALID_ENUM); | ||||
|     } | ||||
|  | @ -614,6 +622,8 @@ GLboolean SoftwareGLContext::gl_is_enabled(GLenum capability) | |||
|         return m_alpha_test_enabled; | ||||
|     case GL_FOG: | ||||
|         return rasterizer_options.fog_enabled; | ||||
|     case GL_SCISSOR_TEST: | ||||
|         return rasterizer_options.scissor_enabled; | ||||
|     } | ||||
| 
 | ||||
|     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: | ||||
|         *data = 4096; | ||||
|         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: | ||||
|         // According to the Khronos docs, we always return GL_INVALID_ENUM if we encounter a non-accepted value
 | ||||
|         // 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() | ||||
| { | ||||
|     m_rasterizer.blit_to(*m_frontbuffer); | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ | |||
| #include <AK/Vector.h> | ||||
| #include <LibGfx/Bitmap.h> | ||||
| #include <LibGfx/Matrix4x4.h> | ||||
| #include <LibGfx/Rect.h> | ||||
| #include <LibGfx/Vector3.h> | ||||
| 
 | ||||
| namespace GL { | ||||
|  | @ -96,6 +97,7 @@ public: | |||
|     virtual void gl_fogf(GLenum pname, GLfloat param) override; | ||||
|     virtual void gl_fogi(GLenum pname, GLint 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; | ||||
| 
 | ||||
| private: | ||||
|  | @ -231,7 +233,8 @@ private: | |||
|             decltype(&SoftwareGLContext::gl_draw_arrays), | ||||
|             decltype(&SoftwareGLContext::gl_draw_elements), | ||||
|             decltype(&SoftwareGLContext::gl_depth_range), | ||||
|             decltype(&SoftwareGLContext::gl_polygon_offset)>; | ||||
|             decltype(&SoftwareGLContext::gl_polygon_offset), | ||||
|             decltype(&SoftwareGLContext::gl_scissor)>; | ||||
| 
 | ||||
|         using ExtraSavedArguments = Variant< | ||||
|             FloatMatrix4x4>; | ||||
|  |  | |||
|  | @ -183,11 +183,15 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re | |||
|     }; | ||||
| 
 | ||||
|     // 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
 | ||||
|     const int bx0 = max(0,                      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; | ||||
|     const int by0 = max(0,                      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 bx0 =  max(render_bounds.left(),   min(min(v0.x(), v1.x()), v2.x()))                  / RASTERIZER_BLOCK_SIZE; | ||||
|     int const bx1 = (min(render_bounds.right(),  max(max(v0.x(), v1.x()), v2.x())) + block_padding) / RASTERIZER_BLOCK_SIZE; | ||||
|     int const by0 =  max(render_bounds.top(),    min(min(v0.y(), v1.y()), v2.y()))                  / 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
 | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|             // 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
 | ||||
|                 for (int y = 0; y < RASTERIZER_BLOCK_SIZE; y++) { | ||||
|                 for (int y = 0; y < RASTERIZER_BLOCK_SIZE; y++) | ||||
|                     pixel_mask[y] = -1; | ||||
|                 } | ||||
|             } else { | ||||
|                 // The block overlaps at least one triangle edge.
 | ||||
|                 // 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; | ||||
| 
 | ||||
|                     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; | ||||
|                     } | ||||
|                 } | ||||
|  | @ -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_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) | ||||
|  | @ -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 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); | ||||
|     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) | ||||
| { | ||||
|     wait_for_all_threads(); | ||||
| 
 | ||||
|     if (m_options.scissor_enabled) { | ||||
|         m_depth_buffer->clear(m_options.scissor_box, depth); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     m_depth_buffer->clear(depth); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ | |||
| #include <AK/Array.h> | ||||
| #include <AK/OwnPtr.h> | ||||
| #include <LibGfx/Bitmap.h> | ||||
| #include <LibGfx/Rect.h> | ||||
| #include <LibGfx/Vector4.h> | ||||
| 
 | ||||
| namespace GL { | ||||
|  | @ -44,6 +45,8 @@ struct RasterizerOptions { | |||
|     GLboolean fog_enabled { false }; | ||||
|     GLfloat fog_start { 0.0f }; | ||||
|     GLfloat fog_end { 1.0f }; | ||||
|     bool scissor_enabled { false }; | ||||
|     Gfx::IntRect scissor_box {}; | ||||
|     GLenum draw_buffer { GL_BACK }; | ||||
|     GLfloat depth_offset_factor { 0 }; | ||||
|     GLfloat depth_offset_constant { 0 }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jelle Raaijmakers
						Jelle Raaijmakers