test(vulkan): cover content clipping when the window rect differs from content
- commit
- d26124e4df92c2b9ac50917ca70ece01033c3833
- author
- brice · · 2026-10-04 15:39 UTC
- committer
- brice · · 2026-10-04 19:08 UTC
- parent
- 506f1e5
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +60 -0
A internal/adapters/vulkan/scene_rect_content_test.go +60 -0
| @@ -0,0 +1,60 @@ | |||
| 1 | + | package vulkan | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "image" | |
| 5 | + | "testing" | |
| 6 | + | ||
| 7 | + | "github.com/bnema/neferwl/internal/ports" | |
| 8 | + | ) | |
| 9 | + | ||
| 10 | + | // A window animated by option B shows a rect that differs from its content | |
| 11 | + | // (the client has its final size already). These walk tests need no Vulkan | |
| 12 | + | // device: a single-pixel buffer is a solid quad. | |
| 13 | + | func TestSceneContentVsWindowRect(t *testing.T) { | |
| 14 | + | r := &Renderer{width: 80, height: 60} | |
| 15 | + | // A draw's rect is its corners: x0, y0, x1, y1. | |
| 16 | + | // walk returns the content draws: the window's background fill is first. | |
| 17 | + | walk := func(rect ports.Rect, lw, lh int, geo ports.Rect) []draw { | |
| 18 | + | c := ports.SurfaceContent{ | |
| 19 | + | ID: 1, Width: 1, Height: 1, LogicalW: lw, LogicalH: lh, Geometry: geo, | |
| 20 | + | Solid: &ports.SolidColor{R: 1, A: 1}, Opaque: true, | |
| 21 | + | } | |
| 22 | + | s := ports.Scene{Windows: []ports.SceneWindow{{ID: 1, Rect: rect}}} | |
| 23 | + | contents := map[ports.WindowID]ports.SurfaceContent{1: c} | |
| 24 | + | ds := r.draws(s, contents, newDamage(&target{}, s, image.Rect(0, 0, 80, 60))) | |
| 25 | + | if len(ds) < 2 { | |
| 26 | + | t.Fatalf("no content draw: %+v", ds) | |
| 27 | + | } | |
| 28 | + | return append([]draw(nil), ds[1:]...) | |
| 29 | + | } | |
| 30 | + | ||
| 31 | + | t.Run("rect smaller than content is clipped", func(t *testing.T) { | |
| 32 | + | rect := ports.Rect{X: 10, Y: 10, W: 20, H: 20} | |
| 33 | + | for _, geo := range []ports.Rect{{}, {X: 5, Y: 5, W: 30, H: 30}} { | |
| 34 | + | ds := walk(rect, 40, 40, geo) | |
| 35 | + | clip := image.Rect(10, 10, 30, 30) | |
| 36 | + | for _, d := range ds { | |
| 37 | + | got := image.Rect(int(d.pc.rect[0]), int(d.pc.rect[1]), int(d.pc.rect[2]), int(d.pc.rect[3])) | |
| 38 | + | if !got.In(clip) { | |
| 39 | + | t.Fatalf("geometry %+v: draw %v outside rect %v", geo, got, clip) | |
| 40 | + | } | |
| 41 | + | } | |
| 42 | + | if d := ds[0].pc.rect; d != [4]int32{10, 10, 30, 30} { | |
| 43 | + | t.Fatalf("geometry %+v: content = %v, want the whole rect", geo, d) | |
| 44 | + | } | |
| 45 | + | } | |
| 46 | + | }) | |
| 47 | + | ||
| 48 | + | t.Run("rect larger than content shows only the content", func(t *testing.T) { | |
| 49 | + | rect := ports.Rect{X: 10, Y: 10, W: 50, H: 40} | |
| 50 | + | ds := walk(rect, 20, 16, ports.Rect{}) | |
| 51 | + | if len(ds) != 1 || ds[0].pc.rect != [4]int32{10, 10, 30, 26} { | |
| 52 | + | t.Fatalf("content = %+v, want 20x16 at the rect origin", ds) | |
| 53 | + | } | |
| 54 | + | // Geometry shifts the surface so its geometry origin sits at the rect origin. | |
| 55 | + | ds = walk(rect, 24, 20, ports.Rect{X: 4, Y: 4, W: 20, H: 16}) | |
| 56 | + | if len(ds) != 1 || ds[0].pc.rect != [4]int32{10, 10, 30, 26} { | |
| 57 | + | t.Fatalf("content with geometry = %+v, want 20x16 at the rect origin", ds) | |
| 58 | + | } | |
| 59 | + | }) | |
| 60 | + | } | |
| @@ -0,0 +1,60 @@ | |||||
| 1 | + | package vulkan | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "image" | |||
| 5 | + | "testing" | |||
| 6 | + | ||||
| 7 | + | "github.com/bnema/neferwl/internal/ports" | |||
| 8 | + | ) | |||
| 9 | + | ||||
| 10 | + | // A window animated by option B shows a rect that differs from its content | |||
| 11 | + | // (the client has its final size already). These walk tests need no Vulkan | |||
| 12 | + | // device: a single-pixel buffer is a solid quad. | |||
| 13 | + | func TestSceneContentVsWindowRect(t *testing.T) { | |||
| 14 | + | r := &Renderer{width: 80, height: 60} | |||
| 15 | + | // A draw's rect is its corners: x0, y0, x1, y1. | |||
| 16 | + | // walk returns the content draws: the window's background fill is first. | |||
| 17 | + | walk := func(rect ports.Rect, lw, lh int, geo ports.Rect) []draw { | |||
| 18 | + | c := ports.SurfaceContent{ | |||
| 19 | + | ID: 1, Width: 1, Height: 1, LogicalW: lw, LogicalH: lh, Geometry: geo, | |||
| 20 | + | Solid: &ports.SolidColor{R: 1, A: 1}, Opaque: true, | |||
| 21 | + | } | |||
| 22 | + | s := ports.Scene{Windows: []ports.SceneWindow{{ID: 1, Rect: rect}}} | |||
| 23 | + | contents := map[ports.WindowID]ports.SurfaceContent{1: c} | |||
| 24 | + | ds := r.draws(s, contents, newDamage(&target{}, s, image.Rect(0, 0, 80, 60))) | |||
| 25 | + | if len(ds) < 2 { | |||
| 26 | + | t.Fatalf("no content draw: %+v", ds) | |||
| 27 | + | } | |||
| 28 | + | return append([]draw(nil), ds[1:]...) | |||
| 29 | + | } | |||
| 30 | + | ||||
| 31 | + | t.Run("rect smaller than content is clipped", func(t *testing.T) { | |||
| 32 | + | rect := ports.Rect{X: 10, Y: 10, W: 20, H: 20} | |||
| 33 | + | for _, geo := range []ports.Rect{{}, {X: 5, Y: 5, W: 30, H: 30}} { | |||
| 34 | + | ds := walk(rect, 40, 40, geo) | |||
| 35 | + | clip := image.Rect(10, 10, 30, 30) | |||
| 36 | + | for _, d := range ds { | |||
| 37 | + | got := image.Rect(int(d.pc.rect[0]), int(d.pc.rect[1]), int(d.pc.rect[2]), int(d.pc.rect[3])) | |||
| 38 | + | if !got.In(clip) { | |||
| 39 | + | t.Fatalf("geometry %+v: draw %v outside rect %v", geo, got, clip) | |||
| 40 | + | } | |||
| 41 | + | } | |||
| 42 | + | if d := ds[0].pc.rect; d != [4]int32{10, 10, 30, 30} { | |||
| 43 | + | t.Fatalf("geometry %+v: content = %v, want the whole rect", geo, d) | |||
| 44 | + | } | |||
| 45 | + | } | |||
| 46 | + | }) | |||
| 47 | + | ||||
| 48 | + | t.Run("rect larger than content shows only the content", func(t *testing.T) { | |||
| 49 | + | rect := ports.Rect{X: 10, Y: 10, W: 50, H: 40} | |||
| 50 | + | ds := walk(rect, 20, 16, ports.Rect{}) | |||
| 51 | + | if len(ds) != 1 || ds[0].pc.rect != [4]int32{10, 10, 30, 26} { | |||
| 52 | + | t.Fatalf("content = %+v, want 20x16 at the rect origin", ds) | |||
| 53 | + | } | |||
| 54 | + | // Geometry shifts the surface so its geometry origin sits at the rect origin. | |||
| 55 | + | ds = walk(rect, 24, 20, ports.Rect{X: 4, Y: 4, W: 20, H: 16}) | |||
| 56 | + | if len(ds) != 1 || ds[0].pc.rect != [4]int32{10, 10, 30, 26} { | |||
| 57 | + | t.Fatalf("content with geometry = %+v, want 20x16 at the rect origin", ds) | |||
| 58 | + | } | |||
| 59 | + | }) | |||
| 60 | + | } | |||