diff --git a/gpu/pack.go b/gpu/pack.go index 3f8c9250..cb0ca023 100644 --- a/gpu/pack.go +++ b/gpu/pack.go @@ -46,20 +46,24 @@ func (p *packer) newPage() { } func (p *packer) tryAdd(s image.Point) (placement, bool) { + if len(p.spaces) == 0 || len(p.sizes) == 0 { + return placement{}, false + } + var ( - bestIdx = -1 - bestSpace image.Rectangle - bestSize = p.maxDims + bestIdx *image.Rectangle + bestSize = p.maxDims + lastSize = p.sizes[len(p.sizes)-1] ) // Go backwards to prioritize smaller spaces. - for i, space := range p.spaces { + for i := range p.spaces { + space := &p.spaces[i] rightSpace := space.Dx() - s.X bottomSpace := space.Dy() - s.Y if rightSpace < 0 || bottomSpace < 0 { continue } - idx := len(p.sizes) - 1 - size := p.sizes[idx] + size := lastSize if x := space.Min.X + s.X; x > size.X { if x > p.maxDims.X { continue @@ -73,16 +77,16 @@ func (p *packer) tryAdd(s image.Point) (placement, bool) { size.Y = y } if size.X*size.Y < bestSize.X*bestSize.Y { - bestIdx = i - bestSpace = space + bestIdx = space bestSize = size } } - if bestIdx == -1 { + if bestIdx == nil { return placement{}, false } // Remove space. - p.spaces[bestIdx] = p.spaces[len(p.spaces)-1] + bestSpace := *bestIdx + *bestIdx = p.spaces[len(p.spaces)-1] p.spaces = p.spaces[:len(p.spaces)-1] // Put s in the top left corner and add the (at most) // two smaller spaces. diff --git a/gpu/pack_test.go b/gpu/pack_test.go new file mode 100644 index 00000000..98db6eb5 --- /dev/null +++ b/gpu/pack_test.go @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +package gpu + +import ( + "image" + "testing" +) + +func BenchmarkPacker(b *testing.B) { + var p packer + p.maxDims = image.Point{X: 4096, Y: 4096} + for i := 0; i < b.N; i++ { + p.clear() + p.newPage() + for k := 0; k < 500; k++ { + _, ok := p.tryAdd(xy(k)) + if !ok { + b.Fatal("add failed", i, k, xy(k)) + } + } + } +} + +func xy(v int) image.Point { + return image.Point{ + X: ((v / 16) % 16) + 8, + Y: (v % 16) + 8, + } +}