Fix all possible data races

- Update to go 1.19 for new atomic types
- Use atomic for StitchedImage query counter
- Make sure that we don't copy any tile objects
This commit is contained in:
David Vogel 2022-08-12 11:39:55 +02:00
parent 65f7cb4e60
commit c9d2a37903
5 changed files with 12 additions and 10 deletions

View File

@ -28,8 +28,8 @@ type ImageTile struct {
scaleDivider int // Downscales the coordinates and images on the fly.
image image.Image // Either a rectangle or an RGBA image. The bounds of this image are determined by the filename.
imageMutex *sync.RWMutex //
image image.Image // Either a rectangle or an RGBA image. The bounds of this image are determined by the filename.
imageMutex *sync.RWMutex
invalidationChan chan struct{} // Used to send invalidation requests to the tile's goroutine.
timeoutChan chan struct{} // Used to determine whether the tile is still being accessed or not.

View File

@ -39,7 +39,8 @@ func LoadImageTiles(path string, scaleDivider int) (ImageTiles, error) {
// InvalidateAboveY invalidates all cached images that have no pixel at the given y coordinate or below.
func (it ImageTiles) InvalidateAboveY(y int) {
for _, tile := range it {
for i := range it {
tile := &it[i] // Need to copy a reference.
if tile.Bounds().Max.Y <= y {
tile.Invalidate()
}

View File

@ -54,10 +54,10 @@ func (sic *StitchedImageCache) Regenerate() *image.RGBA {
// List of tiles that intersect with the to be generated cache image.
intersectingTiles := []*ImageTile{}
for i, tile := range si.tiles {
for i := range si.tiles {
tile := &si.tiles[i]
if tile.Bounds().Overlaps(sic.rect) {
tilePtr := &si.tiles[i]
intersectingTiles = append(intersectingTiles, tilePtr)
intersectingTiles = append(intersectingTiles, tile)
}
}

View File

@ -9,6 +9,7 @@ import (
"fmt"
"image"
"image/color"
"sync/atomic"
)
// StitchedImageCacheGridSize defines the worker chunk size when the cache image is regenerated.
@ -37,7 +38,7 @@ type StitchedImage struct {
cacheRowYOffset int // Defines the pixel offset of the first cache row.
oldCacheRowIndex int
queryCounter int
queryCounter atomic.Int64
}
// NewStitchedImage creates a new image from several single image tiles.
@ -98,7 +99,7 @@ func (si *StitchedImage) At(x, y int) color.Color {
// At(Bounds().Max.X-1, Bounds().Max.Y-1) // returns the bottom-right pixel.
func (si *StitchedImage) RGBAAt(x, y int) color.RGBA {
// Assume that every pixel is only queried once.
si.queryCounter++
si.queryCounter.Add(1)
// Determine the cache rowIndex index.
rowIndex := (y + si.cacheRowYOffset) / si.cacheRowHeight
@ -142,5 +143,5 @@ func (si *StitchedImage) Opaque() bool {
func (si *StitchedImage) Progress() (value, max int) {
size := si.Bounds().Size()
return si.queryCounter, size.X * size.Y
return int(si.queryCounter.Load()), size.X * size.Y
}

2
go.mod
View File

@ -1,6 +1,6 @@
module github.com/Dadido3/noita-mapcap
go 1.18
go 1.19
require (
github.com/1lann/promptui v0.8.1-0.20220708222609-81fad96dd5e1