@forgeax/engine-render 0.1.25 → 0.1.27
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 +18 -0
- package/dist/assembly/factory.d.ts +1 -1
- package/dist/assembly/factory.d.ts.map +1 -1
- package/dist/assembly/material/assembly.d.ts +4 -17
- package/dist/assembly/material/assembly.d.ts.map +1 -1
- package/dist/assembly/material/standard-layer-projection.d.ts.map +1 -1
- package/dist/assembly/material/surface-projection.d.ts.map +1 -1
- package/dist/assembly/webgpu-renderer.d.ts +0 -1
- package/dist/assembly/webgpu-renderer.d.ts.map +1 -1
- package/dist/authoring.mjs +1 -1
- package/dist/{chunk-JSEDTZYS.mjs → chunk-GF523LHF.mjs} +6 -6
- package/dist/chunk-GF523LHF.mjs.map +1 -0
- package/dist/{chunk-TCLDX7SZ.mjs → chunk-TMIASV2N.mjs} +403 -457
- package/dist/chunk-TMIASV2N.mjs.map +1 -0
- package/dist/{chunk-N3RT2EUR.mjs → chunk-XDP6XE5V.mjs} +104 -56
- package/dist/chunk-XDP6XE5V.mjs.map +1 -0
- package/dist/construct-renderer.mjs +153 -13
- package/dist/construct-renderer.mjs.map +1 -1
- package/dist/extract/contracts.d.ts +6 -6
- package/dist/extract/contracts.d.ts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/internal.mjs +1 -1
- package/dist/pipeline-spec-types.d.ts +2 -0
- package/dist/pipeline-spec-types.d.ts.map +1 -1
- package/dist/pipeline-spec.d.ts.map +1 -1
- package/dist/record/frame.d.ts.map +1 -1
- package/dist/record/main-pass-geometry.d.ts +2 -2
- package/dist/record/main-pass-geometry.d.ts.map +1 -1
- package/dist/record/main-pass-material.d.ts +20 -2
- package/dist/record/main-pass-material.d.ts.map +1 -1
- package/dist/record/main-pass-sprite-draws.d.ts +3 -3
- package/dist/record/main-pass-sprite-draws.d.ts.map +1 -1
- package/dist/record/main-pass.d.ts.map +1 -1
- package/dist/record/material-uniforms.d.ts +4 -0
- package/dist/record/material-uniforms.d.ts.map +1 -0
- package/dist/record/render-context.d.ts +2 -2
- package/dist/record/render-context.d.ts.map +1 -1
- package/dist/record/shadow-pass.d.ts +2 -3
- package/dist/record/shadow-pass.d.ts.map +1 -1
- package/dist/recovery/render-system-candidate.d.ts.map +1 -1
- package/dist/render-system-extract-tail.d.ts +2 -0
- package/dist/render-system-extract-tail.d.ts.map +1 -1
- package/dist/render-system-extract.d.ts +27 -10
- package/dist/render-system-extract.d.ts.map +1 -1
- package/dist/render-system.d.ts.map +1 -1
- package/dist/temporal/index.mjs +2 -2
- package/package.json +20 -20
- package/src/__tests__/fixtures/ai-weapon-spirit/README.md +20 -0
- package/src/__tests__/fixtures/ai-weapon-spirit/low-poly-toon.wgsl +178 -0
- package/src/__tests__/fixtures/ai-weapon-spirit/material.json +97 -0
- package/src/__tests__/fixtures/ai-weapon-spirit/painterly-surface.wgsl +55 -0
- package/src/__tests__/gpu-driven-view-gpu-evidence.ts +3 -3
- package/src/__tests__/gpu-driven-view.browser.test.ts +11 -3
- package/src/__tests__/material-contract-inventory.unit.test.ts +43 -0
- package/src/__tests__/{material-static-dynamic-route.unit.test.ts → material-layer-projection.unit.test.ts} +30 -47
- package/src/__tests__/material-program-dispatch.unit.test.ts +48 -0
- package/src/__tests__/renderer-factory-material-contract.unit.test.ts +2 -2
- package/src/__tests__/skinned-shadow-caster.test.ts +14 -14
- package/src/__tests__/surface-variant-provenance.integration.test.ts +1 -1
- package/src/assembly/factory.ts +0 -3
- package/src/assembly/material/assembly.ts +8 -40
- package/src/assembly/material/standard-layer-projection.ts +3 -1
- package/src/assembly/material/surface-projection.ts +2 -1
- package/src/assembly/webgpu-renderer.ts +17 -9
- package/src/extract/contracts.ts +6 -6
- package/src/materials.ts +3 -3
- package/src/pipeline-spec-types.ts +2 -0
- package/src/pipeline-spec.ts +7 -3
- package/src/record/__tests__/standard-pbr-ubo-layout.unit.test.ts +68 -1
- package/src/record/frame.ts +7 -1
- package/src/record/main-pass-geometry.ts +340 -279
- package/src/record/main-pass-material.ts +87 -2
- package/src/record/main-pass-sprite-draws.ts +65 -168
- package/src/record/main-pass.ts +24 -246
- package/src/record/material-uniforms.ts +186 -0
- package/src/record/render-context.ts +4 -0
- package/src/record/shadow-pass.ts +86 -28
- package/src/recovery/render-system-candidate.ts +5 -1
- package/src/render-system-extract-tail.ts +54 -13
- package/src/render-system-extract.ts +103 -64
- package/src/render-system.ts +19 -0
- package/dist/assembly/material/pipeline-projection.d.ts +0 -30
- package/dist/assembly/material/pipeline-projection.d.ts.map +0 -1
- package/dist/chunk-JSEDTZYS.mjs.map +0 -1
- package/dist/chunk-N3RT2EUR.mjs.map +0 -1
- package/dist/chunk-TCLDX7SZ.mjs.map +0 -1
- package/src/assembly/material/pipeline-projection.ts +0 -63
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
import type { PointsLinesRecordPlan } from '../points-lines/record';
|
|
45
45
|
import { POINTS_LINES_MATERIAL_SHADER_ID } from '../points-lines/record';
|
|
46
46
|
import type { RenderRecordPhase } from '../render-contract';
|
|
47
|
-
import type { MaterialSnapshot, RenderableSnapshot } from '../render-system-extract';
|
|
47
|
+
import type { DispatchEntry, MaterialSnapshot, RenderableSnapshot } from '../render-system-extract';
|
|
48
48
|
import {
|
|
49
49
|
PROBE_BLEND_RECORD_BYTE_SIZE,
|
|
50
50
|
PROBE_BLEND_RECORD_STRIDE,
|
|
@@ -120,6 +120,8 @@ type MaterialPipelineLookup = {
|
|
|
120
120
|
readonly topology: PrimitiveTopology;
|
|
121
121
|
readonly indexFormat: 'uint16' | 'uint32';
|
|
122
122
|
readonly variantSet: string | undefined;
|
|
123
|
+
readonly vertexEntry: string | undefined;
|
|
124
|
+
readonly fragmentEntry: string | undefined;
|
|
123
125
|
readonly passKind: PassKind;
|
|
124
126
|
readonly layoutProjection: import('@forgeax/engine-geometry').VertexLayoutProjection;
|
|
125
127
|
readonly sampleCount: number;
|
|
@@ -365,8 +367,10 @@ export function recordGeometryDraws(
|
|
|
365
367
|
submeshMaterial: MaterialSnapshot,
|
|
366
368
|
entityKey: number,
|
|
367
369
|
materialWorld: World,
|
|
370
|
+
materialShaderId?: string,
|
|
368
371
|
) => BindGroup,
|
|
369
372
|
passKind: PassKind = 'forward',
|
|
373
|
+
selectedDispatch?: readonly DispatchEntry[],
|
|
370
374
|
): void {
|
|
371
375
|
const {
|
|
372
376
|
runtime,
|
|
@@ -381,6 +385,17 @@ export function recordGeometryDraws(
|
|
|
381
385
|
viewBindGroup,
|
|
382
386
|
viewBindGroupDynamicOffset = 0,
|
|
383
387
|
} = c;
|
|
388
|
+
const materialPasses = new Map<number, Map<number, DispatchEntry[]>>();
|
|
389
|
+
for (const dispatch of selectedDispatch ?? []) {
|
|
390
|
+
let byMaterial = materialPasses.get(dispatch.renderableIndex);
|
|
391
|
+
if (byMaterial === undefined) {
|
|
392
|
+
byMaterial = new Map();
|
|
393
|
+
materialPasses.set(dispatch.renderableIndex, byMaterial);
|
|
394
|
+
}
|
|
395
|
+
const passes = byMaterial.get(dispatch.materialHandle);
|
|
396
|
+
if (passes === undefined) byMaterial.set(dispatch.materialHandle, [dispatch]);
|
|
397
|
+
else passes.push(dispatch);
|
|
398
|
+
}
|
|
384
399
|
const diagnosticsEnabled = materialDiagnosticsEnabled();
|
|
385
400
|
const colorFormatOverride = c.transparentColorFormat as GPUTextureFormat | undefined;
|
|
386
401
|
// The prepared Standard topology is the frame authority. A bind-group
|
|
@@ -438,6 +453,8 @@ export function recordGeometryDraws(
|
|
|
438
453
|
variantSet: string | undefined,
|
|
439
454
|
colorFormat: GPUTextureFormat | undefined,
|
|
440
455
|
layoutProjection: import('@forgeax/engine-geometry').VertexLayoutProjection,
|
|
456
|
+
vertexEntry?: string,
|
|
457
|
+
fragmentEntry?: string,
|
|
441
458
|
): MaterialShaderPipelineEntry | null => {
|
|
442
459
|
// The fallback MRT is an extension of the built-in Standard PBR output
|
|
443
460
|
// contract only. The render pass may carry a second attachment whenever
|
|
@@ -463,6 +480,8 @@ export function recordGeometryDraws(
|
|
|
463
480
|
cached.topology === topology &&
|
|
464
481
|
cached.indexFormat === indexFormat &&
|
|
465
482
|
cached.variantSet === variantSet &&
|
|
483
|
+
cached.vertexEntry === vertexEntry &&
|
|
484
|
+
cached.fragmentEntry === fragmentEntry &&
|
|
466
485
|
cached.passKind === passKind &&
|
|
467
486
|
cached.layoutProjection.digest === layoutProjection.digest &&
|
|
468
487
|
cached.sampleCount === sampleCount &&
|
|
@@ -474,10 +493,12 @@ export function recordGeometryDraws(
|
|
|
474
493
|
}
|
|
475
494
|
}
|
|
476
495
|
const resolvedVariantSetResult =
|
|
477
|
-
|
|
478
|
-
(materialShaderId === 'forgeax::sprite' || materialShaderId === 'forgeax::sprite-lit')
|
|
496
|
+
runtime.getMaterialArtifact?.(materialShaderId) !== undefined
|
|
479
497
|
? ({ ok: true, value: undefined } as const)
|
|
480
|
-
:
|
|
498
|
+
: variantSet === undefined &&
|
|
499
|
+
(materialShaderId === 'forgeax::sprite' || materialShaderId === 'forgeax::sprite-lit')
|
|
500
|
+
? ({ ok: true, value: undefined } as const)
|
|
501
|
+
: variantSetFromVertexLayoutProjection(layoutProjection, variantSet);
|
|
481
502
|
if (!resolvedVariantSetResult.ok) {
|
|
482
503
|
runtime.errorRegistry.fire(resolvedVariantSetResult.error);
|
|
483
504
|
return null;
|
|
@@ -508,6 +529,8 @@ export function recordGeometryDraws(
|
|
|
508
529
|
undefined,
|
|
509
530
|
undefined,
|
|
510
531
|
reflectionFallbackFormats,
|
|
532
|
+
vertexEntry,
|
|
533
|
+
fragmentEntry,
|
|
511
534
|
) ?? null;
|
|
512
535
|
const handle =
|
|
513
536
|
profilePhase === undefined
|
|
@@ -528,6 +551,8 @@ export function recordGeometryDraws(
|
|
|
528
551
|
topology,
|
|
529
552
|
indexFormat,
|
|
530
553
|
variantSet,
|
|
554
|
+
vertexEntry,
|
|
555
|
+
fragmentEntry,
|
|
531
556
|
passKind,
|
|
532
557
|
layoutProjection,
|
|
533
558
|
sampleCount,
|
|
@@ -591,7 +616,8 @@ export function recordGeometryDraws(
|
|
|
591
616
|
// decal submesh) is NOT skipped at the entity level; its opaque submeshes
|
|
592
617
|
// draw here and the per-submesh loop below skips the transparent ones
|
|
593
618
|
// (they are drawn in the blend sub-pass instead).
|
|
594
|
-
if (splitLdrSprite && isEntityFullyTransparent(entry.source))
|
|
619
|
+
if (selectedDispatch === undefined && splitLdrSprite && isEntityFullyTransparent(entry.source))
|
|
620
|
+
continue;
|
|
595
621
|
|
|
596
622
|
const pipelineTag: 'unlit' = 'unlit';
|
|
597
623
|
|
|
@@ -975,295 +1001,315 @@ export function recordGeometryDraws(
|
|
|
975
1001
|
const materialHandle = submeshMaterial.materialHandle ?? 0;
|
|
976
1002
|
if (materialHandles === undefined || !materialHandles.has(materialHandle)) continue;
|
|
977
1003
|
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
// objects form the WeakMap chain and fully discriminate the
|
|
997
|
-
// binding state since sampler/textureView/buffer handle identities
|
|
998
|
-
// are stable across frames.
|
|
999
|
-
//
|
|
1000
|
-
// feat-20260625-refactor-sprite-as-transparent-mesh M3 / w13:
|
|
1001
|
-
// sprite materials now use the same per-submesh BG construction
|
|
1002
|
-
// (the sprite-specific BG branch above is deleted; sprite per-
|
|
1003
|
-
// submesh single-slot is still enforced via materialSlotIndices
|
|
1004
|
-
// and the sprite-shaped paramSnapshot fills the PBR-shaped BGL
|
|
1005
|
-
// bindings via fallback textures for the 4 unused slots).
|
|
1006
|
-
// feat-city-glb Bug 5: per-submesh material BG assembly extracted to
|
|
1007
|
-
// the shared `buildPerSubmeshMaterialBg` closure (also called by the
|
|
1008
|
-
// LDR blend sub-pass). Resolves the shader's user-region textures
|
|
1009
|
-
// (baseColor/MR/normal + a custom Nth texture), emissive/occlusion
|
|
1010
|
-
// injection, and Skylight merge; deduped cross-entity via the
|
|
1011
|
-
// shaderId-outer `materialBgShared` cache.
|
|
1012
|
-
const materialSlot = materialSlotIndices[i]?.[matSlotIdx] ?? materialSlotIndices[i]?.[0] ?? 0;
|
|
1013
|
-
const processValue = (
|
|
1014
|
-
globalThis as {
|
|
1015
|
-
process?: { env?: Record<string, string | undefined> };
|
|
1004
|
+
const draws: readonly (DispatchEntry | undefined)[] =
|
|
1005
|
+
selectedDispatch === undefined
|
|
1006
|
+
? [undefined]
|
|
1007
|
+
: (materialPasses.get(entry.renderableIndex)?.get(submeshMaterial.materialHandle ?? 0) ??
|
|
1008
|
+
[]);
|
|
1009
|
+
for (const selectedPass of draws) {
|
|
1010
|
+
const selectedShaderId =
|
|
1011
|
+
selectedPass === undefined
|
|
1012
|
+
? submeshMaterial.materialShaderId
|
|
1013
|
+
: selectedPass.materialShaderId;
|
|
1014
|
+
const selectedRenderState =
|
|
1015
|
+
selectedPass === undefined ? submeshMaterial.renderState : selectedPass.renderState;
|
|
1016
|
+
const selectedStencil =
|
|
1017
|
+
(selectedPass === undefined ? entry.stencilReference : selectedPass.stencilReference) ??
|
|
1018
|
+
0;
|
|
1019
|
+
if (selectedStencil !== lastStencilReference) {
|
|
1020
|
+
pass.setStencilReference(selectedStencil);
|
|
1021
|
+
lastStencilReference = selectedStencil;
|
|
1016
1022
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
(
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1023
|
+
// feat-city-glb Bug 5 (per-submesh transparency): in the LDR split, a
|
|
1024
|
+
// transparent submesh is drawn in the blend sub-pass (non-sRGB view),
|
|
1025
|
+
// NOT here in the sRGB geometry pass. Skip it. Opaque submeshes of the
|
|
1026
|
+
// same (mixed) mesh still draw here. Single-material / fully-opaque
|
|
1027
|
+
// meshes are unaffected (their submesh materials are not transparent).
|
|
1028
|
+
if (
|
|
1029
|
+
splitLdrSprite &&
|
|
1030
|
+
(selectedPass === undefined
|
|
1031
|
+
? submeshMaterial.transparent === true
|
|
1032
|
+
: selectedRenderState?.blend !== undefined)
|
|
1033
|
+
) {
|
|
1034
|
+
continue;
|
|
1035
|
+
}
|
|
1036
|
+
// bug-20260610 layer 7d: per-submesh BG construction. Texture
|
|
1037
|
+
// views resolve from `matsForRebind[smIdx]` so the j-th submesh
|
|
1038
|
+
// sees its own materials[j] textures (baseColor / MR / normal /
|
|
1039
|
+
// emissive / occlusion). Pick slot j when materials.length covers
|
|
1040
|
+
// smIdx; otherwise fall back to slot 0 (count-mismatch already
|
|
1041
|
+
// filtered by extract; this guard handles the materials.length=1
|
|
1042
|
+
// single-material path mapped over multi-submesh meshes safely).
|
|
1043
|
+
// This BG drops entityKey: identical-texture-set submeshes
|
|
1044
|
+
// (whether on the same entity or different ones) share one BG via
|
|
1045
|
+
// the shaderId-outer `materialBgShared` cache. The 14 handle
|
|
1046
|
+
// objects form the WeakMap chain and fully discriminate the
|
|
1047
|
+
// binding state since sampler/textureView/buffer handle identities
|
|
1048
|
+
// are stable across frames.
|
|
1049
|
+
//
|
|
1050
|
+
// feat-20260625-refactor-sprite-as-transparent-mesh M3 / w13:
|
|
1051
|
+
// sprite materials now use the same per-submesh BG construction
|
|
1052
|
+
// (the sprite-specific BG branch above is deleted; sprite per-
|
|
1053
|
+
// submesh single-slot is still enforced via materialSlotIndices
|
|
1054
|
+
// and the sprite-shaped paramSnapshot fills the PBR-shaped BGL
|
|
1055
|
+
// bindings via fallback textures for the 4 unused slots).
|
|
1056
|
+
// feat-city-glb Bug 5: per-submesh material BG assembly extracted to
|
|
1057
|
+
// the shared `buildPerSubmeshMaterialBg` closure (also called by the
|
|
1058
|
+
// LDR blend sub-pass). Resolves the shader's user-region textures
|
|
1059
|
+
// (baseColor/MR/normal + a custom Nth texture), emissive/occlusion
|
|
1060
|
+
// injection, and Skylight merge; deduped cross-entity via the
|
|
1061
|
+
// shaderId-outer `materialBgShared` cache.
|
|
1062
|
+
const materialSlot =
|
|
1063
|
+
materialSlotIndices[i]?.[matSlotIdx] ?? materialSlotIndices[i]?.[0] ?? 0;
|
|
1064
|
+
const processValue = (
|
|
1065
|
+
globalThis as {
|
|
1066
|
+
process?: { env?: Record<string, string | undefined> };
|
|
1067
|
+
}
|
|
1068
|
+
).process;
|
|
1069
|
+
if (
|
|
1070
|
+
processValue?.env?.FORGEAX_MATERIAL_PIPELINE_DIAGNOSTICS === '1' &&
|
|
1071
|
+
(submeshMaterial.materialShaderId === 'forgeax::default-standard-pbr' ||
|
|
1072
|
+
submeshMaterial.materialShaderId === 'forgeax::pbr-skin')
|
|
1073
|
+
) {
|
|
1074
|
+
console.error(
|
|
1075
|
+
`[render-material] draw receipt: ${JSON.stringify({
|
|
1076
|
+
entityIndex: entry.renderableIndex,
|
|
1036
1077
|
materialSlot,
|
|
1037
|
-
submeshMaterial,
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
)
|
|
1041
|
-
|
|
1042
|
-
|
|
1078
|
+
materialHandle: submeshMaterial.materialHandle,
|
|
1079
|
+
clearcoat: submeshMaterial.paramSnapshot?.clearcoat,
|
|
1080
|
+
shader: submeshMaterial.materialShaderId,
|
|
1081
|
+
})}`,
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
perSubmeshBg =
|
|
1085
|
+
profilePhase === undefined
|
|
1086
|
+
? resolveMaterialBindGroup(
|
|
1043
1087
|
materialSlot,
|
|
1044
1088
|
submeshMaterial,
|
|
1045
1089
|
entry.source.entityKey,
|
|
1046
1090
|
entry.world ?? c.world,
|
|
1047
|
-
|
|
1091
|
+
selectedShaderId,
|
|
1092
|
+
)
|
|
1093
|
+
: profileGeometrySegment(c, passKind, 'material-bind-groups', () =>
|
|
1094
|
+
resolveMaterialBindGroup(
|
|
1095
|
+
materialSlot,
|
|
1096
|
+
submeshMaterial,
|
|
1097
|
+
entry.source.entityKey,
|
|
1098
|
+
entry.world ?? c.world,
|
|
1099
|
+
selectedShaderId,
|
|
1100
|
+
),
|
|
1101
|
+
);
|
|
1102
|
+
materialGroup1DynamicOffsets[0] = materialSlot * MATERIAL_PER_ENTITY_STRIDE;
|
|
1103
|
+
pass.setBindGroup(1, perSubmeshBg, materialGroup1DynamicOffsets, 0, 1);
|
|
1104
|
+
const smTopology = sm.topology;
|
|
1105
|
+
const smMaterialShaderId =
|
|
1106
|
+
selectedPass !== undefined
|
|
1107
|
+
? selectedShaderId
|
|
1108
|
+
: entry.source.skin !== undefined
|
|
1109
|
+
? isStandardPbrSkinMaterialShader(submeshMaterial.materialShaderId)
|
|
1110
|
+
? submeshMaterial.materialShaderId
|
|
1111
|
+
: SKIN_MATERIAL_SHADER_ID
|
|
1112
|
+
: submeshMaterial.materialShaderId;
|
|
1113
|
+
const probeBlendAvailable =
|
|
1114
|
+
probeBlendRecordAvailable && isStandardPbrMaterialShader(smMaterialShaderId);
|
|
1115
|
+
const isSpriteShader =
|
|
1116
|
+
smMaterialShaderId === 'forgeax::sprite' || smMaterialShaderId === 'forgeax::sprite-lit';
|
|
1117
|
+
// Preserve the dedicated sprite-pass state when the linear-LDR graph
|
|
1118
|
+
// routes a sprite through this generic geometry path. Negative scale
|
|
1119
|
+
// flips winding, so back-face culling would erase the quad.
|
|
1120
|
+
const basePipelineRenderState = isSpriteShader
|
|
1121
|
+
? {
|
|
1122
|
+
...selectedRenderState,
|
|
1123
|
+
depthWriteEnabled: false,
|
|
1124
|
+
depthCompare: 'less-equal' as const,
|
|
1125
|
+
cullMode: 'none' as const,
|
|
1126
|
+
blend: selectedRenderState?.blend ?? SPRITE_PREMULTIPLIED_ALPHA_BLEND,
|
|
1127
|
+
}
|
|
1128
|
+
: geometryRenderStateForTopology(smTopology, selectedRenderState);
|
|
1129
|
+
const pipelineRenderState = geometryRenderStateForPass(basePipelineRenderState, passKind);
|
|
1130
|
+
let smPipelineHandle: typeof pipelineState.unlitPipeline;
|
|
1131
|
+
let materialGroup2Contract: 'mesh' | 'skin' | 'cluster' | 'skin-cluster' | undefined;
|
|
1132
|
+
let materialPipelineEntry: MaterialShaderPipelineEntry | null = null;
|
|
1133
|
+
if (smMaterialShaderId === undefined || smMaterialShaderId === 'forgeax::default-unlit') {
|
|
1134
|
+
const unlitShaderId = smMaterialShaderId ?? 'forgeax::default-unlit';
|
|
1135
|
+
const unlitProjectionVariantResult = variantSetFromVertexLayoutProjection(
|
|
1136
|
+
entry.mesh.layoutProjection,
|
|
1137
|
+
undefined,
|
|
1138
|
+
);
|
|
1139
|
+
if (!unlitProjectionVariantResult.ok) {
|
|
1140
|
+
runtime.errorRegistry.fire(unlitProjectionVariantResult.error);
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
const unlitHasColor =
|
|
1144
|
+
unlitProjectionVariantResult.value === 'VERTEX_COLOR_AVAILABLE=true';
|
|
1145
|
+
const unlitVariantSet = standardStorageVariantSet(
|
|
1146
|
+
runtime.device.caps.storageBuffer,
|
|
1147
|
+
unlitHasColor,
|
|
1148
|
+
);
|
|
1149
|
+
const unlitRsp = resolveMaterialPipeline(
|
|
1150
|
+
unlitShaderId,
|
|
1151
|
+
pipelineRenderState,
|
|
1152
|
+
smTopology,
|
|
1153
|
+
entry.mesh.indexFormat,
|
|
1154
|
+
unlitVariantSet,
|
|
1155
|
+
colorFormatOverride,
|
|
1156
|
+
entry.mesh.layoutProjection,
|
|
1157
|
+
selectedPass?.vertexEntry,
|
|
1158
|
+
selectedPass?.fragmentEntry,
|
|
1159
|
+
);
|
|
1160
|
+
materialPipelineEntry = unlitRsp;
|
|
1161
|
+
smPipelineHandle =
|
|
1162
|
+
unlitRsp?.pipeline ??
|
|
1163
|
+
(colorFormatOverride === undefined
|
|
1164
|
+
? selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive)
|
|
1165
|
+
: null);
|
|
1166
|
+
} else if (smMaterialShaderId !== undefined) {
|
|
1167
|
+
// feat-20260609 M4.5 / w38 (D-11): the variantSet handed to
|
|
1168
|
+
// getMaterialShaderPipeline MUST mirror the boot-time
|
|
1169
|
+
// `definesKey` rule at createRenderer.ts:2483-2485 (sortedEntries
|
|
1170
|
+
// .every(v=>v===true) ? '' : 'A=v+...'). manifest variant.definesKey
|
|
1171
|
+
// is `''` for the all-true variant, so HDRP (both axes true) must
|
|
1172
|
+
// pass the canonical empty key to hit that variant via
|
|
1173
|
+
// findVariantByKey. Passing the expanded form would produce a
|
|
1174
|
+
// miss and silently fall back to the registered default WGSL,
|
|
1175
|
+
// creating a layout/binding mismatch under HDRP.
|
|
1176
|
+
//
|
|
1177
|
+
// URP path passes the explicit expanded form because the URP
|
|
1178
|
+
// variant's manifest definesKey IS that exact non-empty string
|
|
1179
|
+
// (CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAILABLE=true)
|
|
1180
|
+
// -- the canonical-empty rule only applies to the all-true case.
|
|
1181
|
+
const hasVertexColor = entry.mesh.layoutProjection.attributes.some(
|
|
1182
|
+
(attribute) => attribute.key === 'color',
|
|
1183
|
+
);
|
|
1184
|
+
// The all-true HDRP variant uses the canonical empty key only when
|
|
1185
|
+
// every variant axis is true. A plain mesh adds the geometry-owned
|
|
1186
|
+
// VERTEX_COLOR_AVAILABLE=false axis, so retain the two capability
|
|
1187
|
+
// axes explicitly or the selector would silently choose the URP
|
|
1188
|
+
// group(2) layout for an HDRP cluster bind group.
|
|
1189
|
+
const capabilityVariantSet = standardTopologyVariantSet(
|
|
1190
|
+
c.standardLighting,
|
|
1191
|
+
runtime.device.caps.storageBuffer,
|
|
1192
|
+
hasVertexColor,
|
|
1193
|
+
probeBlendAvailable,
|
|
1194
|
+
);
|
|
1195
|
+
const transmissionAvailable = requestsStandardTransmissionVariant(submeshMaterial);
|
|
1196
|
+
const materialCapabilityVariantSet =
|
|
1197
|
+
transmissionAvailable && !capabilityVariantSet.includes('TRANSMISSION_AVAILABLE=')
|
|
1198
|
+
? `${capabilityVariantSet === '' ? '' : `${capabilityVariantSet}+`}TRANSMISSION_AVAILABLE=true`
|
|
1199
|
+
: capabilityVariantSet;
|
|
1200
|
+
// Sprite's base request must retain the boot-selected artifact. Only
|
|
1201
|
+
// SpriteInstances uses the explicit empty key for the
|
|
1202
|
+
// PER_INSTANCE_REGION=true variant; synthesizing the generic PBR
|
|
1203
|
+
// capability axes for a base sprite would invent a lazy module label
|
|
1204
|
+
// that has no boot seed and skip the first HDR draw.
|
|
1205
|
+
const variantSet = isSpriteShader
|
|
1206
|
+
? smMaterialShaderId === 'forgeax::sprite' && entry.source.spriteInstances !== undefined
|
|
1207
|
+
? ''
|
|
1208
|
+
: undefined
|
|
1209
|
+
: entry.variantSet === undefined
|
|
1210
|
+
? materialCapabilityVariantSet
|
|
1211
|
+
: capabilityVariantSet === ''
|
|
1212
|
+
? entry.variantSet
|
|
1213
|
+
: `${capabilityVariantSet}+${entry.variantSet}`;
|
|
1214
|
+
const cachedPipeline = resolveMaterialPipeline(
|
|
1215
|
+
smMaterialShaderId,
|
|
1216
|
+
pipelineRenderState,
|
|
1217
|
+
smTopology,
|
|
1218
|
+
entry.mesh.indexFormat,
|
|
1219
|
+
variantSet,
|
|
1220
|
+
colorFormatOverride,
|
|
1221
|
+
entry.mesh.layoutProjection,
|
|
1222
|
+
selectedPass?.vertexEntry,
|
|
1223
|
+
selectedPass?.fragmentEntry,
|
|
1224
|
+
);
|
|
1225
|
+
// feat-20260615-pipeline-spec-ssot M6-T1: cache miss resolves to
|
|
1226
|
+
// null uniformly across URP / HDRP / skin shaders. Charter P3
|
|
1227
|
+
// explicit failure: the pre-M6 URP-path silent fallback to the
|
|
1228
|
+
// boot-time `pipelineState.standardPipeline*` (M4.5-followup w43)
|
|
1229
|
+
// masked real PipelineSpecError build failures behind a
|
|
1230
|
+
// layout-compatible-but-wrong PSO. The per-submesh
|
|
1231
|
+
// `if (smPipelineHandle === null) continue` skip-draw (which
|
|
1232
|
+
// already covered HDRP-active and skin miss paths) is now the
|
|
1233
|
+
// single uniform recovery shape -- one frame of skip-draw on
|
|
1234
|
+
// first-touch, then the cached PSO flows in once the async
|
|
1235
|
+
// build resolves. The pre-loop skin-PSO probe still skips the
|
|
1236
|
+
// entire entry on first-submesh probe miss; this site only
|
|
1237
|
+
// fires on per-submesh topology variance miss.
|
|
1238
|
+
materialPipelineEntry = cachedPipeline;
|
|
1239
|
+
smPipelineHandle = cachedPipeline?.pipeline ?? null;
|
|
1240
|
+
} else {
|
|
1241
|
+
smPipelineHandle = selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive);
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1244
|
+
if (smPipelineHandle === null) {
|
|
1245
|
+
if (diagnosticsEnabled) {
|
|
1246
|
+
console.error(
|
|
1247
|
+
`[render-material] draw skipped: ${JSON.stringify({
|
|
1248
|
+
entityKey: entry.source.entityKey,
|
|
1249
|
+
materialHandle: submeshMaterial.materialHandle,
|
|
1250
|
+
shader: smMaterialShaderId,
|
|
1251
|
+
reason: 'pipeline-unavailable',
|
|
1252
|
+
})}`,
|
|
1048
1253
|
);
|
|
1049
|
-
materialGroup1DynamicOffsets[0] = materialSlot * MATERIAL_PER_ENTITY_STRIDE;
|
|
1050
|
-
pass.setBindGroup(1, perSubmeshBg, materialGroup1DynamicOffsets, 0, 1);
|
|
1051
|
-
const smTopology = sm.topology;
|
|
1052
|
-
const smMaterialShaderId =
|
|
1053
|
-
entry.source.skin !== undefined
|
|
1054
|
-
? isStandardPbrSkinMaterialShader(submeshMaterial.materialShaderId)
|
|
1055
|
-
? submeshMaterial.materialShaderId
|
|
1056
|
-
: SKIN_MATERIAL_SHADER_ID
|
|
1057
|
-
: submeshMaterial.materialShaderId;
|
|
1058
|
-
const probeBlendAvailable =
|
|
1059
|
-
probeBlendRecordAvailable && isStandardPbrMaterialShader(smMaterialShaderId);
|
|
1060
|
-
const isSpriteShader =
|
|
1061
|
-
smMaterialShaderId === 'forgeax::sprite' || smMaterialShaderId === 'forgeax::sprite-lit';
|
|
1062
|
-
// Preserve the dedicated sprite-pass state when the linear-LDR graph
|
|
1063
|
-
// routes a sprite through this generic geometry path. Negative scale
|
|
1064
|
-
// flips winding, so back-face culling would erase the quad.
|
|
1065
|
-
const basePipelineRenderState = isSpriteShader
|
|
1066
|
-
? {
|
|
1067
|
-
...submeshMaterial.renderState,
|
|
1068
|
-
depthWriteEnabled: false,
|
|
1069
|
-
depthCompare: 'less-equal' as const,
|
|
1070
|
-
cullMode: 'none' as const,
|
|
1071
|
-
blend: submeshMaterial.renderState?.blend ?? SPRITE_PREMULTIPLIED_ALPHA_BLEND,
|
|
1072
1254
|
}
|
|
1073
|
-
: geometryRenderStateForTopology(smTopology, submeshMaterial.renderState);
|
|
1074
|
-
const pipelineRenderState = geometryRenderStateForPass(basePipelineRenderState, passKind);
|
|
1075
|
-
let smPipelineHandle: typeof pipelineState.unlitPipeline;
|
|
1076
|
-
let materialGroup2Contract: 'mesh' | 'skin' | 'cluster' | 'skin-cluster' | undefined;
|
|
1077
|
-
let materialPipelineEntry: MaterialShaderPipelineEntry | null = null;
|
|
1078
|
-
if (smMaterialShaderId === undefined || smMaterialShaderId === 'forgeax::default-unlit') {
|
|
1079
|
-
const unlitShaderId = smMaterialShaderId ?? 'forgeax::default-unlit';
|
|
1080
|
-
const unlitProjectionVariantResult = variantSetFromVertexLayoutProjection(
|
|
1081
|
-
entry.mesh.layoutProjection,
|
|
1082
|
-
undefined,
|
|
1083
|
-
);
|
|
1084
|
-
if (!unlitProjectionVariantResult.ok) {
|
|
1085
|
-
runtime.errorRegistry.fire(unlitProjectionVariantResult.error);
|
|
1086
1255
|
continue;
|
|
1087
1256
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
entry.mesh.indexFormat,
|
|
1098
|
-
unlitVariantSet,
|
|
1099
|
-
colorFormatOverride,
|
|
1100
|
-
entry.mesh.layoutProjection,
|
|
1101
|
-
);
|
|
1102
|
-
materialPipelineEntry = unlitRsp;
|
|
1103
|
-
smPipelineHandle =
|
|
1104
|
-
unlitRsp?.pipeline ??
|
|
1105
|
-
(colorFormatOverride === undefined
|
|
1106
|
-
? selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive)
|
|
1107
|
-
: null);
|
|
1108
|
-
} else if (smMaterialShaderId !== undefined) {
|
|
1109
|
-
// feat-20260609 M4.5 / w38 (D-11): the variantSet handed to
|
|
1110
|
-
// getMaterialShaderPipeline MUST mirror the boot-time
|
|
1111
|
-
// `definesKey` rule at createRenderer.ts:2483-2485 (sortedEntries
|
|
1112
|
-
// .every(v=>v===true) ? '' : 'A=v+...'). manifest variant.definesKey
|
|
1113
|
-
// is `''` for the all-true variant, so HDRP (both axes true) must
|
|
1114
|
-
// pass the canonical empty key to hit that variant via
|
|
1115
|
-
// findVariantByKey. Passing the expanded form would produce a
|
|
1116
|
-
// miss and silently fall back to the registered default WGSL,
|
|
1117
|
-
// creating a layout/binding mismatch under HDRP.
|
|
1118
|
-
//
|
|
1119
|
-
// URP path passes the explicit expanded form because the URP
|
|
1120
|
-
// variant's manifest definesKey IS that exact non-empty string
|
|
1121
|
-
// (CLUSTER_FORWARD_AVAILABLE=false+STORAGE_BUFFER_AVAILABLE=true)
|
|
1122
|
-
// -- the canonical-empty rule only applies to the all-true case.
|
|
1123
|
-
const hasVertexColor = entry.mesh.layoutProjection.attributes.some(
|
|
1124
|
-
(attribute) => attribute.key === 'color',
|
|
1125
|
-
);
|
|
1126
|
-
// The all-true HDRP variant uses the canonical empty key only when
|
|
1127
|
-
// every variant axis is true. A plain mesh adds the geometry-owned
|
|
1128
|
-
// VERTEX_COLOR_AVAILABLE=false axis, so retain the two capability
|
|
1129
|
-
// axes explicitly or the selector would silently choose the URP
|
|
1130
|
-
// group(2) layout for an HDRP cluster bind group.
|
|
1131
|
-
const capabilityVariantSet = standardTopologyVariantSet(
|
|
1132
|
-
c.standardLighting,
|
|
1133
|
-
runtime.device.caps.storageBuffer,
|
|
1134
|
-
hasVertexColor,
|
|
1257
|
+
// The probe record is an ABI extension of the built-in Standard PBR
|
|
1258
|
+
// shaders only. RenderScene may retain a record on every projected
|
|
1259
|
+
// renderable, but unlit/custom shaders still use the one-binding
|
|
1260
|
+
// instances BGL and must never receive the probe bind group. Resolve
|
|
1261
|
+
// this per submesh so mixed-material meshes cannot cross the layouts.
|
|
1262
|
+
const instanceDraws = resolveGeometryInstanceBuffer(
|
|
1263
|
+
c,
|
|
1264
|
+
entry,
|
|
1265
|
+
identityInstanceDraws,
|
|
1135
1266
|
probeBlendAvailable,
|
|
1136
1267
|
);
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
//
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
: `${capabilityVariantSet}+${entry.variantSet}`;
|
|
1156
|
-
const cachedPipeline = resolveMaterialPipeline(
|
|
1157
|
-
smMaterialShaderId,
|
|
1158
|
-
pipelineRenderState,
|
|
1159
|
-
smTopology,
|
|
1160
|
-
entry.mesh.indexFormat,
|
|
1161
|
-
variantSet,
|
|
1162
|
-
colorFormatOverride,
|
|
1163
|
-
entry.mesh.layoutProjection,
|
|
1164
|
-
);
|
|
1165
|
-
// feat-20260615-pipeline-spec-ssot M6-T1: cache miss resolves to
|
|
1166
|
-
// null uniformly across URP / HDRP / skin shaders. Charter P3
|
|
1167
|
-
// explicit failure: the pre-M6 URP-path silent fallback to the
|
|
1168
|
-
// boot-time `pipelineState.standardPipeline*` (M4.5-followup w43)
|
|
1169
|
-
// masked real PipelineSpecError build failures behind a
|
|
1170
|
-
// layout-compatible-but-wrong PSO. The per-submesh
|
|
1171
|
-
// `if (smPipelineHandle === null) continue` skip-draw (which
|
|
1172
|
-
// already covered HDRP-active and skin miss paths) is now the
|
|
1173
|
-
// single uniform recovery shape -- one frame of skip-draw on
|
|
1174
|
-
// first-touch, then the cached PSO flows in once the async
|
|
1175
|
-
// build resolves. The pre-loop skin-PSO probe still skips the
|
|
1176
|
-
// entire entry on first-submesh probe miss; this site only
|
|
1177
|
-
// fires on per-submesh topology variance miss.
|
|
1178
|
-
materialPipelineEntry = cachedPipeline;
|
|
1179
|
-
smPipelineHandle = cachedPipeline?.pipeline ?? null;
|
|
1180
|
-
} else {
|
|
1181
|
-
smPipelineHandle = selectGeometryPipeline(pipelineState, isHdrTarget, msaaActive);
|
|
1182
|
-
}
|
|
1183
|
-
|
|
1184
|
-
if (smPipelineHandle === null) {
|
|
1185
|
-
if (diagnosticsEnabled) {
|
|
1268
|
+
if (instanceDraws === null) continue;
|
|
1269
|
+
// Standard clustered PBR variants declare the unified cluster/SSAO
|
|
1270
|
+
// group(2) layout. Unlit and other URP-layout materials must bind the
|
|
1271
|
+
// ordinary mesh group instead; choosing one group for the whole pass
|
|
1272
|
+
// makes Dawn reject an otherwise valid unlit pipeline and invalidates
|
|
1273
|
+
// the command buffer before it reaches the surface.
|
|
1274
|
+
if (!isSkinEntry) {
|
|
1275
|
+
materialGroup2Contract = materialPipelineEntry?.group2Contract;
|
|
1276
|
+
if (materialGroup2Contract === undefined) continue;
|
|
1277
|
+
const selectedGroup = selectMaterialGroup2(
|
|
1278
|
+
meshGroup2,
|
|
1279
|
+
meshBindGroup,
|
|
1280
|
+
materialGroup2Contract,
|
|
1281
|
+
);
|
|
1282
|
+
if (selectedGroup === null) continue;
|
|
1283
|
+
group2BindGroup = selectedGroup;
|
|
1284
|
+
}
|
|
1285
|
+
if (diagnosticsEnabled && submeshMaterial.textureHandles !== undefined) {
|
|
1186
1286
|
console.error(
|
|
1187
|
-
`[render-material] draw
|
|
1287
|
+
`[render-material] draw submitted: ${JSON.stringify({
|
|
1188
1288
|
entityKey: entry.source.entityKey,
|
|
1189
1289
|
materialHandle: submeshMaterial.materialHandle,
|
|
1190
1290
|
shader: smMaterialShaderId,
|
|
1191
|
-
|
|
1291
|
+
textureHandles: [...submeshMaterial.textureHandles.entries()].map(
|
|
1292
|
+
([field, handle]) => ({
|
|
1293
|
+
field,
|
|
1294
|
+
handle,
|
|
1295
|
+
}),
|
|
1296
|
+
),
|
|
1297
|
+
skin: isSkinEntry
|
|
1298
|
+
? {
|
|
1299
|
+
resourcesReady: skinResources !== null,
|
|
1300
|
+
psoReady: skinPsoProbe !== null,
|
|
1301
|
+
paletteBufferReady: skinSlice?.buffer !== undefined,
|
|
1302
|
+
paletteByteOffset: skinSlice?.byteOffset,
|
|
1303
|
+
dynamicOffsets: [...group2DynamicOffsets],
|
|
1304
|
+
}
|
|
1305
|
+
: undefined,
|
|
1306
|
+
pipelineReady: true,
|
|
1192
1307
|
})}`,
|
|
1193
1308
|
);
|
|
1194
1309
|
}
|
|
1195
|
-
|
|
1196
|
-
}
|
|
1197
|
-
// The probe record is an ABI extension of the built-in Standard PBR
|
|
1198
|
-
// shaders only. RenderScene may retain a record on every projected
|
|
1199
|
-
// renderable, but unlit/custom shaders still use the one-binding
|
|
1200
|
-
// instances BGL and must never receive the probe bind group. Resolve
|
|
1201
|
-
// this per submesh so mixed-material meshes cannot cross the layouts.
|
|
1202
|
-
const instanceDraws = resolveGeometryInstanceBuffer(
|
|
1203
|
-
c,
|
|
1204
|
-
entry,
|
|
1205
|
-
identityInstanceDraws,
|
|
1206
|
-
probeBlendAvailable,
|
|
1207
|
-
);
|
|
1208
|
-
if (instanceDraws === null) continue;
|
|
1209
|
-
// Standard clustered PBR variants declare the unified cluster/SSAO
|
|
1210
|
-
// group(2) layout. Unlit and other URP-layout materials must bind the
|
|
1211
|
-
// ordinary mesh group instead; choosing one group for the whole pass
|
|
1212
|
-
// makes Dawn reject an otherwise valid unlit pipeline and invalidates
|
|
1213
|
-
// the command buffer before it reaches the surface.
|
|
1214
|
-
if (!isSkinEntry) {
|
|
1215
|
-
materialGroup2Contract = materialPipelineEntry?.group2Contract;
|
|
1216
|
-
if (materialGroup2Contract === undefined) continue;
|
|
1217
|
-
const selectedGroup = selectMaterialGroup2(
|
|
1218
|
-
meshGroup2,
|
|
1219
|
-
meshBindGroup,
|
|
1220
|
-
materialGroup2Contract,
|
|
1221
|
-
);
|
|
1222
|
-
if (selectedGroup === null) continue;
|
|
1223
|
-
group2BindGroup = selectedGroup;
|
|
1224
|
-
}
|
|
1225
|
-
if (diagnosticsEnabled && submeshMaterial.textureHandles !== undefined) {
|
|
1226
|
-
console.error(
|
|
1227
|
-
`[render-material] draw submitted: ${JSON.stringify({
|
|
1228
|
-
entityKey: entry.source.entityKey,
|
|
1229
|
-
materialHandle: submeshMaterial.materialHandle,
|
|
1230
|
-
shader: smMaterialShaderId,
|
|
1231
|
-
textureHandles: [...submeshMaterial.textureHandles.entries()].map(
|
|
1232
|
-
([field, handle]) => ({
|
|
1233
|
-
field,
|
|
1234
|
-
handle,
|
|
1235
|
-
}),
|
|
1236
|
-
),
|
|
1237
|
-
skin: isSkinEntry
|
|
1238
|
-
? {
|
|
1239
|
-
resourcesReady: skinResources !== null,
|
|
1240
|
-
psoReady: skinPsoProbe !== null,
|
|
1241
|
-
paletteBufferReady: skinSlice?.buffer !== undefined,
|
|
1242
|
-
paletteByteOffset: skinSlice?.byteOffset,
|
|
1243
|
-
dynamicOffsets: [...group2DynamicOffsets],
|
|
1244
|
-
}
|
|
1245
|
-
: undefined,
|
|
1246
|
-
pipelineReady: true,
|
|
1247
|
-
})}`,
|
|
1248
|
-
);
|
|
1249
|
-
}
|
|
1250
|
-
pass.setBindGroup(2, group2BindGroup, group2DynamicOffsets);
|
|
1310
|
+
pass.setBindGroup(2, group2BindGroup, group2DynamicOffsets);
|
|
1251
1311
|
|
|
1252
|
-
|
|
1253
|
-
recordOcclusionCandidate(() =>
|
|
1254
|
-
submitSubmeshDraws(
|
|
1255
|
-
pass,
|
|
1256
|
-
bindingState,
|
|
1257
|
-
smPipelineHandle,
|
|
1258
|
-
instanceDraws,
|
|
1259
|
-
entry.mesh.indexed,
|
|
1260
|
-
sm.indexCount,
|
|
1261
|
-
sm.vertexCount,
|
|
1262
|
-
sm.indexOffset,
|
|
1263
|
-
),
|
|
1264
|
-
);
|
|
1265
|
-
} else {
|
|
1266
|
-
profileGeometrySegment(c, passKind, 'draw-submit', () =>
|
|
1312
|
+
if (profilePhase === undefined) {
|
|
1267
1313
|
recordOcclusionCandidate(() =>
|
|
1268
1314
|
submitSubmeshDraws(
|
|
1269
1315
|
pass,
|
|
@@ -1275,11 +1321,26 @@ export function recordGeometryDraws(
|
|
|
1275
1321
|
sm.vertexCount,
|
|
1276
1322
|
sm.indexOffset,
|
|
1277
1323
|
),
|
|
1278
|
-
)
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1324
|
+
);
|
|
1325
|
+
} else {
|
|
1326
|
+
profileGeometrySegment(c, passKind, 'draw-submit', () =>
|
|
1327
|
+
recordOcclusionCandidate(() =>
|
|
1328
|
+
submitSubmeshDraws(
|
|
1329
|
+
pass,
|
|
1330
|
+
bindingState,
|
|
1331
|
+
smPipelineHandle,
|
|
1332
|
+
instanceDraws,
|
|
1333
|
+
entry.mesh.indexed,
|
|
1334
|
+
sm.indexCount,
|
|
1335
|
+
sm.vertexCount,
|
|
1336
|
+
sm.indexOffset,
|
|
1337
|
+
),
|
|
1338
|
+
),
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
if (diagnosticsEnabled && perSubmeshBg !== null) {
|
|
1342
|
+
recordIblPipelineBinding(c, submeshMaterial, smPipelineHandle, perSubmeshBg);
|
|
1343
|
+
}
|
|
1283
1344
|
}
|
|
1284
1345
|
}
|
|
1285
1346
|
}
|