Avoid rendering rectangles (and characters) that are outside the window bounds.

While debugging an issue with the dx11 backend, I noticed that 4coder only clipped rectangles that are outside the screen vertically. Another potential issue (it might be the intended behavior) causes some things to not work with line wrapping, which means that we could have very long horizontal lines, causing a lot of vertices being sent through the render pipeline that will just be clipped after the vertex shader. This causes higher than necessary GPU memory usage, and low performance for things that aren't rendered in the end.

An example of problematic is:
```c
u8 data[ ] = {0,0,0,0,...,0}; // With a lot of zero, and no space between them.
```

This fix just checks that at least one vertex of each rectangle we try to draw is in the screen. It would be better to use the current clip rect, but it's not available at that point in the pipeline. If we want we can modify the API a little to pass it down, as a parameter to those functions.

Using RenderDoc, I saw the vertex count going from over 500K to 13K with this change, and the performance were from 57ms to 25ms. So perfs are not great (but still an improvement), but testing the bounds of 500K vertices is not free. Fixing the line wrapping issue would probably help getting back to reasonable frame rate.
This commit is contained in:
Simon Anciaux 2024-04-03 15:52:44 +02:00 committed by Peter Slattery
parent dadb7dc49a
commit 52124edcd8
1 changed files with 27 additions and 2 deletions

View File

@ -146,13 +146,26 @@ draw_rectangle_outline(Render_Target *target, Rect_f32 rect, f32 roundness, f32
vertices[4].xy = V2f32(rect.x0, rect.y1); vertices[4].xy = V2f32(rect.x0, rect.y1);
vertices[5].xy = V2f32(rect.x1, rect.y1); vertices[5].xy = V2f32(rect.x1, rect.y1);
// NOTE simon (03/04/24): If any vertex is in the render target bounds, we draw the rectangle.
// It would be better to use the current clip rect, but it's not available here. We could pass
// it down in the function signature if necessary.
Rect_f32 target_rect = Rf32( 0, 0, ( f32 ) target->width, ( f32 ) target->height );
b32 draw = false;
Vec2_f32 center = rect_center(rect); Vec2_f32 center = rect_center(rect);
for (i32 i = 0; i < ArrayCount(vertices); i += 1){ for (i32 i = 0; i < ArrayCount(vertices); i += 1){
vertices[i].uvw = V3f32(center.x, center.y, roundness); vertices[i].uvw = V3f32(center.x, center.y, roundness);
vertices[i].color = color; vertices[i].color = color;
vertices[i].half_thickness = half_thickness; vertices[i].half_thickness = half_thickness;
draw = draw || rect_contains_point( target_rect, vertices[ i ].xy );
} }
draw = true;
if ( draw ) {
draw__write_vertices_in_current_group(target, vertices, ArrayCount(vertices)); draw__write_vertices_in_current_group(target, vertices, ArrayCount(vertices));
}
} }
internal void internal void
@ -235,12 +248,24 @@ draw_font_glyph(Render_Target *target, Face *face, u32 codepoint, Vec2_f32 p,
vertices[3] = vertices[1]; vertices[3] = vertices[1];
vertices[4] = vertices[2]; vertices[4] = vertices[2];
// NOTE simon (03/04/24): If any vertex is in the render target bounds, we draw the rectangle.
// It would be better to use the current clip rect, but it's not available here. We could pass
// it down in the function signature if necessary.
Rect_f32 target_rect = Rf32( 0, 0, ( f32 ) target->width, ( f32 ) target->height );
b32 draw = false;
for (i32 i = 0; i < ArrayCount(vertices); i += 1){ for (i32 i = 0; i < ArrayCount(vertices); i += 1){
vertices[i].color = color; vertices[i].color = color;
vertices[i].half_thickness = 0.f; vertices[i].half_thickness = 0.f;
draw = draw || rect_contains_point( target_rect, vertices[ i ].xy );
} }
draw = true;
if ( draw ) {
draw__write_vertices_in_current_group(target, vertices, ArrayCount(vertices)); draw__write_vertices_in_current_group(target, vertices, ArrayCount(vertices));
}
} }
//////////////////////////////// ////////////////////////////////