extends Node ## Where does a frame go? (G2 performance analysis.) The benchmark fight of round 13 in the ## lane view, paused so every variant renders the same scene; each group is hidden or ## simplified for four seconds and the frame time is taken again. On a GPU-bound machine the ## differences are the render cost of the group. VSync may cap the result (120 Hz = 8.33 ms). ## Run: godot --path . --resolution 1920x1080 res://tools/luneraria/g2_cost_split.tscn -- --out=res://docs/luneraria/logs/g2/cost-split.json const Game = preload("res://scripts/luneraria/lune_game.gd") var out: String = "res://docs/luneraria/logs/g2/cost-split.json" var results: Array = [] func _ready() -> void: for arg: String in OS.get_cmdline_user_args(): if arg.begins_with("--out="): out = arg.get_slice("=", 1) call_deferred("run") func measure(label: String) -> void: for i: int in 20: await get_tree().process_frame var t0: int = Time.get_ticks_usec() var count: int = 0 var end: int = Time.get_ticks_msec() + 4000 while Time.get_ticks_msec() < end: await RenderingServer.frame_post_draw count += 1 var entry := {"variant": label, "frame_ms": (Time.get_ticks_usec() - t0) / 1000.0 / count, "draw_calls": Performance.get_monitor(Performance.RENDER_TOTAL_DRAW_CALLS_IN_FRAME)} results.append(entry) print("COST %-28s %.2f ms/frame, %d draw calls" % [label, entry.frame_ms, entry.draw_calls]) func run() -> void: Soundscape.enabled = false DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED) var game: Node3D = Game.new() add_child(game) game.start({"seed": 5, "human_slot": 0}) var state: LuneMatch = game.match_state state.round_number = 13 for slot: int in range(6): state.players[slot].draft.gold = 100000 state.players[slot].draft.roster.clear() LuneBot.plan(state, slot, "ausgewogen") game._on_ready() game.camera.look_at_point(Vector3(-10, 0, 10), 34.0, true) for i: int in 60: await get_tree().process_frame game.paused = true var world: Node3D = game.world await measure("everything") for view: Node3D in world.tower_views.values(): view.visible = false await measure("towers hidden") for view: Node3D in world.tower_views.values(): view.visible = true var plain := StandardMaterial3D.new() plain.albedo_color = Color(.7, .68, .62) var saved: Array = [] for view: Node3D in world.tower_views.values(): for instance: GeometryInstance3D in view._instances: saved.append([instance, instance.material_override]) instance.material_override = plain await measure("towers with a plain material") for entry: Array in saved: (entry[0] as GeometryInstance3D).material_override = entry[1] for view: Node3D in world.ancient_views.values(): view.visible = false await measure("Ancients hidden") for view: Node3D in world.ancient_views.values(): view.visible = true world.grotto_view.visible = false await measure("grotto hidden") world.grotto_view.visible = true game._units_root.visible = false await measure("figures hidden") game._units_root.visible = true world.sun.shadow_enabled = false await measure("sun shadows off") world.sun.shadow_enabled = true var report := {"window": get_window().size, "gpu": RenderingServer.get_video_adapter_name(), "engine": Engine.get_version_info().string, "scene": "round 13, six full armies, lane view (-10, 10) zoom 34, combat paused", "results": results} DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(out.get_base_dir())) var file := FileAccess.open(out, FileAccess.WRITE) file.store_string(JSON.stringify(report, "\t")) file.close() get_tree().quit()