extends SceneTree
## PROBE (not a gate) — the Parallax surface-detail tier on a REAL level: map_flat's empty
## DCLevel + one Bricks105 brush wall made through the journal (as the player would),
## LevelPackMaterial switched Normal maps <-> Parallax with set_detail (NOT the Settings
## row, so the player's saved settings are untouched). Per tier and pose: the viewport's
## measured GPU time (median of interleaved rounds, 2x supersampled) + a screenshot.
## DISPLAY=:0 <godot> --path . --rendering-driver vulkan --script res://scenes/test/_probe_pom_level.gd -- --out DIR
const ProbeWindow := preload("res://scenes/test/probe_window.gd")
const TIERS := ["normal_maps", "parallax"]
# The wall: x -3..3, y 0..3, z -1..-0.5; its +Z face is the one we look at.
const POSES := [
["grazing", Vector3(-2.6, 1.4, 0.15), Vector3(1.5, 1.2, -0.5)],
["close", Vector3(0.3, 1.5, 0.9), Vector3(0.0, 1.4, -0.5)],
["far", Vector3(0.0, 1.5, 16.0), Vector3(0.0, 1.5, -0.5)],
]
const WARM := 30
const MEASURE := 90
const ROUNDS := 3
const SUPERSAMPLE := 2.0
const SIZE := Vector2i(1600, 900)
var _out := "/tmp/pom_level"
var _tex := "ambientcg/Bricks105" # --tex <pack/name> to render another material
var _ws := ""
var _next_i3 := 0
var _ready_frames := 0
var _setup_frames := 0
var _map: Node = null
var _cam: Camera3D
var _vp: RID
var _case := 0
var _round := 0
var _f := 0
var _acc := 0.0
var _samples := {}
func _box(lo: Vector3, hi: Vector3) -> Array:
return [1, 0, 0, hi.x, -1, 0, 0, -lo.x, 0, 1, 0, hi.y, 0, -1, 0, -lo.y, 0, 0, 1, hi.z, 0, 0, -1, -lo.z]
func _initialize() -> void:
var args := OS.get_cmdline_user_args()
var i := args.find("--out")
if i >= 0 and i + 1 < args.size():
_out = args[i + 1]
var ti := args.find("--tex")
if ti >= 0 and ti + 1 < args.size():
_tex = args[ti + 1]
DirAccess.make_dir_recursive_absolute(_out)
DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
DisplayServer.window_set_size(SIZE)
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
_ws = ProbeWindow.free_workspace()
print("PROBE i3 workspace: %s" % (_ws if _ws != "" else "(none)"))
_map = (load("res://scenes/maps/map_flat.tscn") as PackedScene).instantiate()
root.add_child(_map)
func _process(_d: float) -> bool:
if _ready_frames < 20:
if _ws != "" and _ready_frames == 0 and Time.get_ticks_msec() >= _next_i3:
_next_i3 = Time.get_ticks_msec() + 1000
ProbeWindow.move_to(_ws, SIZE)
if ProbeWindow.drawing(root):
_ready_frames += 1
elif Time.get_ticks_msec() > 30000:
print("PROBE FAIL window never drew (size %s)" % root.size)
quit(1)
return true
return false
_setup_frames += 1
if _setup_frames == 10:
var persist: Node = _map.get("_persist")
var ft: Array = []
for k in 6:
ft.append({"tex": _tex, "mode": 1})
persist.record("brush.create", {"planes": _box(Vector3(-3, 0, -1), Vector3(3, 3, -0.5)), "proj": [],
"material_id": 1, "level_id": 0, "sky": false, "face_tex": ft})
persist.refold()
_cam = Camera3D.new()
_cam.fov = 70
root.add_child(_cam)
_cam.make_current()
var sun := DirectionalLight3D.new()
sun.rotation_degrees = Vector3(-25, -70, 0) # low, from the side: relief reads
root.add_child(sun)
root.scaling_3d_mode = Viewport.SCALING_3D_MODE_BILINEAR
root.scaling_3d_scale = SUPERSAMPLE
root.msaa_3d = Viewport.MSAA_DISABLED
root.use_taa = false
_vp = root.get_viewport_rid()
RenderingServer.viewport_set_measure_render_time(_vp, true)
return false
if _setup_frames < 60:
var packs: Variant = _map.get("_packs")
if packs != null:
packs.sync()
return false
if _setup_frames == 60:
var mi := (_map.get("level") as Node).get_node("LevelMesh") as MeshInstance3D
print("PROBE level aabb %s, packs %s" % [mi.get_aabb(), str(_map.get("_packs"))])
_set_case()
return false
_f += 1
if _f > WARM:
_acc += RenderingServer.viewport_get_measured_render_time_gpu(_vp)
if _f == WARM + MEASURE:
var pose: String = POSES[_case / TIERS.size()][0]
var tier: String = TIERS[_case % TIERS.size()]
var ms := _acc / MEASURE
if ms <= 0.0:
print("PROBE FAIL %s/%s measured 0 ms" % [pose, tier])
quit(1)
return true
var key := "%s/%s" % [pose, tier]
if not _samples.has(key):
_samples[key] = []
_samples[key].append(ms)
if _round == 0:
root.get_texture().get_image().save_png("%s/%s_%s.png" % [_out, pose, tier])
_case += 1
if _case >= POSES.size() * TIERS.size():
_case = 0
_round += 1
if _round >= ROUNDS:
_report()
quit(0)
return true
_set_case()
return false
func _set_case() -> void:
var p: Array = POSES[_case / TIERS.size()]
(_map.get("_packs") as LevelPackMaterial).set_detail(_case % TIERS.size())
_cam.look_at_from_position(p[1], p[2])
_f = 0
_acc = 0.0
func _report() -> void:
var px := Vector2(root.size) * SUPERSAMPLE
print("PROBE GPU ms, median of %d interleaved rounds x %d frames, %dx%d shaded px" % [ROUNDS, MEASURE, int(px.x), int(px.y)])
for p: Array in POSES:
var base := 0.0
for t: String in TIERS:
var v: Array = _samples["%s/%s" % [p[0], t]].duplicate()
v.sort()
var med: float = v[v.size() / 2]
if t == "normal_maps":
base = med
print("PROBE %-8s %-12s %.3f ms (+%.3f) rounds %s" % [p[0], t, med, med - base,
str(v.map(func(x: float) -> String: return "%.3f" % x))])