Prepare v0.12.1 for release

This commit is contained in:
Noah 2022-04-16 17:50:40 -07:00
parent c5353df211
commit 9cdc7260bb
6 changed files with 101 additions and 2 deletions

View File

@ -1,5 +1,37 @@
# Changes # Changes
## v0.12.1 (April 16 2022)
This update focuses on memory and performance improvements for the game.
Some larger levels such as "Azulian Tag - Forest" could run out of
memory on 32-bit systems. To improve on memory usage, the game more
aggressively frees SDL2 textures when no longer needed and it doesn't
try to keep the _whole_ level's chunks ready in memory (as rendered
images) -- only the chunks near the window viewport are loaded, and
chunks that leave the viewport are freed to reclaim memory. Improvements
are still a work in progress.
New fields are added to the F3 debug overlay to peek at its performance:
* "Textures:" shows the count of SDL2 textures currently loaded
in memory. Some textures, such as toolbar buttons and the
loadscreen wallpaper, lazy load and persist in memory. Most level
and doodad textures should free when the level exits.
* "Sys/Heap:" shows current memory utilization in terms of MiB taken
from the OS and MiB of active heap memory, respectively.
* "Threads:" counts the number of goroutines currently active. In
gameplay, each actor monitors its PubSub queue on a goroutine and
these should clean up when the level exits.
* "Chunks:" shows the count of level chunks inside and outside the
loading viewport.
Some other changes and bug fixes in this release include:
* Fixed the bug where the player was able to "climb" vertical walls to
their right.
* When entering a cheat code that changes the default player character
during gameplay, you immediately become that character.
## v0.12.0 (March 27 2022) ## v0.12.0 (March 27 2022)
This update adds several new features to gameplay and the Level Editor. This update adds several new features to gameplay and the Level Editor.

View File

@ -7,6 +7,7 @@ import (
"os" "os"
"regexp" "regexp"
"runtime" "runtime"
"runtime/pprof"
"sort" "sort"
"strconv" "strconv"
"time" "time"
@ -88,6 +89,10 @@ func main() {
Aliases: []string{"d"}, Aliases: []string{"d"},
Usage: "enable debug level logging", Usage: "enable debug level logging",
}, },
&cli.StringFlag{
Name: "pprof",
Usage: "record pprof metrics to a filename",
},
&cli.StringFlag{ &cli.StringFlag{
Name: "chdir", Name: "chdir",
Usage: "working directory for the game's runtime package", Usage: "working directory for the game's runtime package",
@ -125,6 +130,23 @@ func main() {
} }
} }
// Recording pprof stats?
if cpufile := c.String("pprof"); cpufile != "" {
log.Info("Saving CPU profiling data to %s", cpufile)
fh, err := os.Create(cpufile)
if err != nil {
log.Error("--pprof: can't create file: %s", err)
return err
}
defer fh.Close()
if err := pprof.StartCPUProfile(fh); err != nil {
log.Error("pprof: %s", err)
return err
}
defer pprof.StopCPUProfile()
}
var filename string var filename string
if c.NArg() > 0 { if c.NArg() > 0 {
filename = c.Args().Get(0) filename = c.Args().Get(0)

View File

@ -17,7 +17,7 @@ var (
// Debug overlay (FPS etc.) settings. // Debug overlay (FPS etc.) settings.
DebugFontFilename = SansBoldFont DebugFontFilename = SansBoldFont
DebugFontSize = 16 DebugFontSize = 14
DebugLabelColor = render.MustHexColor("#FF9900") DebugLabelColor = render.MustHexColor("#FF9900")
DebugValueColor = render.MustHexColor("#00CCFF") DebugValueColor = render.MustHexColor("#00CCFF")
DebugStrokeDarken = 80 DebugStrokeDarken = 80

View File

@ -2,6 +2,7 @@ package doodle
import ( import (
"fmt" "fmt"
"runtime"
"strings" "strings"
"git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/apps/doodle/pkg/balance"
@ -38,6 +39,11 @@ var (
fpsInterval uint32 = 1000 fpsInterval uint32 = 1000
fpsDoNotCap bool // remove the FPS delay cap in main loop fpsDoNotCap bool // remove the FPS delay cap in main loop
// Memory usage metrics.
memHeap uint64 // Current heap memory size (shrinks on GC)
memSys uint64 // Current total memory usage
numGoroutine int
// Custom labels for individual Scenes to add debug info. // Custom labels for individual Scenes to add debug info.
customDebugLabels []debugLabel customDebugLabels []debugLabel
) )
@ -72,13 +78,17 @@ func (d *Doodle) DrawDebugOverlay() {
"FPS:", "FPS:",
"Scene:", "Scene:",
"Mouse:", "Mouse:",
"Tex:", "Textures:",
"Sys/Heap:",
"Threads:",
} }
values = []string{ values = []string{
fmt.Sprintf("%d %s", fpsCurrent, framesSkipped), fmt.Sprintf("%d %s", fpsCurrent, framesSkipped),
d.Scene.Name(), d.Scene.Name(),
fmt.Sprintf("%d,%d", d.event.CursorX, d.event.CursorY), fmt.Sprintf("%d,%d", d.event.CursorX, d.event.CursorY),
texCount, texCount,
fmt.Sprintf("%d MiB / %d MiB", memSys, memHeap),
fmt.Sprintf("%d", numGoroutine),
} }
) )
@ -202,4 +212,22 @@ func (d *Doodle) TrackFPS(skipped uint32) {
// FPS in the title bar. // FPS in the title bar.
d.Engine.SetTitle(fmt.Sprintf("%s (%d FPS)", d.Title(), fpsCurrent)) d.Engine.SetTitle(fmt.Sprintf("%s (%d FPS)", d.Title(), fpsCurrent))
// Refresh memory usage.
GetMemUsage()
}
// GetMemUsage collects statistics on memory utilization.
func GetMemUsage() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
memHeap = bToMb(m.Alloc)
memSys = bToMb(m.Sys)
numGoroutine = runtime.NumGoroutine()
}
func bToMb(b uint64) uint64 {
return b / 1024 / 1024
} }

