Merge da683098966021dd8addec7bf26cd3fba80db495 into 74503b06728886efee45120ebb821810347ca353
3 files · +24 -11
M internal/adapters/selection/backdrop_test.go +11 -2
| @@ -31,13 +31,22 @@ func TestWithBackdrops(t *testing.T) { | |||
| 31 | 31 | ||
| 32 | 32 | huge := ports.Frame{Width: maxBackdrop + 1, Height: 1, Stride: (maxBackdrop + 1) * 4, Format: ports.XRGB8888} | |
| 33 | 33 | _, err = New(ports.Screenshot, ports.VideoSettings{}, nil, false).WithBackdrops(map[uint32]ports.Frame{9: huge}) | |
| 34 | - | assert.ErrorContains(t, err, "at most 4096", "the caller freezes only outputs CanBackdrop accepts") | |
| 34 | + | assert.ErrorContains(t, err, "at most 8192", "the caller freezes only outputs CanBackdrop accepts") | |
| 35 | + | ||
| 36 | + | huge = ports.Frame{Width: 7680, Height: 4320, Stride: 7680 * 4, Format: ports.XRGB8888} | |
| 37 | + | _, err = New(ports.Screenshot, ports.VideoSettings{}, nil, false).WithBackdrops(map[uint32]ports.Frame{9: huge}) | |
| 38 | + | assert.ErrorContains(t, err, "67108864 bytes") | |
| 35 | 39 | } | |
| 36 | 40 | ||
| 37 | 41 | func TestCanBackdrop(t *testing.T) { | |
| 38 | 42 | assert.True(t, CanBackdrop(ports.Output{Width: 3840, Height: 2160})) | |
| 39 | 43 | assert.True(t, CanBackdrop(ports.Output{Width: 2160, Height: 4096})) | |
| 40 | - | assert.False(t, CanBackdrop(ports.Output{Width: 5120, Height: 2880})) | |
| 44 | + | assert.True(t, CanBackdrop(ports.Output{Width: 5120, Height: 2160})) | |
| 45 | + | assert.True(t, CanBackdrop(ports.Output{Width: 8192, Height: 2048}), "exact byte budget") | |
| 46 | + | assert.False(t, CanBackdrop(ports.Output{Width: 8192, Height: 2049})) | |
| 47 | + | assert.False(t, CanBackdrop(ports.Output{Width: 7680, Height: 4320})) | |
| 48 | + | assert.False(t, CanBackdrop(ports.Output{Width: 8193, Height: 1})) | |
| 49 | + | assert.False(t, CanBackdrop(ports.Output{Width: 1, Height: 8193})) | |
| 41 | 50 | assert.False(t, CanBackdrop(ports.Output{}), "an unknown mode stays live") | |
| 42 | 51 | } | |
| 43 | 52 | ||
| @@ -31,13 +31,22 @@ func TestWithBackdrops(t *testing.T) { | |||||
| 31 | 31 | ||||
| 32 | huge := ports.Frame{Width: maxBackdrop + 1, Height: 1, Stride: (maxBackdrop + 1) * 4, Format: ports.XRGB8888} | 32 | huge := ports.Frame{Width: maxBackdrop + 1, Height: 1, Stride: (maxBackdrop + 1) * 4, Format: ports.XRGB8888} | ||
| 33 | _, err = New(ports.Screenshot, ports.VideoSettings{}, nil, false).WithBackdrops(map[uint32]ports.Frame{9: huge}) | 33 | _, err = New(ports.Screenshot, ports.VideoSettings{}, nil, false).WithBackdrops(map[uint32]ports.Frame{9: huge}) | ||
| 34 | - | assert.ErrorContains(t, err, "at most 4096", "the caller freezes only outputs CanBackdrop accepts") | 34 | + | assert.ErrorContains(t, err, "at most 8192", "the caller freezes only outputs CanBackdrop accepts") |
| 35 | + | ||||
| 36 | + | huge = ports.Frame{Width: 7680, Height: 4320, Stride: 7680 * 4, Format: ports.XRGB8888} | |||
| 37 | + | _, err = New(ports.Screenshot, ports.VideoSettings{}, nil, false).WithBackdrops(map[uint32]ports.Frame{9: huge}) | |||
| 38 | + | assert.ErrorContains(t, err, "67108864 bytes") | |||
| 35 | } | 39 | } | ||
| 36 | 40 | ||||
| 37 | func TestCanBackdrop(t *testing.T) { | 41 | func TestCanBackdrop(t *testing.T) { | ||
| 38 | assert.True(t, CanBackdrop(ports.Output{Width: 3840, Height: 2160})) | 42 | assert.True(t, CanBackdrop(ports.Output{Width: 3840, Height: 2160})) | ||
| 39 | assert.True(t, CanBackdrop(ports.Output{Width: 2160, Height: 4096})) | 43 | assert.True(t, CanBackdrop(ports.Output{Width: 2160, Height: 4096})) | ||
| 40 | - | assert.False(t, CanBackdrop(ports.Output{Width: 5120, Height: 2880})) | 44 | + | assert.True(t, CanBackdrop(ports.Output{Width: 5120, Height: 2160})) |
| 45 | + | assert.True(t, CanBackdrop(ports.Output{Width: 8192, Height: 2048}), "exact byte budget") | |||
| 46 | + | assert.False(t, CanBackdrop(ports.Output{Width: 8192, Height: 2049})) | |||
| 47 | + | assert.False(t, CanBackdrop(ports.Output{Width: 7680, Height: 4320})) | |||
| 48 | + | assert.False(t, CanBackdrop(ports.Output{Width: 8193, Height: 1})) | |||
| 49 | + | assert.False(t, CanBackdrop(ports.Output{Width: 1, Height: 8193})) | |||
| 41 | assert.False(t, CanBackdrop(ports.Output{}), "an unknown mode stays live") | 50 | assert.False(t, CanBackdrop(ports.Output{}), "an unknown mode stays live") | ||
| 42 | } | 51 | } | ||
| 43 | 52 | ||||
M internal/adapters/selection/selector.go +11 -7
| @@ -87,13 +87,17 @@ func (s *Selector) WithCapabilities(c ports.Capabilities) *Selector { | |||
| 87 | 87 | return s | |
| 88 | 88 | } | |
| 89 | 89 | ||
| 90 | - | // maxBackdrop is the largest side NeferGUI accepts for one image. | |
| 91 | - | const maxBackdrop = 4096 | |
| 90 | + | // These bounds mirror NeferGUI's image dimension and cache byte limits. | |
| 91 | + | const ( | |
| 92 | + | maxBackdrop = 8192 | |
| 93 | + | maxBackdropBytes = 64 << 20 | |
| 94 | + | ) | |
| 92 | 95 | ||
| 93 | - | // CanBackdrop reports whether an output of this physical mode can show a | |
| 94 | - | // frozen frame. A larger output must stay live: freeze only the others. | |
| 96 | + | // CanBackdrop reports whether an output's physical mode fits NeferGUI's image | |
| 97 | + | // limits. Outputs exceeding either the side or byte limit stay live. | |
| 95 | 98 | func CanBackdrop(o ports.Output) bool { | |
| 96 | - | return o.Width > 0 && o.Height > 0 && max(o.Width, o.Height) <= maxBackdrop | |
| 99 | + | return o.Width > 0 && o.Height > 0 && max(o.Width, o.Height) <= maxBackdrop && | |
| 100 | + | o.Width <= maxBackdropBytes/ports.BytesPerPixel/o.Height | |
| 97 | 101 | } | |
| 98 | 102 | ||
| 99 | 103 | // WithBackdrops draws each output's frozen frame under its overlay instead of | |
| @@ -103,8 +107,8 @@ func CanBackdrop(o ports.Output) bool { | |||
| 103 | 107 | func (s *Selector) WithBackdrops(frames map[uint32]ports.Frame) (*Selector, error) { | |
| 104 | 108 | s.backdrops = make(map[uint32]image.Image, len(frames)) | |
| 105 | 109 | for id, f := range frames { | |
| 106 | - | if f.Width > maxBackdrop || f.Height > maxBackdrop { | |
| 107 | - | return s, fmt.Errorf("selection: frozen frame of output %d is %dx%d, at most %d per side", id, f.Width, f.Height, maxBackdrop) | |
| 110 | + | if !CanBackdrop(ports.Output{Width: f.Width, Height: f.Height}) { | |
| 111 | + | return s, fmt.Errorf("selection: frozen frame of output %d is %dx%d, at most %d per side and %d bytes", id, f.Width, f.Height, maxBackdrop, maxBackdropBytes) | |
| 108 | 112 | } | |
| 109 | 113 | s.backdrops[id] = backdropImage(f) | |
| 110 | 114 | } | |
| @@ -87,13 +87,17 @@ func (s *Selector) WithCapabilities(c ports.Capabilities) *Selector { | |||||
| 87 | return s | 87 | return s | ||
| 88 | } | 88 | } | ||
| 89 | 89 | ||||
| 90 | - | // maxBackdrop is the largest side NeferGUI accepts for one image. | 90 | + | // These bounds mirror NeferGUI's image dimension and cache byte limits. |
| 91 | - | const maxBackdrop = 4096 | 91 | + | const ( |
| 92 | + | maxBackdrop = 8192 | |||
| 93 | + | maxBackdropBytes = 64 << 20 | |||
| 94 | + | ) | |||
| 92 | 95 | ||||
| 93 | - | // CanBackdrop reports whether an output of this physical mode can show a | 96 | + | // CanBackdrop reports whether an output's physical mode fits NeferGUI's image |
| 94 | - | // frozen frame. A larger output must stay live: freeze only the others. | 97 | + | // limits. Outputs exceeding either the side or byte limit stay live. |
| 95 | func CanBackdrop(o ports.Output) bool { | 98 | func CanBackdrop(o ports.Output) bool { | ||
| 96 | - | return o.Width > 0 && o.Height > 0 && max(o.Width, o.Height) <= maxBackdrop | 99 | + | return o.Width > 0 && o.Height > 0 && max(o.Width, o.Height) <= maxBackdrop && |
| 100 | + | o.Width <= maxBackdropBytes/ports.BytesPerPixel/o.Height | |||
| 97 | } | 101 | } | ||
| 98 | 102 | ||||
| 99 | // WithBackdrops draws each output's frozen frame under its overlay instead of | 103 | // WithBackdrops draws each output's frozen frame under its overlay instead of | ||
| @@ -103,8 +107,8 @@ func CanBackdrop(o ports.Output) bool { | |||||
| 103 | func (s *Selector) WithBackdrops(frames map[uint32]ports.Frame) (*Selector, error) { | 107 | func (s *Selector) WithBackdrops(frames map[uint32]ports.Frame) (*Selector, error) { | ||
| 104 | s.backdrops = make(map[uint32]image.Image, len(frames)) | 108 | s.backdrops = make(map[uint32]image.Image, len(frames)) | ||
| 105 | for id, f := range frames { | 109 | for id, f := range frames { | ||
| 106 | - | if f.Width > maxBackdrop || f.Height > maxBackdrop { | 110 | + | if !CanBackdrop(ports.Output{Width: f.Width, Height: f.Height}) { |
| 107 | - | return s, fmt.Errorf("selection: frozen frame of output %d is %dx%d, at most %d per side", id, f.Width, f.Height, maxBackdrop) | 111 | + | return s, fmt.Errorf("selection: frozen frame of output %d is %dx%d, at most %d per side and %d bytes", id, f.Width, f.Height, maxBackdrop, maxBackdropBytes) |
| 108 | } | 112 | } | ||
| 109 | s.backdrops[id] = backdropImage(f) | 113 | s.backdrops[id] = backdropImage(f) | ||
| 110 | } | 114 | } | ||
M internal/app/freeze_test.go +2 -2
| @@ -32,6 +32,6 @@ func TestFreezes(t *testing.T) { | |||
| 32 | 32 | // Outputs too large for a backdrop are not frozen, so their screenshot is | |
| 33 | 33 | // live like their selector. | |
| 34 | 34 | func TestFrozenOutputs(t *testing.T) { | |
| 35 | - | outputs := []ports.Output{{ID: 7, Width: 3840, Height: 2160}, {ID: 8, Width: 5120, Height: 2880}, {ID: 9, Width: 1080, Height: 1920}, {ID: 10}} | |
| 36 | - | assert.Equal(t, []uint32{7, 9}, frozenOutputs(outputs)) | |
| 35 | + | outputs := []ports.Output{{ID: 7, Width: 3840, Height: 2160}, {ID: 8, Width: 5120, Height: 2160}, {ID: 9, Width: 1080, Height: 1920}, {ID: 10}, {ID: 11, Width: 7680, Height: 4320}} | |
| 36 | + | assert.Equal(t, []uint32{7, 8, 9}, frozenOutputs(outputs)) | |
| 37 | 37 | } | |
| @@ -32,6 +32,6 @@ func TestFreezes(t *testing.T) { | |||||
| 32 | // Outputs too large for a backdrop are not frozen, so their screenshot is | 32 | // Outputs too large for a backdrop are not frozen, so their screenshot is | ||
| 33 | // live like their selector. | 33 | // live like their selector. | ||
| 34 | func TestFrozenOutputs(t *testing.T) { | 34 | func TestFrozenOutputs(t *testing.T) { | ||
| 35 | - | outputs := []ports.Output{{ID: 7, Width: 3840, Height: 2160}, {ID: 8, Width: 5120, Height: 2880}, {ID: 9, Width: 1080, Height: 1920}, {ID: 10}} | 35 | + | outputs := []ports.Output{{ID: 7, Width: 3840, Height: 2160}, {ID: 8, Width: 5120, Height: 2160}, {ID: 9, Width: 1080, Height: 1920}, {ID: 10}, {ID: 11, Width: 7680, Height: 4320}} |
| 36 | - | assert.Equal(t, []uint32{7, 9}, frozenOutputs(outputs)) | 36 | + | assert.Equal(t, []uint32{7, 8, 9}, frozenOutputs(outputs)) |
| 37 | } | 37 | } | ||