internal/atlas: save and restore only necessary part

Updates #3334
This commit is contained in:
Hajime Hoshi
2026-01-09 21:30:35 +09:00
parent ed20332919
commit f8ba9bfca5
2 changed files with 45 additions and 16 deletions
+22 -15
View File
@@ -127,6 +127,7 @@ type restoreInfo struct {
valid bool
screen bool
pixels *graphics.ManagedBytes
region image.Rectangle
}
func (b *backend) tryAlloc(width, height int) (*packing.Node, bool) {
@@ -851,25 +852,30 @@ func EndFrame(graphicsDriver graphicsdriver.Graphics) error {
continue
}
var pixels *graphics.ManagedBytes
if !b.screen {
var err error
pixels = graphics.NewManagedBytes(4*b.width*b.height, func(bytes []byte) {
args := []graphicsdriver.PixelsArgs{
{
Pixels: bytes,
Region: image.Rect(0, 0, b.width, b.height),
},
var region image.Rectangle
if !b.screen && b.page != nil {
region = b.page.AllocatedRegion()
if !region.Empty() {
var err error
pixels = graphics.NewManagedBytes(4*region.Dx()*region.Dy(), func(bytes []byte) {
args := []graphicsdriver.PixelsArgs{
{
Pixels: bytes,
Region: region,
},
}
err = b.backendImage.ReadPixels(graphicsDriver, args)
})
if err != nil {
return err
}
err = b.backendImage.ReadPixels(graphicsDriver, args)
})
if err != nil {
return err
}
}
b.restoreInfo = restoreInfo{
valid: true,
screen: b.screen,
pixels: pixels,
region: region,
}
}
default:
@@ -970,10 +976,11 @@ func BeginFrame(graphicsDriver graphicsdriver.Graphics) error {
continue
}
b.backendImage = graphicscommand.NewImage(b.width, b.height, b.restoreInfo.screen, "")
if b.restoreInfo.pixels == nil {
if b.restoreInfo.region != image.Rect(0, 0, b.width, b.height) {
b.clear(image.Rect(0, 0, b.width, b.height))
} else {
b.backendImage.WritePixels(b.restoreInfo.pixels, image.Rect(0, 0, b.width, b.height))
}
if b.restoreInfo.pixels != nil {
b.backendImage.WritePixels(b.restoreInfo.pixels, b.restoreInfo.region)
}
}
needToRestoreGPUResources.Store(false)
+23 -1
View File
@@ -188,11 +188,15 @@ func (p *Page) Free(node *Node) {
}
var (
skipAll = errors.New("skip all")
skipAll = errors.New("skip all")
skipChildren = errors.New("skip children")
)
func walk(n *Node, f func(n *Node) error) error {
if err := f(n); err != nil {
if errors.Is(err, skipChildren) {
return nil
}
return err
}
if n.child0 != nil {
@@ -350,3 +354,21 @@ func (p *Page) extend(newWidth int, newHeight int) func() {
return rollback
}
func (p *Page) AllocatedRegion() image.Rectangle {
var r image.Rectangle
if p.root == nil {
return r
}
_ = walk(p.root, func(n *Node) error {
if n.region.In(r) {
return skipChildren
}
if n.used {
r = r.Union(n.region)
return skipChildren
}
return nil
})
return r
}