diff options
author | Jelle Raaijmakers <jelle@gmta.nl> | 2021-11-27 19:00:16 +0100 |
---|---|---|
committer | Brian Gianforcaro <b.gianfo@gmail.com> | 2021-11-28 09:20:58 -0800 |
commit | bb58f6ccabc0e47fd5ef4dfcc911fbc6db0e8677 (patch) | |
tree | ab1a7910a08a5b3d1948a0dbe321abcee96609e0 /Userland/Libraries | |
parent | 6dd2ebfe8e3a4927edfc49fc4f14ca08189631e0 (diff) | |
download | serenity-bb58f6ccabc0e47fd5ef4dfcc911fbc6db0e8677.zip |
LibGL: Implement `glScissor()`
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibGL/DepthBuffer.cpp | 8 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/DepthBuffer.h | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/GL/gl.h | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/GLContext.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/GLUtils.cpp | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/SoftwareGLContext.cpp | 28 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/SoftwareGLContext.h | 5 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/SoftwareRasterizer.cpp | 36 | ||||
-rw-r--r-- | Userland/Libraries/LibGL/SoftwareRasterizer.h | 3 |
9 files changed, 83 insertions, 10 deletions
diff --git a/Userland/Libraries/LibGL/DepthBuffer.cpp b/Userland/Libraries/LibGL/DepthBuffer.cpp index 5f22211004..a45812133f 100644 --- a/Userland/Libraries/LibGL/DepthBuffer.cpp +++ b/Userland/Libraries/LibGL/DepthBuffer.cpp @@ -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; +} + } diff --git a/Userland/Libraries/LibGL/DepthBuffer.h b/Userland/Libraries/LibGL/DepthBuffer.h index 3ce1b6acc5..bdb6d4563b 100644 --- a/Userland/Libraries/LibGL/DepthBuffer.h +++ b/Userland/Libraries/LibGL/DepthBuffer.h @@ -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; diff --git a/Userland/Libraries/LibGL/GL/gl.h b/Userland/Libraries/LibGL/GL/gl.h index dc8406d6e8..a0fb0bac3d 100644 --- a/Userland/Libraries/LibGL/GL/gl.h +++ b/Userland/Libraries/LibGL/GL/gl.h @@ -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 } diff --git a/Userland/Libraries/LibGL/GLContext.h b/Userland/Libraries/LibGL/GLContext.h index a972e65090..5d89c105da 100644 --- a/Userland/Libraries/LibGL/GLContext.h +++ b/Userland/Libraries/LibGL/GLContext.h @@ -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; }; diff --git a/Userland/Libraries/LibGL/GLUtils.cpp b/Userland/Libraries/LibGL/GLUtils.cpp index 20515e9039..19556c9b5c 100644 --- a/Userland/Libraries/LibGL/GLUtils.cpp +++ b/Userland/Libraries/LibGL/GLUtils.cpp @@ -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); +} diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.cpp b/Userland/Libraries/LibGL/SoftwareGLContext.cpp index 2bc4658631..60d46741ca 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.cpp +++ b/Userland/Libraries/LibGL/SoftwareGLContext.cpp @@ -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); diff --git a/Userland/Libraries/LibGL/SoftwareGLContext.h b/Userland/Libraries/LibGL/SoftwareGLContext.h index 0ac2c46c97..16c13ef0b1 100644 --- a/Userland/Libraries/LibGL/SoftwareGLContext.h +++ b/Userland/Libraries/LibGL/SoftwareGLContext.h @@ -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>; diff --git a/Userland/Libraries/LibGL/SoftwareRasterizer.cpp b/Userland/Libraries/LibGL/SoftwareRasterizer.cpp index bf561b87f7..9ebeeb2a1e 100644 --- a/Userland/Libraries/LibGL/SoftwareRasterizer.cpp +++ b/Userland/Libraries/LibGL/SoftwareRasterizer.cpp @@ -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); + + 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(Gfx::Color(r, g, b, a)); + 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); } diff --git a/Userland/Libraries/LibGL/SoftwareRasterizer.h b/Userland/Libraries/LibGL/SoftwareRasterizer.h index aee17abeca..6a54e8e35b 100644 --- a/Userland/Libraries/LibGL/SoftwareRasterizer.h +++ b/Userland/Libraries/LibGL/SoftwareRasterizer.h @@ -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 }; |