internal/atlas: ensure the given sizes must be power of 2

Updates #2519
This commit is contained in:
Hajime Hoshi 2023-01-02 19:07:30 +09:00
parent b4d8519f97
commit bb1021a549
4 changed files with 82 additions and 2 deletions

View File

@ -60,3 +60,5 @@ func (i *Image) EnsureIsolatedForTesting() {
} }
var FlushDeferredForTesting = flushDeferred var FlushDeferredForTesting = flushDeferred
var ToPowerOf2 = toPowerOf2

View File

@ -728,6 +728,17 @@ func EndFrame(graphicsDriver graphicsdriver.Graphics) error {
return nil return nil
} }
func toPowerOf2(x int) int {
if x <= 0 {
return 0
}
p2 := 1
for p2*2 <= x {
p2 *= 2
}
return p2
}
func BeginFrame(graphicsDriver graphicsdriver.Graphics) error { func BeginFrame(graphicsDriver graphicsdriver.Graphics) error {
defer backendsM.Unlock() defer backendsM.Unlock()
@ -746,7 +757,7 @@ func BeginFrame(graphicsDriver graphicsdriver.Graphics) error {
minSize = 1024 minSize = 1024
} }
if maxSize == 0 { if maxSize == 0 {
maxSize = restorable.MaxImageSize(graphicsDriver) maxSize = toPowerOf2(restorable.MaxImageSize(graphicsDriver))
} }
}) })
if err != nil { if err != nil {

View File

@ -736,4 +736,52 @@ func TestImageWritePixelsModify(t *testing.T) {
} }
} }
func TestPowerOf2(t *testing.T) {
testCases := []struct {
In int
Out int
}{
{
In: 1023,
Out: 512,
},
{
In: 1024,
Out: 1024,
},
{
In: 1025,
Out: 1024,
},
{
In: 10000,
Out: 8192,
},
{
In: 16384,
Out: 16384,
},
{
In: 1,
Out: 1,
},
{
In: 0,
Out: 0,
},
{
In: -1,
Out: 0,
},
}
for _, tc := range testCases {
got := atlas.ToPowerOf2(tc.In)
want := tc.Out
if got != want {
t.Errorf("packing.ToPowerOf2(%d): got: %d, want: %d", tc.In, got, want)
}
}
}
// TODO: Add tests to extend image on an atlas out of the main loop // TODO: Add tests to extend image on an atlas out of the main loop

View File

@ -31,7 +31,26 @@ type Page struct {
maxSize int maxSize int
} }
func isPositivePowerOf2(x int) bool {
if x <= 0 {
return false
}
for x > 1 {
if x/2*2 != x {
return false
}
x /= 2
}
return true
}
func NewPage(initSize int, maxSize int) *Page { func NewPage(initSize int, maxSize int) *Page {
if !isPositivePowerOf2(initSize) {
panic(fmt.Sprintf("packing: initSize must be a positive power of 2 but %d", initSize))
}
if !isPositivePowerOf2(maxSize) {
panic(fmt.Sprintf("packing: maxSize must be a positive power of 2 but %d", maxSize))
}
return &Page{ return &Page{
width: initSize, width: initSize,
height: initSize, height: initSize,
@ -256,7 +275,7 @@ func (p *Page) extendFor(width, height int) bool {
if newWidth > p.maxSize || newHeight > p.maxSize { if newWidth > p.maxSize || newHeight > p.maxSize {
if newWidth > p.maxSize && newHeight > p.maxSize { if newWidth > p.maxSize && newHeight > p.maxSize {
panic(fmt.Sprintf("packing: too big extension: (%d, %d)", newWidth, newHeight)) panic(fmt.Sprintf("packing: too big extension: allocating size: (%d, %d), current size: (%d, %d), new size: (%d, %d), (i, j): (%d, %d), max size: %d", width, height, p.width, p.height, newWidth, newHeight, i, j, p.maxSize))
} }
continue continue
} }