internal/debug: bug fix: add SwitchLogger to dump logs for each frame correctly

Closes #2731
This commit is contained in:
Hajime Hoshi 2023-08-26 00:50:45 +09:00
parent b29fc5672c
commit 4116fd3eb4
4 changed files with 89 additions and 5 deletions

20
internal/debug/debug.go Normal file
View File

@ -0,0 +1,20 @@
// Copyright 2023 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package debug
type Logger interface {
Logf(format string, args ...any)
Flush()
}

View File

@ -18,10 +18,58 @@ package debug
import (
"fmt"
"sync"
)
const IsDebug = true
var theLogger = &logger{}
var flushM sync.Mutex
// Logf calls the current global logger's Logf.
// Logf buffers the arguments and doesn't dump the log immediately.
// You can dump logs by calling SwitchLogger and Flush.
//
// Logf is not concurrent safe.
func Logf(format string, args ...any) {
fmt.Printf(format, args...)
theLogger.Logf(format, args...)
}
// SwitchLogger sets a new logger as the current logger and returns the original global logger.
// The new global logger and the returned logger have separate statuses, so you can use them for different goroutines.
//
// SwitchLogger and a returned Logger are not concurrent safe.
func SwitchLogger() Logger {
current := theLogger
theLogger = &logger{}
return current
}
type logger struct {
items []logItem
}
type logItem struct {
format string
args []any
}
func (l *logger) Logf(format string, args ...any) {
l.items = append(l.items, logItem{
format: format,
args: args,
})
}
func (l *logger) Flush() {
// Flushing is protected by a mutex not to mix another logger's logs.
flushM.Lock()
defer flushM.Unlock()
for i, item := range l.items {
fmt.Printf(item.format, item.args...)
l.items[i] = logItem{}
}
l.items = l.items[:0]
}

View File

@ -20,3 +20,15 @@ const IsDebug = false
func Logf(format string, args ...any) {
}
func SwitchLogger() Logger {
return dummyLogger{}
}
type dummyLogger struct{}
func (dummyLogger) Logf(format string, args ...any) {
}
func (dummyLogger) Flush() {
}

View File

@ -197,9 +197,13 @@ func (q *commandQueue) Flush(graphicsDriver graphicsdriver.Graphics, endFrame bo
}
}
logger := debug.SwitchLogger()
var flushErr error
runOnRenderThread(func() {
if err := q.flush(graphicsDriver, endFrame); err != nil {
defer logger.Flush()
if err := q.flush(graphicsDriver, endFrame, logger); err != nil {
if sync {
return
}
@ -220,7 +224,7 @@ func (q *commandQueue) Flush(graphicsDriver graphicsdriver.Graphics, endFrame bo
}
// flush must be called the main thread.
func (q *commandQueue) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool) (err error) {
func (q *commandQueue) flush(graphicsDriver graphicsdriver.Graphics, endFrame bool, logger debug.Logger) (err error) {
// If endFrame is true, Begin/End should be called to ensure the framebuffer is swapped.
if len(q.commands) == 0 && !endFrame {
return nil
@ -228,7 +232,7 @@ func (q *commandQueue) flush(graphicsDriver graphicsdriver.Graphics, endFrame bo
es := q.indices
vs := q.vertices
debug.Logf("Graphics commands:\n")
logger.Logf("Graphics commands:\n")
if err := graphicsDriver.Begin(); err != nil {
return err
@ -287,7 +291,7 @@ func (q *commandQueue) flush(graphicsDriver graphicsdriver.Graphics, endFrame bo
if err := c.Exec(graphicsDriver, indexOffset); err != nil {
return err
}
debug.Logf(" %s\n", c)
logger.Logf(" %s\n", c)
// TODO: indexOffset should be reset if the command type is different
// from the previous one. This fix is needed when another drawing command is
// introduced than drawTrianglesCommand.