diff options
Diffstat (limited to 'Userland/Libraries/LibSoftGPU')
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Config.h | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Device.cpp | 79 | ||||
-rw-r--r-- | Userland/Libraries/LibSoftGPU/Device.h | 1 |
3 files changed, 86 insertions, 1 deletions
diff --git a/Userland/Libraries/LibSoftGPU/Config.h b/Userland/Libraries/LibSoftGPU/Config.h index 8a551ca40b..0292a153cd 100644 --- a/Userland/Libraries/LibSoftGPU/Config.h +++ b/Userland/Libraries/LibSoftGPU/Config.h @@ -6,8 +6,15 @@ #pragma once +#define INCREASE_STATISTICS_COUNTER(stat, n) \ + do { \ + if constexpr (ENABLE_STATISTICS_OVERLAY) \ + stat += (n); \ + } while (0) + namespace SoftGPU { +static constexpr bool ENABLE_STATISTICS_OVERLAY = false; static constexpr int RASTERIZER_BLOCK_SIZE = 8; static constexpr int NUM_SAMPLERS = 32; diff --git a/Userland/Libraries/LibSoftGPU/Device.cpp b/Userland/Libraries/LibSoftGPU/Device.cpp index f97d95b18b..da18894ec1 100644 --- a/Userland/Libraries/LibSoftGPU/Device.cpp +++ b/Userland/Libraries/LibSoftGPU/Device.cpp @@ -6,6 +6,7 @@ */ #include <AK/Function.h> +#include <LibCore/ElapsedTimer.h> #include <LibGfx/Painter.h> #include <LibGfx/Vector2.h> #include <LibGfx/Vector3.h> @@ -14,6 +15,12 @@ namespace SoftGPU { +static long long g_num_rasterized_triangles; +static long long g_num_pixels; +static long long g_num_pixels_shaded; +static long long g_num_pixels_blended; +static long long g_num_sampler_calls; + using IntVector2 = Gfx::Vector2<int>; using IntVector3 = Gfx::Vector3<int>; @@ -113,6 +120,8 @@ static constexpr void setup_blend_factors(BlendFactor mode, FloatVector4& consta template<typename PS> static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& render_target, DepthBuffer& depth_buffer, const Triangle& triangle, PS pixel_shader) { + INCREASE_STATISTICS_COUNTER(g_num_rasterized_triangles, 1); + // 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 VERIFY((render_target.width() % RASTERIZER_BLOCK_SIZE) == 0); @@ -257,6 +266,7 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re // Generate the coverage mask if (!options.scissor_enabled && test_point(b0) && test_point(b1) && test_point(b2) && test_point(b3)) { + INCREASE_STATISTICS_COUNTER(g_num_pixels, RASTERIZER_BLOCK_SIZE * RASTERIZER_BLOCK_SIZE); // The block is fully contained within the triangle. Fill the mask with all 1s for (int y = 0; y < RASTERIZER_BLOCK_SIZE; y++) pixel_mask[y] = -1; @@ -268,8 +278,10 @@ 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) && (!options.scissor_enabled || render_bounds.contains(x0 + x, y0 + y))) + if (test_point(coords) && (!options.scissor_enabled || render_bounds.contains(x0 + x, y0 + y))) { + INCREASE_STATISTICS_COUNTER(g_num_pixels, 1); pixel_mask[y] |= 1 << x; + } } } } @@ -401,6 +413,7 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re float fog_fragment_depth = interpolate(vertex0_eye_absz, vertex1_eye_absz, vertex2_eye_absz, barycentric); *pixel = pixel_shader(uv, vertex_color, fog_fragment_depth); + INCREASE_STATISTICS_COUNTER(g_num_pixels_shaded, 1); } } @@ -490,6 +503,7 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re + FloatVector4(float_dst.w(), float_dst.w(), float_dst.w(), float_dst.w()) * dst_factor_dst_alpha; *dst = (*dst & ~options.color_mask) | (to_rgba32(*src * src_factor + float_dst * dst_factor) & options.color_mask); + INCREASE_STATISTICS_COUNTER(g_num_pixels_blended, 1); } } } else { @@ -795,6 +809,7 @@ void Device::submit_triangle(const Triangle& triangle, Vector<size_t> const& ena auto const& sampler = m_samplers[i]; FloatVector4 texel = sampler.sample_2d({ uv.x(), uv.y() }); + INCREASE_STATISTICS_COUNTER(g_num_sampler_calls, 1); // FIXME: Implement more blend modes switch (sampler.config().fixed_function_texture_env_mode) { @@ -890,6 +905,9 @@ void Device::blit(Gfx::Bitmap const& source, int x, int y) { wait_for_all_threads(); + INCREASE_STATISTICS_COUNTER(g_num_pixels, source.width() * source.height()); + INCREASE_STATISTICS_COUNTER(g_num_pixels_shaded, source.width() * source.height()); + Gfx::Painter painter { *m_render_target }; painter.blit({ x, y }, source, source.rect(), 1.0f, true); } @@ -900,6 +918,65 @@ void Device::blit_to(Gfx::Bitmap& target) Gfx::Painter painter { target }; painter.blit({ 0, 0 }, *m_render_target, m_render_target->rect(), 1.0f, false); + + if constexpr (ENABLE_STATISTICS_OVERLAY) + draw_statistics_overlay(target); +} + +void Device::draw_statistics_overlay(Gfx::Bitmap& target) +{ + static Core::ElapsedTimer timer; + static String debug_string; + static int frame_counter; + + frame_counter++; + int milliseconds = 0; + if (timer.is_valid()) + milliseconds = timer.elapsed(); + else + timer.start(); + + Gfx::Painter painter { target }; + + if (milliseconds > 500) { + + if (g_num_pixels == 0) + g_num_pixels = 1; + + int num_rendertarget_pixels = m_render_target->width() * m_render_target->height(); + + StringBuilder builder; + builder.append(String::formatted("Timings : {:.1}ms {:.1}FPS\n", + static_cast<double>(milliseconds) / frame_counter, + (milliseconds > 0) ? 1000.0 * frame_counter / milliseconds : 9999.0)); + builder.append(String::formatted("Triangles : {}\n", g_num_rasterized_triangles)); + builder.append(String::formatted("Pixels : {}, Shaded: {}%, Blended: {}%, Overdraw: {}%\n", + g_num_pixels, + g_num_pixels_shaded * 100 / g_num_pixels, + g_num_pixels_blended * 100 / g_num_pixels_shaded, + g_num_pixels_shaded * 100 / num_rendertarget_pixels - 100)); + builder.append(String::formatted("Sampler calls: {}\n", g_num_sampler_calls)); + + debug_string = builder.to_string(); + + frame_counter = 0; + timer.start(); + } + + g_num_rasterized_triangles = 0; + g_num_pixels = 0; + g_num_pixels_shaded = 0; + g_num_pixels_blended = 0; + g_num_sampler_calls = 0; + + auto& font = Gfx::FontDatabase::default_fixed_width_font(); + + for (int y = -1; y < 2; y++) + for (int x = -1; x < 2; x++) + if (x != 0 && y != 0) + painter.draw_text(target.rect().translated(x + 2, y + 2), debug_string, font, Gfx::TextAlignment::TopLeft, Gfx::Color::Black); + + painter.draw_text(target.rect().translated(2, 2), debug_string, font, Gfx::TextAlignment::TopLeft, Gfx::Color::White); } void Device::wait_for_all_threads() const diff --git a/Userland/Libraries/LibSoftGPU/Device.h b/Userland/Libraries/LibSoftGPU/Device.h index 9fdd2803ee..f8e2c1dcb6 100644 --- a/Userland/Libraries/LibSoftGPU/Device.h +++ b/Userland/Libraries/LibSoftGPU/Device.h @@ -91,6 +91,7 @@ public: private: void submit_triangle(Triangle const& triangle, Vector<size_t> const& enabled_texture_units); + void draw_statistics_overlay(Gfx::Bitmap&); private: RefPtr<Gfx::Bitmap> m_render_target; |