gioui.org@v0.6.1-0.20240506124620-7a9ce51988ce/gpu/headless/headless_test.go (about) 1 // SPDX-License-Identifier: Unlicense OR MIT 2 3 package headless 4 5 import ( 6 "image" 7 "image/color" 8 "testing" 9 10 "gioui.org/internal/f32color" 11 "gioui.org/op" 12 "gioui.org/op/clip" 13 "gioui.org/op/paint" 14 ) 15 16 func TestHeadless(t *testing.T) { 17 w, release := newTestWindow(t) 18 defer release() 19 20 sz := w.size 21 col := color.NRGBA{A: 0xff, R: 0xca, G: 0xfe} 22 var ops op.Ops 23 paint.ColorOp{Color: col}.Add(&ops) 24 // Paint only part of the screen to avoid the glClear optimization. 25 paint.FillShape(&ops, col, clip.Rect(image.Rect(0, 0, sz.X-100, sz.Y-100)).Op()) 26 if err := w.Frame(&ops); err != nil { 27 t.Fatal(err) 28 } 29 30 img := image.NewRGBA(image.Rectangle{Max: w.Size()}) 31 err := w.Screenshot(img) 32 if err != nil { 33 t.Fatal(err) 34 } 35 if isz := img.Bounds().Size(); isz != sz { 36 t.Errorf("got %v screenshot, expected %v", isz, sz) 37 } 38 if got := img.RGBAAt(0, 0); got != f32color.NRGBAToRGBA(col) { 39 t.Errorf("got color %v, expected %v", got, f32color.NRGBAToRGBA(col)) 40 } 41 } 42 43 func TestClipping(t *testing.T) { 44 w, release := newTestWindow(t) 45 defer release() 46 47 col := color.NRGBA{A: 0xff, R: 0xca, G: 0xfe} 48 col2 := color.NRGBA{A: 0xff, R: 0x00, G: 0xfe} 49 var ops op.Ops 50 paint.ColorOp{Color: col}.Add(&ops) 51 clip.RRect{ 52 Rect: image.Rect(50, 50, 250, 250), 53 SE: 75, 54 }.Push(&ops) 55 paint.PaintOp{}.Add(&ops) 56 paint.ColorOp{Color: col2}.Add(&ops) 57 clip.RRect{ 58 Rect: image.Rect(100, 100, 350, 350), 59 NW: 75, 60 }.Push(&ops) 61 paint.PaintOp{}.Add(&ops) 62 if err := w.Frame(&ops); err != nil { 63 t.Fatal(err) 64 } 65 66 img := image.NewRGBA(image.Rectangle{Max: w.Size()}) 67 err := w.Screenshot(img) 68 if err != nil { 69 t.Fatal(err) 70 } 71 if *dumpImages { 72 if err := saveImage("clip.png", img); err != nil { 73 t.Fatal(err) 74 } 75 } 76 var bg color.NRGBA 77 tests := []struct { 78 x, y int 79 color color.NRGBA 80 }{ 81 {120, 120, col}, 82 {130, 130, col2}, 83 {210, 210, col2}, 84 {230, 230, bg}, 85 } 86 for _, test := range tests { 87 if got := img.RGBAAt(test.x, test.y); got != f32color.NRGBAToRGBA(test.color) { 88 t.Errorf("(%d,%d): got color %v, expected %v", test.x, test.y, got, f32color.NRGBAToRGBA(test.color)) 89 } 90 } 91 } 92 93 func TestDepth(t *testing.T) { 94 w, release := newTestWindow(t) 95 defer release() 96 var ops op.Ops 97 98 blue := color.NRGBA{B: 0xFF, A: 0xFF} 99 paint.FillShape(&ops, blue, clip.Rect(image.Rect(0, 0, 50, 100)).Op()) 100 red := color.NRGBA{R: 0xFF, A: 0xFF} 101 paint.FillShape(&ops, red, clip.Rect(image.Rect(0, 0, 100, 50)).Op()) 102 if err := w.Frame(&ops); err != nil { 103 t.Fatal(err) 104 } 105 106 img := image.NewRGBA(image.Rectangle{Max: w.Size()}) 107 err := w.Screenshot(img) 108 if err != nil { 109 t.Fatal(err) 110 } 111 if *dumpImages { 112 if err := saveImage("depth.png", img); err != nil { 113 t.Fatal(err) 114 } 115 } 116 tests := []struct { 117 x, y int 118 color color.NRGBA 119 }{ 120 {25, 25, red}, 121 {75, 25, red}, 122 {25, 75, blue}, 123 } 124 for _, test := range tests { 125 if got := img.RGBAAt(test.x, test.y); got != f32color.NRGBAToRGBA(test.color) { 126 t.Errorf("(%d,%d): got color %v, expected %v", test.x, test.y, got, f32color.NRGBAToRGBA(test.color)) 127 } 128 } 129 } 130 131 func TestNoOps(t *testing.T) { 132 w, release := newTestWindow(t) 133 defer release() 134 if err := w.Frame(nil); err != nil { 135 t.Error(err) 136 } 137 } 138 139 func newTestWindow(t *testing.T) (*Window, func()) { 140 t.Helper() 141 sz := image.Point{X: 800, Y: 600} 142 w, err := NewWindow(sz.X, sz.Y) 143 if err != nil { 144 t.Skipf("headless windows not supported: %v", err) 145 } 146 return w, func() { 147 w.Release() 148 } 149 }