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.
This commit is contained in:
Stephan Unverwerth 2021-05-08 23:17:13 +02:00 committed by Andreas Kling
parent 608f81e6c2
commit e8f66f821c
Notes: sideshowbarker 2024-07-18 18:26:20 +09:00
2 changed files with 43 additions and 11 deletions

View file

@ -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)

View file

@ -6,7 +6,9 @@
#pragma once
#include "DepthBuffer.h"
#include "GLStruct.h"
#include <AK/OwnPtr.h>
#include <LibGfx/Bitmap.h>
#include <LibGfx/Vector4.h>
@ -32,6 +34,7 @@ public:
private:
RefPtr<Gfx::Bitmap> m_render_target;
OwnPtr<DepthBuffer> m_depth_buffer;
RasterizerOptions m_options;
};