summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibGL/SoftwareRasterizer.cpp
diff options
context:
space:
mode:
authorStephan Unverwerth <s.unverwerth@gmx.de>2021-05-08 23:17:13 +0200
committerAndreas Kling <kling@serenityos.org>2021-05-09 15:58:35 +0200
commite8f66f821ce10ac3a78bfd395887b0dd5557c996 (patch)
tree5986f31953aeb6f123c7e7dbac050f137ce37124 /Userland/Libraries/LibGL/SoftwareRasterizer.cpp
parent608f81e6c2220fe2dc01c8c903ccc3706243dcd3 (diff)
downloadserenity-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.cpp51
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)