feat(dispatcher): [indoor-lookup] + [indoor-xform] probes
Instruments the per-MeshRef draw loop in WbDrawDispatcher: - [indoor-lookup]: per cell entity, dumps render-data hit/miss, IsSetup, parts count, and a partsHit/partsMiss tally over the SetupParts. Disambiguates hypothesis H2 (WB produces empty ObjectRenderData with zero parts) and H6 (dispatcher fails to traverse Setup). - [indoor-xform]: only fires for the cell's synthetic geometry part (the SetupPart whose GfxObjId has bit 32 set, per WB's PrepareEnvCellMeshData cellGeomId convention). Logs the three composed transform translations: entityWorld, meshRef.PartTransform, partTransform, and the final composed matrix translation. Disambiguates hypothesis H5 (transform double-apply — composedT lands at 2 × cellOrigin). Rate-limited via the ShouldEmitIndoorProbe instance helper added in Task 6 (now consumed — no longer dead code). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
36a29ceff5
commit
9b948b6ad5
1 changed files with 53 additions and 0 deletions
|
|
@ -685,6 +685,42 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
ulong gfxObjId = meshRef.GfxObjId;
|
||||
|
||||
var renderData = _meshAdapter.TryGetRenderData(gfxObjId);
|
||||
|
||||
// [indoor-lookup] probe — emit once per cell entity per sec.
|
||||
// Fires BEFORE the null-renderData early-continue so a miss still
|
||||
// emits hit=false, distinguishing H2 (empty batches) from H6
|
||||
// (dispatcher fails to traverse Setup).
|
||||
ulong lookupCellId = (ulong)gfxObjId;
|
||||
if (RenderingDiagnostics.IsEnvCellId(lookupCellId)
|
||||
&& RenderingDiagnostics.ProbeIndoorLookupEnabled
|
||||
// Rate-limit in a separate namespace from [indoor-walk]/[indoor-cull]
|
||||
// (which key on the same gfxObjId). Without this, IndoorAll=1 would
|
||||
// silence the lookup probe whenever the walk probe fired first.
|
||||
&& ShouldEmitIndoorProbe(lookupCellId | 0x8000_0000_0000_0000UL))
|
||||
{
|
||||
bool hit = renderData is not null;
|
||||
bool isSetup = hit && renderData!.IsSetup;
|
||||
int partCount = isSetup ? renderData!.SetupParts.Count : 0;
|
||||
|
||||
int partsHit = 0, partsMiss = 0;
|
||||
if (isSetup)
|
||||
{
|
||||
foreach (var (partId, _) in renderData!.SetupParts)
|
||||
{
|
||||
if (_meshAdapter.TryGetRenderData(partId) is not null) partsHit++;
|
||||
else partsMiss++;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasEnvCellGeom = isSetup
|
||||
&& renderData!.SetupParts.Exists(t => (t.GfxObjId & 0x1_0000_0000UL) != 0);
|
||||
|
||||
Console.WriteLine(
|
||||
$"[indoor-lookup] cellId=0x{lookupCellId:X8} " +
|
||||
$"hit={hit} isSetup={isSetup} partCount={partCount} " +
|
||||
$"hasEnvCellGeom={hasEnvCellGeom} partsHit={partsHit} partsMiss={partsMiss}");
|
||||
}
|
||||
|
||||
if (renderData is null)
|
||||
{
|
||||
// Tier 1 cache (#53): mesh data is still async-decoding via
|
||||
|
|
@ -717,6 +753,23 @@ public sealed unsafe class WbDrawDispatcher : IDisposable
|
|||
var model = ComposePartWorldMatrix(
|
||||
entityWorld, meshRef.PartTransform, partTransform);
|
||||
|
||||
// [indoor-xform] probe — only for the cell's synthetic
|
||||
// geometry part (bit 32 set, per WB's PrepareEnvCellMeshData
|
||||
// cellGeomId convention). One line per part per sec.
|
||||
// Disambiguates hypothesis H5 (transform double-apply —
|
||||
// composedT lands at 2 × cellOrigin).
|
||||
if ((partGfxObjId & 0x1_0000_0000UL) != 0
|
||||
&& RenderingDiagnostics.ProbeIndoorXformEnabled
|
||||
&& ShouldEmitIndoorProbe(partGfxObjId))
|
||||
{
|
||||
Console.WriteLine(
|
||||
$"[indoor-xform] cellGeomId=0x{partGfxObjId:X16} " +
|
||||
$"entityWorldT=({entityWorld.Translation.X:F2},{entityWorld.Translation.Y:F2},{entityWorld.Translation.Z:F2}) " +
|
||||
$"meshRefT=({meshRef.PartTransform.Translation.X:F2},{meshRef.PartTransform.Translation.Y:F2},{meshRef.PartTransform.Translation.Z:F2}) " +
|
||||
$"partT=({partTransform.Translation.X:F2},{partTransform.Translation.Y:F2},{partTransform.Translation.Z:F2}) " +
|
||||
$"composedT=({model.Translation.X:F2},{model.Translation.Y:F2},{model.Translation.Z:F2})");
|
||||
}
|
||||
|
||||
var restPose = partTransform * meshRef.PartTransform;
|
||||
ClassifyBatches(partData, partGfxObjId, model, entity, meshRef, palHash, metaTable, restPose, collector);
|
||||
drewAny = true;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue