summaryrefslogtreecommitdiff
path: root/Userland/Libraries/LibSoftGPU
diff options
context:
space:
mode:
authorStephan Unverwerth <s.unverwerth@serenityos.org>2021-12-30 01:04:55 +0100
committerAndreas Kling <kling@serenityos.org>2022-01-01 15:09:21 +0100
commitb7c0c32f24c2028453b5c6a402f5068717cd773c (patch)
tree88253ecb3d0657eddf601a771ab308e2f679d5d7 /Userland/Libraries/LibSoftGPU
parentfe36edf6ae4fa5d003ee60ce4d2fb755c59bec48 (diff)
downloadserenity-b7c0c32f24c2028453b5c6a402f5068717cd773c.zip
LibSoftGPU: Add option to render a debug overlay
This displays statistics regarding frame timings and number of pixels rendered. Timings are based on the time between draw_debug_overlay() invocations. This measures actual number of frames presented to the user vs. wall clock time so this also includes everything the app might do besides rendering. Triangles are counted after clipping. This number might actually be higher than the number of triangles coming from LibGL. Pixels are counted after the initial scissor and coverage test. Pixels rejected here are not counted. Shaded pixels is the percentage of all pixels that made it to the shading stage. Blended pixels is the percentage of shaded pixels that were alpha blended to the color buffer. Overdraw measures how many pixels were shaded vs. how many pixels the render target has. e.g. a 640x480 render target has 307200 pixels. If exactly that many pixels are shaded the overdraw number will read 0%. 614400 shaded pixels will read as an overdraw of 100%. Sampler calls is simply the number of times sampler.sample_2d() was called.
Diffstat (limited to 'Userland/Libraries/LibSoftGPU')
-rw-r--r--Userland/Libraries/LibSoftGPU/Config.h7
-rw-r--r--Userland/Libraries/LibSoftGPU/Device.cpp79
-rw-r--r--Userland/Libraries/LibSoftGPU/Device.h1
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;