Linked repository source
examples/bunny_mark/project/main.gd
This read-only view comes from the file in the Gododin repository. It retains its design, example or evidence context.
Download the original file · Return to the guide
extends Node2D
# Equal seeded identities, texture footprint and fixed-step physics across
# three transport paths. Driver CPU excludes engine rendering; actual frame
# intervals are reported separately. Verification and capture are untimed.
enum Mode { GDSCRIPT, NODE, FIELD, BULK_GD }
const MODE_NAMES := ["gd", "node", "field", "gd-bulk"]
const POPULATION_SEED := GdBunnies.POPULATION_SEED
var mode: int = Mode.GDSCRIPT
var count := 2500
var speed_scale := 1.0
var gravity_on := true
## the assigned Resource; Reset restores the last-applied values. Canonical
## evaluation runs never read it.
@export var preset: Resource
var _population_seed := POPULATION_SEED
var _texture: Texture2D = GdBunnies.TEXTURE
var _draw_scale := GdBunnies.DRAW_SCALE
var _applied := {}
var field_ready := false
var native_bunnies: Array[Sprite2D] = []
var failed := false
var stopping := false
var steps := 0
var canonical_history := true
var eval_active := false
var eval_mode := "gd"
var eval_count := 2500
var eval_frames := 1200
var eval_warm := 0
var eval_timed := 0
var eval_done_warm := 0
var eval_done_timed := 0
var eval_window_usec := 0.0
var frame_intervals := PackedFloat64Array()
var previous_frame_usec := 0
var start_on_click := false
var eval_started := false
var unfocused_samples := 0
func _ready() -> void:
# Retained staging is reused after direct server-thread consumption.
if not RenderingServer.is_on_render_thread():
_fail("separate_render_thread_unsupported")
return
var seen := {}
for arg in OS.get_cmdline_user_args():
var key: String = arg.split("=", true, 1)[0]
if seen.has(key):
_fail("duplicate_argument=" + key)
return
seen[key] = true
if arg == "--eval":
eval_active = true
elif arg == "--eval-start-on-click":
start_on_click = true
elif arg.begins_with("--mode="):
eval_mode = arg.trim_prefix("--mode=")
elif arg.begins_with("--count=") and arg.trim_prefix("--count=").is_valid_int():
eval_count = int(arg.trim_prefix("--count="))
elif arg.begins_with("--frames=") and arg.trim_prefix("--frames=").is_valid_int():
eval_frames = int(arg.trim_prefix("--frames="))
else:
_fail("unknown_or_invalid_argument=" + arg)
return
if not _create_canvas_quad():
return
%ModeOption.add_item("GDScript loop", Mode.GDSCRIPT)
%ModeOption.add_item("Native per-node", Mode.NODE)
%ModeOption.add_item("Native staged", Mode.FIELD)
%ModeOption.add_item("GDScript bulk", Mode.BULK_GD)
%ModeOption.item_selected.connect(_on_mode_selected)
%CountSlider.value_changed.connect(_on_count_changed)
%SpeedSlider.value_changed.connect(_on_speed_changed)
%GravityCheck.toggled.connect(_on_gravity_toggled)
if not eval_active:
%ApplyPreset.pressed.connect(_on_apply_preset)
%ResetPreset.pressed.connect(_on_reset_preset)
$StatsTimer.timeout.connect(_update_stats)
if eval_active:
Engine.max_fps = 0
if DisplayServer.get_name() != "headless":
DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED, get_window().get_window_id())
if not _eval_pacing_ok():
return
if eval_mode not in MODE_NAMES or eval_count < 1 or eval_count > 20000 or eval_frames < 4 or eval_frames > 100000:
_fail("bad_arguments")
return
count = eval_count
eval_warm = eval_frames / 2
eval_timed = eval_frames - eval_warm
frame_intervals.resize(eval_timed - 1)
%ModeOption.disabled = true
%CountSlider.editable = false
%SpeedSlider.editable = false
%GravityCheck.disabled = true
if not _switch_mode(MODE_NAMES.find(eval_mode)):
return
print("GODODIN_BUNNY_MARK_EVAL_START workload=bunny-mark-v2 mode=%s count=%d warm=%d timed=%d" % [eval_mode,count,eval_warm,eval_timed])
else:
_apply_preset_values()
_switch_mode(Mode.GDSCRIPT)
%CountSlider.set_value_no_signal(count)
%CountLabel.text = str(count)
_update_stats()
# A scene-owned ArrayMesh uses the same local corners and UV direction as
# Sprite2D: screen top-left is (-7,-7) with UV(0,0). Dev5 QuadMesh/PlaneMesh
# FACE_Z generates an inverted V mapping for this CanvasItem convention.
func _create_canvas_quad() -> bool:
var arrays := []
arrays.resize(Mesh.ARRAY_MAX)
arrays[Mesh.ARRAY_VERTEX] = PackedVector3Array([Vector3(-7,-7,0),Vector3(7,-7,0),Vector3(7,7,0),Vector3(-7,7,0)])
arrays[Mesh.ARRAY_TEX_UV] = PackedVector2Array([Vector2(0,0),Vector2(1,0),Vector2(1,1),Vector2(0,1)])
arrays[Mesh.ARRAY_INDEX] = PackedInt32Array([0,1,2,0,2,3])
var quad := ArrayMesh.new()
quad.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, arrays)
$Field/MMI.multimesh.mesh = quad
return _verify_canvas_quad()
func _verify_canvas_quad() -> bool:
var quad := $Field/MMI.multimesh.mesh as ArrayMesh
if quad == null or quad.get_surface_count() != 1 or quad.surface_get_primitive_type(0) != Mesh.PRIMITIVE_TRIANGLES:
return _fail("quad_surface")
var arrays := quad.surface_get_arrays(0)
var vertices: PackedVector3Array = arrays[Mesh.ARRAY_VERTEX]
var uv: PackedVector2Array = arrays[Mesh.ARRAY_TEX_UV]
var indices: PackedInt32Array = arrays[Mesh.ARRAY_INDEX]
if vertices.size() != 4 or uv.size() != 4 or indices != PackedInt32Array([0,1,2,0,2,3]):
return _fail("quad_extent")
for i in 4:
# Each uploaded corner must map the sprite's entire 14px rectangle to
# positive-down UVs. This checks the decoded engine mesh, not a local
# duplicate of the staging input.
if vertices[i].z != 0 or absf(vertices[i].x) != 7 or absf(vertices[i].y) != 7 or uv[i] != Vector2((vertices[i].x+7)/14,(vertices[i].y+7)/14):
return _fail("quad_uv")
if vertices[0] != Vector3(-7,-7,0) or vertices[1] != Vector3(7,-7,0) or vertices[2] != Vector3(7,7,0) or vertices[3] != Vector3(-7,7,0):
return _fail("quad_geometry")
return true
func _physics_process(_delta: float) -> void:
if not eval_active and not failed and not stopping:
_step()
func _process(_delta: float) -> void:
if not eval_active or failed or stopping:
return
if start_on_click and not eval_started:
return
if steps == 0 and not get_window().has_focus():
return
if eval_done_warm < eval_warm:
if not _step():
return
eval_done_warm += 1
return
var entry := Time.get_ticks_usec()
if not get_window().has_focus():
unfocused_samples += 1
if previous_frame_usec != 0:
frame_intervals[eval_done_timed - 1] = float(entry - previous_frame_usec)
previous_frame_usec = entry
var submitted := Time.get_ticks_usec()
if not _step():
return
eval_window_usec += float(Time.get_ticks_usec() - submitted)
eval_done_timed += 1
if eval_done_timed >= eval_timed:
stopping = true
_finish_eval()
func _step() -> bool:
match mode:
Mode.GDSCRIPT:
$Bunnies.step_fixed()
Mode.BULK_GD:
$Bulk.step_fixed()
Mode.NODE:
for bunny in native_bunnies:
if not _check(bunny.call("step_fixed"), "node_step"):
return false
Mode.FIELD:
if not _check($Field.call("submit_frame"), "field_step"):
return false
steps += 1
canonical_history = canonical_history and gravity_on and speed_scale == 1.0
return true
func _finish_eval() -> void:
if not _eval_pacing_ok():
return
print("GODODIN_BUNNY_MARK_PROFILE_FOCUS samples=%d unfocused=%d" % [eval_done_timed, unfocused_samples])
if unfocused_samples != 0:
_fail("profile_window_not_focused")
return
if not _verify_population():
return
# Exercise repeated field allocation and same-seed replay outside timing.
if mode == Mode.FIELD:
# Verification must release every readback before the next retained write.
for probe in 2:
if not _check($Field.call("submit_frame"), "reuse_submit") or not _check($Field.call("verify"), "reuse_verify"):
return
print("GODODIN_BUNNY_MARK_RETAINED_REUSE_PASS cycles=2")
for resized in [maxi(1, count / 2), count]:
if not _check($Field.call("set_count", resized), "resize"):
return
if $Field.call("frames_submitted") != 0 or $Field.call("count") != resized:
_fail("resize_state")
return
if not _check($Field.call("submit_frame"), "resize_submit") or not _check($Field.call("verify"), "resize_verify"):
return
# Restore the measured final state so the image and labels describe it.
if not _check($Field.call("set_count", count), "restore_count"):
return
for _frame in steps:
if not _check($Field.call("submit_frame"), "restore_step"):
return
if not _check($Field.call("verify"), "restore_verify"):
return
_update_stats()
if DisplayServer.get_name() == "headless":
_fail("rendered_campaign_requires_display")
return
await RenderingServer.frame_post_draw
var image := get_viewport().get_texture().get_image()
if image == null or image.is_empty() or image.save_png("user://bunny-%s.png" % eval_mode) != OK:
_fail("screenshot")
return
var frame_avg := 0.0
var samples := FileAccess.open("user://bunny-profile.csv", FileAccess.WRITE)
if samples == null:
_fail("profile_samples_open")
return
samples.store_line("arrival_frame,previous_frame_interval_usec")
for index in frame_intervals.size():
samples.store_line("%d,%.0f" % [eval_warm + 2 + index, frame_intervals[index]])
samples.flush()
if samples.get_error() != OK:
_fail("profile_samples_write")
return
for sample in frame_intervals:
frame_avg += sample
frame_avg /= maxi(1, frame_intervals.size())
frame_intervals.sort()
var p95 := frame_intervals[mini(frame_intervals.size()-1, int(ceil(frame_intervals.size()*0.95))-1)] if not frame_intervals.is_empty() else 0.0
if not _shutdown():
return
print("GODODIN_BUNNY_MARK_PASS workload=bunny-mark-v2 mode=%s count=%d frames=%d measured_frames=%d submit_avg_usec=%.3f frame_avg_usec=%.3f frame_p95_usec=%.3f frame_samples=%d verified=%d" % [eval_mode,count,steps,eval_timed,eval_window_usec/eval_timed,frame_avg,p95,frame_intervals.size(),count])
print("GODODIN_BUNNY_MARK_TEARDOWN_PASS staging_live=false count=0")
get_tree().quit(0)
func _input(event: InputEvent) -> void:
if eval_active and start_on_click and not eval_started and event is InputEventMouseButton and event.pressed and get_window().has_focus():
eval_started = true
func _verify_population() -> bool:
match mode:
Mode.BULK_GD:
if $Bulk.state.size() != count * 5 or $Bulk/MMI.multimesh.instance_count != count or $Bulk/MMI.texture != _texture or not $Bulk/MMI.is_visible_in_tree():
return _fail("bulk_drawable")
if not _check($Field.call("verify_buffer", $Bulk.state_buffer(), steps, POPULATION_SEED), "bulk_replay"):
return false
Mode.GDSCRIPT:
if $Bunnies.sprites.size() != count:
return _fail("gd_count")
if not _check($Field.call("verify_buffer", $Bunnies.state_buffer(), steps, POPULATION_SEED), "gd_replay"):
return false
for i in count:
if not _verify_sprite($Bunnies.sprites[i], i):
return false
Mode.NODE:
if native_bunnies.size() != count:
return _fail("node_count")
for i in count:
if not _verify_sprite(native_bunnies[i], i) or not _check(native_bunnies[i].call("verify", i, steps, POPULATION_SEED), "node_replay"):
return false
Mode.FIELD:
if not field_ready or not $Field.visible or $Field.call("count") != count or RenderingServer.multimesh_get_instance_count($Field/MMI.multimesh.get_rid()) != count or $Field/MMI.texture != _texture or not $Field/MMI.is_visible_in_tree() or not _verify_canvas_quad():
return _fail("field_drawable")
if not _check($Field.call("verify"), "field_replay"):
return false
return true
func _verify_sprite(sprite: Sprite2D, index: int) -> bool:
var p := GdBunnies.parameter(index)
if not sprite.is_inside_tree() or not sprite.is_visible_in_tree() or sprite.texture != _texture or sprite.scale != Vector2.ONE * (p[4] * _draw_scale):
return _fail("sprite_drawable index=%d" % index)
return true
func _switch_mode(target: int) -> bool:
$Field.visible = false
$Bulk.visible = false
$Bunnies.clear_all()
_clear_native_bunnies()
if field_ready:
if not _check($Field.call("shutdown"), "mode_shutdown"):
return false
field_ready = false
mode = target
steps = 0
canonical_history = true
match mode:
Mode.GDSCRIPT:
$Bunnies.set_count(count, _population_seed, _texture, _draw_scale)
Mode.BULK_GD:
$Bulk.set_count(count, _population_seed, _texture, _draw_scale)
$Bulk.visible = true
Mode.NODE:
for i in count:
var p := GdBunnies.parameter(i, _population_seed)
var bunny := ClassDB.instantiate("Bunny") as Sprite2D
if bunny == null:
return _fail("native_class")
bunny.texture = _texture
bunny.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
bunny.scale = Vector2.ONE * (p[4] * _draw_scale)
add_child(bunny)
native_bunnies.append(bunny)
if not _check(bunny.call("configure",1280.0,720.0), "configure") or not _check(bunny.call("launch",p[0],p[1],p[2],p[3]), "launch"):
return false
Mode.FIELD:
if not _check($Field.call("setup",count,_population_seed), "setup"):
return false
field_ready = true
$Field.visible = true
%ModeOption.select(mode)
return _apply_motion()
func _clear_native_bunnies() -> void:
for bunny in native_bunnies:
bunny.free()
native_bunnies.clear()
func _on_mode_selected(item: int) -> void:
_switch_mode(item)
_update_stats()
func _on_count_changed(value: float) -> void:
count = int(value)
%CountLabel.text = str(count)
_switch_mode(mode)
_update_stats()
func _on_speed_changed(value: float) -> void:
speed_scale = Vector2(value, 0).x # Match native f32 admission before stepping.
%SpeedLabel.text = "%.2f" % value
_apply_motion()
func _on_gravity_toggled(value: bool) -> void:
gravity_on = value
_apply_motion()
func _apply_preset_values() -> void:
if preset != null:
count = clampi(int(preset.count), 1, 20000)
speed_scale = float(preset.speed_scale)
gravity_on = bool(preset.gravity_on)
_population_seed = int(preset.population_seed)
_texture = preset.texture if preset.texture != null else GdBunnies.TEXTURE
_draw_scale = float(preset.draw_scale) if float(preset.draw_scale) > 0.0 else GdBunnies.DRAW_SCALE
%CountSlider.set_value_no_signal(count)
%CountLabel.text = str(count)
%SpeedSlider.set_value_no_signal(speed_scale)
%SpeedLabel.text = "%.2f" % speed_scale
%GravityCheck.set_pressed_no_signal(gravity_on)
_applied = {"count": count, "speed_scale": speed_scale, "gravity_on": gravity_on, "seed": _population_seed}
func _on_apply_preset() -> void:
# Explicit Apply reads the current assigned Resource — an Inspector edit
# never reaches the simulation on its own.
_apply_preset_values()
_switch_mode(mode)
_update_stats()
func _on_reset_preset() -> void:
# Reset restores the last-applied preset values, discarding interactive
# drift without re-reading the Resource.
if _applied.is_empty():
return
count = int(_applied.count)
speed_scale = float(_applied.speed_scale)
gravity_on = bool(_applied.gravity_on)
_population_seed = int(_applied.seed)
%CountSlider.set_value_no_signal(count)
%CountLabel.text = str(count)
%SpeedSlider.set_value_no_signal(speed_scale)
%SpeedLabel.text = "%.2f" % speed_scale
%GravityCheck.set_pressed_no_signal(gravity_on)
_switch_mode(mode)
_update_stats()
func _apply_motion() -> bool:
var gravity := 900.0 if gravity_on else 0.0
match mode:
Mode.GDSCRIPT:
$Bunnies.speed_scale = speed_scale
$Bunnies.gravity = gravity
Mode.BULK_GD:
$Bulk.speed_scale = speed_scale
$Bulk.gravity = gravity
Mode.NODE:
for bunny in native_bunnies:
if not _check(bunny.call("set_motion",speed_scale,gravity), "motion"):
return false
Mode.FIELD:
if field_ready and not _check($Field.call("set_profile",speed_scale,gravity), "profile"):
return false
return true
func _update_stats() -> void:
if eval_active and start_on_click and not eval_started:
%StatsLabel.text = "Click the scene to start the focused evaluation"
return
%FpsLabel.text = "FPS %d" % Engine.get_frames_per_second()
var verifiable := canonical_history and gravity_on and speed_scale == 1.0
if mode == Mode.FIELD and field_ready:
verifiable = verifiable and $Field.call("verifiable")
%StatsLabel.text = "%s · %d bunnies · %s" % [MODE_NAMES[mode],count,"canonical replay" if verifiable else "custom history"]
func _check(code: int, context: String) -> bool:
return true if code == 0 else _fail("%s code=%d" % [context,code])
func _fail(detail: String) -> bool:
if not failed:
failed = true
push_error("GODODIN_BUNNY_MARK_FAIL " + detail)
get_tree().quit(1)
return false
func _shutdown() -> bool:
var code: int = $Field.call("shutdown")
field_ready = false
if code != 0 or $Field.call("staging_live") or $Field.call("count") != 0:
return _fail("shutdown code=%d" % code)
return true
func _exit_tree() -> void:
# Children leave first; this field is still alive during parent's exit and
# shutdown needs only retained native owners, never its child resources.
_shutdown()
func _eval_pacing_ok() -> bool:
var headless := DisplayServer.get_name() == "headless"
if Engine.max_fps != 0 or (not headless and DisplayServer.window_get_vsync_mode(get_window().get_window_id()) != DisplayServer.VSYNC_DISABLED):
_fail("eval_pacing_changed")
return false
print("GODODIN_BUNNY_MARK_EVAL_PACING vsync=%s max_fps=%d" % ["not_applicable" if headless else "disabled", Engine.max_fps])
return true