summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibSoftGPU
diff options
context:
space:
mode:
authorStephan Unverwerth <s.unverwerth@serenityos.org>2022-01-08 02:49:15 +0100
committerAli Mohammad Pur <Ali.mpfard@gmail.com>2022-01-09 16:21:13 +0330
commit57215d0e1f3d7b8aa7ccc71a5280a765686fdbea (patch)
tree56d294316a7b83aa30b5c8fab67ca6c603a63811 /Userland/Libraries/LibSoftGPU
parent21cad2253545c7433f862e871fbccd7fbd7485a2 (diff)
downloadserenity-57215d0e1f3d7b8aa7ccc71a5280a765686fdbea.zip
LibSoftGPU: Allow arbitrary render target sizes
With the RASTERIZER_BLOCK_SIZE gone we can now render to any size, even odd ones. We have to be careful to not generate out of bounds accesses when calculating the render target and depth buffer pointers. Thus we check the coverage mask and generate nullptrs for pixels that will not be updated. This also masks out pixels that would touch the triangle but are outside the render target/scissor rect bounds.
Diffstat (limited to 'Userland/Libraries/LibSoftGPU')
-rw-r--r--Userland/Libraries/LibSoftGPU/Config.h1
-rw-r--r--Userland/Libraries/LibSoftGPU/Device.cpp63
2 files changed, 27 insertions, 37 deletions
diff --git a/Userland/Libraries/LibSoftGPU/Config.h b/Userland/Libraries/LibSoftGPU/Config.h
index 52bda0c8cf..c31f7a554a 100644
--- a/Userland/Libraries/LibSoftGPU/Config.h
+++ b/Userland/Libraries/LibSoftGPU/Config.h
@@ -15,7 +15,6 @@
namespace SoftGPU {
static constexpr bool ENABLE_STATISTICS_OVERLAY = false;
-static constexpr int RASTERIZER_BLOCK_SIZE = 8;
static constexpr int NUM_SAMPLERS = 32;
static constexpr int SUBPIXEL_BITS = 5;
diff --git a/Userland/Libraries/LibSoftGPU/Device.cpp b/Userland/Libraries/LibSoftGPU/Device.cpp
index c5f601b1df..28f4ae4a38 100644
--- a/Userland/Libraries/LibSoftGPU/Device.cpp
+++ b/Userland/Libraries/LibSoftGPU/Device.cpp
@@ -183,11 +183,6 @@ void Device::rasterize_triangle(const Triangle& triangle)
{
INCREASE_STATISTICS_COUNTER(g_num_rasterized_triangles, 1);
- // Since the algorithm is based on blocks of uniform size, we need
- // to ensure that our m_render_target size is actually a multiple of the block size
- VERIFY((m_render_target->width() % 2) == 0);
- VERIFY((m_render_target->height() % 2) == 0);
-
// Return if alpha testing is a no-op
if (m_options.enable_alpha_test && m_options.alpha_test_func == AlphaTestFunction::Never)
return;
@@ -244,13 +239,6 @@ void Device::rasterize_triangle(const Triangle& triangle)
&& edges.z() >= zero.z();
};
- auto test_scissor4 = [window_scissor_rect](const Vector2<i32x4>& screen_coordinates) -> i32x4 {
- return screen_coordinates.x() >= window_scissor_rect.x()
- && screen_coordinates.x() < window_scissor_rect.x() + window_scissor_rect.width()
- && screen_coordinates.y() >= window_scissor_rect.y()
- && screen_coordinates.y() < window_scissor_rect.y() + window_scissor_rect.height();
- };
-
// Calculate block-based bounds
// clang-format off
int const bx0 = max(render_bounds.left(), min(min(v0.x(), v1.x()), v2.x()) / subpixel_factor) & ~1;
@@ -266,6 +254,11 @@ void Device::rasterize_triangle(const Triangle& triangle)
// FIXME: implement stencil testing
+ int const render_bounds_left = render_bounds.x();
+ int const render_bounds_right = render_bounds.x() + render_bounds.width();
+ int const render_bounds_top = render_bounds.y();
+ int const render_bounds_bottom = render_bounds.y() + render_bounds.height();
+
// Iterate over all blocks within the bounds of the triangle
for (int by = by0; by < by1; by += 2) {
for (int bx = bx0; bx < bx1; bx += 2) {
@@ -281,9 +274,12 @@ void Device::rasterize_triangle(const Triangle& triangle)
// Generate triangle coverage mask
quad.mask = test_point4(edge_values);
- if (m_options.scissor_enabled) {
- quad.mask &= test_scissor4(quad.screen_coordinates);
- }
+
+ // Test quad against intersection of render target size and scissor rect
+ quad.mask &= quad.screen_coordinates.x() >= render_bounds_left
+ && quad.screen_coordinates.x() < render_bounds_right
+ && quad.screen_coordinates.y() >= render_bounds_top
+ && quad.screen_coordinates.y() < render_bounds_bottom;
if (none(quad.mask))
continue;
@@ -298,11 +294,13 @@ void Device::rasterize_triangle(const Triangle& triangle)
to_f32x4(edge_values.z()),
} * one_over_area;
+ int coverage_bits = maskbits(quad.mask);
+
float* depth_ptrs[4] = {
- &m_depth_buffer->scanline(by)[bx],
- &m_depth_buffer->scanline(by)[bx + 1],
- &m_depth_buffer->scanline(by + 1)[bx],
- &m_depth_buffer->scanline(by + 1)[bx + 1],
+ coverage_bits & 1 ? &m_depth_buffer->scanline(by)[bx] : nullptr,
+ coverage_bits & 2 ? &m_depth_buffer->scanline(by)[bx + 1] : nullptr,
+ coverage_bits & 4 ? &m_depth_buffer->scanline(by + 1)[bx] : nullptr,
+ coverage_bits & 8 ? &m_depth_buffer->scanline(by + 1)[bx + 1] : nullptr,
};
// AND the depth mask onto the coverage mask
@@ -416,10 +414,10 @@ void Device::rasterize_triangle(const Triangle& triangle)
continue;
Gfx::RGBA32* color_ptrs[4] = {
- &m_render_target->scanline(by)[bx],
- &m_render_target->scanline(by)[bx + 1],
- &m_render_target->scanline(by + 1)[bx],
- &m_render_target->scanline(by + 1)[bx + 1],
+ coverage_bits & 1 ? &m_render_target->scanline(by)[bx] : nullptr,
+ coverage_bits & 2 ? &m_render_target->scanline(by)[bx + 1] : nullptr,
+ coverage_bits & 4 ? &m_render_target->scanline(by + 1)[bx] : nullptr,
+ coverage_bits & 8 ? &m_render_target->scanline(by + 1)[bx + 1] : nullptr,
};
u32x4 dst_u32;
@@ -456,16 +454,9 @@ void Device::rasterize_triangle(const Triangle& triangle)
}
}
-static Gfx::IntSize closest_multiple(const Gfx::IntSize& min_size, size_t step)
-{
- int width = ((min_size.width() + step - 1) / step) * step;
- int height = ((min_size.height() + step - 1) / step) * step;
- return { width, height };
-}
-
-Device::Device(const Gfx::IntSize& min_size)
- : m_render_target { Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, closest_multiple(min_size, 2)).release_value_but_fixme_should_propagate_errors() }
- , m_depth_buffer { adopt_own(*new DepthBuffer(closest_multiple(min_size, 2))) }
+Device::Device(const Gfx::IntSize& size)
+ : m_render_target { Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, size).release_value_but_fixme_should_propagate_errors() }
+ , m_depth_buffer { adopt_own(*new DepthBuffer(size)) }
{
m_options.scissor_box = m_render_target->rect();
}
@@ -829,12 +820,12 @@ ALWAYS_INLINE bool Device::test_alpha(PixelQuad& quad)
return any(quad.mask);
}
-void Device::resize(const Gfx::IntSize& min_size)
+void Device::resize(const Gfx::IntSize& size)
{
wait_for_all_threads();
- m_render_target = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, closest_multiple(min_size, 2)).release_value_but_fixme_should_propagate_errors();
- m_depth_buffer = adopt_own(*new DepthBuffer(m_render_target->size()));
+ m_render_target = Gfx::Bitmap::try_create(Gfx::BitmapFormat::BGRA8888, size).release_value_but_fixme_should_propagate_errors();
+ m_depth_buffer = adopt_own(*new DepthBuffer(size));
}
void Device::clear_color(const FloatVector4& color)