@carbonenginejs/runtime-resource 0.12.2 → 0.14.0
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 +21 -0
- package/dist/CjsResMan.js +393 -29
- package/dist/CjsResMan.js.map +1 -1
- package/dist/format/carbonEffect/CjsCarbonEffectReader.js +165 -118
- package/dist/format/carbonEffect/CjsCarbonEffectReader.js.map +1 -1
- package/dist/format/carbonEffect/buildCarbonEffectContainer.js +182 -0
- package/dist/format/carbonEffect/buildCarbonEffectContainer.js.map +1 -0
- package/dist/format/carbonEffect/carbonEffectBackendBlock.js +7 -113
- package/dist/format/carbonEffect/carbonEffectBackendBlock.js.map +1 -1
- package/dist/format/carbonEffect/carbonEffectRecords.js +258 -66
- package/dist/format/carbonEffect/carbonEffectRecords.js.map +1 -1
- package/dist/format/carbonEffect/carbonEffectResourceTransform.js +197 -0
- package/dist/format/carbonEffect/carbonEffectResourceTransform.js.map +1 -0
- package/dist/format/effect/effectBodyInventory.js +146 -0
- package/dist/format/effect/effectBodyInventory.js.map +1 -0
- package/dist/format/effect/effectPermutationGraph.js +13 -13
- package/dist/format/effect/effectPermutationGraph.js.map +1 -1
- package/dist/format/index.js +4 -4
- package/dist/formats/black/CjsBlackFormat.js +19 -1
- package/dist/formats/black/CjsBlackFormat.js.map +1 -1
- package/dist/formats/bnk/CjsBnkFormat.js +28 -9
- package/dist/formats/bnk/CjsBnkFormat.js.map +1 -1
- package/dist/formats/bnk/core/busNodes.js +252 -0
- package/dist/formats/bnk/core/busNodes.js.map +1 -0
- package/dist/formats/bnk/core/effectNodes.js +147 -0
- package/dist/formats/bnk/core/effectNodes.js.map +1 -0
- package/dist/formats/bnk/core/eventAction.js +135 -24
- package/dist/formats/bnk/core/eventAction.js.map +1 -1
- package/dist/formats/bnk/core/globalSettings.js +215 -0
- package/dist/formats/bnk/core/globalSettings.js.map +1 -0
- package/dist/formats/bnk/core/helpers.js +37 -5
- package/dist/formats/bnk/core/helpers.js.map +1 -1
- package/dist/formats/bnk/core/musicNodes.js +43 -19
- package/dist/formats/bnk/core/musicNodes.js.map +1 -1
- package/dist/formats/bnk/core/nodeBase.js +28 -7
- package/dist/formats/bnk/core/nodeBase.js.map +1 -1
- package/dist/formats/dds/core/helpers.js +40 -1
- package/dist/formats/dds/core/helpers.js.map +1 -1
- package/dist/formats/dxbc/CjsDxbcFormat.js +45 -0
- package/dist/formats/dxbc/CjsDxbcFormat.js.map +1 -1
- package/dist/formats/dxbc/core/disassemble.js +240 -0
- package/dist/formats/dxbc/core/disassemble.js.map +1 -0
- package/dist/formats/gltf/CjsGltfFormat.js +1 -39
- package/dist/formats/gltf/CjsGltfFormat.js.map +1 -1
- package/dist/formats/gltf/core/helpers.js +1 -21
- package/dist/formats/gltf/core/helpers.js.map +1 -1
- package/dist/formats/hlsl/CjsHlslFormat.js +0 -21
- package/dist/formats/hlsl/CjsHlslFormat.js.map +1 -1
- package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js +118 -49
- package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js.map +1 -1
- package/dist/formats/hlsl/core/detailMapFamily.js +128 -0
- package/dist/formats/hlsl/core/detailMapFamily.js.map +1 -0
- package/dist/formats/hlsl/core/localLightFamily.js +133 -0
- package/dist/formats/hlsl/core/localLightFamily.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js +79 -73
- package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js.map +1 -1
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectBindingManifest.js +8 -1
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectBindingManifest.js.map +1 -1
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectDescription.js +11 -691
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectDescription.js.map +1 -1
- package/dist/formats/index.js +4 -2
- package/dist/formats/index.js.map +1 -1
- package/dist/formats/obj/CjsObjFormat.js +1 -22
- package/dist/formats/obj/CjsObjFormat.js.map +1 -1
- package/dist/formats/obj/core/helpers.js +1 -21
- package/dist/formats/obj/core/helpers.js.map +1 -1
- package/dist/formats/pickle/CjsPickleFormat.js +214 -0
- package/dist/formats/pickle/CjsPickleFormat.js.map +1 -0
- package/dist/formats/pickle/core/CjsPickleProtocol0Reader.js +551 -0
- package/dist/formats/pickle/core/CjsPickleProtocol0Reader.js.map +1 -0
- package/dist/formats/pickle/index.js +2 -0
- package/dist/formats/pickle/index.js.map +1 -0
- package/dist/formats/red/core/redGraph.js +11 -8
- package/dist/formats/red/core/redGraph.js.map +1 -1
- package/dist/formats/stl/CjsStlFormat.js +1 -46
- package/dist/formats/stl/CjsStlFormat.js.map +1 -1
- package/dist/formats/stl/core/helpers.js +1 -21
- package/dist/formats/stl/core/helpers.js.map +1 -1
- package/dist/formats/webgl/CjsWebglFormat.js +33 -55
- package/dist/formats/webgl/CjsWebglFormat.js.map +1 -1
- package/dist/formats/webgl/core/buildGlslEffectContainer.js +70 -0
- package/dist/formats/webgl/core/buildGlslEffectContainer.js.map +1 -0
- package/dist/formats/webgl/core/effectPackage.js +216 -108
- package/dist/formats/webgl/core/effectPackage.js.map +1 -1
- package/dist/formats/webgl/core/errors.js +1 -1
- package/dist/formats/webgl/core/errors.js.map +1 -1
- package/dist/formats/webgl/core/glsl/DxbcGlslEmitter.js +166 -24
- package/dist/formats/webgl/core/glsl/DxbcGlslEmitter.js.map +1 -1
- package/dist/formats/webgl/core/glsl/DxbcGlslOperandFormatter.js +63 -5
- package/dist/formats/webgl/core/glsl/DxbcGlslOperandFormatter.js.map +1 -1
- package/dist/formats/webgl/core/glsl/packedLightFixups.js +98 -0
- package/dist/formats/webgl/core/glsl/packedLightFixups.js.map +1 -0
- package/dist/formats/webgl/core/glslBackendBlock.js +552 -0
- package/dist/formats/webgl/core/glslBackendBlock.js.map +1 -0
- package/dist/formats/webgl/core/glslBackendBodySet.js +243 -0
- package/dist/formats/webgl/core/glslBackendBodySet.js.map +1 -0
- package/dist/formats/webgl/core/{cewgCompleteness.js → glslEffectCompleteness.js} +12 -8
- package/dist/formats/webgl/core/glslEffectCompleteness.js.map +1 -0
- package/dist/formats/webgl/core/helpers.js +33 -172
- package/dist/formats/webgl/core/helpers.js.map +1 -1
- package/dist/formats/webgl/core/inspectGlslEffectContainer.js +122 -0
- package/dist/formats/webgl/core/inspectGlslEffectContainer.js.map +1 -0
- package/dist/formats/webgl/core/readGlslEffectContainer.js +249 -0
- package/dist/formats/webgl/core/readGlslEffectContainer.js.map +1 -0
- package/dist/formats/webgpu/CjsWebgpuFormat.js +15 -15
- package/dist/formats/webgpu/CjsWebgpuFormat.js.map +1 -1
- package/dist/formats/webgpu/core/buildCarbonEffectContainer.js +37 -145
- package/dist/formats/webgpu/core/buildCarbonEffectContainer.js.map +1 -1
- package/dist/formats/webgpu/core/{cewgpu/CewgpuContainer.js → carbonWebgpu/CarbonWebgpuContainer.js} +13 -27
- package/dist/formats/webgpu/core/carbonWebgpu/CarbonWebgpuContainer.js.map +1 -0
- package/dist/formats/webgpu/core/{cewgpu → carbonWebgpu}/containerViews.js +1 -1
- package/dist/formats/webgpu/core/carbonWebgpu/containerViews.js.map +1 -0
- package/dist/formats/webgpu/core/{cewgpu → carbonWebgpu}/validateContainer.js +4 -4
- package/dist/formats/webgpu/core/carbonWebgpu/validateContainer.js.map +1 -0
- package/dist/formats/webgpu/core/effectBackendBodySet.js +18 -18
- package/dist/formats/webgpu/core/effectBackendBodySet.js.map +1 -1
- package/dist/formats/webgpu/core/errors.js +1 -1
- package/dist/formats/webgpu/core/errors.js.map +1 -1
- package/dist/formats/webgpu/core/helpers.js +22 -22
- package/dist/formats/webgpu/core/helpers.js.map +1 -1
- package/dist/formats/webgpu/core/packageEffect.js +11 -15
- package/dist/formats/webgpu/core/packageEffect.js.map +1 -1
- package/dist/formats/webgpu/core/packageEffectSelection.js +1 -1
- package/dist/formats/webgpu/core/packageEffectSelection.js.map +1 -1
- package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js +23 -23
- package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js.map +1 -1
- package/dist/formats/webgpu/core/wgsl/buildWgslSet.js +6 -6
- package/dist/formats/webgpu/core/wgsl/buildWgslSet.js.map +1 -1
- package/dist/formats/yaml/CjsYamlFormat.js +3 -3
- package/dist/formats/yaml/CjsYamlFormat.js.map +1 -1
- package/dist/formats/yaml/core/CjsYamlReader.js +4 -6
- package/dist/formats/yaml/core/CjsYamlReader.js.map +1 -1
- package/dist/formats/yaml/core/helpers.js +27 -1
- package/dist/formats/yaml/core/helpers.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/resource/CjsLoadingObject.js +19 -0
- package/dist/resource/CjsLoadingObject.js.map +1 -0
- package/dist/resource/CjsResource.js +4 -0
- package/dist/resource/CjsResource.js.map +1 -1
- package/dist/resource/ResourceHandlerMode.js +14 -0
- package/dist/resource/ResourceHandlerMode.js.map +1 -0
- package/dist/resource/index.js +2 -0
- package/dist/resource/index.js.map +1 -1
- package/dist/resource/shader/Tr2EffectRes.js +118 -213
- package/dist/resource/shader/Tr2EffectRes.js.map +1 -1
- package/dist/resource/shader/Tr2Shader.js +37 -15
- package/dist/resource/shader/Tr2Shader.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectConstant.js +37 -29
- package/dist/resource/shader/reflection/Tr2EffectConstant.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectDescription.js +39 -34
- package/dist/resource/shader/reflection/Tr2EffectDescription.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectLibrary.js +51 -30
- package/dist/resource/shader/reflection/Tr2EffectLibrary.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js +45 -25
- package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectResource.js +51 -17
- package/dist/resource/shader/reflection/Tr2EffectResource.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectStageInput.js +219 -88
- package/dist/resource/shader/reflection/Tr2EffectStageInput.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectTechnique.js +28 -18
- package/dist/resource/shader/reflection/Tr2EffectTechnique.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2Pass.js +96 -39
- package/dist/resource/shader/reflection/Tr2Pass.js.map +1 -1
- package/dist/resource/shader/reflection/carbonRecordFields.js +159 -0
- package/dist/resource/shader/reflection/carbonRecordFields.js.map +1 -0
- package/dist/resource/shader/reflection/shaderStage.js +22 -0
- package/dist/resource/shader/reflection/shaderStage.js.map +1 -0
- package/dist/resource/shader/sampler/Tr2SamplerSetup.js +68 -10
- package/dist/resource/shader/sampler/Tr2SamplerSetup.js.map +1 -1
- package/dist/worker/CjsResManMainThreadLoader.js +9 -7
- package/dist/worker/CjsResManMainThreadLoader.js.map +1 -1
- package/dist/worker/CjsResManWorker.js +5 -4
- package/dist/worker/CjsResManWorker.js.map +1 -1
- package/dist/worker/CjsResManWorkerLoader.js +9 -6
- package/dist/worker/CjsResManWorkerLoader.js.map +1 -1
- package/docs/README.md +2 -2
- package/docs/architecture.md +12 -3
- package/docs/concepts/resource-lifecycle.md +9 -8
- package/docs/concepts/shader-resource-model.md +14 -17
- package/docs/concepts/writing-an-engine-adapter.md +1 -1
- package/docs/formats/README.md +4 -2
- package/docs/formats/carbon-effect-container.md +127 -26
- package/docs/formats/dxbc/architecture.md +1 -1
- package/docs/formats/dxbc/reference/api.md +28 -0
- package/docs/formats/hlsl/README.md +3 -3
- package/docs/formats/hlsl/architecture.md +8 -9
- package/docs/formats/hlsl/guides/hydrating-json-output.md +3 -5
- package/docs/formats/hlsl/guides/reading-effects.md +5 -1
- package/docs/formats/hlsl/reference/advanced-analysis.md +20 -25
- package/docs/formats/hlsl/reference/api.md +0 -7
- package/docs/formats/hlsl/reference/json-graph.md +1 -4
- package/docs/formats/pickle.md +82 -0
- package/docs/formats/webgl/README.md +71 -13
- package/docs/formats/webgl/architecture.md +16 -17
- package/docs/formats/webgl/carbon-constant-layouts.md +3 -3
- package/docs/formats/webgl/decl-io.md +3 -3
- package/docs/formats/webgl/memory-structured.md +27 -8
- package/docs/formats/webgl/texture-sample.md +1 -1
- package/docs/formats/webgpu/README.md +3 -3
- package/docs/formats/webgpu/architecture.md +5 -6
- package/docs/formats/webgpu/formats/{cewgpu.md → carbon-webgpu.md} +10 -11
- package/docs/formats/webgpu/guides/effect-packaging.md +6 -8
- package/docs/formats/webgpu/reference/api.md +11 -12
- package/docs/formats/webgpu/reference/wgsl-compatibility.md +11 -8
- package/docs/formats/wwise.md +63 -2
- package/docs/reference/classes/core.md +10 -0
- package/docs/reference/classes/formats.md +40 -48
- package/docs/reference/classes/resources.md +2 -2
- package/docs/reference/queues.md +88 -4
- package/docs/reference/workers.md +7 -0
- package/package.json +61 -61
- package/dist/format/carbonEffect/carbonDescriptionFromPortable.js +0 -372
- package/dist/format/carbonEffect/carbonDescriptionFromPortable.js.map +0 -1
- package/dist/format/effect/effectReflectionPackage.js +0 -636
- package/dist/format/effect/effectReflectionPackage.js.map +0 -1
- package/dist/formats/hlsl/core/HlslReader.js +0 -16
- package/dist/formats/hlsl/core/HlslReader.js.map +0 -1
- package/dist/formats/hlsl/core/portableReflection.js +0 -848
- package/dist/formats/hlsl/core/portableReflection.js.map +0 -1
- package/dist/formats/hlsl/portable.js +0 -2
- package/dist/formats/hlsl/portable.js.map +0 -1
- package/dist/formats/webgl/core/cewg/CewgPackage.js +0 -340
- package/dist/formats/webgl/core/cewg/CewgPackage.js.map +0 -1
- package/dist/formats/webgl/core/cewg/CewgPackageBuilder.js +0 -104
- package/dist/formats/webgl/core/cewg/CewgPackageBuilder.js.map +0 -1
- package/dist/formats/webgl/core/cewg/binary.js +0 -19
- package/dist/formats/webgl/core/cewg/binary.js.map +0 -1
- package/dist/formats/webgl/core/cewgCompleteness.js.map +0 -1
- package/dist/formats/webgl/core/effectPackageValidation.js +0 -331
- package/dist/formats/webgl/core/effectPackageValidation.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/CewgpuContainer.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/containerViews.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/validateContainer.js.map +0 -1
- package/dist/resource/shader/portable.js +0 -33
- package/dist/resource/shader/portable.js.map +0 -1
- package/docs/formats/hlsl/reference/portable-reflection.md +0 -141
- package/docs/formats/webgl/effect-reflection.md +0 -127
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { buildCarbonEffectContainer } from '../../../format/carbonEffect/buildCarbonEffectContainer.js';
|
|
2
|
+
import { writeGlslBackendBlock } from './glslBackendBlock.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The WebGL 2 backend adapter for the shared Carbon container builder.
|
|
6
|
+
*
|
|
7
|
+
* The record layout, the permutation walk and the description mapping are shared
|
|
8
|
+
* with WebGPU and live in `format/carbonEffect/buildCarbonEffectContainer.js`.
|
|
9
|
+
* What remains here is the two backend-varying decisions: a program is GLSL ES
|
|
10
|
+
* 3.00 text, and a pass's trailing block is the GLSL lowering data.
|
|
11
|
+
*
|
|
12
|
+
* There is no entry-point assertion to make. GLSL's entry point is `main` by
|
|
13
|
+
* language rule rather than by our emitter's choice, so unlike WGSL there is
|
|
14
|
+
* nothing a future lowerer could change.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Encodes one GLSL stage program.
|
|
19
|
+
*
|
|
20
|
+
* @param {object} shader Translated shader record.
|
|
21
|
+
* @returns {Uint8Array} Program bytes.
|
|
22
|
+
*/
|
|
23
|
+
function encodeProgram(shader) {
|
|
24
|
+
return new TextEncoder().encode(shader.code);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Builds the per-pass backend block for one pass of one translated body.
|
|
29
|
+
*
|
|
30
|
+
* A pass whose stages added no lowering data emits no block at all rather than
|
|
31
|
+
* an empty one, so the description ends where Carbon's would and the optional
|
|
32
|
+
* block stays genuinely optional.
|
|
33
|
+
*
|
|
34
|
+
* @param {object} unit Pass translation unit.
|
|
35
|
+
* @param {string} passKey Enclosing pass key.
|
|
36
|
+
* @returns {Uint8Array|null} Block bytes, or null when the pass has none.
|
|
37
|
+
*/
|
|
38
|
+
function encodeBackendBlock(unit, passKey) {
|
|
39
|
+
const stages = unit.block;
|
|
40
|
+
const transforms = (unit.resourceTransforms ?? []).filter(transform => transform.layoutKey === passKey);
|
|
41
|
+
if (!stages && !transforms.length) return null;
|
|
42
|
+
return writeGlslBackendBlock({
|
|
43
|
+
stages: stages ?? {},
|
|
44
|
+
transforms
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The WebGL encoders, as the shared builder's backend argument. */
|
|
49
|
+
const GLSL_CONTAINER_BACKEND = Object.freeze({
|
|
50
|
+
encodeProgram,
|
|
51
|
+
encodeBackendBlock
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Builds the complete WebGL 2 effect container.
|
|
56
|
+
*
|
|
57
|
+
* @param {object} effectRes Loaded version-15 `Tr2EffectRes`.
|
|
58
|
+
* @param {object} permutationGraph Validated `PGRF` document.
|
|
59
|
+
* @param {object} backendBodySet Translated GLSL bodies.
|
|
60
|
+
* @param {object} [options] Container options.
|
|
61
|
+
* @param {number[]|Uint8Array} [options.compilerVersion] Four version bytes.
|
|
62
|
+
* @param {string} [options.sourceHash] 32 ASCII hash characters.
|
|
63
|
+
* @returns {{bytes:Uint8Array, permutationCount:number, bodyCount:number}} Container and its body accounting.
|
|
64
|
+
*/
|
|
65
|
+
function buildGlslEffectContainer(effectRes, permutationGraph, backendBodySet, options = {}) {
|
|
66
|
+
return buildCarbonEffectContainer(effectRes, permutationGraph, backendBodySet, GLSL_CONTAINER_BACKEND, options);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export { GLSL_CONTAINER_BACKEND, buildGlslEffectContainer };
|
|
70
|
+
//# sourceMappingURL=buildGlslEffectContainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildGlslEffectContainer.js","sources":["../../../../../src/formats/webgl/core/buildGlslEffectContainer.js"],"sourcesContent":["import {\n buildCarbonEffectContainer\n} from \"../../../format/carbonEffect/buildCarbonEffectContainer.js\";\nimport { writeGlslBackendBlock } from \"./glslBackendBlock.js\";\n\n/**\n * The WebGL 2 backend adapter for the shared Carbon container builder.\n *\n * The record layout, the permutation walk and the description mapping are shared\n * with WebGPU and live in `format/carbonEffect/buildCarbonEffectContainer.js`.\n * What remains here is the two backend-varying decisions: a program is GLSL ES\n * 3.00 text, and a pass's trailing block is the GLSL lowering data.\n *\n * There is no entry-point assertion to make. GLSL's entry point is `main` by\n * language rule rather than by our emitter's choice, so unlike WGSL there is\n * nothing a future lowerer could change.\n */\n\n/**\n * Encodes one GLSL stage program.\n *\n * @param {object} shader Translated shader record.\n * @returns {Uint8Array} Program bytes.\n */\nfunction encodeProgram(shader)\n{\n return new TextEncoder().encode(shader.code);\n}\n\n/**\n * Builds the per-pass backend block for one pass of one translated body.\n *\n * A pass whose stages added no lowering data emits no block at all rather than\n * an empty one, so the description ends where Carbon's would and the optional\n * block stays genuinely optional.\n *\n * @param {object} unit Pass translation unit.\n * @param {string} passKey Enclosing pass key.\n * @returns {Uint8Array|null} Block bytes, or null when the pass has none.\n */\nfunction encodeBackendBlock(unit, passKey)\n{\n const stages = unit.block;\n const transforms = (unit.resourceTransforms ?? [])\n .filter((transform) => transform.layoutKey === passKey);\n\n if (!stages && !transforms.length) return null;\n\n return writeGlslBackendBlock({ stages: stages ?? {}, transforms });\n}\n\n/** The WebGL encoders, as the shared builder's backend argument. */\nexport const GLSL_CONTAINER_BACKEND = Object.freeze({ encodeProgram, encodeBackendBlock });\n\n/**\n * Builds the complete WebGL 2 effect container.\n *\n * @param {object} effectRes Loaded version-15 `Tr2EffectRes`.\n * @param {object} permutationGraph Validated `PGRF` document.\n * @param {object} backendBodySet Translated GLSL bodies.\n * @param {object} [options] Container options.\n * @param {number[]|Uint8Array} [options.compilerVersion] Four version bytes.\n * @param {string} [options.sourceHash] 32 ASCII hash characters.\n * @returns {{bytes:Uint8Array, permutationCount:number, bodyCount:number}} Container and its body accounting.\n */\nexport function buildGlslEffectContainer(\n effectRes,\n permutationGraph,\n backendBodySet,\n options = {}\n)\n{\n return buildCarbonEffectContainer(\n effectRes,\n permutationGraph,\n backendBodySet,\n GLSL_CONTAINER_BACKEND,\n options\n );\n}\n\nexport default buildGlslEffectContainer;\n"],"names":["encodeProgram","shader","TextEncoder","encode","code","encodeBackendBlock","unit","passKey","stages","block","transforms","resourceTransforms","filter","transform","layoutKey","length","writeGlslBackendBlock","GLSL_CONTAINER_BACKEND","Object","freeze","buildGlslEffectContainer","effectRes","permutationGraph","backendBodySet","options","buildCarbonEffectContainer"],"mappings":";;;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,aAAaA,CAACC,MAAM,EAC7B;EACI,OAAO,IAAIC,WAAW,EAAE,CAACC,MAAM,CAACF,MAAM,CAACG,IAAI,CAAC;AAChD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,kBAAkBA,CAACC,IAAI,EAAEC,OAAO,EACzC;AACI,EAAA,MAAMC,MAAM,GAAGF,IAAI,CAACG,KAAK;AACzB,EAAA,MAAMC,UAAU,GAAG,CAACJ,IAAI,CAACK,kBAAkB,IAAI,EAAE,EAC5CC,MAAM,CAAEC,SAAS,IAAKA,SAAS,CAACC,SAAS,KAAKP,OAAO,CAAC;EAE3D,IAAI,CAACC,MAAM,IAAI,CAACE,UAAU,CAACK,MAAM,EAAE,OAAO,IAAI;AAE9C,EAAA,OAAOC,qBAAqB,CAAC;AAAER,IAAAA,MAAM,EAAEA,MAAM,IAAI,EAAE;AAAEE,IAAAA;AAAW,GAAC,CAAC;AACtE;;AAEA;MACaO,sBAAsB,GAAGC,MAAM,CAACC,MAAM,CAAC;EAAEnB,aAAa;AAAEK,EAAAA;AAAmB,CAAC;;AAEzF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASe,wBAAwBA,CACpCC,SAAS,EACTC,gBAAgB,EAChBC,cAAc,EACdC,OAAO,GAAG,EAAE,EAEhB;EACI,OAAOC,0BAA0B,CAC7BJ,SAAS,EACTC,gBAAgB,EAChBC,cAAc,EACdN,sBAAsB,EACtBO,OACJ,CAAC;AACL;;;;"}
|
|
@@ -1,19 +1,32 @@
|
|
|
1
|
-
import { EFFECT_INFO_VERSION } from './effectPackageValidation.js';
|
|
2
1
|
import { CjsHlslFormat } from '../../hlsl/CjsHlslFormat.js';
|
|
3
2
|
import { HlslRenderContextEnum, hlslShaderStageName } from '../../hlsl/core/tr2/HlslRenderContextEnum.js';
|
|
4
|
-
import '../../../format/CjsByteReader.js';
|
|
5
3
|
import '@carbonenginejs/runtime-utils/bytes';
|
|
6
|
-
import '../../hlsl/core/
|
|
4
|
+
import '../../hlsl/core/carbonDescriptionToRuntime.js';
|
|
5
|
+
import '../../../format/CjsByteReader.js';
|
|
6
|
+
import '../../../format/compareUtf8.js';
|
|
7
7
|
import { HlslEffectBindingManifest } from '../../hlsl/core/tr2/shader/HlslEffectBindingManifest.js';
|
|
8
8
|
import { buildEffectPermutationGraph, EFFECT_PERMUTATION_GRAPH_VERSION, EFFECT_PERMUTATION_GRAPH_FORMAT, EFFECT_PERMUTATION_GRAPH_CHUNK } from '../../../format/effect/effectPermutationGraph.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { emitGlslWithOptions } from './helpers.js';
|
|
10
|
+
import { inspectGlslEffectContainer } from './inspectGlslEffectContainer.js';
|
|
11
|
+
import { inspectRasterCompleteness } from './glslEffectCompleteness.js';
|
|
12
|
+
import { recogniseDetailMapFamily } from '../../hlsl/core/detailMapFamily.js';
|
|
13
|
+
import { stripLocalLightBindings, recogniseLocalLightFamily } from '../../hlsl/core/localLightFamily.js';
|
|
14
|
+
import { buildGlslBackendBodySet } from './glslBackendBodySet.js';
|
|
15
|
+
import { buildGlslEffectContainer } from './buildGlslEffectContainer.js';
|
|
11
16
|
import { sha256Utf8, sha256Bytes } from '../../../format/effect/sha256.js';
|
|
12
17
|
|
|
18
|
+
/**
|
|
19
|
+
* INFO record version for the in-memory build result.
|
|
20
|
+
*
|
|
21
|
+
* This lived in effectPackageValidation.js, which validated a written chunk
|
|
22
|
+
* package by reading it back. There is no chunk package to read back, so that
|
|
23
|
+
* file is gone and its one surviving constant lives with its only user.
|
|
24
|
+
*/
|
|
25
|
+
const EFFECT_INFO_VERSION = 3;
|
|
13
26
|
const PACKAGE_VERSION = "0.11.1";
|
|
14
27
|
|
|
15
28
|
/**
|
|
16
|
-
* Builds a complete
|
|
29
|
+
* Builds a complete Carbon WebGL package from compiled Tr2 effect bytes.
|
|
17
30
|
*
|
|
18
31
|
* This browser-safe path owns whole-effect selection, stage translation,
|
|
19
32
|
* package assembly, and structural qualification. Filesystem and native-tool
|
|
@@ -39,10 +52,6 @@ function buildEffectPackage(input, options = {}) {
|
|
|
39
52
|
throw new Error("Effect package requires a version-15 compiled effect, got version " + (effectRes.m_version ?? "unknown"));
|
|
40
53
|
}
|
|
41
54
|
const permutationGraph = buildEffectPermutationGraph(effectRes);
|
|
42
|
-
const reflectionPackage = effectRes.m_version === 15 ? buildCompleteEffectReflection(effectRes, permutationGraph, {
|
|
43
|
-
sourceIdentity,
|
|
44
|
-
sourcePath: values.source
|
|
45
|
-
}) : null;
|
|
46
55
|
const variants = buildExportVariants(effectRes, values.allPermutations);
|
|
47
56
|
const bodyMap = new Map();
|
|
48
57
|
const stageMap = new Map();
|
|
@@ -73,7 +82,9 @@ function buildEffectPackage(input, options = {}) {
|
|
|
73
82
|
bodySize: variant.bodySize,
|
|
74
83
|
firstVariantKey: variant.key,
|
|
75
84
|
error: collection.errors.length ? collection.errors.join("; ") : null,
|
|
76
|
-
|
|
85
|
+
// Dropping the light family removes its declarations from the
|
|
86
|
+
// shader, so the manifest must stop advertising them too.
|
|
87
|
+
manifest: values.localLights === "drop" ? stripLocalLightBindings(manifest.toJSON()) : manifest.toJSON(),
|
|
77
88
|
stages: []
|
|
78
89
|
};
|
|
79
90
|
for (const stage of collection.stages) {
|
|
@@ -104,6 +115,8 @@ function buildEffectPackage(input, options = {}) {
|
|
|
104
115
|
shaderSize: stage.bytecode.shaderSize,
|
|
105
116
|
stringTableOffset: stage.bytecode.stringTableOffset,
|
|
106
117
|
bytes: stage.bytecode.bytes,
|
|
118
|
+
detailMapArray: stage.detailMapArray,
|
|
119
|
+
localLights: stage.localLights,
|
|
107
120
|
contracts: [{
|
|
108
121
|
stageKey,
|
|
109
122
|
techniqueName: stage.techniqueName,
|
|
@@ -130,10 +143,15 @@ function buildEffectPackage(input, options = {}) {
|
|
|
130
143
|
const failedShaders = translatedShaders.filter(record => !record.hlsl2webgl?.ok && !record.excluded);
|
|
131
144
|
const excludedShaders = translatedShaders.filter(record => record.excluded);
|
|
132
145
|
const failedBodies = bodies.filter(body => body.error);
|
|
146
|
+
// The same rule the validator applies to a finished file. This function used
|
|
147
|
+
// to carry its own copy, and the two had already drifted: the local one had
|
|
148
|
+
// dropped `hlsl2webgl.reason` from its reason chain, so the library and the
|
|
149
|
+
// validator could describe one incomplete pass two different ways. If two
|
|
150
|
+
// places must agree, one of them calls the other.
|
|
133
151
|
const rasterCompleteness = inspectRasterCompleteness(stages, translatedShaders);
|
|
134
152
|
const availableShaderCount = translatedShaders.filter(record => record.hlsl2webgl?.ok && record.source).length;
|
|
135
153
|
const info = {
|
|
136
|
-
format: "
|
|
154
|
+
format: "CARBON_WEBGL",
|
|
137
155
|
formatVersion: EFFECT_INFO_VERSION,
|
|
138
156
|
packageKind: values.allPermutations ? "tr2-effect-webgl-permutations" : "tr2-effect-webgl",
|
|
139
157
|
targetBackend: "webgl",
|
|
@@ -154,11 +172,9 @@ function buildEffectPackage(input, options = {}) {
|
|
|
154
172
|
permutationMode: values.allPermutations ? "all" : "selected",
|
|
155
173
|
defaultPermutationIndex: defaultPermutationIndex(effectRes.m_permutations),
|
|
156
174
|
sourceEffectVersion: effectRes.m_version,
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
backendProgramCoverage: selectionCoversWholeEffect(values.selection) ? "all-stages" : "filtered"
|
|
161
|
-
} : {}),
|
|
175
|
+
sourceBodyCoverage: "all-unique",
|
|
176
|
+
backendBodyCoverage: values.allPermutations ? "all" : "selected",
|
|
177
|
+
backendProgramCoverage: selectionCoversWholeEffect(values.selection) ? "all-stages" : "filtered",
|
|
162
178
|
permutationCount: variants.length,
|
|
163
179
|
uniqueBodyCount: bodies.length,
|
|
164
180
|
sourcePermutationCount: permutationGraph.variants.length,
|
|
@@ -171,9 +187,6 @@ function buildEffectPackage(input, options = {}) {
|
|
|
171
187
|
permutationCount: permutationGraph.variants.length,
|
|
172
188
|
uniqueBodyCount: permutationGraph.bodies.length
|
|
173
189
|
},
|
|
174
|
-
...(reflectionPackage ? {
|
|
175
|
-
effectReflection: reflectionPackage.pointer
|
|
176
|
-
} : {}),
|
|
177
190
|
bodyStageCount: stages.length,
|
|
178
191
|
uniqueShaderCount: translatedShaders.length,
|
|
179
192
|
translatedShaderCount: translatedShaders.length - failedShaders.length - excludedShaders.length,
|
|
@@ -187,7 +200,7 @@ function buildEffectPackage(input, options = {}) {
|
|
|
187
200
|
allowFailures: values.allowFailures,
|
|
188
201
|
completeness: {
|
|
189
202
|
packageValid: true,
|
|
190
|
-
sourceComplete:
|
|
203
|
+
sourceComplete: effectRes.m_version === 15,
|
|
191
204
|
backendComplete: false,
|
|
192
205
|
runtimeComplete: false
|
|
193
206
|
}
|
|
@@ -208,7 +221,7 @@ function buildEffectPackage(input, options = {}) {
|
|
|
208
221
|
}))
|
|
209
222
|
};
|
|
210
223
|
const glsl = {
|
|
211
|
-
format: "
|
|
224
|
+
format: "CARBON_WEBGL_GLSL_SET",
|
|
212
225
|
formatVersion: 1,
|
|
213
226
|
language: "es300",
|
|
214
227
|
permutationMode: info.permutationMode,
|
|
@@ -237,23 +250,40 @@ function buildEffectPackage(input, options = {}) {
|
|
|
237
250
|
availableShaderCount
|
|
238
251
|
});
|
|
239
252
|
if (!qualification.ok && !values.allowFailures) {
|
|
240
|
-
throw new Error(`
|
|
241
|
-
}
|
|
242
|
-
const chunks = [["INFO", info], ["META", metadata], [EFFECT_PERMUTATION_GRAPH_CHUNK, permutationGraph], ...(reflectionPackage ? [[EFFECT_REFLECTION_CHUNK, reflectionPackage.reflection], [EFFECT_REFLECTION_BLOB_CHUNK, reflectionPackage.blobBytes]] : []), ["GLSL", glsl]];
|
|
243
|
-
if (values.includeSourceEffect) {
|
|
244
|
-
chunks.push(["TR2E", values.sourceBytes]);
|
|
253
|
+
throw new Error(`Carbon WebGL target is incomplete; output was not built. ${qualification.errors.join("; ")}`);
|
|
245
254
|
}
|
|
246
|
-
|
|
247
|
-
|
|
255
|
+
|
|
256
|
+
// The container is the effect. `bytes` is its bytes, and there is no second
|
|
257
|
+
// artifact — the chunk package this function used to build alongside it is
|
|
258
|
+
// gone, along with the chunk assembly that produced it.
|
|
259
|
+
//
|
|
260
|
+
// `info`, `metadata`, `glsl` and `permutationGraph` are still returned.
|
|
261
|
+
// They are the in-memory build result, which is richer than
|
|
262
|
+
// anything the wire carries: the reasons a translation failed live there and
|
|
263
|
+
// nowhere else. What changed is that they are no longer *also* serialised
|
|
264
|
+
// into tagged chunks beside the container.
|
|
265
|
+
const backendBodySet = buildGlslBackendBodySet({
|
|
266
|
+
bodies,
|
|
267
|
+
stages,
|
|
268
|
+
shaders: translatedShaders,
|
|
269
|
+
variants,
|
|
270
|
+
permutationGraph
|
|
271
|
+
});
|
|
272
|
+
const container = buildGlslEffectContainer(effectRes, permutationGraph, backendBodySet, {
|
|
273
|
+
compilerVersion: effectRes.m_compilerVersionBytes
|
|
274
|
+
});
|
|
275
|
+
const bytes = container.bytes;
|
|
276
|
+
const inspection = inspectGlslEffectContainer(bytes, {
|
|
248
277
|
source: values.source
|
|
249
278
|
});
|
|
250
279
|
return Object.freeze({
|
|
251
280
|
bytes,
|
|
281
|
+
permutationCount: container.permutationCount,
|
|
282
|
+
bodyCount: container.bodyCount,
|
|
283
|
+
backendBodySet,
|
|
252
284
|
info: Object.freeze(info),
|
|
253
285
|
metadata: Object.freeze(metadata),
|
|
254
286
|
permutationGraph,
|
|
255
|
-
reflection: reflectionPackage?.reflection ?? null,
|
|
256
|
-
reflectionBlobs: reflectionPackage?.blobBytes ?? null,
|
|
257
287
|
glsl: Object.freeze(glsl),
|
|
258
288
|
inspection: Object.freeze(inspection),
|
|
259
289
|
qualification: Object.freeze(qualification)
|
|
@@ -261,7 +291,7 @@ function buildEffectPackage(input, options = {}) {
|
|
|
261
291
|
}
|
|
262
292
|
function normalizeOptions(input, options) {
|
|
263
293
|
if (!options || typeof options !== "object" || Array.isArray(options)) {
|
|
264
|
-
throw new TypeError("
|
|
294
|
+
throw new TypeError("Carbon WebGL effect options must be an object");
|
|
265
295
|
}
|
|
266
296
|
const sourceBytes = toBytes(input);
|
|
267
297
|
const source = String(options.source ?? "memory").trim() || "memory";
|
|
@@ -271,24 +301,36 @@ function normalizeOptions(input, options) {
|
|
|
271
301
|
stage: options.stage === undefined || options.stage === null ? null : String(options.stage).toLowerCase()
|
|
272
302
|
});
|
|
273
303
|
if (selection.pass !== null && (!Number.isSafeInteger(selection.pass) || selection.pass < 0)) {
|
|
274
|
-
throw new TypeError("
|
|
304
|
+
throw new TypeError("Carbon WebGL effect pass must be a non-negative integer or null");
|
|
275
305
|
}
|
|
276
306
|
if (selection.stage !== null && !["vertex", "pixel", "compute"].includes(selection.stage)) {
|
|
277
|
-
throw new TypeError(`Unsupported
|
|
307
|
+
throw new TypeError(`Unsupported Carbon WebGL effect stage: ${selection.stage}`);
|
|
278
308
|
}
|
|
279
309
|
if (options.emitterOptions !== undefined && (!options.emitterOptions || typeof options.emitterOptions !== "object" || Array.isArray(options.emitterOptions))) {
|
|
280
|
-
throw new TypeError("
|
|
310
|
+
throw new TypeError("Carbon WebGL emitterOptions must be an object");
|
|
281
311
|
}
|
|
282
312
|
return {
|
|
283
313
|
sourceBytes,
|
|
284
314
|
source,
|
|
285
|
-
outputPath: normalizeOptionalString(options.outputPath, "
|
|
315
|
+
outputPath: normalizeOptionalString(options.outputPath, "Carbon WebGL outputPath"),
|
|
286
316
|
sourceIdentity: options.sourceIdentity ?? null,
|
|
287
317
|
generatedAt: options.generatedAt === undefined || options.generatedAt === null ? null : new Date(options.generatedAt).toISOString(),
|
|
288
318
|
allPermutations: options.allPermutations !== false,
|
|
289
319
|
allowFailures: options.allowFailures === true,
|
|
290
|
-
includeSourceEffect: options.includeSourceEffect === true,
|
|
291
320
|
selection,
|
|
321
|
+
// How to lower a recognised local-light family. Defaults to leaving it
|
|
322
|
+
// alone, so a caller that does not ask gets the shader's own resources
|
|
323
|
+
// and the honest texture count.
|
|
324
|
+
localLights: normalizeLocalLightMode(options.localLights),
|
|
325
|
+
// Whether to keep `LightProfileArray`. Defaults to dropping it, because
|
|
326
|
+
// it costs a fragment sampler unit that the quad family does not have
|
|
327
|
+
// to spare, and because nothing currently selects a profile: the index
|
|
328
|
+
// lives in flags bits 4-15 and every `GetCarbonLightData()` writes only
|
|
329
|
+
// bit 0, so the shader's own guard skips the lookup for every light. A
|
|
330
|
+
// dropped profile is therefore observationally identical today and a
|
|
331
|
+
// real loss only once profile indices are written.
|
|
332
|
+
// See /docs/contracts/carbon-light-data.md.
|
|
333
|
+
lightProfile: normalizeLightProfileMode(options.lightProfile),
|
|
292
334
|
emitterOptions: {
|
|
293
335
|
...(options.emitterOptions ?? {})
|
|
294
336
|
}
|
|
@@ -317,7 +359,7 @@ function toBytes(input) {
|
|
|
317
359
|
if (ArrayBuffer.isView(input)) {
|
|
318
360
|
return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
|
|
319
361
|
}
|
|
320
|
-
throw new TypeError("
|
|
362
|
+
throw new TypeError("Carbon WebGL effect input must be Uint8Array, ArrayBuffer, or ArrayBufferView bytes");
|
|
321
363
|
}
|
|
322
364
|
function defaultPermutationIndex(permutations) {
|
|
323
365
|
let multiplier = 1;
|
|
@@ -428,7 +470,12 @@ function collectStages(effectDescription, selection) {
|
|
|
428
470
|
resources: mapToJson(stageInput.resources),
|
|
429
471
|
samplers: mapToJson(stageInput.samplers),
|
|
430
472
|
uavs: mapToJson(stageInput.uavs),
|
|
431
|
-
constants: cloneJson(stageInput.constants ?? [])
|
|
473
|
+
constants: cloneJson(stageInput.constants ?? []),
|
|
474
|
+
// Recognised from reflection here, applied by the emitter.
|
|
475
|
+
// The recogniser is shared with WebGPU so both backends
|
|
476
|
+
// merge exactly the same registers.
|
|
477
|
+
detailMapArray: recogniseDetailMapFamily(mapToJson(stageInput.resources)),
|
|
478
|
+
localLights: recogniseLocalLightFamily(mapToJson(stageInput.resources))
|
|
432
479
|
});
|
|
433
480
|
}
|
|
434
481
|
if (!selection.stage && declaredStageCount === 0) {
|
|
@@ -441,15 +488,137 @@ function collectStages(effectDescription, selection) {
|
|
|
441
488
|
errors
|
|
442
489
|
};
|
|
443
490
|
}
|
|
491
|
+
|
|
492
|
+
/** Local-light lowering modes this packager accepts. */
|
|
493
|
+
const LOCAL_LIGHT_MODES = Object.freeze(["none", "packed-texture", "constant-buffer", "drop"]);
|
|
494
|
+
|
|
495
|
+
/** How `LightProfileArray` is treated. */
|
|
496
|
+
const LIGHT_PROFILE_MODES = Object.freeze(["drop", "keep"]);
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Normalizes the light-profile mode.
|
|
500
|
+
*
|
|
501
|
+
* @param {string|undefined|null} value Requested mode.
|
|
502
|
+
* @returns {string} Normalized mode.
|
|
503
|
+
*/
|
|
504
|
+
function normalizeLightProfileMode(value) {
|
|
505
|
+
const mode = value === undefined || value === null ? "drop" : String(value);
|
|
506
|
+
if (!LIGHT_PROFILE_MODES.includes(mode)) {
|
|
507
|
+
throw new TypeError(`Carbon WebGL lightProfile must be one of ${LIGHT_PROFILE_MODES.join(", ")}; got "${mode}"`);
|
|
508
|
+
}
|
|
509
|
+
return mode;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Emitter options that drop `LightProfileArray` and neutralise its samples.
|
|
514
|
+
*
|
|
515
|
+
* Only applies when the local-light family is left alone. `packed-texture`,
|
|
516
|
+
* `constant-buffer` and `drop` each already decide what happens to the profile
|
|
517
|
+
* register, and asking for it twice would either be redundant or fight them.
|
|
518
|
+
*
|
|
519
|
+
* @param {object|null} plan Recognised local-light family, if any.
|
|
520
|
+
* @param {string} localLightMode Normalized local-light mode.
|
|
521
|
+
* @param {string} profileMode Normalized light-profile mode.
|
|
522
|
+
* @returns {object|null} Emitter options, or null when nothing to do.
|
|
523
|
+
*/
|
|
524
|
+
function lightProfileEmitterOptions(plan, localLightMode, profileMode) {
|
|
525
|
+
if (profileMode !== "drop" || localLightMode !== "none") return null;
|
|
526
|
+
if (!Number.isInteger(plan?.profileRegister)) return null;
|
|
527
|
+
return {
|
|
528
|
+
neutralResourceRegisters: [plan.profileRegister]
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Normalizes the local-light lowering mode.
|
|
534
|
+
*
|
|
535
|
+
* @param {string|undefined|null} value Requested mode.
|
|
536
|
+
* @returns {string} Normalized mode.
|
|
537
|
+
*/
|
|
538
|
+
function normalizeLocalLightMode(value) {
|
|
539
|
+
if (value === undefined || value === null) return "none";
|
|
540
|
+
const mode = String(value);
|
|
541
|
+
if (!LOCAL_LIGHT_MODES.includes(mode)) {
|
|
542
|
+
throw new TypeError(`Carbon WebGL localLights must be one of ${LOCAL_LIGHT_MODES.join(", ")}; got "${mode}"`);
|
|
543
|
+
}
|
|
544
|
+
return mode;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Builds the emitter profile that lowers a recognised local-light family.
|
|
549
|
+
*
|
|
550
|
+
* Carbon's local lights are two structured buffers plus an optional profile
|
|
551
|
+
* texture. WebGL 2 has no structured buffers, so one of these lowerings is
|
|
552
|
+
* required for the shader to bind its lights at all; WebGPU needs none of it and
|
|
553
|
+
* binds them natively.
|
|
554
|
+
*
|
|
555
|
+
* The constants here match the CLI packager's resolvers exactly, so the two
|
|
556
|
+
* pipelines produce identical output while they still both exist. They are not
|
|
557
|
+
* endorsements: `dataTexelBase` and `capacity` are values that happened to work,
|
|
558
|
+
* and the constant-buffer route is known to fail on light count.
|
|
559
|
+
*
|
|
560
|
+
* @param {object} plan Recognised local-light family.
|
|
561
|
+
* @param {string} mode Lowering mode.
|
|
562
|
+
* @returns {object|null} Emitter options fragment, or null when not lowering.
|
|
563
|
+
*/
|
|
564
|
+
function localLightEmitterOptions(plan, mode) {
|
|
565
|
+
if (!plan || mode === "none") return null;
|
|
566
|
+
if (mode === "drop") {
|
|
567
|
+
// No lighting at all: the declarations go and every read lowers to zero.
|
|
568
|
+
// Kept because isolating a lighting problem is easier without lights,
|
|
569
|
+
// not because the texture budget needs it any more.
|
|
570
|
+
return {
|
|
571
|
+
stubResourceRegisters: plan.registers
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
if (mode === "packed-texture") {
|
|
575
|
+
return {
|
|
576
|
+
lightPackedTexture: {
|
|
577
|
+
indexRegister: plan.indexRegister,
|
|
578
|
+
dataRegister: plan.dataRegister,
|
|
579
|
+
profileRegister: plan.profileRegister,
|
|
580
|
+
registerIndex: plan.indexRegister,
|
|
581
|
+
name: "cjsLocalLightTexture",
|
|
582
|
+
dataTexelBase: 131072
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
if (mode === "constant-buffer") {
|
|
587
|
+
// Slot 6 is `g_uiTransforms` in the constant-buffer slot contract. There
|
|
588
|
+
// is no collision on space-object shaders, which carry no UI transforms,
|
|
589
|
+
// but this is squatting on a reserved number and should move.
|
|
590
|
+
return {
|
|
591
|
+
lightConstantBuffer: {
|
|
592
|
+
indexRegister: plan.indexRegister,
|
|
593
|
+
dataRegister: plan.dataRegister,
|
|
594
|
+
profileRegister: plan.profileRegister,
|
|
595
|
+
registerIndex: 6,
|
|
596
|
+
name: "cb6",
|
|
597
|
+
capacity: 40
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
throw new Error(`Unknown local-light lowering mode "${mode}"`);
|
|
602
|
+
}
|
|
444
603
|
function translateStages(shaderMap, stageMap, values) {
|
|
445
604
|
const emitInto = (record, pairVaryings) => {
|
|
446
605
|
try {
|
|
606
|
+
const profileNeutral = lightProfileEmitterOptions(record.localLights, values.localLights, values.lightProfile);
|
|
607
|
+
// Remembered on the record so the body set can emit the resource
|
|
608
|
+
// transform that accounts for the dropped resource. The transform's
|
|
609
|
+
// identity includes the pass key, which is not known here.
|
|
610
|
+
if (profileNeutral) record.lightProfileNeutral = record.localLights;
|
|
447
611
|
const result = emitGlslWithOptions(record.bytes, {
|
|
448
612
|
...values.emitterOptions,
|
|
449
613
|
source: `${values.source}#${record.firstStageKey}`,
|
|
450
614
|
...(pairVaryings?.length ? {
|
|
451
615
|
pairVaryings
|
|
452
|
-
} : {})
|
|
616
|
+
} : {}),
|
|
617
|
+
...(record.detailMapArray ? {
|
|
618
|
+
detailMapArrayRegisters: record.detailMapArray.registers
|
|
619
|
+
} : {}),
|
|
620
|
+
...(localLightEmitterOptions(record.localLights, values.localLights) ?? {}),
|
|
621
|
+
...(profileNeutral ?? {})
|
|
453
622
|
});
|
|
454
623
|
const stageInterface = normalizeBitangentStageInterface(result, record);
|
|
455
624
|
record.emit = {
|
|
@@ -662,80 +831,19 @@ function validateStageSourceShape(record) {
|
|
|
662
831
|
if (record.stageName === "pixel" && (hasVertexOutput || hasVertexInterface) && !hasFragmentOutput) {
|
|
663
832
|
return "pixel stage source looks like vertex GLSL";
|
|
664
833
|
}
|
|
665
|
-
if (record.stageName === "compute" && !/\
|
|
666
|
-
return "compute stage source does not write any
|
|
834
|
+
if (record.stageName === "compute" && !/\bcjsUav\d+(_s\d+)?\b/u.test(source)) {
|
|
835
|
+
return "compute stage source does not write any cjsUav output";
|
|
667
836
|
}
|
|
668
837
|
return null;
|
|
669
838
|
}
|
|
670
|
-
function inspectRasterCompleteness(stages, shaders) {
|
|
671
|
-
const shaderMap = new Map(shaders.map(shader => [shader.key, shader]));
|
|
672
|
-
const groups = new Map();
|
|
673
|
-
for (const stage of stages) {
|
|
674
|
-
if (!["vertex", "pixel"].includes(stage.stageName)) {
|
|
675
|
-
continue;
|
|
676
|
-
}
|
|
677
|
-
const key = `${stage.bodyKey}:${stage.techniqueName}:${stage.passIndex}`;
|
|
678
|
-
const group = groups.get(key) ?? {
|
|
679
|
-
key,
|
|
680
|
-
bodyKey: stage.bodyKey,
|
|
681
|
-
techniqueName: stage.techniqueName,
|
|
682
|
-
passIndex: stage.passIndex,
|
|
683
|
-
vertex: null,
|
|
684
|
-
pixel: null,
|
|
685
|
-
duplicateStages: []
|
|
686
|
-
};
|
|
687
|
-
if (group[stage.stageName]) {
|
|
688
|
-
group.duplicateStages.push(stage.stageName);
|
|
689
|
-
}
|
|
690
|
-
group[stage.stageName] = stage;
|
|
691
|
-
groups.set(key, group);
|
|
692
|
-
}
|
|
693
|
-
const incompletePasses = [];
|
|
694
|
-
let completePassCount = 0;
|
|
695
|
-
for (const group of groups.values()) {
|
|
696
|
-
const missingStages = [];
|
|
697
|
-
const unavailableStages = [];
|
|
698
|
-
for (const stageName of ["vertex", "pixel"]) {
|
|
699
|
-
const stage = group[stageName];
|
|
700
|
-
if (!stage) {
|
|
701
|
-
missingStages.push(stageName);
|
|
702
|
-
continue;
|
|
703
|
-
}
|
|
704
|
-
const shader = shaderMap.get(stage.shaderKey);
|
|
705
|
-
if (!shader?.hlsl2webgl?.ok || !shader.source) {
|
|
706
|
-
unavailableStages.push({
|
|
707
|
-
stageName,
|
|
708
|
-
stageKey: stage.key,
|
|
709
|
-
shaderKey: stage.shaderKey,
|
|
710
|
-
reason: shader?.hlsl2webgl?.validationError || shader?.hlsl2webgl?.error || shader?.excluded?.reason || "translated source is unavailable"
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
}
|
|
714
|
-
if (!missingStages.length && !unavailableStages.length && !group.duplicateStages.length) {
|
|
715
|
-
completePassCount++;
|
|
716
|
-
} else {
|
|
717
|
-
incompletePasses.push({
|
|
718
|
-
...group,
|
|
719
|
-
missingStages,
|
|
720
|
-
unavailableStages,
|
|
721
|
-
duplicateStages: [...new Set(group.duplicateStages)].sort()
|
|
722
|
-
});
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
return {
|
|
726
|
-
expectedPassCount: groups.size,
|
|
727
|
-
completePassCount,
|
|
728
|
-
incompletePasses
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
839
|
function normalizeSourceIdentity(values) {
|
|
732
840
|
const identity = values.sourceIdentity;
|
|
733
841
|
if (identity !== null && (!identity || typeof identity !== "object" || Array.isArray(identity))) {
|
|
734
|
-
throw new TypeError("
|
|
842
|
+
throw new TypeError("Carbon WebGL sourceIdentity must be an object");
|
|
735
843
|
}
|
|
736
844
|
const sha256 = sha256Bytes(values.sourceBytes);
|
|
737
845
|
if (identity?.sha256 !== undefined && identity?.sha256 !== null && identity.sha256 !== sha256) {
|
|
738
|
-
throw new Error("
|
|
846
|
+
throw new Error("Carbon WebGL sourceIdentity.sha256 does not match the exact effect input bytes");
|
|
739
847
|
}
|
|
740
848
|
return Object.freeze({
|
|
741
849
|
filePath: identity?.filePath ?? values.source,
|
|
@@ -759,11 +867,11 @@ function qualifyEffectPackage({
|
|
|
759
867
|
availableShaderCount
|
|
760
868
|
}) {
|
|
761
869
|
const errors = [];
|
|
762
|
-
if (info.format !== "
|
|
763
|
-
errors.push("invalid
|
|
870
|
+
if (info.format !== "CARBON_WEBGL" || glsl.format !== "CARBON_WEBGL_GLSL_SET") {
|
|
871
|
+
errors.push("invalid Carbon WebGL package envelope");
|
|
764
872
|
}
|
|
765
873
|
if (!Array.isArray(metadata.variants) || !Array.isArray(glsl.shaders)) {
|
|
766
|
-
errors.push("missing
|
|
874
|
+
errors.push("missing Carbon WebGL graph arrays");
|
|
767
875
|
}
|
|
768
876
|
if (failedShaders.length) {
|
|
769
877
|
errors.push(`${failedShaders.length} shader translation(s) failed`);
|