///|
/// Micro-benchmarks for the atlas quad hot path. These isolate the cost of
/// individual builders so regressions in cache-key hashing or vertex packing
/// do not get swallowed by full-pipeline benches in kagura_engine.
///|
fn bench_atlas_draw_source(page_image_id : Int) -> @atlas.AtlasDrawSource {
let repo = @atlas.new_simple_atlas_image_repository(8, 8, page_image_id)
let key = @atlas.new_asset_key("renderer2d/bench/source")
let _ = @atlas.create_atlas_image(repo, key, @atlas.default_image_spec(2, 2))
match @atlas.get_atlas_draw_source(repo, key) {
Some(value) => value
None => panic()
}
}
///|
test "bench atlas_quad_resource_cache_key 10000" (b : @bench.T) {
let source = bench_atlas_draw_source(820)
let dst = @gfx.new_image_handle(1, 1920, 1080)
let shader = @gfx.new_shader_handle(2, "atlas_quad_bench")
let dst_region = @gfx.new_dst_region(0, 0, 1920, 1080, 6)
let blend = @gfx.BlendMode::from_int(1)
let uniform_dwords = [1, 2, 3, 4]
b.bench(name="atlas_quad/resource_cache_key_10000", fn() {
let mut acc = 0
for i in 0..<10000 {
let left = (i % 256).to_double() * 2.0
let top = (i / 256).to_double() * 2.0
acc = acc +
atlas_quad_resource_cache_key(
dst,
shader,
dst_region,
blend,
source,
left,
top,
left + 2.0,
top + 2.0,
uniform_dwords,
)
}
b.keep(acc)
})
}
///|
test "bench atlas_quad_vertex_data 10000" (b : @bench.T) {
let source = bench_atlas_draw_source(821)
b.bench(name="atlas_quad/vertex_data_10000", fn() {
let mut acc = 0.0
for i in 0..<10000 {
let left = (i % 256).to_double() * 2.0
let top = (i / 256).to_double() * 2.0
let v = atlas_quad_vertex_data(source, left, top, left + 2.0, top + 2.0)
acc = acc + v[0] + v[15]
}
b.keep(acc)
})
}
///|
test "bench new_atlas_quad_draw_command 10000" (b : @bench.T) {
let source = bench_atlas_draw_source(822)
let dst = @gfx.new_image_handle(1, 1920, 1080)
let shader = @gfx.new_shader_handle(2, "atlas_quad_bench")
let dst_region = @gfx.new_dst_region(0, 0, 1920, 1080, 6)
let blend = @gfx.BlendMode::from_int(1)
let uniform_dwords = [1, 2, 3, 4]
b.bench(name="atlas_quad/new_draw_command_10000", fn() {
let commands : Array[@gfx.DrawTrianglesCommand] = []
for i in 0..<10000 {
let left = (i % 256).to_double() * 2.0
let top = (i / 256).to_double() * 2.0
commands.push(
new_atlas_quad_draw_command(
dst,
shader,
dst_region,
0,
7,
11,
blend,
source,
left,
top,
left + 2.0,
top + 2.0,
uniform_dwords,
),
)
}
b.keep(commands.length())
})
}
///|
test "bench new_atlas_quad_batch_draw_command 10000 quads" (b : @bench.T) {
let source = bench_atlas_draw_source(823)
let dst = @gfx.new_image_handle(1, 1920, 1080)
let shader = @gfx.new_shader_handle(2, "atlas_batch_bench")
let dst_region = @gfx.new_dst_region(0, 0, 1920, 1080, 6)
let blend = @gfx.BlendMode::from_int(1)
let uniform_dwords = [1, 2, 3, 4]
// Pre-build the rect buffer outside the timed region (the caller in a real
// game would also reuse this between frames).
let rects : Array[Double] = Array::make(10000 * 4, 0.0)
for i in 0..<10000 {
let left = (i % 256).to_double() * 2.0
let top = (i / 256).to_double() * 2.0
rects[i * 4] = left
rects[i * 4 + 1] = top
rects[i * 4 + 2] = left + 2.0
rects[i * 4 + 3] = top + 2.0
}
b.bench(name="atlas_quad/batch_draw_command_10000", fn() {
let cmd = new_atlas_quad_batch_draw_command(
dst, shader, dst_region, 7, 11, blend, source, rects, uniform_dwords,
)
b.keep(cmd.resource_cache_key)
})
}