Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion codegen/ffi_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4325,6 +4325,14 @@
"return_type": "i32",
"is_unsafe": true
},
"goud_renderer_get_frame_phase_timings": {
"source_file": "ffi/renderer/metrics.rs",
"params": [
"out_timings: *mut FfiFramePhaseTimings"
],
"return_type": "i32",
"is_unsafe": true
},
"goud_renderer_get_stats": {
"source_file": "ffi/renderer/handles.rs",
"params": [
Expand Down Expand Up @@ -6396,5 +6404,5 @@
"is_unsafe": false
}
},
"total_count": 648
"total_count": 649
}
17 changes: 16 additions & 1 deletion codegen/ffi_mapping.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,19 @@
"ui_draw_calls"
]
},
"FramePhaseTimings": {
"ffi_name": "FfiFramePhaseTimings",
"fields": [
"surface_acquire_us",
"shadow_build_us",
"render3d_scene_us",
"uniform_upload_us",
"render_pass_us",
"gpu_submit_us",
"readback_stall_us",
"surface_present_us"
]
},
"DebuggerConfig": {
"ffi_name": "GoudDebuggerConfig",
"fields": [
Expand Down Expand Up @@ -486,6 +499,7 @@
"*mut FfiPoolStats": "ctypes.POINTER(FfiPoolStats)",
"*mut FfiArenaStats": "ctypes.POINTER(FfiArenaStats)",
"*mut FfiRenderMetrics": "ctypes.POINTER(RenderMetrics)",
"*mut FfiFramePhaseTimings": "ctypes.POINTER(FfiFramePhaseTimings)",
"*const u32": "ctypes.POINTER(ctypes.c_uint32)"
},
"ffi_functions": {
Expand Down Expand Up @@ -1223,7 +1237,8 @@
"goud_frame_arena_stats": {}
},
"render_metrics": {
"goud_renderer_get_frame_metrics": {}
"goud_renderer_get_frame_metrics": {},
"goud_renderer_get_frame_phase_timings": {}
}
}
}
47 changes: 47 additions & 0 deletions codegen/generated/goud_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,48 @@ typedef struct FfiRenderMetrics {
uint32_t ui_draw_calls;
} FfiRenderMetrics;

/**
* FFI-safe per-frame phase timings for performance diagnosis.
*/
typedef struct FfiFramePhaseTimings {
/**
* Time to acquire the next surface texture (us).
*/
uint64_t surface_acquire_us;
/**
* GPU shadow depth pass recording and execution time (us).
*/
uint64_t shadow_pass_us;
/**
* Shadow map build time (us).
*/
uint64_t shadow_build_us;
/**
* 3D scene render time (us).
*/
uint64_t render3d_scene_us;
/**
* Uniform upload and pipeline creation time (us).
*/
uint64_t uniform_upload_us;
/**
* GPU render pass recording time (us).
*/
uint64_t render_pass_us;
/**
* GPU command submission time (us).
*/
uint64_t gpu_submit_us;
/**
* GPU readback stall time (us).
*/
uint64_t readback_stall_us;
/**
* Surface present / vsync wait time (us).
*/
uint64_t surface_present_us;
} FfiFramePhaseTimings;

/**
* Opaque font handle for native FFI text rendering.
*/
Expand Down Expand Up @@ -2057,6 +2099,11 @@ uint32_t goud_renderer_get_coordinate_origin(struct GoudContextId context_id);
*/
int32_t goud_renderer_get_frame_metrics(struct GoudContextId context_id, struct FfiRenderMetrics *out_metrics);

/**
* Retrieves per-frame phase timings for performance diagnosis.
*/
int32_t goud_renderer_get_frame_phase_timings(struct FfiFramePhaseTimings *out_timings);

