92 lines
2.3 KiB
Go
92 lines
2.3 KiB
Go
|
package uix
|
||
|
|
||
|
import (
|
||
|
"runtime"
|
||
|
"sync"
|
||
|
|
||
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||
|
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||
|
"git.kirsle.net/go/render"
|
||
|
)
|
||
|
|
||
|
// Memory optimization features of the Canvas.
|
||
|
|
||
|
/*
|
||
|
LoadUnloadChunks optimizes memory for (level) canvases by warming up chunk images
|
||
|
that fall within the LoadingViewport and freeing chunks that are outside of it.
|
||
|
*/
|
||
|
func (w *Canvas) LoadUnloadChunks() {
|
||
|
if w.level == nil || shmem.Tick%balance.CanvasLoadUnloadModuloTicks != 0 || !balance.Feature.LoadUnloadChunk {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
vp = w.LoadingViewport()
|
||
|
chunks = make(chan render.Point)
|
||
|
chunksInside = map[render.Point]interface{}{}
|
||
|
chunksTeardown = []*level.Chunk{}
|
||
|
cores = runtime.NumCPU()
|
||
|
wg sync.WaitGroup
|
||
|
|
||
|
// Collect metrics for the debug overlay.
|
||
|
resultInside int
|
||
|
resultOutside int
|
||
|
)
|
||
|
|
||
|
// Collect the chunks that are inside the viewport so we know which ones are not.
|
||
|
for chunk := range w.level.Chunker.IterViewportChunks(vp) {
|
||
|
chunksInside[chunk] = nil
|
||
|
}
|
||
|
|
||
|
// Spawn background goroutines to process the chunks quickly.
|
||
|
for i := 0; i < cores; i++ {
|
||
|
wg.Add(1)
|
||
|
go func(i int) {
|
||
|
for coord := range chunks {
|
||
|
if chunk, ok := w.level.Chunker.GetChunk(coord); ok {
|
||
|
chunk := chunk
|
||
|
|
||
|
if _, ok := chunksInside[coord]; ok {
|
||
|
// Preload its bitmap image.
|
||
|
_ = chunk.CachedBitmap(render.Invisible)
|
||
|
resultInside++
|
||
|
} else {
|
||
|
// Unload its bitmap and texture.
|
||
|
chunksTeardown = append(chunksTeardown, chunk)
|
||
|
resultOutside++
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
wg.Done()
|
||
|
}(i)
|
||
|
}
|
||
|
|
||
|
for chunk := range w.level.Chunker.IterChunks() {
|
||
|
chunks <- chunk
|
||
|
}
|
||
|
close(chunks)
|
||
|
wg.Wait()
|
||
|
|
||
|
// Tear down the SDL2 textures of chunks to free.
|
||
|
for i, chunk := range chunksTeardown {
|
||
|
if chunk == nil {
|
||
|
log.Error("LoadUnloadChunks: chunksTeardown#%d was nil??", i)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
chunk.Teardown()
|
||
|
}
|
||
|
|
||
|
// Export the metrics for the debug overlay.
|
||
|
w.loadUnloadInside = resultInside
|
||
|
w.loadUnloadOutside = resultOutside
|
||
|
}
|
||
|
|
||
|
// LoadUnloadMetrics returns the canvas's stored metrics from the LoadUnloadChunks
|
||
|
// function, for the debug overlay.
|
||
|
func (w *Canvas) LoadUnloadMetrics() (inside, outside int) {
|
||
|
return w.loadUnloadInside, w.loadUnloadOutside
|
||
|
}
|