Prepare v0.12.1 for release
This commit is contained in:
parent
c5353df211
commit
9cdc7260bb
32
Changes.md
32
Changes.md
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
30
pkg/fps.go
30
pkg/fps.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user