/**
* Draws UTF-8 text in immediate mode.
*/
Expand Down
46 changes: 46 additions & 0 deletions codegen/goud_sdk.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2320,6 +2320,52 @@
}
]
},
"FramePhaseTimings": {
"kind": "value",
"doc": "Per-frame phase timings for performance diagnosis. All values in microseconds.",
"fields": [
{
"name": "surfaceAcquireUs",
"type": "u64",
"doc": "Time to acquire the next surface texture (us)"
},
{
"name": "shadowBuildUs",
"type": "u64",
"doc": "Shadow map build time (us)"
},
{
"name": "render3dSceneUs",
"type": "u64",
"doc": "3D scene render time (us)"
},
{
"name": "uniformUploadUs",
"type": "u64",
"doc": "Uniform upload and pipeline creation time (us)"
},
{
"name": "renderPassUs",
"type": "u64",
"doc": "GPU render pass recording time (us)"
},
{
"name": "gpuSubmitUs",
"type": "u64",
"doc": "GPU command submission time (us)"
},
{
"name": "readbackStallUs",
"type": "u64",
"doc": "GPU readback stall time (us)"
},
{
"name": "surfacePresentUs",
"type": "u64",
"doc": "Surface present / vsync wait time (us)"
}
]
},
"DebuggerConfig": {
"kind": "value",
"doc": "Pre-init debugger runtime configuration for desktop contexts.",
Expand Down
3 changes: 3 additions & 0 deletions codegen/sdk_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,8 @@ def to_camel(name: str) -> str:
"*mut FfiText": "ctypes.POINTER(FfiText)",
"*const FfiText": "ctypes.POINTER(FfiText)",
"*mut FfiRenderMetrics": "ctypes.POINTER(FfiRenderMetrics)",
"*mut FfiFramePhaseTimings": "ctypes.POINTER(FfiFramePhaseTimings)",
"FfiFramePhaseTimings": "FfiFramePhaseTimings",
"*mut FfiPoolStats": "ctypes.POINTER(FfiPoolStats)",
"*mut FfiArenaStats": "ctypes.POINTER(FfiArenaStats)",
"*const u32": "ctypes.POINTER(ctypes.c_uint32)",
Expand Down Expand Up @@ -408,6 +410,7 @@ def resolve_ctypes_type(
"*mut GoudRenderStats": "ref GoudRenderStats",
"*mut FpsStats": "ref GoudFpsStats",
"*mut RenderMetrics": "ref FfiRenderMetrics",
"*mut FfiFramePhaseTimings": "ref FfiFramePhaseTimings",
"Option<CollisionCallback>": "IntPtr",
"GoudContextId": "GoudContextId",
"GoudResult": "GoudResult",
Expand Down
30 changes: 30 additions & 0 deletions examples/csharp/character_sandbox/GameConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ sealed class GameConfig
public bool VariedAnims { get; init; } = false;
public bool PhaseLock { get; init; } = false;
public bool Profile { get; init; } = false;
public int ProfileDuration { get; init; } = 10;
public bool Shadows { get; init; } = false;
public uint ShadowSize { get; init; } = 1024;
public bool Vsync { get; init; } = true;

public static GameConfig Parse(string[] args)
{
Expand All @@ -17,6 +21,10 @@ public static GameConfig Parse(string[] args)
bool variedAnims = false;
bool phaseLock = false;
bool profile = false;
int profileDuration = 10;
bool shadows = false;
uint shadowSize = 1024;
bool vsync = true;

for (int i = 0; i < args.Length; i++)
{
Expand Down Expand Up @@ -47,6 +55,24 @@ public static GameConfig Parse(string[] args)
{
profile = true;
}
else if (args[i] == "--duration" && i + 1 < args.Length && int.TryParse(args[i + 1], out int d))
{
profileDuration = Math.Max(1, d);
i++;
}
else if (args[i] == "--shadows")
{
shadows = true;
}
else if (args[i] == "--shadow-size" && i + 1 < args.Length && uint.TryParse(args[i + 1], out uint ss))
{
shadowSize = ss;
i++;
}
else if (args[i] == "--no-vsync")
{
vsync = false;
}
}

return new GameConfig
Expand All @@ -57,6 +83,10 @@ public static GameConfig Parse(string[] args)
VariedAnims = variedAnims,
PhaseLock = phaseLock,
Profile = profile,
ProfileDuration = profileDuration,
Shadows = shadows,
ShadowSize = shadowSize,
Vsync = vsync,
};
}
}
22 changes: 22 additions & 0 deletions examples/csharp/character_sandbox/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
PROFILE_DURATION ?= 10
NPC_COUNT ?= 200
ANIMAL_COUNT ?= 80
SHADOW_SIZE ?= 2048

# Allow net8 apps to run on newer .NET runtimes
export DOTNET_ROLL_FORWARD := Major

.PHONY: profile profile-stress run

profile:
dotnet run --project . -- --profile --duration $(PROFILE_DURATION) \
--npcs $(NPC_COUNT) --animals $(ANIMAL_COUNT) \
--shadows --shadow-size $(SHADOW_SIZE)

profile-stress:
dotnet run --project . -- --profile --duration $(PROFILE_DURATION) \
--npcs 400 --animals 100 \
--shadows --shadow-size $(SHADOW_SIZE)

run:
dotnet run --project .
Loading
Loading