170 lines
4.0 KiB
Go
170 lines
4.0 KiB
Go
package world
|
|
|
|
import (
|
|
"image/color"
|
|
"testing"
|
|
|
|
"github.com/fogleman/gg"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func BenchmarkDrawPlanSinglePass_Lines_GG(b *testing.B) {
|
|
w := NewWorld(600, 600)
|
|
w.IndexOnViewportChange(1000, 700, 1.0)
|
|
|
|
// Make a lot of lines, including ones that likely wrap.
|
|
for i := 0; i < 4000; i++ {
|
|
x1 := float64(i % 600)
|
|
y1 := float64((i * 7) % 600)
|
|
x2 := float64((i*13 + 500) % 600) // shift to create various deltas
|
|
y2 := float64((i*17 + 300) % 600)
|
|
_, _ = w.AddLine(x1, y1, x2, y2)
|
|
}
|
|
w.Reindex()
|
|
|
|
params := RenderParams{
|
|
ViewportWidthPx: 1000,
|
|
ViewportHeightPx: 700,
|
|
MarginXPx: 250,
|
|
MarginYPx: 175,
|
|
CameraXWorldFp: 300 * SCALE,
|
|
CameraYWorldFp: 300 * SCALE,
|
|
CameraZoom: 1.0,
|
|
Options: &RenderOptions{
|
|
BackgroundColor: color.RGBA{A: 255},
|
|
},
|
|
}
|
|
|
|
plan, err := w.buildRenderPlanStageA(params)
|
|
if err != nil {
|
|
b.Fatalf("build plan: %v", err)
|
|
}
|
|
|
|
dc := gg.NewContext(params.CanvasWidthPx(), params.CanvasHeightPx())
|
|
drawer := &GGDrawer{DC: dc}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
w.drawPlanSinglePass(drawer, plan, true, drawPlanSinglePassClipEnabled, false)
|
|
}
|
|
}
|
|
|
|
func BenchmarkDrawPlanSinglePass_Lines_Fake(b *testing.B) {
|
|
w := NewWorld(600, 600)
|
|
w.IndexOnViewportChange(1000, 700, 1.0)
|
|
|
|
for i := 0; i < 4000; i++ {
|
|
x1 := float64(i % 600)
|
|
y1 := float64((i * 7) % 600)
|
|
x2 := float64((i*13 + 500) % 600)
|
|
y2 := float64((i*17 + 300) % 600)
|
|
_, _ = w.AddLine(x1, y1, x2, y2)
|
|
}
|
|
w.Reindex()
|
|
|
|
params := RenderParams{
|
|
ViewportWidthPx: 1000,
|
|
ViewportHeightPx: 700,
|
|
MarginXPx: 250,
|
|
MarginYPx: 175,
|
|
CameraXWorldFp: 300 * SCALE,
|
|
CameraYWorldFp: 300 * SCALE,
|
|
CameraZoom: 1.0,
|
|
Options: &RenderOptions{
|
|
BackgroundColor: color.RGBA{A: 255},
|
|
},
|
|
}
|
|
|
|
plan, err := w.buildRenderPlanStageA(params)
|
|
if err != nil {
|
|
b.Fatalf("build plan: %v", err)
|
|
}
|
|
|
|
drawer := &fakePrimitiveDrawer{}
|
|
|
|
b.ReportAllocs()
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
// Reset command log so it doesn't grow forever and dominate allocations.
|
|
drawer.Reset()
|
|
w.drawPlanSinglePass(drawer, plan, true, drawPlanSinglePassClipEnabled, false)
|
|
}
|
|
}
|
|
|
|
func TestRender_IncrementalShift_UsesOuterClip_NotPerTileClips(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
w := NewWorld(10, 10)
|
|
w.IndexOnViewportChange(100, 80, 1.0)
|
|
w.resetGrid(2 * SCALE)
|
|
|
|
_, _ = w.AddPoint(5, 5)
|
|
w.Reindex()
|
|
|
|
params := RenderParams{
|
|
ViewportWidthPx: 100,
|
|
ViewportHeightPx: 80,
|
|
MarginXPx: 25,
|
|
MarginYPx: 20,
|
|
CameraXWorldFp: 5 * SCALE,
|
|
CameraYWorldFp: 5 * SCALE,
|
|
CameraZoom: 1.0,
|
|
Options: &RenderOptions{
|
|
Incremental: &IncrementalPolicy{AllowShiftOnly: false},
|
|
},
|
|
}
|
|
|
|
// First render initializes state.
|
|
d1 := &fakePrimitiveDrawer{}
|
|
require.NoError(t, w.Render(d1, params))
|
|
|
|
// Small pan.
|
|
params2 := params
|
|
params2.CameraXWorldFp += 1 * SCALE
|
|
|
|
d2 := &fakePrimitiveDrawer{}
|
|
require.NoError(t, w.Render(d2, params2))
|
|
|
|
// Expect very few ClipRect calls (dirty strips count), not per tile.
|
|
clipCmds := d2.CommandsByName("ClipRect")
|
|
require.NotEmpty(t, clipCmds)
|
|
require.LessOrEqual(t, len(clipCmds), 4)
|
|
}
|
|
|
|
func TestRender_BatchesConsecutiveLinesByStyleID(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
w := NewWorld(10, 10)
|
|
w.IndexOnViewportChange(100, 80, 1.0)
|
|
|
|
// Two lines with default style, same priority.
|
|
_, _ = w.AddLine(1, 1, 8, 1)
|
|
_, _ = w.AddLine(1, 2, 8, 2)
|
|
w.Reindex()
|
|
|
|
params := RenderParams{
|
|
ViewportWidthPx: 100,
|
|
ViewportHeightPx: 80,
|
|
MarginXPx: 25,
|
|
MarginYPx: 20,
|
|
CameraXWorldFp: 5 * SCALE,
|
|
CameraYWorldFp: 5 * SCALE,
|
|
CameraZoom: 1.0,
|
|
}
|
|
|
|
d := &fakePrimitiveDrawer{}
|
|
require.NoError(t, w.Render(d, params))
|
|
|
|
// We expect at least two AddLine, but only 1 Stroke for that run in a tile.
|
|
adds := d.CommandsByName("AddLine")
|
|
strokes := d.CommandsByName("Stroke")
|
|
require.GreaterOrEqual(t, len(adds), 2)
|
|
require.GreaterOrEqual(t, len(strokes), 1)
|
|
|
|
// Stronger: within any consecutive group of AddLine commands, count strokes <= 1.
|
|
// (Keep it loose to avoid depending on tile partitioning.)
|
|
}
|