diff options
author | Stephan Unverwerth <s.unverwerth@gmx.de> | 2021-05-08 23:17:13 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-09 15:58:35 +0200 |
commit | e8f66f821ce10ac3a78bfd395887b0dd5557c996 (patch) | |
tree | 5986f31953aeb6f123c7e7dbac050f137ce37124 /Userland/Libraries/LibGL/SoftwareRasterizer.cpp | |
parent | 608f81e6c2220fe2dc01c8c903ccc3706243dcd3 (diff) | |
download | serenity-e8f66f821ce10ac3a78bfd395887b0dd5557c996.zip |
LibGL: Add depth tests and writes to SoftwareRasterizer
Tests against and writes to the depth buffer when GL_DEPTH_TEST is
enabled via glEnable(). Currently fragment z is always compared against
existing depth with GL_LESS.
Diffstat (limited to 'Userland/Libraries/LibGL/SoftwareRasterizer.cpp')
-rw-r--r-- | Userland/Libraries/LibGL/SoftwareRasterizer.cpp | 51 |
1 files changed, 40 insertions, 11 deletions
diff --git a/Userland/Libraries/LibGL/SoftwareRasterizer.cpp b/Userland/Libraries/LibGL/SoftwareRasterizer.cpp index 031edf9b03..d8b155d3af 100644 --- a/Userland/Libraries/LibGL/SoftwareRasterizer.cpp +++ b/Userland/Libraries/LibGL/SoftwareRasterizer.cpp @@ -22,6 +22,12 @@ constexpr static float triangle_area(const FloatVector2& a, const FloatVector2& return ((c.x - a.x) * (b.y - a.y) - (c.y - a.y) * (b.x - a.x)) / 2; } +template<typename T> +constexpr static T interpolate(const T& v0, const T& v1, const T& v2, const FloatVector4& barycentric_coords) +{ + return v0 * barycentric_coords.x() + v1 * barycentric_coords.y() + v2 * barycentric_coords.z(); +} + static Gfx::RGBA32 to_rgba32(const FloatVector4& v) { auto clamped = v.clamped(0, 1); @@ -33,7 +39,7 @@ static Gfx::RGBA32 to_rgba32(const FloatVector4& v) } template<typename PS> -static void rasterize_triangle(Gfx::Bitmap& render_target, const GLTriangle& triangle, PS pixel_shader) +static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& render_target, DepthBuffer& depth_buffer, const GLTriangle& triangle, PS pixel_shader) { // Since the algorithm is based on blocks of uniform size, we need // to ensure that our render_target size is actually a multiple of the block size @@ -125,7 +131,7 @@ static void rasterize_triangle(Gfx::Bitmap& render_target, const GLTriangle& tri || (a.z() < zero.z() && b.z() < zero.z() && c.z() < zero.z() && d.z() < zero.z())) continue; - // barycentric coordinate derrivatives + // barycentric coordinate derivatives auto dcdx = (b - a) / RASTERIZER_BLOCK_SIZE; auto dcdy = (c - a) / RASTERIZER_BLOCK_SIZE; @@ -134,9 +140,20 @@ static void rasterize_triangle(Gfx::Bitmap& render_target, const GLTriangle& tri // Fill the block without further coverage tests for (int y = y0; y < y1; y++) { auto coords = a; - auto* pixels = &render_target.scanline(y)[x0]; + auto* pixel = &render_target.scanline(y)[x0]; + auto* depth = &depth_buffer.scanline(y)[x0]; for (int x = x0; x < x1; x++) { - *pixels++ = to_rgba32(pixel_shader(coords, triangle)); + if (options.enable_depth_test) { + float z = interpolate(triangle.vertices[0].z, triangle.vertices[1].z, triangle.vertices[2].z, coords); + if (z < *depth) { + *pixel = to_rgba32(pixel_shader(coords, triangle)); + *depth = z; + } + } else { + *pixel = to_rgba32(pixel_shader(coords, triangle)); + } + pixel++; + depth++; coords = coords + dcdx; } a = a + dcdy; @@ -146,12 +163,22 @@ static void rasterize_triangle(Gfx::Bitmap& render_target, const GLTriangle& tri // We need to test coverage of every pixel within the block for (int y = y0; y < y1; y++) { auto coords = a; - auto* pixels = &render_target.scanline(y)[x0]; + auto* pixel = &render_target.scanline(y)[x0]; + auto* depth = &depth_buffer.scanline(y)[x0]; for (int x = x0; x < x1; x++) { if (test_point(coords)) { - *pixels = to_rgba32(pixel_shader(coords, triangle)); + if (options.enable_depth_test) { + float z = interpolate(triangle.vertices[0].z, triangle.vertices[1].z, triangle.vertices[2].z, coords); + if (z < *depth) { + *pixel = to_rgba32(pixel_shader(coords, triangle)); + *depth = z; + } + } else { + *pixel = to_rgba32(pixel_shader(coords, triangle)); + } } - pixels++; + pixel++; + depth++; coords = coords + dcdx; } a = a + dcdy; @@ -170,13 +197,14 @@ static Gfx::IntSize closest_multiple(const Gfx::IntSize& min_size, size_t step) SoftwareRasterizer::SoftwareRasterizer(const Gfx::IntSize& min_size) : m_render_target { Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, closest_multiple(min_size, RASTERIZER_BLOCK_SIZE)) } + , m_depth_buffer { adopt_own(*new DepthBuffer(closest_multiple(min_size, RASTERIZER_BLOCK_SIZE))) } { } void SoftwareRasterizer::submit_triangle(const GLTriangle& triangle) { if (m_options.shade_smooth) { - rasterize_triangle(*m_render_target, triangle, [](const FloatVector4& v, const GLTriangle& t) -> FloatVector4 { + rasterize_triangle(m_options, *m_render_target, *m_depth_buffer, triangle, [](const FloatVector4& v, const GLTriangle& t) -> FloatVector4 { const float r = t.vertices[0].r * v.x() + t.vertices[1].r * v.y() + t.vertices[2].r * v.z(); const float g = t.vertices[0].g * v.x() + t.vertices[1].g * v.y() + t.vertices[2].g * v.z(); const float b = t.vertices[0].b * v.x() + t.vertices[1].b * v.y() + t.vertices[2].b * v.z(); @@ -184,7 +212,7 @@ void SoftwareRasterizer::submit_triangle(const GLTriangle& triangle) return { r, g, b, a }; }); } else { - rasterize_triangle(*m_render_target, triangle, [](const FloatVector4&, const GLTriangle& t) -> FloatVector4 { + rasterize_triangle(m_options, *m_render_target, *m_depth_buffer, triangle, [](const FloatVector4&, const GLTriangle& t) -> FloatVector4 { return { t.vertices[0].r, t.vertices[0].g, t.vertices[0].b, t.vertices[0].a }; }); } @@ -195,6 +223,7 @@ void SoftwareRasterizer::resize(const Gfx::IntSize& min_size) wait_for_all_threads(); m_render_target = Gfx::Bitmap::create(Gfx::BitmapFormat::BGRA8888, closest_multiple(min_size, RASTERIZER_BLOCK_SIZE)); + m_depth_buffer = adopt_own(*new DepthBuffer(m_render_target->size())); } void SoftwareRasterizer::clear_color(const FloatVector4& color) @@ -209,11 +238,11 @@ void SoftwareRasterizer::clear_color(const FloatVector4& color) m_render_target->fill(Gfx::Color(r, g, b, a)); } -void SoftwareRasterizer::clear_depth(float) +void SoftwareRasterizer::clear_depth(float depth) { wait_for_all_threads(); - // FIXME: implement this + m_depth_buffer->clear(depth); } void SoftwareRasterizer::blit_to(Gfx::Bitmap& target) |