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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions codegen/gen_ts_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,15 +156,15 @@ def gen_web_wrapper():
lines = [
f"// {HEADER_COMMENT}",
"",
"import type { IGoudGame, IUiManager, IUiStyle, IUiEvent, UiNodeId, IEntity, IColor, IVec2, ITransform2DData, ISpriteData, IRenderStats, IContact, IFpsStats, IRenderMetrics, IDebuggerConfig, IContextConfig, IMemoryCategoryStats, IMemorySummary, IDebuggerCapture, IDebuggerReplayArtifact, IPhysicsRaycastHit2D, IPhysicsCollisionEvent2D, IAnimationEventData, IPreloadAssetRequest, IPreloadOptions, IPreloadProgress, IRenderCapabilities, IPhysicsCapabilities, IAudioCapabilities, IInputCapabilities, INetworkCapabilities, INetworkStats, INetworkSimulationConfig, INetworkConnectResult, INetworkPacket, IP2pMeshConfig, IRollbackConfig, PreloadAssetInput, PreloadAssetKind, ISpriteCmd, ITextCmd } from '../types/engine.g.js';",
"import type { IGoudGame, IUiManager, IUiStyle, IUiEvent, UiNodeId, IEntity, IColor, IVec2, ITransform2DData, ISpriteData, IRenderStats, IContact, IFpsStats, IRenderMetrics, IFramePhaseTimings, IDebuggerConfig, IContextConfig, IMemoryCategoryStats, IMemorySummary, IDebuggerCapture, IDebuggerReplayArtifact, IPhysicsRaycastHit2D, IPhysicsCollisionEvent2D, IAnimationEventData, IPreloadAssetRequest, IPreloadOptions, IPreloadProgress, IRenderCapabilities, IPhysicsCapabilities, IAudioCapabilities, IInputCapabilities, INetworkCapabilities, INetworkStats, INetworkSimulationConfig, INetworkConnectResult, INetworkPacket, IP2pMeshConfig, IRollbackConfig, PreloadAssetInput, PreloadAssetKind, ISpriteCmd, ITextCmd } from '../types/engine.g.js';",
"import { Color, Vec2, Vec3 } from '../types/math.g.js';",
"import { PhysicsBackend2D, RenderBackendKind, WindowBackendKind } from '../types/input.g.js';",
"import { attachInputHandlers } from './input.g.js';",
"",
"export { Color, Vec2, Vec3 } from '../types/math.g.js';",
"export { Key, MouseButton, PhysicsBackend2D, RenderBackendKind, WindowBackendKind } from '../types/input.g.js';",
"export { Rect } from '../types/math.g.js';",
"export type { IGoudGame, IUiManager, IUiStyle, IUiEvent, UiNodeId, IEntity, IColor, IVec2, ITransform2DData, ISpriteData, IRenderStats, IContact, IFpsStats, IRenderMetrics, IDebuggerConfig, IContextConfig, IMemoryCategoryStats, IMemorySummary, IDebuggerCapture, IDebuggerReplayArtifact, IPhysicsRaycastHit2D, IPhysicsCollisionEvent2D, IAnimationEventData, IPreloadAssetRequest, IPreloadOptions, IPreloadProgress, IRenderCapabilities, IPhysicsCapabilities, IAudioCapabilities, IInputCapabilities, INetworkCapabilities, INetworkStats, INetworkSimulationConfig, INetworkConnectResult, INetworkPacket, IP2pMeshConfig, IRollbackConfig, PreloadAssetInput, PreloadAssetKind } from '../types/engine.g.js';",
"export type { IGoudGame, IUiManager, IUiStyle, IUiEvent, UiNodeId, IEntity, IColor, IVec2, ITransform2DData, ISpriteData, IRenderStats, IContact, IFpsStats, IRenderMetrics, IFramePhaseTimings, IDebuggerConfig, IContextConfig, IMemoryCategoryStats, IMemorySummary, IDebuggerCapture, IDebuggerReplayArtifact, IPhysicsRaycastHit2D, IPhysicsCollisionEvent2D, IAnimationEventData, IPreloadAssetRequest, IPreloadOptions, IPreloadProgress, IRenderCapabilities, IPhysicsCapabilities, IAudioCapabilities, IInputCapabilities, INetworkCapabilities, INetworkStats, INetworkSimulationConfig, INetworkConnectResult, INetworkPacket, IP2pMeshConfig, IRollbackConfig, PreloadAssetInput, PreloadAssetKind } from '../types/engine.g.js';",
"",
"const PRELOAD_TEXTURE_EXTENSIONS = new Set(['png', 'jpg', 'jpeg', 'gif', 'bmp', 'webp', 'tga', 'dds']);",
"const PRELOAD_FONT_EXTENSIONS = new Set(['ttf', 'otf', 'woff', 'woff2', 'fnt']);",
Expand Down Expand Up @@ -1204,6 +1204,7 @@ def gen_web_wrapper():
lines.append(" // TODO: wasm FPS overlay -- these stub methods satisfy the IGoudGame interface")
lines.append(" getFpsStats(): IFpsStats { return { currentFps: this.handle.fps, minFps: 0, maxFps: 0, avgFps: 0, frameTimeMs: 0 }; }")
lines.append(" getRenderMetrics(): IRenderMetrics { return { drawCallCount: 0, spritesSubmitted: 0, spritesDrawn: 0, spritesCulled: 0, batchesSubmitted: 0, avgSpritesPerBatch: 0, spriteRenderMs: 0, textRenderMs: 0, uiRenderMs: 0, totalRenderMs: 0, textDrawCalls: 0, textGlyphCount: 0, uiDrawCalls: 0 }; }")
lines.append(" getFramePhaseTimings(): IFramePhaseTimings { return { surfaceAcquireUs: 0, shadowPassUs: 0, shadowBuildUs: 0, render3dSceneUs: 0, uniformUploadUs: 0, renderPassUs: 0, gpuSubmitUs: 0, readbackStallUs: 0, surfacePresentUs: 0, animEvalUs: 0, bonePackUs: 0, boneUploadUs: 0 }; }")
lines.append(" setFpsOverlayEnabled(_enabled: boolean): void {}")
lines.append(" setFpsUpdateInterval(_interval: number): void {}")
lines.append(" setFpsOverlayCorner(_corner: number): void {}")
Expand Down
12 changes: 12 additions & 0 deletions codegen/generated/goud_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -1293,6 +1293,18 @@ typedef struct FfiFramePhaseTimings {
* Surface present / vsync wait time (us).
*/
uint64_t surface_present_us;
/**
* Animation evaluation time (us).
*/
uint64_t anim_eval_us;
/**
* Bone matrix packing time (us).
*/
uint64_t bone_pack_us;
/**
* Bone matrix GPU upload time (us).
*/
uint64_t bone_upload_us;
} FfiFramePhaseTimings;

/**
Expand Down
37 changes: 37 additions & 0 deletions codegen/goud_sdk.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -2329,6 +2329,11 @@
"type": "u64",
"doc": "Time to acquire the next surface texture (us)"
},
{
"name": "shadowPassUs",
"type": "u64",
"doc": "GPU shadow depth pass recording and execution time (us)"
},
{
"name": "shadowBuildUs",
"type": "u64",
Expand Down Expand Up @@ -2363,6 +2368,21 @@
"name": "surfacePresentUs",
"type": "u64",
"doc": "Surface present / vsync wait time (us)"
},
{
"name": "animEvalUs",
"type": "u64",
"doc": "Animation evaluation time (us)"
},
{
"name": "bonePackUs",
"type": "u64",
"doc": "Bone matrix packing time (us)"
},
{
"name": "boneUploadUs",
"type": "u64",
"doc": "Bone matrix GPU upload time (us)"
}
]
},
Expand Down Expand Up @@ -5947,6 +5967,12 @@
"params": [],
"returns": "i32"
},
{
"name": "getFramePhaseTimings",
"doc": "Returns per-frame phase timings for performance diagnosis (all values in microseconds)",
"params": [],
"returns": "FramePhaseTimings"
},
{
"name": "render3D",
"doc": "Renders all 3D objects",
Expand Down Expand Up @@ -13309,6 +13335,17 @@
"getAnimationEvaluationSavedCount": {
"ffi": "goud_renderer3d_get_animation_evaluation_saved_count"
},
"getFramePhaseTimings": {
"ffi": "goud_renderer_get_frame_phase_timings",
"no_context": true,
"out_params": [
{
"name": "out_timings",
"type": "FramePhaseTimings"
}
],
"returns_struct": "FramePhaseTimings"
},
"render3D": {
"ffi": "goud_renderer3d_render"
},
Expand Down
5 changes: 5 additions & 0 deletions codegen/ts_node_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ def gen_interface():
if schema["types"]["RenderMetrics"].get("doc"):
lines.append(f"/** {schema['types']['RenderMetrics']['doc']} */")
lines.append(f"export interface IRenderMetrics {{ {rm_str}; }}")
fpt_fields = schema["types"]["FramePhaseTimings"]["fields"]
fpt_str = "; ".join(f"{to_camel(f['name'])}: number" for f in fpt_fields)
if schema["types"]["FramePhaseTimings"].get("doc"):
lines.append(f"/** {schema['types']['FramePhaseTimings']['doc']} */")
lines.append(f"export interface IFramePhaseTimings {{ {fpt_str}; }}")
dbg_cfg_fields = []
for f in schema["types"]["DebuggerConfig"]["fields"]:
ts_ft = "boolean" if f["type"] == "bool" else "string"
Expand Down
1 change: 1 addition & 0 deletions codegen/ts_node_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"RenderStats": "IRenderStats",
"FpsStats": "IFpsStats",
"RenderMetrics": "IRenderMetrics",
"FramePhaseTimings": "IFramePhaseTimings",
"DebuggerConfig": "IDebuggerConfig",
"ContextConfig": "IContextConfig",
"MemoryCategoryStats": "IMemoryCategoryStats",
Expand Down
6 changes: 4 additions & 2 deletions codegen/ts_node_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,12 +86,12 @@ def gen_node_wrapper():
lines = [
f"// {HEADER_COMMENT}",
"",
"import type { IGoudGame, IUiManager, IUiStyle, IUiEvent, UiNodeId, IEntity, IColor, IVec2, IVec3, ITransform2DData, ISpriteData, IRenderStats, IContact, IFpsStats, IRenderMetrics, IDebuggerConfig, IContextConfig, IMemoryCategoryStats, IMemorySummary, IDebuggerCapture, IDebuggerReplayArtifact, IPhysicsRaycastHit2D, IPhysicsCollisionEvent2D, IAnimationEventData, IPreloadAssetRequest, IPreloadOptions, IPreloadProgress, IRenderCapabilities, IPhysicsCapabilities, IAudioCapabilities, IInputCapabilities, INetworkCapabilities, INetworkStats, INetworkSimulationConfig, IPhysicsWorld2D, IPhysicsWorld3D, IP2pMeshConfig, IRollbackConfig, IBoundingBox3D, ICharacterMoveResult, PreloadAssetInput, PreloadAssetKind, ISpriteCmd, ITextCmd } from '../types/engine.g.js';",
"import type { IGoudGame, IUiManager, IUiStyle, IUiEvent, UiNodeId, IEntity, IColor, IVec2, IVec3, ITransform2DData, ISpriteData, IRenderStats, IContact, IFpsStats, IRenderMetrics, IFramePhaseTimings, IDebuggerConfig, IContextConfig, IMemoryCategoryStats, IMemorySummary, IDebuggerCapture, IDebuggerReplayArtifact, IPhysicsRaycastHit2D, IPhysicsCollisionEvent2D, IAnimationEventData, IPreloadAssetRequest, IPreloadOptions, IPreloadProgress, IRenderCapabilities, IPhysicsCapabilities, IAudioCapabilities, IInputCapabilities, INetworkCapabilities, INetworkStats, INetworkSimulationConfig, IPhysicsWorld2D, IPhysicsWorld3D, IP2pMeshConfig, IRollbackConfig, IBoundingBox3D, ICharacterMoveResult, PreloadAssetInput, PreloadAssetKind, ISpriteCmd, ITextCmd } from '../types/engine.g.js';",
"import { PhysicsBackend2D, RenderBackendKind, WindowBackendKind } from '../types/input.g.js';",
"import { Color, Vec2, Vec3 } from '../types/math.g.js';",
"export { Color, Vec2, Vec3 } from '../types/math.g.js';",
"export { Key, MouseButton, PhysicsBackend2D, RenderBackendKind, WindowBackendKind } from '../types/input.g.js';",
"export type { IGoudGame, IUiManager, IUiStyle, IUiEvent, UiNodeId, IEntity, IColor, IVec2, IVec3, ITransform2DData, ISpriteData, IRenderStats, IContact, IFpsStats, IRenderMetrics, IDebuggerConfig, IContextConfig, IMemoryCategoryStats, IMemorySummary, IDebuggerCapture, IDebuggerReplayArtifact, IPhysicsRaycastHit2D, IPhysicsCollisionEvent2D, IAnimationEventData, IRenderCapabilities, IPhysicsCapabilities, IAudioCapabilities, IInputCapabilities, INetworkCapabilities, INetworkStats, INetworkSimulationConfig, IPhysicsWorld2D, IPhysicsWorld3D, IP2pMeshConfig, IRollbackConfig, IBoundingBox3D, ICharacterMoveResult } from '../types/engine.g.js';",
"export type { IGoudGame, IUiManager, IUiStyle, IUiEvent, UiNodeId, IEntity, IColor, IVec2, IVec3, ITransform2DData, ISpriteData, IRenderStats, IContact, IFpsStats, IRenderMetrics, IFramePhaseTimings, IDebuggerConfig, IContextConfig, IMemoryCategoryStats, IMemorySummary, IDebuggerCapture, IDebuggerReplayArtifact, IPhysicsRaycastHit2D, IPhysicsCollisionEvent2D, IAnimationEventData, IRenderCapabilities, IPhysicsCapabilities, IAudioCapabilities, IInputCapabilities, INetworkCapabilities, INetworkStats, INetworkSimulationConfig, IPhysicsWorld2D, IPhysicsWorld3D, IP2pMeshConfig, IRollbackConfig, IBoundingBox3D, ICharacterMoveResult } from '../types/engine.g.js';",
"",
"export interface INetworkConnectResult { handle: number; peerId: number; }",
"export interface INetworkPacket { peerId: number; data: Uint8Array; }",
Expand Down Expand Up @@ -360,6 +360,8 @@ def gen_node_wrapper():
lines.append(" return this.native.getFpsStats() as unknown as IFpsStats;")
elif mn == "getRenderMetrics":
lines.append(" return this.native.getRenderMetrics() as unknown as IRenderMetrics;")
elif mn == "getFramePhaseTimings":
lines.append(" return this.native.getFramePhaseTimings() as unknown as IFramePhaseTimings;")
elif mn == "getMemorySummary":
lines.append(" return mapMemorySummary(this.native.getMemorySummary());")
elif mn == "getNetworkStats":
Expand Down
28 changes: 27 additions & 1 deletion examples/csharp/character_sandbox/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,16 @@ static void Main(string[] args)
int animEval = game.GetAnimationEvaluationCount();
int animSaved = game.GetAnimationEvaluationSavedCount();
int boneUploads = game.GetBoneMatrixUploadCount();
var pt = game.GetFramePhaseTimings();

Console.Write(
$"\rFPS: {fpsFrames / fpsTimer:F1} Agents: {crowd.Count} " +
$"Draws: {draws} Visible: {visible}/{visible + culled} " +
$"Instanced: {instanced} Instances: {activeInst} " +
$"AnimEval: {animEval} Saved: {animSaved} Bones: {boneUploads} "
$"AnimEval: {animEval} Saved: {animSaved} Bones: {boneUploads} " +
$"[anim={pt.AnimEvalUs}us bone={pt.BonePackUs}+{pt.BoneUploadUs}us " +
$"shadow={pt.ShadowPassUs}us render={pt.RenderPassUs}us " +
$"present={pt.SurfacePresentUs}us] "
);

fpsFrames = 0;
Expand Down Expand Up @@ -206,6 +210,7 @@ static void RunProfile(GoudGame game, CrowdSystem crowd, GameConfig config)
int instanced = game.GetInstancedDrawCalls();
int animEval = game.GetAnimationEvaluationCount();
int animSaved = game.GetAnimationEvaluationSavedCount();
var pt = game.GetFramePhaseTimings();

// Console summary
Console.WriteLine();
Expand All @@ -217,6 +222,11 @@ static void RunProfile(GoudGame game, CrowdSystem crowd, GameConfig config)
Console.WriteLine($" Frame Time: Min {minFrame:F2}ms / Max {maxFrame:F2}ms / Avg {avgFrame:F2}ms");
Console.WriteLine($" Draws: {draws} Visible: {visible}/{visible + culled} Instanced: {instanced}");
Console.WriteLine($" AnimEval: {animEval} Saved: {animSaved} Agents: {crowd.Count}");
Console.WriteLine($" Phase Timings (last frame, us):");
Console.WriteLine($" surface_acquire={pt.SurfaceAcquireUs} shadow_pass={pt.ShadowPassUs} shadow_build={pt.ShadowBuildUs}");
Console.WriteLine($" render3d_scene={pt.Render3dSceneUs} uniform_upload={pt.UniformUploadUs} render_pass={pt.RenderPassUs}");
Console.WriteLine($" gpu_submit={pt.GpuSubmitUs} readback_stall={pt.ReadbackStallUs} surface_present={pt.SurfacePresentUs}");
Console.WriteLine($" anim_eval={pt.AnimEvalUs} bone_pack={pt.BonePackUs} bone_upload={pt.BoneUploadUs}");

// Write markdown report
string profilingDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "profiling");
Expand Down Expand Up @@ -246,6 +256,22 @@ static void RunProfile(GoudGame game, CrowdSystem crowd, GameConfig config)
md.AppendLine($"- Visible: {visible}/{visible + culled}");
md.AppendLine($"- Instanced: {instanced}");
md.AppendLine($"- AnimEval: {animEval}, Saved: {animSaved}");
md.AppendLine();
md.AppendLine("## Phase Timings (last frame, microseconds)");
md.AppendLine($"| Phase | Time (us) |");
md.AppendLine($"|-------|-----------|");
md.AppendLine($"| surface_acquire | {pt.SurfaceAcquireUs} |");
md.AppendLine($"| shadow_pass | {pt.ShadowPassUs} |");
md.AppendLine($"| shadow_build | {pt.ShadowBuildUs} |");
md.AppendLine($"| render3d_scene | {pt.Render3dSceneUs} |");
md.AppendLine($"| uniform_upload | {pt.UniformUploadUs} |");
md.AppendLine($"| render_pass | {pt.RenderPassUs} |");
md.AppendLine($"| gpu_submit | {pt.GpuSubmitUs} |");
md.AppendLine($"| readback_stall | {pt.ReadbackStallUs} |");
md.AppendLine($"| surface_present | {pt.SurfacePresentUs} |");
md.AppendLine($"| anim_eval | {pt.AnimEvalUs} |");
md.AppendLine($"| bone_pack | {pt.BonePackUs} |");
md.AppendLine($"| bone_upload | {pt.BoneUploadUs} |");

File.WriteAllText(mdPath, md.ToString());
Console.WriteLine($"\nReport written to: {mdPath}");
Expand Down
1 change: 1 addition & 0 deletions goud_engine/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ web-sys = { version = "0.3", optional = true, features = [
sdl2 = { version = "0.38", optional = true, features = ["bundled", "raw-window-handle"] }
bumpalo = "3.20.2"
smallvec = "1.15.1"
rustc-hash = "2"

[target.'cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))'.dependencies]
interprocess = { git = "https://github.com/kotauskas/interprocess", rev = "41facdd4e7517cae4b99a44b24671603bc65041e", optional = true }
Expand Down
5 changes: 5 additions & 0 deletions goud_engine/src/core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,10 @@ pub mod pool;
pub mod providers;
pub mod serialization;

/// Fast hash map using `FxHashMap` — ideal for integer keys on hot paths.
pub type FastMap<K, V> = rustc_hash::FxHashMap<K, V>;
/// Fast hash set using `FxHashSet` — ideal for integer keys on hot paths.
pub type FastSet<V> = rustc_hash::FxHashSet<V>;

#[cfg(feature = "native")]
pub mod input_manager;
3 changes: 3 additions & 0 deletions goud_engine/src/ffi/renderer/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ pub unsafe extern "C" fn goud_renderer_get_frame_phase_timings(
gpu_submit_us: timings.gpu_submit_us,
readback_stall_us: timings.readback_stall_us,
surface_present_us: timings.surface_present_us,
anim_eval_us: timings.anim_eval_us,
bone_pack_us: timings.bone_pack_us,
bone_upload_us: timings.bone_upload_us,
};
0
}
6 changes: 6 additions & 0 deletions goud_engine/src/ffi/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ pub struct FfiFramePhaseTimings {
pub readback_stall_us: u64,
/// Surface present / vsync wait time (us).
pub surface_present_us: u64,
/// Animation evaluation time (us).
pub anim_eval_us: u64,
/// Bone matrix packing time (us).
pub bone_pack_us: u64,
/// Bone matrix GPU upload time (us).
pub bone_upload_us: u64,
}

// ============================================================================
Expand Down
Loading
Loading