internal/atlas: bug fix: copy the image slice before iterating it

Closes #2729
This commit is contained in:
Hajime Hoshi 2023-08-23 14:39:21 +09:00
parent 269fc2bd4d
commit 7ea3cd4738
2 changed files with 52 additions and 1 deletions

View File

@ -826,4 +826,41 @@ func TestDestinationCountOverflow(t *testing.T) {
}
}
// Issue #2729
func TestIteratingImagesToPutOnSourceBackend(t *testing.T) {
const w, h = 16, 16
src := atlas.NewImage(w, h, atlas.ImageTypeRegular)
defer src.MarkDisposed()
srcs := make([]*atlas.Image, 10)
for i := range srcs {
srcs[i] = atlas.NewImage(w, h, atlas.ImageTypeRegular)
defer srcs[i].MarkDisposed()
}
dst := atlas.NewImage(w, h, atlas.ImageTypeRegular)
defer dst.MarkDisposed()
// Use srcs as detinations once.
vs := quadVertices(w, h, 0, 0, 1)
is := graphics.QuadIndices()
dr := graphicsdriver.Region{
X: 0,
Y: 0,
Width: w,
Height: h,
}
for _, img := range srcs {
img.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false)
}
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
// Use srcs as sources. This will register an image to imagesToPutOnSourceBackend.
// Check iterating the registered image works correctly.
for i := 0; i < 100; i++ {
for _, src := range srcs {
dst.DrawTriangles([graphics.ShaderImageCount]*atlas.Image{src}, vs, is, graphicsdriver.BlendCopy, dr, graphicsdriver.Region{}, [graphics.ShaderImageCount - 1][2]float32{}, atlas.NearestFilterShader, nil, false)
}
atlas.PutImagesOnSourceBackendForTesting(ui.GraphicsDriverForTesting())
}
}
// TODO: Add tests to extend image on an atlas out of the main loop

View File

@ -19,9 +19,14 @@ package atlas
// If the number of items is big, a map might be better than a slice.
type smallImageSet struct {
s []*Image
tmp []*Image
}
func (s *smallImageSet) add(image *Image) {
if image == nil {
panic("atlas: nil image cannot be added")
}
for _, img := range s.s {
if img == image {
return
@ -42,9 +47,18 @@ func (s *smallImageSet) remove(image *Image) {
}
func (s *smallImageSet) forEach(f func(*Image)) {
for _, img := range s.s {
// Copy images to a temporary buffer since f might modify the original slice s.s (#2729).
s.tmp = append(s.tmp, s.s...)
for _, img := range s.tmp {
f(img)
}
// Clear the temporary buffer.
for i := range s.tmp {
s.tmp[i] = nil
}
s.tmp = s.tmp[:0]
}
func (s *smallImageSet) clear() {