View File

@ -57,6 +57,9 @@ type MainScene struct {
// happens one time, and does not re-adapt when the window is made // happens one time, and does not re-adapt when the window is made
// tall enough again. // tall enough again.
landscapeMode bool landscapeMode bool
// Debug F3 overlay vars
debLoadingViewport *string
} }
/* /*
@ -88,6 +91,11 @@ func (s *MainScene) Name() string {
// Setup the scene. // Setup the scene.
func (s *MainScene) Setup(d *Doodle) error { func (s *MainScene) Setup(d *Doodle) error {
s.debLoadingViewport = new(string)
customDebugLabels = []debugLabel{
{"Chunks:", s.debLoadingViewport},
}
s.Supervisor = ui.NewSupervisor() s.Supervisor = ui.NewSupervisor()
if err := s.SetupDemoLevel(d); err != nil { if err := s.SetupDemoLevel(d); err != nil {
@ -405,6 +413,9 @@ func (s *MainScene) SetupDemoLevel(d *Doodle) error {
func (s *MainScene) Loop(d *Doodle, ev *event.State) error { func (s *MainScene) Loop(d *Doodle, ev *event.State) error {
s.Supervisor.Loop(ev) s.Supervisor.Loop(ev)
inside, outside := s.canvas.LoadUnloadMetrics()
*s.debLoadingViewport = fmt.Sprintf("%d in %d out", inside, outside)
if err := s.scripting.Loop(); err != nil { if err := s.scripting.Loop(); err != nil {
log.Error("MainScene.Loop: scripting.Loop: %s", err) log.Error("MainScene.Loop: scripting.Loop: %s", err)
} }

View File

@ -63,6 +63,12 @@ func ShowWithProgress() {
visible = true visible = true
withProgress = true withProgress = true
subtitle = "" subtitle = ""
// TODO: hide the progress trough. With the new LoadUnloadChunks,
// the progress bar does nothing - all the loading time is spent
// reading the level from disk and then it starts.
withProgress = false
SetProgress(0) SetProgress(0)
} }