extends SceneTree
## Probe: what each SunshineClouds2 resolution_scale costs with the MOUNTAIN's real
## cloud resource (scenes/maps/mountain_clouds.tres, which leaves resolution_scale at
## the default 1 = Half). Feeds the Low / Medium / High presets (#93 §2): Medium needs
## a cloud tier between "off" and what High ships.
##
## Viewport GPU render time, median + p90 over WINDOW frames per tier, after SETTLE
## frames for the temporal accumulation and buffer rebuild. Needs a display:
## "$HYPER_TPS_GODOT" --path . --script res://scenes/test/_probe_cloud_quality_cost.gd
const ProbeWindow := preload("res://scenes/test/probe_window.gd")
const SIZE := Vector2i(1600, 900)
const SETTLE := 90
const WINDOW := 150
## [label, enabled, resolution_scale]
const TIERS := [
["off", false, 1], ["native", true, 0], ["half", true, 1],
["quarter", true, 2], ["eighth", true, 3], ["half_again", true, 1],
]
var _ws := ""
var _next_i3 := 0
var _ready_frames := 0
var _vp_rid: RID
var _fx: CompositorEffect
var _tier := -1
var _n := 0
var _samples: Array = []
var _results: Array = []
func _initialize() -> void:
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)"))
var env := Environment.new()
env.background_mode = Environment.BG_SKY
env.sky = Sky.new()
env.sky.sky_material = ProceduralSkyMaterial.new()
var we := WorldEnvironment.new()
we.environment = env
we.compositor = Compositor.new()
_fx = (load("res://scenes/maps/mountain_clouds.tres") as CompositorEffect).duplicate()
var fx: Array[CompositorEffect] = [_fx]
we.compositor.compositor_effects = fx
root.add_child(we)
var sun := DirectionalLight3D.new()
sun.rotation_degrees = Vector3(-35, 30, 0)
root.add_child(sun)
# Below the deck (floor 650, ceiling 1450), looking up into it: the view a player
# on the mountain has, and the one that marches the most cloud.
var cam := Camera3D.new()
cam.position = Vector3(0, 300, 0)
cam.rotation_degrees = Vector3(20, 0, 0)
cam.far = 40000
root.add_child(cam)
cam.make_current()
_vp_rid = root.get_viewport_rid()
RenderingServer.viewport_set_measure_render_time(_vp_rid, true)
func _set_tier(i: int) -> void:
_tier = i
_n = 0
_samples = []
_fx.enabled = bool(TIERS[i][1])
_fx.set("resolution_scale", int(TIERS[i][2]))
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
if _tier < 0:
_set_tier(0)
return false
_n += 1
if _n > SETTLE:
_samples.append(RenderingServer.viewport_get_measured_render_time_gpu(_vp_rid))
if _n >= SETTLE + WINDOW:
_samples.sort()
var med: float = _samples[_samples.size() / 2]
var p90: float = _samples[int(_samples.size() * 0.9)]
_results.append([TIERS[_tier][0], med, p90])
print("PROBE clouds %-10s GPU ms median %6.2f p90 %6.2f (n=%d)" % [TIERS[_tier][0], med, p90, _samples.size()])
if _tier + 1 < TIERS.size():
_set_tier(_tier + 1)
else:
print("PROBE size %s adapter: %s" % [root.size, RenderingServer.get_video_adapter_name()])
return true
return false