@aura3d/debug 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/AnimationInspector.d.ts +25 -0
- package/dist/AnimationInspector.d.ts.map +1 -0
- package/dist/AnimationInspector.js +46 -0
- package/dist/AnimationInspector.js.map +1 -0
- package/dist/ChromeTraceExporter.d.ts +35 -0
- package/dist/ChromeTraceExporter.d.ts.map +1 -0
- package/dist/ChromeTraceExporter.js +110 -0
- package/dist/ChromeTraceExporter.js.map +1 -0
- package/dist/DebugLineCanvasRenderer.d.ts +24 -0
- package/dist/DebugLineCanvasRenderer.d.ts.map +1 -0
- package/dist/DebugLineCanvasRenderer.js +58 -0
- package/dist/DebugLineCanvasRenderer.js.map +1 -0
- package/dist/DebugOverlay.d.ts +18 -0
- package/dist/DebugOverlay.d.ts.map +1 -0
- package/dist/DebugOverlay.js +19 -0
- package/dist/DebugOverlay.js.map +1 -0
- package/dist/DrawCallTracker.d.ts +22 -0
- package/dist/DrawCallTracker.d.ts.map +1 -0
- package/dist/DrawCallTracker.js +28 -0
- package/dist/DrawCallTracker.js.map +1 -0
- package/dist/ECSInspector.d.ts +16 -0
- package/dist/ECSInspector.d.ts.map +1 -0
- package/dist/ECSInspector.js +12 -0
- package/dist/ECSInspector.js.map +1 -0
- package/dist/GPUProfiler.d.ts +22 -0
- package/dist/GPUProfiler.d.ts.map +1 -0
- package/dist/GPUProfiler.js +32 -0
- package/dist/GPUProfiler.js.map +1 -0
- package/dist/MaterialDiagnostics.d.ts +17 -0
- package/dist/MaterialDiagnostics.d.ts.map +1 -0
- package/dist/MaterialDiagnostics.js +43 -0
- package/dist/MaterialDiagnostics.js.map +1 -0
- package/dist/PhysicsDebugAdapter.d.ts +29 -0
- package/dist/PhysicsDebugAdapter.d.ts.map +1 -0
- package/dist/PhysicsDebugAdapter.js +57 -0
- package/dist/PhysicsDebugAdapter.js.map +1 -0
- package/dist/Profiler.d.ts +24 -0
- package/dist/Profiler.d.ts.map +1 -0
- package/dist/Profiler.js +56 -0
- package/dist/Profiler.js.map +1 -0
- package/dist/RenderStateInspector.d.ts +19 -0
- package/dist/RenderStateInspector.d.ts.map +1 -0
- package/dist/RenderStateInspector.js +33 -0
- package/dist/RenderStateInspector.js.map +1 -0
- package/dist/ReportExporter.d.ts +12 -0
- package/dist/ReportExporter.d.ts.map +1 -0
- package/dist/ReportExporter.js +27 -0
- package/dist/ReportExporter.js.map +1 -0
- package/dist/ResourceTracker.d.ts +23 -0
- package/dist/ResourceTracker.d.ts.map +1 -0
- package/dist/ResourceTracker.js +41 -0
- package/dist/ResourceTracker.js.map +1 -0
- package/dist/SceneHelpers.d.ts +46 -0
- package/dist/SceneHelpers.d.ts.map +1 -0
- package/dist/SceneHelpers.js +137 -0
- package/dist/SceneHelpers.js.map +1 -0
- package/dist/ShaderDiagnostics.d.ts +20 -0
- package/dist/ShaderDiagnostics.d.ts.map +1 -0
- package/dist/ShaderDiagnostics.js +49 -0
- package/dist/ShaderDiagnostics.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/package.json +18 -0
- package/src/AnimationInspector.ts +71 -0
- package/src/ChromeTraceExporter.ts +158 -0
- package/src/DebugLineCanvasRenderer.ts +96 -0
- package/src/DebugOverlay.ts +35 -0
- package/src/DrawCallTracker.ts +46 -0
- package/src/ECSInspector.ts +23 -0
- package/src/GPUProfiler.ts +48 -0
- package/src/MaterialDiagnostics.ts +59 -0
- package/src/PhysicsDebugAdapter.ts +86 -0
- package/src/Profiler.ts +77 -0
- package/src/RenderStateInspector.ts +45 -0
- package/src/ReportExporter.ts +32 -0
- package/src/ResourceTracker.ts +59 -0
- package/src/SceneHelpers.ts +188 -0
- package/src/ShaderDiagnostics.ts +64 -0
- package/src/index.ts +46 -0
- package/tsconfig.json +32 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {} from "@aura3d/rendering";
|
|
2
|
+
export class ShaderDiagnostics {
|
|
3
|
+
inspectSources(sources, compileLog = null) {
|
|
4
|
+
return {
|
|
5
|
+
label: sources.label,
|
|
6
|
+
marker: sources.marker,
|
|
7
|
+
markerPresentInVertex: sources.vertex.includes(sources.marker),
|
|
8
|
+
markerPresentInFragment: sources.fragment.includes(sources.marker),
|
|
9
|
+
attributes: extractNames(/\b(?:in|attribute)\s+\w+\s+(\w+)\s*;/g, `${sources.vertex}\n${sources.fragment}`),
|
|
10
|
+
uniforms: extractNames(/\buniform\s+\w+\s+(\w+)(?:\s*\[[^\]]+\])?\s*;/g, `${sources.vertex}\n${sources.fragment}`),
|
|
11
|
+
compileLog
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
inspectProgram(program, compileLog = null) {
|
|
15
|
+
return {
|
|
16
|
+
label: program.label,
|
|
17
|
+
marker: program.marker,
|
|
18
|
+
markerPresentInVertex: true,
|
|
19
|
+
markerPresentInFragment: true,
|
|
20
|
+
attributes: [...program.reflection.attributes.keys()],
|
|
21
|
+
uniforms: [...program.reflection.uniforms],
|
|
22
|
+
compileLog
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
assertMarker(report) {
|
|
26
|
+
if (!report.markerPresentInVertex || !report.markerPresentInFragment) {
|
|
27
|
+
throw new ShaderDiagnosticError("Shader marker mismatch", report);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class ShaderDiagnosticError extends Error {
|
|
32
|
+
report;
|
|
33
|
+
constructor(message, report) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.report = report;
|
|
36
|
+
this.name = "ShaderDiagnosticError";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function extractNames(pattern, source) {
|
|
40
|
+
const names = new Set();
|
|
41
|
+
let match;
|
|
42
|
+
while ((match = pattern.exec(source)) !== null) {
|
|
43
|
+
if (match[1]) {
|
|
44
|
+
names.add(match[1]);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return [...names];
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=ShaderDiagnostics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShaderDiagnostics.js","sourceRoot":"","sources":["../../../../packages/debug/src/ShaderDiagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgD,MAAM,mBAAmB,CAAC;AAYjF,MAAM,OAAO,iBAAiB;IAC5B,cAAc,CAAC,OAAsB,EAAE,aAA4B,IAAI;QACrE,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,qBAAqB,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;YAC9D,uBAAuB,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC;YAClE,UAAU,EAAE,YAAY,CAAC,uCAAuC,EAAE,GAAG,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC;YAC3G,QAAQ,EAAE,YAAY,CAAC,gDAAgD,EAAE,GAAG,OAAO,CAAC,MAAM,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC;YAClH,UAAU;SACX,CAAC;IACJ,CAAC;IAED,cAAc,CAAC,OAA4B,EAAE,aAA4B,IAAI;QAC3E,OAAO;YACL,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,qBAAqB,EAAE,IAAI;YAC3B,uBAAuB,EAAE,IAAI;YAC7B,UAAU,EAAE,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;YACrD,QAAQ,EAAE,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;YAC1C,UAAU;SACX,CAAC;IACJ,CAAC;IAED,YAAY,CAAC,MAA8B;QACzC,IAAI,CAAC,MAAM,CAAC,qBAAqB,IAAI,CAAC,MAAM,CAAC,uBAAuB,EAAE,CAAC;YACrE,MAAM,IAAI,qBAAqB,CAAC,wBAAwB,EAAE,MAAM,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;CACF;AAED,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAG5B;IAFlB,YACE,OAAe,EACC,MAA8B;QAE9C,KAAK,CAAC,OAAO,CAAC,CAAC;QAFC,WAAM,GAAN,MAAM,CAAwB;QAG9C,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED,SAAS,YAAY,CAAC,OAAe,EAAE,MAAc;IACnD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/C,IAAI,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACb,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export { DrawCallTracker } from "./DrawCallTracker.js";
|
|
2
|
+
export type { DrawCallRecord, DrawCallSnapshot } from "./DrawCallTracker.js";
|
|
3
|
+
export { RenderStateInspector, RenderStateLeakError } from "./RenderStateInspector.js";
|
|
4
|
+
export type { RenderStateDiff, RenderStateSnapshot, RenderStateValue } from "./RenderStateInspector.js";
|
|
5
|
+
export { ShaderDiagnosticError, ShaderDiagnostics } from "./ShaderDiagnostics.js";
|
|
6
|
+
export type { ShaderDiagnosticReport } from "./ShaderDiagnostics.js";
|
|
7
|
+
export { MaterialDiagnosticError, MaterialDiagnostics } from "./MaterialDiagnostics.js";
|
|
8
|
+
export type { MaterialDiagnosticReport } from "./MaterialDiagnostics.js";
|
|
9
|
+
export { PhysicsDebugAdapter } from "./PhysicsDebugAdapter.js";
|
|
10
|
+
export type { PhysicsDebugSnapshot, PhysicsStackEvidence } from "./PhysicsDebugAdapter.js";
|
|
11
|
+
export { AnimationInspector } from "./AnimationInspector.js";
|
|
12
|
+
export type { AnimationDebugSnapshot, AnimationVisualEvidence, SkeletonDebugSnapshot } from "./AnimationInspector.js";
|
|
13
|
+
export { Profiler } from "./Profiler.js";
|
|
14
|
+
export type { ProfilerMarker, ProfilerSnapshot } from "./Profiler.js";
|
|
15
|
+
export { GPUProfiler } from "./GPUProfiler.js";
|
|
16
|
+
export type { GPUProfilerSnapshot, GPUSample, GPUProfilerTimer } from "./GPUProfiler.js";
|
|
17
|
+
export { ChromeTraceExporter } from "./ChromeTraceExporter.js";
|
|
18
|
+
export type { ChromeTrace, ChromeTraceEvent, ChromeTraceExportOptions } from "./ChromeTraceExporter.js";
|
|
19
|
+
export { ResourceLeakError, ResourceTracker } from "./ResourceTracker.js";
|
|
20
|
+
export type { ResourceLeakReport, TrackedResource } from "./ResourceTracker.js";
|
|
21
|
+
export { ECSInspector } from "./ECSInspector.js";
|
|
22
|
+
export type { ECSInspectorSnapshot, ECSWorldLike } from "./ECSInspector.js";
|
|
23
|
+
export { DebugOverlay } from "./DebugOverlay.js";
|
|
24
|
+
export type { DebugOverlayRow, DebugOverlaySection, DebugOverlaySnapshot } from "./DebugOverlay.js";
|
|
25
|
+
export { DebugLineCanvasRenderer } from "./DebugLineCanvasRenderer.js";
|
|
26
|
+
export type { DebugLineCanvasRendererOptions, DebugLineCanvasRenderResult, DebugRenderLine } from "./DebugLineCanvasRenderer.js";
|
|
27
|
+
export { buildAxesHelper, buildBoundsHelper, buildCameraFrustumHelper, buildDirectionalLightHelper, buildGridHelper, buildSkeletonHelper } from "./SceneHelpers.js";
|
|
28
|
+
export type { AxesHelperOptions, BoundsHelperOptions, CameraFrustumHelperOptions, DebugColor, DebugVec3, DirectionalLightHelperOptions, GridHelperOptions, SkeletonHelperJoint } from "./SceneHelpers.js";
|
|
29
|
+
export { ReportExporter } from "./ReportExporter.js";
|
|
30
|
+
export type { DebugReport } from "./ReportExporter.js";
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/debug/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACvF,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxG,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClF,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACxF,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACtH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACxG,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC1E,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACpG,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,YAAY,EAAE,8BAA8B,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACjI,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,2BAA2B,EAC3B,eAAe,EACf,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,iBAAiB,EACjB,mBAAmB,EACnB,0BAA0B,EAC1B,UAAU,EACV,SAAS,EACT,6BAA6B,EAC7B,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { DrawCallTracker } from "./DrawCallTracker.js";
|
|
2
|
+
export { RenderStateInspector, RenderStateLeakError } from "./RenderStateInspector.js";
|
|
3
|
+
export { ShaderDiagnosticError, ShaderDiagnostics } from "./ShaderDiagnostics.js";
|
|
4
|
+
export { MaterialDiagnosticError, MaterialDiagnostics } from "./MaterialDiagnostics.js";
|
|
5
|
+
export { PhysicsDebugAdapter } from "./PhysicsDebugAdapter.js";
|
|
6
|
+
export { AnimationInspector } from "./AnimationInspector.js";
|
|
7
|
+
export { Profiler } from "./Profiler.js";
|
|
8
|
+
export { GPUProfiler } from "./GPUProfiler.js";
|
|
9
|
+
export { ChromeTraceExporter } from "./ChromeTraceExporter.js";
|
|
10
|
+
export { ResourceLeakError, ResourceTracker } from "./ResourceTracker.js";
|
|
11
|
+
export { ECSInspector } from "./ECSInspector.js";
|
|
12
|
+
export { DebugOverlay } from "./DebugOverlay.js";
|
|
13
|
+
export { DebugLineCanvasRenderer } from "./DebugLineCanvasRenderer.js";
|
|
14
|
+
export { buildAxesHelper, buildBoundsHelper, buildCameraFrustumHelper, buildDirectionalLightHelper, buildGridHelper, buildSkeletonHelper } from "./SceneHelpers.js";
|
|
15
|
+
export { ReportExporter } from "./ReportExporter.js";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/debug/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEvF,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAElF,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAExF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,2BAA2B,EAC3B,eAAe,EACf,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@aura3d/debug",
|
|
3
|
+
"version": "1.0.6",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@aura3d/animation": "1.0.6",
|
|
7
|
+
"@aura3d/rendering": "1.0.6",
|
|
8
|
+
"@aura3d/physics": "1.0.6"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts"
|
|
18
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { AnimationMixer, AnimationMixerSnapshot, Skeleton } from "@aura3d/animation";
|
|
2
|
+
|
|
3
|
+
export type SkeletonDebugSnapshot = {
|
|
4
|
+
readonly boneCount: number;
|
|
5
|
+
readonly boneNames: readonly string[];
|
|
6
|
+
readonly paletteMatrixCount: number;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
export type AnimationDebugSnapshot = {
|
|
10
|
+
readonly mixer: AnimationMixerSnapshot;
|
|
11
|
+
readonly skeleton?: SkeletonDebugSnapshot;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export type AnimationVisualEvidence = {
|
|
15
|
+
readonly actionCount: number;
|
|
16
|
+
readonly playingActionCount: number;
|
|
17
|
+
readonly sampledTargetCount: number;
|
|
18
|
+
readonly sampledTargets: readonly string[];
|
|
19
|
+
readonly skeletonBoneCount: number;
|
|
20
|
+
readonly paletteMatrixCount: number;
|
|
21
|
+
readonly paletteHash?: string;
|
|
22
|
+
readonly stableHash: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export class AnimationInspector {
|
|
26
|
+
snapshot(mixer: Pick<AnimationMixer, "snapshot">, skeleton?: Skeleton): AnimationDebugSnapshot {
|
|
27
|
+
const snapshot: AnimationDebugSnapshot = {
|
|
28
|
+
mixer: mixer.snapshot()
|
|
29
|
+
};
|
|
30
|
+
if (skeleton) {
|
|
31
|
+
return {
|
|
32
|
+
...snapshot,
|
|
33
|
+
skeleton: {
|
|
34
|
+
boneCount: skeleton.bones.length,
|
|
35
|
+
boneNames: skeleton.bones.map((bone) => bone.name),
|
|
36
|
+
paletteMatrixCount: skeleton.matrixPalette().length
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return snapshot;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
visualEvidence(mixer: Pick<AnimationMixer, "snapshot">, skeleton?: Skeleton): AnimationVisualEvidence {
|
|
44
|
+
const snapshot = mixer.snapshot();
|
|
45
|
+
const sampledTargets = Object.keys(snapshot.values).sort();
|
|
46
|
+
const palette = skeleton?.matrixPalette();
|
|
47
|
+
const evidenceWithoutHash = {
|
|
48
|
+
actionCount: snapshot.actionCount,
|
|
49
|
+
playingActionCount: snapshot.actions.filter((action) => action.playing).length,
|
|
50
|
+
sampledTargetCount: sampledTargets.length,
|
|
51
|
+
sampledTargets,
|
|
52
|
+
skeletonBoneCount: skeleton?.bones.length ?? 0,
|
|
53
|
+
paletteMatrixCount: palette?.length ?? 0,
|
|
54
|
+
...(palette ? { paletteHash: stableHash(palette.map((matrix) => matrix.map((value) => Number(value.toFixed(6))))) } : {})
|
|
55
|
+
};
|
|
56
|
+
return {
|
|
57
|
+
...evidenceWithoutHash,
|
|
58
|
+
stableHash: stableHash(evidenceWithoutHash)
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function stableHash(value: unknown): string {
|
|
64
|
+
const input = JSON.stringify(value);
|
|
65
|
+
let hash = 2166136261;
|
|
66
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
67
|
+
hash ^= input.charCodeAt(index);
|
|
68
|
+
hash = Math.imul(hash, 16777619);
|
|
69
|
+
}
|
|
70
|
+
return (hash >>> 0).toString(16).padStart(8, "0");
|
|
71
|
+
}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import type { ProfilerMarker, ProfilerSnapshot } from "./Profiler.js";
|
|
2
|
+
import type { GPUSample, GPUProfilerSnapshot } from "./GPUProfiler.js";
|
|
3
|
+
|
|
4
|
+
export interface ChromeTraceEvent {
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly cat: string;
|
|
7
|
+
readonly ph: "M" | "X" | "C" | "i";
|
|
8
|
+
readonly ts: number;
|
|
9
|
+
readonly pid: number;
|
|
10
|
+
readonly tid: number;
|
|
11
|
+
readonly dur?: number;
|
|
12
|
+
readonly args?: Record<string, number | string | boolean | null>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ChromeTrace {
|
|
16
|
+
readonly traceEvents: readonly ChromeTraceEvent[];
|
|
17
|
+
readonly displayTimeUnit: "ms";
|
|
18
|
+
readonly metadata: {
|
|
19
|
+
readonly source: "aura3d-debug-chrome-trace-exporter";
|
|
20
|
+
readonly profileName: string;
|
|
21
|
+
readonly cpuMarkerCount: number;
|
|
22
|
+
readonly gpuSampleCount: number;
|
|
23
|
+
readonly claimBoundary: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface ChromeTraceExportOptions {
|
|
28
|
+
readonly profileName?: string;
|
|
29
|
+
readonly processId?: number;
|
|
30
|
+
readonly cpuThreadId?: number;
|
|
31
|
+
readonly gpuThreadId?: number;
|
|
32
|
+
readonly includeCounters?: boolean;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export class ChromeTraceExporter {
|
|
36
|
+
static create(
|
|
37
|
+
cpu: ProfilerSnapshot,
|
|
38
|
+
gpu?: GPUProfilerSnapshot,
|
|
39
|
+
options: ChromeTraceExportOptions = {}
|
|
40
|
+
): ChromeTrace {
|
|
41
|
+
const profileName = options.profileName?.trim() || "Aura3D profile";
|
|
42
|
+
const processId = positiveInteger(options.processId, 1);
|
|
43
|
+
const cpuThreadId = positiveInteger(options.cpuThreadId, 1);
|
|
44
|
+
const gpuThreadId = positiveInteger(options.gpuThreadId, 2);
|
|
45
|
+
const events: ChromeTraceEvent[] = [
|
|
46
|
+
metadataEvent("process_name", processId, cpuThreadId, { name: "Aura3D" }),
|
|
47
|
+
metadataEvent("thread_name", processId, cpuThreadId, { name: "CPU" }),
|
|
48
|
+
metadataEvent("thread_name", processId, gpuThreadId, { name: "GPU" })
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
for (const marker of cpu.markers) {
|
|
52
|
+
events.push(cpuMarkerEvent(marker, processId, cpuThreadId));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (gpu) {
|
|
56
|
+
for (const sample of gpu.samples) {
|
|
57
|
+
events.push(gpuSampleEvent(sample, processId, gpuThreadId));
|
|
58
|
+
}
|
|
59
|
+
if (gpu.supported === false) {
|
|
60
|
+
events.push({
|
|
61
|
+
name: "gpu_timing_unavailable",
|
|
62
|
+
cat: "gpu",
|
|
63
|
+
ph: "i",
|
|
64
|
+
ts: 0,
|
|
65
|
+
pid: processId,
|
|
66
|
+
tid: gpuThreadId,
|
|
67
|
+
args: { reason: gpu.unavailableReason ?? "GPU timing unavailable" }
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (options.includeCounters !== false) {
|
|
73
|
+
events.push({
|
|
74
|
+
name: "profile_counters",
|
|
75
|
+
cat: "counters",
|
|
76
|
+
ph: "C",
|
|
77
|
+
ts: 0,
|
|
78
|
+
pid: processId,
|
|
79
|
+
tid: cpuThreadId,
|
|
80
|
+
args: {
|
|
81
|
+
cpuMarkerCount: cpu.markerCount,
|
|
82
|
+
cpuTotalDurationMs: fixed(cpu.totalDurationMs),
|
|
83
|
+
gpuSampleCount: gpu?.sampleCount ?? 0,
|
|
84
|
+
gpuSupported: gpu?.supported ?? false
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
traceEvents: events,
|
|
91
|
+
displayTimeUnit: "ms",
|
|
92
|
+
metadata: {
|
|
93
|
+
source: "aura3d-debug-chrome-trace-exporter",
|
|
94
|
+
profileName,
|
|
95
|
+
cpuMarkerCount: cpu.markerCount,
|
|
96
|
+
gpuSampleCount: gpu?.sampleCount ?? 0,
|
|
97
|
+
claimBoundary: "Chrome trace export is bounded local profiling evidence; it is not Unity/Unreal profiler parity."
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
static toJson(trace: ChromeTrace): string {
|
|
103
|
+
return `${JSON.stringify(trace, null, 2)}\n`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function metadataEvent(name: "process_name" | "thread_name", pid: number, tid: number, args: { readonly name: string }): ChromeTraceEvent {
|
|
108
|
+
return {
|
|
109
|
+
name,
|
|
110
|
+
cat: "__metadata",
|
|
111
|
+
ph: "M",
|
|
112
|
+
ts: 0,
|
|
113
|
+
pid,
|
|
114
|
+
tid,
|
|
115
|
+
args
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function cpuMarkerEvent(marker: ProfilerMarker, pid: number, tid: number): ChromeTraceEvent {
|
|
120
|
+
return {
|
|
121
|
+
name: marker.name,
|
|
122
|
+
cat: "cpu",
|
|
123
|
+
ph: "X",
|
|
124
|
+
ts: millisecondsToMicroseconds(marker.startMs),
|
|
125
|
+
dur: millisecondsToMicroseconds(marker.durationMs),
|
|
126
|
+
pid,
|
|
127
|
+
tid,
|
|
128
|
+
args: {
|
|
129
|
+
depth: marker.depth,
|
|
130
|
+
endMs: fixed(marker.endMs)
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function gpuSampleEvent(sample: GPUSample, pid: number, tid: number): ChromeTraceEvent {
|
|
136
|
+
return {
|
|
137
|
+
name: sample.label,
|
|
138
|
+
cat: "gpu",
|
|
139
|
+
ph: "X",
|
|
140
|
+
ts: 0,
|
|
141
|
+
dur: millisecondsToMicroseconds(sample.durationMs),
|
|
142
|
+
pid,
|
|
143
|
+
tid,
|
|
144
|
+
args: { durationMs: fixed(sample.durationMs) }
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function millisecondsToMicroseconds(value: number): number {
|
|
149
|
+
return Math.max(0, Math.round(value * 1_000));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function positiveInteger(value: number | undefined, fallback: number): number {
|
|
153
|
+
return Number.isInteger(value) && Number(value) > 0 ? Number(value) : fallback;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function fixed(value: number): number {
|
|
157
|
+
return Number(value.toFixed(4));
|
|
158
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
export interface DebugRenderLine {
|
|
2
|
+
readonly from: readonly [number, number, number];
|
|
3
|
+
readonly to: readonly [number, number, number];
|
|
4
|
+
readonly color: readonly [number, number, number, number];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface DebugLineCanvasRendererOptions {
|
|
8
|
+
readonly scale?: number;
|
|
9
|
+
readonly origin?: readonly [number, number];
|
|
10
|
+
readonly axis?: "xy" | "xz";
|
|
11
|
+
readonly lineWidth?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface DebugLineCanvasRenderResult {
|
|
15
|
+
readonly lineCount: number;
|
|
16
|
+
readonly bounds: {
|
|
17
|
+
readonly minX: number;
|
|
18
|
+
readonly minY: number;
|
|
19
|
+
readonly maxX: number;
|
|
20
|
+
readonly maxY: number;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class DebugLineCanvasRenderer {
|
|
25
|
+
render(
|
|
26
|
+
context: CanvasRenderingContext2D,
|
|
27
|
+
lines: readonly DebugRenderLine[],
|
|
28
|
+
options: DebugLineCanvasRendererOptions = {}
|
|
29
|
+
): DebugLineCanvasRenderResult {
|
|
30
|
+
const scale = options.scale ?? 1;
|
|
31
|
+
if (!Number.isFinite(scale) || scale <= 0) {
|
|
32
|
+
throw new RangeError("Debug line canvas scale must be a finite positive number.");
|
|
33
|
+
}
|
|
34
|
+
const origin = options.origin ?? [0, 0];
|
|
35
|
+
const axis = options.axis ?? "xy";
|
|
36
|
+
const lineWidth = options.lineWidth ?? 1;
|
|
37
|
+
if (!Number.isFinite(lineWidth) || lineWidth <= 0) {
|
|
38
|
+
throw new RangeError("Debug line canvas width must be a finite positive number.");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const bounds = {
|
|
42
|
+
minX: Number.POSITIVE_INFINITY,
|
|
43
|
+
minY: Number.POSITIVE_INFINITY,
|
|
44
|
+
maxX: Number.NEGATIVE_INFINITY,
|
|
45
|
+
maxY: Number.NEGATIVE_INFINITY
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
context.save();
|
|
49
|
+
context.lineWidth = lineWidth;
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
const from = project(line.from, axis, scale, origin);
|
|
52
|
+
const to = project(line.to, axis, scale, origin);
|
|
53
|
+
include(bounds, from);
|
|
54
|
+
include(bounds, to);
|
|
55
|
+
context.strokeStyle = rgba(line.color);
|
|
56
|
+
context.beginPath();
|
|
57
|
+
context.moveTo(from[0], from[1]);
|
|
58
|
+
context.lineTo(to[0], to[1]);
|
|
59
|
+
context.stroke();
|
|
60
|
+
}
|
|
61
|
+
context.restore();
|
|
62
|
+
|
|
63
|
+
if (lines.length === 0) {
|
|
64
|
+
return { lineCount: 0, bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0 } };
|
|
65
|
+
}
|
|
66
|
+
return { lineCount: lines.length, bounds };
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function project(
|
|
71
|
+
point: readonly [number, number, number],
|
|
72
|
+
axis: "xy" | "xz",
|
|
73
|
+
scale: number,
|
|
74
|
+
origin: readonly [number, number]
|
|
75
|
+
): readonly [number, number] {
|
|
76
|
+
const y = axis === "xy" ? point[1] : point[2];
|
|
77
|
+
return [origin[0] + point[0] * scale, origin[1] - y * scale];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function include(bounds: { minX: number; minY: number; maxX: number; maxY: number }, point: readonly [number, number]): void {
|
|
81
|
+
bounds.minX = Math.min(bounds.minX, point[0]);
|
|
82
|
+
bounds.minY = Math.min(bounds.minY, point[1]);
|
|
83
|
+
bounds.maxX = Math.max(bounds.maxX, point[0]);
|
|
84
|
+
bounds.maxY = Math.max(bounds.maxY, point[1]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function rgba(color: readonly [number, number, number, number]): string {
|
|
88
|
+
const r = Math.round(clamp01(color[0]) * 255);
|
|
89
|
+
const g = Math.round(clamp01(color[1]) * 255);
|
|
90
|
+
const b = Math.round(clamp01(color[2]) * 255);
|
|
91
|
+
return `rgba(${r}, ${g}, ${b}, ${clamp01(color[3])})`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function clamp01(value: number): number {
|
|
95
|
+
return Math.min(1, Math.max(0, Number.isFinite(value) ? value : 0));
|
|
96
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface DebugOverlaySection {
|
|
2
|
+
readonly title: string;
|
|
3
|
+
readonly rows: readonly DebugOverlayRow[];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface DebugOverlayRow {
|
|
7
|
+
readonly label: string;
|
|
8
|
+
readonly value: string | number | boolean | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface DebugOverlaySnapshot {
|
|
12
|
+
readonly sections: readonly DebugOverlaySection[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class DebugOverlay {
|
|
16
|
+
private readonly sections = new Map<string, DebugOverlayRow[]>();
|
|
17
|
+
|
|
18
|
+
setSection(title: string, rows: readonly DebugOverlayRow[]): void {
|
|
19
|
+
const trimmed = title.trim();
|
|
20
|
+
if (trimmed.length === 0) {
|
|
21
|
+
throw new Error("Debug overlay section title is required");
|
|
22
|
+
}
|
|
23
|
+
this.sections.set(trimmed, rows.map((row) => ({ ...row })));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
removeSection(title: string): void {
|
|
27
|
+
this.sections.delete(title);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
snapshot(): DebugOverlaySnapshot {
|
|
31
|
+
return {
|
|
32
|
+
sections: [...this.sections.entries()].map(([title, rows]) => ({ title, rows: [...rows] }))
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type DrawCommand, type RenderDeviceDiagnostics } from "@aura3d/rendering";
|
|
2
|
+
|
|
3
|
+
export interface DrawCallRecord {
|
|
4
|
+
readonly label: string;
|
|
5
|
+
readonly topology: string;
|
|
6
|
+
readonly indexed: boolean;
|
|
7
|
+
readonly count: number;
|
|
8
|
+
readonly shader: string | null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface DrawCallSnapshot {
|
|
12
|
+
readonly frame: number;
|
|
13
|
+
readonly total: number;
|
|
14
|
+
readonly records: readonly DrawCallRecord[];
|
|
15
|
+
readonly zeroDrawCallFailure: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class DrawCallTracker {
|
|
19
|
+
private frame = 0;
|
|
20
|
+
private readonly records: DrawCallRecord[] = [];
|
|
21
|
+
|
|
22
|
+
beginFrame(): void {
|
|
23
|
+
this.frame += 1;
|
|
24
|
+
this.records.length = 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
record(command: DrawCommand): void {
|
|
28
|
+
this.records.push({
|
|
29
|
+
label: command.label ?? "draw",
|
|
30
|
+
topology: command.topology,
|
|
31
|
+
indexed: command.indexBuffer !== undefined,
|
|
32
|
+
count: command.indexCount ?? command.vertexCount,
|
|
33
|
+
shader: command.shader?.label ?? null
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
capture(deviceDiagnostics?: RenderDeviceDiagnostics): DrawCallSnapshot {
|
|
38
|
+
const total = deviceDiagnostics?.drawCalls ?? this.records.length;
|
|
39
|
+
return {
|
|
40
|
+
frame: this.frame,
|
|
41
|
+
total,
|
|
42
|
+
records: [...this.records],
|
|
43
|
+
zeroDrawCallFailure: total === 0
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ECSWorldLike {
|
|
2
|
+
entities?(): readonly unknown[];
|
|
3
|
+
query?(...args: unknown[]): Iterable<unknown>;
|
|
4
|
+
readonly entityCount?: number;
|
|
5
|
+
profiler?: { snapshot(): unknown };
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ECSInspectorSnapshot {
|
|
9
|
+
readonly entityCount: number;
|
|
10
|
+
readonly profiler?: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class ECSInspector {
|
|
14
|
+
snapshot(world: ECSWorldLike): ECSInspectorSnapshot {
|
|
15
|
+
const entityCount = typeof world.entityCount === "number"
|
|
16
|
+
? world.entityCount
|
|
17
|
+
: world.entities?.().length ?? 0;
|
|
18
|
+
return {
|
|
19
|
+
entityCount,
|
|
20
|
+
...(world.profiler ? { profiler: world.profiler.snapshot() } : {})
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface GPUProfilerSnapshot {
|
|
2
|
+
readonly supported: boolean;
|
|
3
|
+
readonly sampleCount: number;
|
|
4
|
+
readonly samples: readonly GPUSample[];
|
|
5
|
+
readonly unavailableReason?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface GPUSample {
|
|
9
|
+
readonly label: string;
|
|
10
|
+
readonly durationMs: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface GPUProfilerTimer {
|
|
14
|
+
end(durationMs?: number): GPUSample;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class GPUProfiler {
|
|
18
|
+
private readonly samples: GPUSample[] = [];
|
|
19
|
+
|
|
20
|
+
constructor(
|
|
21
|
+
private readonly supported = false,
|
|
22
|
+
private readonly unavailableReason = "GPU timing extension unavailable"
|
|
23
|
+
) {}
|
|
24
|
+
|
|
25
|
+
begin(label: string): GPUProfilerTimer {
|
|
26
|
+
const trimmed = label.trim();
|
|
27
|
+
if (trimmed.length === 0) {
|
|
28
|
+
throw new Error("GPU profiler sample label is required");
|
|
29
|
+
}
|
|
30
|
+
const start = performance.now();
|
|
31
|
+
return {
|
|
32
|
+
end: (durationMs = performance.now() - start) => {
|
|
33
|
+
const sample = { label: trimmed, durationMs };
|
|
34
|
+
this.samples.push(sample);
|
|
35
|
+
return sample;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
snapshot(): GPUProfilerSnapshot {
|
|
41
|
+
return {
|
|
42
|
+
supported: this.supported,
|
|
43
|
+
sampleCount: this.samples.length,
|
|
44
|
+
samples: [...this.samples],
|
|
45
|
+
...(this.supported ? {} : { unavailableReason: this.unavailableReason })
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MaterialBinding,
|
|
3
|
+
MaterialBindingError,
|
|
4
|
+
type Material,
|
|
5
|
+
type MaterialInstance,
|
|
6
|
+
type RenderShaderProgram
|
|
7
|
+
} from "@aura3d/rendering";
|
|
8
|
+
|
|
9
|
+
export interface MaterialDiagnosticReport {
|
|
10
|
+
readonly materialName: string;
|
|
11
|
+
readonly shaderLabel: string;
|
|
12
|
+
readonly valid: boolean;
|
|
13
|
+
readonly diagnostics: readonly string[];
|
|
14
|
+
readonly uniforms: readonly string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class MaterialDiagnostics {
|
|
18
|
+
inspect(material: Material | MaterialInstance, shader: RenderShaderProgram): MaterialDiagnosticReport {
|
|
19
|
+
const binding = new MaterialBinding();
|
|
20
|
+
const materialName = "baseMaterial" in material ? material.baseMaterial.name : material.name;
|
|
21
|
+
try {
|
|
22
|
+
const result = binding.bind(material, shader);
|
|
23
|
+
return {
|
|
24
|
+
materialName,
|
|
25
|
+
shaderLabel: shader.label,
|
|
26
|
+
valid: true,
|
|
27
|
+
diagnostics: [],
|
|
28
|
+
uniforms: [...result.uniforms.keys()]
|
|
29
|
+
};
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (error instanceof MaterialBindingError) {
|
|
32
|
+
return {
|
|
33
|
+
materialName,
|
|
34
|
+
shaderLabel: shader.label,
|
|
35
|
+
valid: false,
|
|
36
|
+
diagnostics: error.diagnostics,
|
|
37
|
+
uniforms: []
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
assertValid(report: MaterialDiagnosticReport): void {
|
|
45
|
+
if (!report.valid) {
|
|
46
|
+
throw new MaterialDiagnosticError("Material diagnostics reported invalid binding", report);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class MaterialDiagnosticError extends Error {
|
|
52
|
+
constructor(
|
|
53
|
+
message: string,
|
|
54
|
+
public readonly report: MaterialDiagnosticReport
|
|
55
|
+
) {
|
|
56
|
+
super(message);
|
|
57
|
+
this.name = "MaterialDiagnosticError";
|
|
58
|
+
}
|
|
59
|
+
}
|