VSE timeline, when many (hundreds/thousands) of thumbnails were visible, was very slow to redraw. This PR makes them 3-10x faster to redraw, by stopping doing things that are slow :) Part of #126087 thumbnail improvements task. - No longer do mute semitransparency or corner rounding on the CPU, do it in shader instead. - Stop creating a separate GPU texture for each thumbnail, on every repaint, and drawing each thumbnail as a separate draw call. Instead, put thumbnails into a single texture atlas (using a simple shelf packing algorithm), and draw them in batch, passing data via UBO. The atlas is still re-created every frame, but that does not seem to be a performance issue. Thumbnails are cropped horizontally based on how much of their parts are visible (e.g. a narrow strip on screen), so realistically the atlas size is kinda proportional to screen size, and ends up being just several megabytes of data transfer between CPU -> GPU each frame. On this Sprite Fright edit timeline view (612 visible thumbnails), time taken to repaint the timeline window: - Mac (M1 Max, Metal): 68.1ms -> 4.7ms - Windows (Ryzen 5950X, RTX 3080Ti, OpenGL): 23.7ms -> 6.8ms This also fixes a visual issue with thumbnails, where when strips are very tall, the "rounded corners" that were poked right into the thumbnail bitmap on the CPU were showing up due to actual bitmap being scaled up a lot. Pull Request: https://projects.blender.org/blender/blender/pulls/126972
40 lines
1.1 KiB
GLSL
40 lines
1.1 KiB
GLSL
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/* Signed distance to rounded box, centered at origin.
|
|
* Reference: https://iquilezles.org/articles/distfunctions2d/ */
|
|
float sdf_rounded_box(vec2 pos, vec2 size, float radius)
|
|
{
|
|
vec2 q = abs(pos) - size + radius;
|
|
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - radius;
|
|
}
|
|
|
|
void strip_box(float left,
|
|
float right,
|
|
float bottom,
|
|
float top,
|
|
vec2 pos,
|
|
out vec2 r_pos1,
|
|
out vec2 r_pos2,
|
|
out vec2 r_size,
|
|
out vec2 r_center,
|
|
out vec2 r_pos,
|
|
out float r_radius)
|
|
{
|
|
/* Snap to pixel grid coordinates, so that outline/border is non-fractional
|
|
* pixel sizes. */
|
|
r_pos1 = round(vec2(left, bottom));
|
|
r_pos2 = round(vec2(right, top));
|
|
/* Make sure strip is at least 1px wide. */
|
|
r_pos2.x = max(r_pos2.x, r_pos1.x + 1.0);
|
|
r_size = (r_pos2 - r_pos1) * 0.5;
|
|
r_center = (r_pos1 + r_pos2) * 0.5;
|
|
r_pos = round(pos);
|
|
|
|
r_radius = context_data.round_radius;
|
|
if (r_radius > r_size.x) {
|
|
r_radius = 0.0;
|
|
}
|
|
}
|