~eliasnaur/gio

827e20d84d0ce049c83445a1c8805d001c24b65a — Egon Elbre 4 months ago 8bc6737
gpu: optimize pack.tryAdd

name       old time/op  new time/op  delta
Packer-32   559µs ± 2%   295µs ± 1%  -47.18%  (p=0.008 n=5+5)

Signed-off-by: Egon Elbre <egonelbre@gmail.com>
2 files changed, 44 insertions(+), 10 deletions(-)

M gpu/pack.go
A gpu/pack_test.go
M gpu/pack.go => gpu/pack.go +14 -10
@@ 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.

A gpu/pack_test.go => gpu/pack_test.go +30 -0
@@ 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,
	}
}