test(vulkan): cover rotated steady-state allocations in the perf gate
- commit
- fcceab58bdd3c1f56b9fc962882e6911ea599625
- author
- brice · · 2026-10-03 19:15 UTC
- parent
- ca6770e
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +33 -45
M internal/adapters/vulkan/output_transform_test.go +0 -25
| @@ -47,28 +47,3 @@ func TestRendererOutputTransform(t *testing.T) { | |||
| 47 | 47 | } | |
| 48 | 48 | } | |
| 49 | 49 | } | |
| 50 | - | ||
| 51 | - | // A rotated output keeps the steady-state frame free of extra allocations: | |
| 52 | - | // orient works in place. | |
| 53 | - | func TestRenderSteadyStateAllocationsRotated(t *testing.T) { | |
| 54 | - | r, err := New(32, 24) | |
| 55 | - | if err != nil { | |
| 56 | - | t.Skipf("Vulkan unavailable: %v", err) | |
| 57 | - | } | |
| 58 | - | defer r.Close() | |
| 59 | - | scene := ports.Scene{Seq: 1, Transform: 1, Scale: 1, Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 24, H: 32}}}} | |
| 60 | - | content := solidContent(t, 8, 8, color.RGBA{R: 255, A: 255}) | |
| 61 | - | content.ID, content.Surface, content.Seq, content.Version = 1, 1, 1, 1 | |
| 62 | - | contents := map[ports.WindowID]ports.SurfaceContent{1: content} | |
| 63 | - | frame := func() { | |
| 64 | - | if err := render(r, scene, contents); err != nil { | |
| 65 | - | t.Fatal(err) | |
| 66 | - | } | |
| 67 | - | } | |
| 68 | - | frame() | |
| 69 | - | if allocs := testing.AllocsPerRun(20, frame); allocs > 13 { | |
| 70 | - | t.Errorf("rotated steady-state Render: %.1f allocs/frame, want <=13", allocs) | |
| 71 | - | } else { | |
| 72 | - | t.Logf("rotated steady-state Render: %.1f allocs/frame", allocs) | |
| 73 | - | } | |
| 74 | - | } | |
| @@ -47,28 +47,3 @@ func TestRendererOutputTransform(t *testing.T) { | |||||
| 47 | } | 47 | } | ||
| 48 | } | 48 | } | ||
| 49 | } | 49 | } | ||
| 50 | - | ||||
| 51 | - | // A rotated output keeps the steady-state frame free of extra allocations: | |||
| 52 | - | // orient works in place. | |||
| 53 | - | func TestRenderSteadyStateAllocationsRotated(t *testing.T) { | |||
| 54 | - | r, err := New(32, 24) | |||
| 55 | - | if err != nil { | |||
| 56 | - | t.Skipf("Vulkan unavailable: %v", err) | |||
| 57 | - | } | |||
| 58 | - | defer r.Close() | |||
| 59 | - | scene := ports.Scene{Seq: 1, Transform: 1, Scale: 1, Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 24, H: 32}}}} | |||
| 60 | - | content := solidContent(t, 8, 8, color.RGBA{R: 255, A: 255}) | |||
| 61 | - | content.ID, content.Surface, content.Seq, content.Version = 1, 1, 1, 1 | |||
| 62 | - | contents := map[ports.WindowID]ports.SurfaceContent{1: content} | |||
| 63 | - | frame := func() { | |||
| 64 | - | if err := render(r, scene, contents); err != nil { | |||
| 65 | - | t.Fatal(err) | |||
| 66 | - | } | |||
| 67 | - | } | |||
| 68 | - | frame() | |||
| 69 | - | if allocs := testing.AllocsPerRun(20, frame); allocs > 13 { | |||
| 70 | - | t.Errorf("rotated steady-state Render: %.1f allocs/frame, want <=13", allocs) | |||
| 71 | - | } else { | |||
| 72 | - | t.Logf("rotated steady-state Render: %.1f allocs/frame", allocs) | |||
| 73 | - | } | |||
| 74 | - | } | |||
M internal/adapters/vulkan/scene_perf_test.go +33 -20
| @@ -8,27 +8,40 @@ import ( | |||
| 8 | 8 | "github.com/bnema/neferwl/internal/ports" | |
| 9 | 9 | ) | |
| 10 | 10 | ||
| 11 | - | // TestRenderSteadyStateAllocations measures the cost of a small stable scene. | |
| 11 | + | // TestRenderSteadyStateAllocations measures the cost of a small stable scene, | |
| 12 | + | // on a normal and on a rotated output (orient works in place). | |
| 12 | 13 | func TestRenderSteadyStateAllocations(t *testing.T) { | |
| 13 | - | r, err := New(32, 32) | |
| 14 | - | if err != nil { | |
| 15 | - | t.Skipf("Vulkan unavailable: %v", err) | |
| 16 | - | } | |
| 17 | - | defer r.Close() | |
| 18 | - | scene := ports.Scene{Seq: 1, Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 32, H: 32}}}} | |
| 19 | - | content := solidContent(t, 8, 8, color.RGBA{R: 255, A: 255}) | |
| 20 | - | content.ID, content.Surface, content.Seq, content.Version = 1, 1, 1, 1 | |
| 21 | - | contents := map[ports.WindowID]ports.SurfaceContent{1: content} | |
| 22 | - | frame := func() { | |
| 23 | - | if err := render(r, scene, contents); err != nil { | |
| 24 | - | t.Fatal(err) | |
| 25 | - | } | |
| 26 | - | } | |
| 27 | - | frame() | |
| 28 | - | if allocs := testing.AllocsPerRun(20, frame); allocs > 13 { | |
| 29 | - | t.Errorf("small steady-state Render: %.1f allocs/frame, want <=13", allocs) | |
| 30 | - | } else { | |
| 31 | - | t.Logf("small steady-state Render: %.1f allocs/frame", allocs) | |
| 14 | + | for _, tc := range []struct { | |
| 15 | + | name string | |
| 16 | + | transform ports.BufferTransform | |
| 17 | + | tw, th int | |
| 18 | + | sceneW, sceneH int | |
| 19 | + | }{ | |
| 20 | + | {"transform 0", 0, 32, 32, 32, 32}, | |
| 21 | + | {"transform 1", 1, 32, 24, 24, 32}, | |
| 22 | + | } { | |
| 23 | + | t.Run(tc.name, func(t *testing.T) { | |
| 24 | + | r, err := New(tc.tw, tc.th) | |
| 25 | + | if err != nil { | |
| 26 | + | t.Skipf("Vulkan unavailable: %v", err) | |
| 27 | + | } | |
| 28 | + | defer r.Close() | |
| 29 | + | scene := ports.Scene{Seq: 1, Transform: tc.transform, Scale: 1, Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: tc.sceneW, H: tc.sceneH}}}} | |
| 30 | + | content := solidContent(t, 8, 8, color.RGBA{R: 255, A: 255}) | |
| 31 | + | content.ID, content.Surface, content.Seq, content.Version = 1, 1, 1, 1 | |
| 32 | + | contents := map[ports.WindowID]ports.SurfaceContent{1: content} | |
| 33 | + | frame := func() { | |
| 34 | + | if err := render(r, scene, contents); err != nil { | |
| 35 | + | t.Fatal(err) | |
| 36 | + | } | |
| 37 | + | } | |
| 38 | + | frame() | |
| 39 | + | if allocs := testing.AllocsPerRun(20, frame); allocs > 13 { | |
| 40 | + | t.Errorf("small steady-state Render: %.1f allocs/frame, want <=13", allocs) | |
| 41 | + | } else { | |
| 42 | + | t.Logf("small steady-state Render: %.1f allocs/frame", allocs) | |
| 43 | + | } | |
| 44 | + | }) | |
| 32 | 45 | } | |
| 33 | 46 | } | |
| 34 | 47 | ||
| @@ -8,27 +8,40 @@ import ( | |||||
| 8 | "github.com/bnema/neferwl/internal/ports" | 8 | "github.com/bnema/neferwl/internal/ports" | ||
| 9 | ) | 9 | ) | ||
| 10 | 10 | ||||
| 11 | - | // TestRenderSteadyStateAllocations measures the cost of a small stable scene. | 11 | + | // TestRenderSteadyStateAllocations measures the cost of a small stable scene, |
| 12 | + | // on a normal and on a rotated output (orient works in place). | |||
| 12 | func TestRenderSteadyStateAllocations(t *testing.T) { | 13 | func TestRenderSteadyStateAllocations(t *testing.T) { | ||
| 13 | - | r, err := New(32, 32) | 14 | + | for _, tc := range []struct { |
| 14 | - | if err != nil { | 15 | + | name string |
| 15 | - | t.Skipf("Vulkan unavailable: %v", err) | 16 | + | transform ports.BufferTransform |
| 16 | - | } | 17 | + | tw, th int |
| 17 | - | defer r.Close() | 18 | + | sceneW, sceneH int |
| 18 | - | scene := ports.Scene{Seq: 1, Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: 32, H: 32}}}} | 19 | + | }{ |
| 19 | - | content := solidContent(t, 8, 8, color.RGBA{R: 255, A: 255}) | 20 | + | {"transform 0", 0, 32, 32, 32, 32}, |
| 20 | - | content.ID, content.Surface, content.Seq, content.Version = 1, 1, 1, 1 | 21 | + | {"transform 1", 1, 32, 24, 24, 32}, |
| 21 | - | contents := map[ports.WindowID]ports.SurfaceContent{1: content} | 22 | + | } { |
| 22 | - | frame := func() { | 23 | + | t.Run(tc.name, func(t *testing.T) { |
| 23 | - | if err := render(r, scene, contents); err != nil { | 24 | + | r, err := New(tc.tw, tc.th) |
| 24 | - | t.Fatal(err) | 25 | + | if err != nil { |
| 25 | - | } | 26 | + | t.Skipf("Vulkan unavailable: %v", err) |
| 26 | - | } | 27 | + | } |
| 27 | - | frame() | 28 | + | defer r.Close() |
| 28 | - | if allocs := testing.AllocsPerRun(20, frame); allocs > 13 { | 29 | + | scene := ports.Scene{Seq: 1, Transform: tc.transform, Scale: 1, Windows: []ports.SceneWindow{{ID: 1, Rect: ports.Rect{W: tc.sceneW, H: tc.sceneH}}}} |
| 29 | - | t.Errorf("small steady-state Render: %.1f allocs/frame, want <=13", allocs) | 30 | + | content := solidContent(t, 8, 8, color.RGBA{R: 255, A: 255}) |
| 30 | - | } else { | 31 | + | content.ID, content.Surface, content.Seq, content.Version = 1, 1, 1, 1 |
| 31 | - | t.Logf("small steady-state Render: %.1f allocs/frame", allocs) | 32 | + | contents := map[ports.WindowID]ports.SurfaceContent{1: content} |
| 33 | + | frame := func() { | |||
| 34 | + | if err := render(r, scene, contents); err != nil { | |||
| 35 | + | t.Fatal(err) | |||
| 36 | + | } | |||
| 37 | + | } | |||
| 38 | + | frame() | |||
| 39 | + | if allocs := testing.AllocsPerRun(20, frame); allocs > 13 { | |||
| 40 | + | t.Errorf("small steady-state Render: %.1f allocs/frame, want <=13", allocs) | |||
| 41 | + | } else { | |||
| 42 | + | t.Logf("small steady-state Render: %.1f allocs/frame", allocs) | |||
| 43 | + | } | |||
| 44 | + | }) | |||
| 32 | } | 45 | } | ||
| 33 | } | 46 | } | ||
| 34 | 47 | ||||