@carbonenginejs/runtime-resource 0.10.0 → 0.11.1
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/dist/format/effect/effectPermutationGraph.js +257 -0
- package/dist/format/effect/effectPermutationGraph.js.map +1 -0
- package/dist/format/effect/effectReflectionPackage.js +636 -0
- package/dist/format/effect/effectReflectionPackage.js.map +1 -0
- package/dist/format/effect/sha256.js +114 -0
- package/dist/format/effect/sha256.js.map +1 -0
- package/dist/formats/dxbc/CjsDxbcFormat.js +142 -0
- package/dist/formats/dxbc/CjsDxbcFormat.js.map +1 -0
- package/dist/formats/dxbc/core/DxbcReader.js +266 -0
- package/dist/formats/dxbc/core/DxbcReader.js.map +1 -0
- package/dist/formats/dxbc/core/container.js +169 -0
- package/dist/formats/dxbc/core/container.js.map +1 -0
- package/dist/formats/dxbc/core/decoder.js +789 -0
- package/dist/formats/dxbc/core/decoder.js.map +1 -0
- package/dist/formats/dxbc/core/errors.js +19 -0
- package/dist/formats/dxbc/core/errors.js.map +1 -0
- package/dist/formats/dxbc/core/helpers.js +220 -0
- package/dist/formats/dxbc/core/helpers.js.map +1 -0
- package/dist/formats/dxbc/core/opcodes.js +45 -0
- package/dist/formats/dxbc/core/opcodes.js.map +1 -0
- package/dist/formats/dxbc/core/program.js +91 -0
- package/dist/formats/dxbc/core/program.js.map +1 -0
- package/dist/formats/dxbc/core/signature.js +172 -0
- package/dist/formats/dxbc/core/signature.js.map +1 -0
- package/dist/formats/dxbc/index.js +2 -0
- package/dist/formats/dxbc/index.js.map +1 -0
- package/dist/formats/hlsl/CjsHlslFormat.js +254 -0
- package/dist/formats/hlsl/CjsHlslFormat.js.map +1 -0
- package/dist/formats/hlsl/core/HlslBinaryUtils.js +15 -0
- package/dist/formats/hlsl/core/HlslBinaryUtils.js.map +1 -0
- package/dist/formats/hlsl/core/HlslEffectReadError.js +19 -0
- package/dist/formats/hlsl/core/HlslEffectReadError.js.map +1 -0
- package/dist/formats/hlsl/core/HlslEffectStateManager.js +130 -0
- package/dist/formats/hlsl/core/HlslEffectStateManager.js.map +1 -0
- package/dist/formats/hlsl/core/HlslReader.js +266 -0
- package/dist/formats/hlsl/core/HlslReader.js.map +1 -0
- package/dist/formats/hlsl/core/HlslRenderStateSetup.js +37 -0
- package/dist/formats/hlsl/core/HlslRenderStateSetup.js.map +1 -0
- package/dist/formats/hlsl/core/HlslResourceSetDescription.js +94 -0
- package/dist/formats/hlsl/core/HlslResourceSetDescription.js.map +1 -0
- package/dist/formats/hlsl/core/HlslShaderBytecode.js +44 -0
- package/dist/formats/hlsl/core/HlslShaderBytecode.js.map +1 -0
- package/dist/formats/hlsl/core/analysis.js +51 -0
- package/dist/formats/hlsl/core/analysis.js.map +1 -0
- package/dist/formats/hlsl/core/helpers.js +270 -0
- package/dist/formats/hlsl/core/helpers.js.map +1 -0
- package/dist/formats/hlsl/core/json.js +284 -0
- package/dist/formats/hlsl/core/json.js.map +1 -0
- package/dist/formats/hlsl/core/metadata.js +327 -0
- package/dist/formats/hlsl/core/metadata.js.map +1 -0
- package/dist/formats/hlsl/core/portableReflection.js +848 -0
- package/dist/formats/hlsl/core/portableReflection.js.map +1 -0
- package/dist/formats/hlsl/core/render-states.js +280 -0
- package/dist/formats/hlsl/core/render-states.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/HlslRenderContextEnum.js +43 -0
- package/dist/formats/hlsl/core/tr2/HlslRenderContextEnum.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js +294 -0
- package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/resources/HlslShaderPermutation.js +33 -0
- package/dist/formats/hlsl/core/tr2/resources/HlslShaderPermutation.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectBindingManifest.js +416 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectBindingManifest.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectConstant.js +40 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectConstant.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectDescription.js +742 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectDescription.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectLibrary.js +52 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectLibrary.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectParameterAnnotation.js +38 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectParameterAnnotation.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectResource.js +50 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectResource.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectStageInput.js +86 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectStageInput.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectTechnique.js +31 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslEffectTechnique.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslPass.js +42 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslPass.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslSamplerDescription.js +55 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslSamplerDescription.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslSamplerSetup.js +29 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslSamplerSetup.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslShader.js +220 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslShader.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslShaderOption.js +30 -0
- package/dist/formats/hlsl/core/tr2/shader/HlslShaderOption.js.map +1 -0
- package/dist/formats/hlsl/index.js +2 -0
- package/dist/formats/hlsl/index.js.map +1 -0
- package/dist/formats/hlsl/portable.js +2 -0
- package/dist/formats/hlsl/portable.js.map +1 -0
- package/dist/formats/index.js +4 -0
- package/dist/formats/index.js.map +1 -1
- package/dist/formats/webgl/CjsWebglFormat.js +221 -0
- package/dist/formats/webgl/CjsWebglFormat.js.map +1 -0
- package/dist/formats/webgl/core/cewg/CewgPackage.js +339 -0
- package/dist/formats/webgl/core/cewg/CewgPackage.js.map +1 -0
- package/dist/formats/webgl/core/cewg/CewgPackageBuilder.js +104 -0
- package/dist/formats/webgl/core/cewg/CewgPackageBuilder.js.map +1 -0
- package/dist/formats/webgl/core/cewg/binary.js +101 -0
- package/dist/formats/webgl/core/cewg/binary.js.map +1 -0
- package/dist/formats/webgl/core/cewgCompleteness.js +81 -0
- package/dist/formats/webgl/core/cewgCompleteness.js.map +1 -0
- package/dist/formats/webgl/core/effectPackage.js +789 -0
- package/dist/formats/webgl/core/effectPackage.js.map +1 -0
- package/dist/formats/webgl/core/effectPackageValidation.js +331 -0
- package/dist/formats/webgl/core/effectPackageValidation.js.map +1 -0
- package/dist/formats/webgl/core/errors.js +27 -0
- package/dist/formats/webgl/core/errors.js.map +1 -0
- package/dist/formats/webgl/core/glsl/DxbcGlslEmitter.js +2678 -0
- package/dist/formats/webgl/core/glsl/DxbcGlslEmitter.js.map +1 -0
- package/dist/formats/webgl/core/glsl/DxbcGlslHelpers.js +89 -0
- package/dist/formats/webgl/core/glsl/DxbcGlslHelpers.js.map +1 -0
- package/dist/formats/webgl/core/glsl/DxbcGlslOperandFormatter.js +428 -0
- package/dist/formats/webgl/core/glsl/DxbcGlslOperandFormatter.js.map +1 -0
- package/dist/formats/webgl/core/helpers.js +306 -0
- package/dist/formats/webgl/core/helpers.js.map +1 -0
- package/dist/formats/webgl/index.js +2 -0
- package/dist/formats/webgl/index.js.map +1 -0
- package/dist/formats/webgpu/CjsWebgpuFormat.js +376 -0
- package/dist/formats/webgpu/CjsWebgpuFormat.js.map +1 -0
- package/dist/formats/webgpu/core/cewgpu/CewgpuPackage.js +415 -0
- package/dist/formats/webgpu/core/cewgpu/CewgpuPackage.js.map +1 -0
- package/dist/formats/webgpu/core/cewgpu/CewgpuPackageBuilder.js +100 -0
- package/dist/formats/webgpu/core/cewgpu/CewgpuPackageBuilder.js.map +1 -0
- package/dist/formats/webgpu/core/cewgpu/binary.js +93 -0
- package/dist/formats/webgpu/core/cewgpu/binary.js.map +1 -0
- package/dist/formats/webgpu/core/cewgpu/tags.js +17 -0
- package/dist/formats/webgpu/core/cewgpu/tags.js.map +1 -0
- package/dist/formats/webgpu/core/effectAnalysis.js +82 -0
- package/dist/formats/webgpu/core/effectAnalysis.js.map +1 -0
- package/dist/formats/webgpu/core/effectBackendBodySet.js +305 -0
- package/dist/formats/webgpu/core/effectBackendBodySet.js.map +1 -0
- package/dist/formats/webgpu/core/effectPackageValidation.js +1078 -0
- package/dist/formats/webgpu/core/effectPackageValidation.js.map +1 -0
- package/dist/formats/webgpu/core/errors.js +20 -0
- package/dist/formats/webgpu/core/errors.js.map +1 -0
- package/dist/formats/webgpu/core/helpers.js +448 -0
- package/dist/formats/webgpu/core/helpers.js.map +1 -0
- package/dist/formats/webgpu/core/ir/analyzeRegisterValues.js +223 -0
- package/dist/formats/webgpu/core/ir/analyzeRegisterValues.js.map +1 -0
- package/dist/formats/webgpu/core/ir/buildControlFlow.js +220 -0
- package/dist/formats/webgpu/core/ir/buildControlFlow.js.map +1 -0
- package/dist/formats/webgpu/core/ir/indexableTemps.js +137 -0
- package/dist/formats/webgpu/core/ir/indexableTemps.js.map +1 -0
- package/dist/formats/webgpu/core/ir/inferValueTypes.js +454 -0
- package/dist/formats/webgpu/core/ir/inferValueTypes.js.map +1 -0
- package/dist/formats/webgpu/core/ir/lowerDxbcToIr.js +494 -0
- package/dist/formats/webgpu/core/ir/lowerDxbcToIr.js.map +1 -0
- package/dist/formats/webgpu/core/ir/resolveRegisterFlow.js +177 -0
- package/dist/formats/webgpu/core/ir/resolveRegisterFlow.js.map +1 -0
- package/dist/formats/webgpu/core/ir/sourceLanes.js +61 -0
- package/dist/formats/webgpu/core/ir/sourceLanes.js.map +1 -0
- package/dist/formats/webgpu/core/packageEffect.js +300 -0
- package/dist/formats/webgpu/core/packageEffect.js.map +1 -0
- package/dist/formats/webgpu/core/packageEffectSelection.js +164 -0
- package/dist/formats/webgpu/core/packageEffectSelection.js.map +1 -0
- package/dist/formats/webgpu/core/packageMetadata.js +8 -0
- package/dist/formats/webgpu/core/packageMetadata.js.map +1 -0
- package/dist/formats/webgpu/core/schema.js +4 -0
- package/dist/formats/webgpu/core/schema.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js +275 -0
- package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/buildWgslBindingPlan.js +182 -0
- package/dist/formats/webgpu/core/wgsl/buildWgslBindingPlan.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/buildWgslSet.js +324 -0
- package/dist/formats/webgpu/core/wgsl/buildWgslSet.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/emitWgsl.js +356 -0
- package/dist/formats/webgpu/core/wgsl/emitWgsl.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/hoistEscapingValues.js +77 -0
- package/dist/formats/webgpu/core/wgsl/hoistEscapingValues.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerBindingLayout.js +451 -0
- package/dist/formats/webgpu/core/wgsl/lowerBindingLayout.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerComputeProgram.js +754 -0
- package/dist/formats/webgpu/core/wgsl/lowerComputeProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerCreateHistogramsComputeProgram.js +457 -0
- package/dist/formats/webgpu/core/wgsl/lowerCreateHistogramsComputeProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerFragmentProgram.js +1572 -0
- package/dist/formats/webgpu/core/wgsl/lowerFragmentProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerMergeHistogramsComputeProgram.js +659 -0
- package/dist/formats/webgpu/core/wgsl/lowerMergeHistogramsComputeProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerParticleClearComputePrograms.js +734 -0
- package/dist/formats/webgpu/core/wgsl/lowerParticleClearComputePrograms.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerParticleEmitComputeProgram.js +583 -0
- package/dist/formats/webgpu/core/wgsl/lowerParticleEmitComputeProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerSkinVerticesComputeProgram.js +621 -0
- package/dist/formats/webgpu/core/wgsl/lowerSkinVerticesComputeProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerSortComputeProgram.js +824 -0
- package/dist/formats/webgpu/core/wgsl/lowerSortComputeProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerSortInnerComputeProgram.js +697 -0
- package/dist/formats/webgpu/core/wgsl/lowerSortInnerComputeProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerSortStepComputeProgram.js +559 -0
- package/dist/formats/webgpu/core/wgsl/lowerSortStepComputeProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/lowerVertexProgram.js +1328 -0
- package/dist/formats/webgpu/core/wgsl/lowerVertexProgram.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/particleEmitSemanticDigest.js +110 -0
- package/dist/formats/webgpu/core/wgsl/particleEmitSemanticDigest.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/precisionControls.js +55 -0
- package/dist/formats/webgpu/core/wgsl/precisionControls.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/selectionPlans.js +758 -0
- package/dist/formats/webgpu/core/wgsl/selectionPlans.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/uniformity.js +78 -0
- package/dist/formats/webgpu/core/wgsl/uniformity.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/validateExactComputeIr.js +196 -0
- package/dist/formats/webgpu/core/wgsl/validateExactComputeIr.js.map +1 -0
- package/dist/formats/webgpu/core/wgsl/validateHandleOperand.js +37 -0
- package/dist/formats/webgpu/core/wgsl/validateHandleOperand.js.map +1 -0
- package/dist/formats/webgpu/index.js +2 -0
- package/dist/formats/webgpu/index.js.map +1 -0
- package/dist/resource/shader/Tr2EffectRes.js +159 -150
- package/dist/resource/shader/Tr2EffectRes.js.map +1 -1
- package/dist/resource/shader/Tr2MaterialArea.js +23 -28
- package/dist/resource/shader/Tr2MaterialArea.js.map +1 -1
- package/dist/resource/shader/Tr2MaterialMesh.js +21 -27
- package/dist/resource/shader/Tr2MaterialMesh.js.map +1 -1
- package/dist/resource/shader/Tr2MaterialRes.js +24 -29
- package/dist/resource/shader/Tr2MaterialRes.js.map +1 -1
- package/dist/resource/shader/Tr2Shader.js +45 -39
- package/dist/resource/shader/Tr2Shader.js.map +1 -1
- package/dist/resource/shader/Tr2ShaderPermutation.js +30 -32
- package/dist/resource/shader/Tr2ShaderPermutation.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectConstant.js +113 -78
- package/dist/resource/shader/reflection/Tr2EffectConstant.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectDefine.js +17 -23
- package/dist/resource/shader/reflection/Tr2EffectDefine.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectDescription.js +23 -29
- package/dist/resource/shader/reflection/Tr2EffectDescription.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectLibrary.js +44 -40
- package/dist/resource/shader/reflection/Tr2EffectLibrary.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js +82 -86
- package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectResource.js +55 -61
- package/dist/resource/shader/reflection/Tr2EffectResource.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectStageInput.js +49 -45
- package/dist/resource/shader/reflection/Tr2EffectStageInput.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectTechnique.js +25 -30
- package/dist/resource/shader/reflection/Tr2EffectTechnique.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2Pass.js +30 -32
- package/dist/resource/shader/reflection/Tr2Pass.js.map +1 -1
- package/dist/resource/shader/sampler/Tr2SamplerSetup.js +21 -26
- package/dist/resource/shader/sampler/Tr2SamplerSetup.js.map +1 -1
- package/docs/formats/README.md +4 -0
- package/docs/formats/provenance.md +11 -3
- package/docs/reference/classes/formats.md +440 -0
- package/format-notices/dxbc/LICENSE +21 -0
- package/format-notices/dxbc/NOTICE +20 -0
- package/format-notices/hlsl/LICENSE +21 -0
- package/format-notices/hlsl/NOTICE +25 -0
- package/format-notices/webgl/LICENSE +21 -0
- package/format-notices/webgl/NOTICE +35 -0
- package/format-notices/webgpu/LICENSE +21 -0
- package/format-notices/webgpu/NOTICE +31 -0
- package/package.json +6 -1
- package/dist/resource/shader/portableValidation.js +0 -461
- package/dist/resource/shader/portableValidation.js.map +0 -1
|
@@ -0,0 +1,621 @@
|
|
|
1
|
+
import { analyzeRegisterValues } from '../ir/analyzeRegisterValues.js';
|
|
2
|
+
import { buildControlFlow } from '../ir/buildControlFlow.js';
|
|
3
|
+
import { inferValueTypes } from '../ir/inferValueTypes.js';
|
|
4
|
+
import { resolveRegisterFlow } from '../ir/resolveRegisterFlow.js';
|
|
5
|
+
import { lowerBindingLayout } from './lowerBindingLayout.js';
|
|
6
|
+
import { requireRefactoringAllowed } from './precisionControls.js';
|
|
7
|
+
import { buildSelectionPlans } from './selectionPlans.js';
|
|
8
|
+
import { validateSm50ResourceExtensions } from './validateExactComputeIr.js';
|
|
9
|
+
|
|
10
|
+
const COMPONENTS = Object.freeze(["x", "y", "z", "w"]);
|
|
11
|
+
const DECLARATION_OPCODES = Object.freeze(["dcl_global_flags", "dcl_constant_buffer", "dcl_resource_structured", "dcl_resource_structured", "dcl_unordered_access_view_structured", "dcl_input", "dcl_temps", "dcl_thread_group"]);
|
|
12
|
+
const BODY_OPCODES = Object.freeze(["ult", "if", "imad", "ld_structured", "iadd", "ld_structured", "ld_structured", "ld_structured", "ine", "if", "and", "ubfe", "ushr", "imad", "ld_structured", "and", "ubfe", "ushr", "utof", "utof", "mul", "iadd", "ld_structured", "ld_structured", "ld_structured", "iadd", "ld_structured", "ld_structured", "ld_structured", "mul", "mul", "mul", "mad", "mad", "mad", "ld_structured", "ld_structured", "ld_structured", "mad", "mad", "mad", "iadd", "ld_structured", "ld_structured", "ld_structured", "mad", "mad", "mad", "else", "and", "iadd", "ld_structured", "ld_structured", "ld_structured", "endif", "mov", "dp4", "dp4", "dp4", "imad", "store_structured", "iadd", "store_structured", "store_structured", "endif", "ret"]);
|
|
13
|
+
const BODY_OPERANDS = Object.freeze(["temp:0:x:0: | input_thread_id::x:: | constant_buffer:3:x:3,0:", "temp:0:x:0:", "temp:0:xy:0: | input_thread_id::xxxx:: | constant_buffer:3:yyyy:3,0: | constant_buffer:3:zwzz:3,0:", "temp:1:x:1: | temp:0:x:0: | immediate32::::#0 | resource:1:xxxx:1:", "temp:0:xz:0: | temp:0:xxxx:0: | immediate32::::#1,#0,#2,#0", "temp:1:y:1: | temp:0:x:0: | immediate32::::#0 | resource:1:xxxx:1:", "temp:1:z:1: | temp:0:z:0: | immediate32::::#0 | resource:1:xxxx:1:", "temp:0:x:0: | temp:0:y:0: | immediate32::::#0 | resource:1:xxxx:1:", "temp:0:y:0: | constant_buffer:3:x:3,1: | immediate32::::#4294967295", "temp:0:y:0:", "temp:0:y:0: | temp:0:x:0: | immediate32::::#255", "temp:0:zw:0: | immediate32::::#0,#0,#8,#8 | immediate32::::#0,#0,#8,#16 | temp:0:xxxx:0:", "temp:2:x:2: | temp:0:x:0: | immediate32::::#24", "temp:2:y:2: | input_thread_id::x:: | constant_buffer:3:y:3,0: | constant_buffer:3:x:3,1:", "temp:2:y:2: | temp:2:y:2: | immediate32::::#0 | resource:1:xxxx:1:", "temp:2:z:2: | temp:2:y:2: | immediate32::::#255", "temp:3:xy:3: | immediate32::::#8,#8,#0,#0 | immediate32::::#8,#16,#0,#0 | temp:2:yyyy:2:", "temp:2:y:2: | temp:2:y:2: | immediate32::::#24", "temp:4:yz:4: | temp:3:xxyx:3:", "temp:4:xw:4: | temp:2:zzzy:2:", "temp:3:xyzw:3: | temp:4:xyzw:4: | immediate32::::#998277249,#998277249,#998277249,#998277249", "temp:0:y:0: | temp:0:y:0: | constant_buffer:3:y:3,1:", "temp:4:xyzw:4: | temp:0:y:0: | immediate32::::#0 | resource:0:xyzw:0:", "temp:5:xyzw:5: | temp:0:y:0: | immediate32::::#16 | resource:0:xyzw:0:", "temp:6:xyzw:6: | temp:0:y:0: | immediate32::::#32 | resource:0:xyzw:0:", "temp:0:yz:0: | temp:0:zzwz:0: | constant_buffer:3:yyyy:3,1:", "temp:7:xyzw:7: | temp:0:y:0: | immediate32::::#0 | resource:0:xyzw:0:", "temp:8:xyzw:8: | temp:0:y:0: | immediate32::::#16 | resource:0:xyzw:0:", "temp:9:xyzw:9: | temp:0:y:0: | immediate32::::#32 | resource:0:xyzw:0:", "temp:7:xyzw:7: | temp:3:yyyy:3: | temp:7:xyzw:7:", "temp:8:xyzw:8: | temp:3:yyyy:3: | temp:8:xyzw:8:", "temp:9:xyzw:9: | temp:3:yyyy:3: | temp:9:xyzw:9:", "temp:4:xyzw:4: | temp:4:xyzw:4: | temp:3:xxxx:3: | temp:7:xyzw:7:", "temp:5:xyzw:5: | temp:5:xyzw:5: | temp:3:xxxx:3: | temp:8:xyzw:8:", "temp:6:xyzw:6: | temp:6:xyzw:6: | temp:3:xxxx:3: | temp:9:xyzw:9:", "temp:7:xyzw:7: | temp:0:z:0: | immediate32::::#0 | resource:0:xyzw:0:", "temp:8:xyzw:8: | temp:0:z:0: | immediate32::::#16 | resource:0:xyzw:0:", "temp:9:xyzw:9: | temp:0:z:0: | immediate32::::#32 | resource:0:xyzw:0:", "temp:4:xyzw:4: | temp:7:xyzw:7: | temp:3:zzzz:3: | temp:4:xyzw:4:", "temp:5:xyzw:5: | temp:8:xyzw:8: | temp:3:zzzz:3: | temp:5:xyzw:5:", "temp:6:xyzw:6: | temp:9:xyzw:9: | temp:3:zzzz:3: | temp:6:xyzw:6:", "temp:0:y:0: | temp:2:x:2: | constant_buffer:3:y:3,1:", "temp:2:xyzw:2: | temp:0:y:0: | immediate32::::#0 | resource:0:xyzw:0:", "temp:7:xyzw:7: | temp:0:y:0: | immediate32::::#16 | resource:0:xyzw:0:", "temp:8:xyzw:8: | temp:0:y:0: | immediate32::::#32 | resource:0:xyzw:0:", "temp:2:xyzw:2: | temp:2:xyzw:2: | temp:3:wwww:3: | temp:4:xyzw:4:", "temp:4:xyzw:4: | temp:7:xyzw:7: | temp:3:wwww:3: | temp:5:xyzw:5:", "temp:3:xyzw:3: | temp:8:xyzw:8: | temp:3:wwww:3: | temp:6:xyzw:6:", "", "temp:0:x:0: | temp:0:x:0: | immediate32::::#255", "temp:0:x:0: | temp:0:x:0: | constant_buffer:3:y:3,1:", "temp:2:xyzw:2: | temp:0:x:0: | immediate32::::#0 | resource:0:xyzw:0:", "temp:4:xyzw:4: | temp:0:x:0: | immediate32::::#16 | resource:0:xyzw:0:", "temp:3:xyzw:3: | temp:0:x:0: | immediate32::::#32 | resource:0:xyzw:0:", "", "temp:1:w:1: | immediate32::::#1065353216", "temp:0:x:0: | temp:1:xyzw:1: | temp:2:xyzw:2:", "temp:0:y:0: | temp:1:xyzw:1: | temp:4:xyzw:4:", "temp:0:z:0: | temp:1:xyzw:1: | temp:3:xyzw:3:", "temp:0:w:0: | input_thread_id::x:: | immediate32::::#3 | constant_buffer:3:x:3,2:", "uav:0:x:0: | temp:0:w:0: | immediate32::::#0 | temp:0:x:0:", "temp:1:xy:1: | temp:0:wwww:0: | immediate32::::#1,#2,#0,#0", "uav:0:x:0: | temp:1:x:1: | immediate32::::#0 | temp:0:y:0:", "uav:0:x:0: | temp:1:y:1: | immediate32::::#0 | temp:0:z:0:", "", ""]);
|
|
14
|
+
const BLOCK_BEFORE = new Set(["else", "endif"]);
|
|
15
|
+
const BLOCK_AFTER = new Set(["if", "else", "endif", "ret"]);
|
|
16
|
+
const CONTROL_KIND = Object.freeze({
|
|
17
|
+
if: "selection",
|
|
18
|
+
else: "selection",
|
|
19
|
+
endif: "selection",
|
|
20
|
+
ret: "termination"
|
|
21
|
+
});
|
|
22
|
+
function clonePlain(value) {
|
|
23
|
+
if (Array.isArray(value)) return value.map(clonePlain);
|
|
24
|
+
if (value && typeof value === "object") {
|
|
25
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, clonePlain(entry)]));
|
|
26
|
+
}
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
function deepFreeze(value) {
|
|
30
|
+
if (!value || typeof value !== "object" || Object.isFrozen(value)) return value;
|
|
31
|
+
for (const entry of Object.values(value)) deepFreeze(entry);
|
|
32
|
+
return Object.freeze(value);
|
|
33
|
+
}
|
|
34
|
+
function buildBlocks(instructions) {
|
|
35
|
+
const leaders = new Set([0]);
|
|
36
|
+
for (let index = 0; index < instructions.length; index += 1) {
|
|
37
|
+
if (BLOCK_BEFORE.has(instructions[index].opcodeName)) leaders.add(index);
|
|
38
|
+
if (BLOCK_AFTER.has(instructions[index].opcodeName) && index + 1 < instructions.length) {
|
|
39
|
+
leaders.add(index + 1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const starts = Array.from(leaders).sort((left, right) => left - right);
|
|
43
|
+
return starts.map((start, blockIndex) => {
|
|
44
|
+
const end = (starts[blockIndex + 1] ?? instructions.length) - 1;
|
|
45
|
+
const last = instructions[end];
|
|
46
|
+
return {
|
|
47
|
+
kind: "basic-block",
|
|
48
|
+
id: `block${blockIndex}`,
|
|
49
|
+
index: blockIndex,
|
|
50
|
+
startInstruction: start,
|
|
51
|
+
endInstruction: end,
|
|
52
|
+
startDxbcOffset: instructions[start].dxbcOffset,
|
|
53
|
+
endDxbcOffset: last.dxbcOffset,
|
|
54
|
+
instructionIndices: Array.from({
|
|
55
|
+
length: end - start + 1
|
|
56
|
+
}, (_, offset) => start + offset),
|
|
57
|
+
terminator: CONTROL_KIND[last.opcodeName] ? last.opcodeName : null
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function analysisSnapshot(program) {
|
|
62
|
+
return {
|
|
63
|
+
blocks: program.blocks,
|
|
64
|
+
controlFlow: program.controlFlow,
|
|
65
|
+
values: program.values,
|
|
66
|
+
instructions: program.instructions.map(instruction => ({
|
|
67
|
+
dataflow: instruction.dataflow,
|
|
68
|
+
typeInfo: instruction.typeInfo
|
|
69
|
+
}))
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function validateAnalysisMetadata(program) {
|
|
73
|
+
const rebuilt = clonePlain(program);
|
|
74
|
+
rebuilt.instructions = rebuilt.instructions.map(instruction => {
|
|
75
|
+
delete instruction.dataflow;
|
|
76
|
+
delete instruction.typeInfo;
|
|
77
|
+
return instruction;
|
|
78
|
+
});
|
|
79
|
+
rebuilt.blocks = buildBlocks(rebuilt.instructions);
|
|
80
|
+
delete rebuilt.controlFlow;
|
|
81
|
+
delete rebuilt.values;
|
|
82
|
+
buildControlFlow(rebuilt);
|
|
83
|
+
analyzeRegisterValues(rebuilt);
|
|
84
|
+
resolveRegisterFlow(rebuilt);
|
|
85
|
+
inferValueTypes(rebuilt);
|
|
86
|
+
if (JSON.stringify(analysisSnapshot(program)) !== JSON.stringify(analysisSnapshot(rebuilt))) {
|
|
87
|
+
throw new Error("WGSL structured skinning compute CFG, SSA, or type metadata is inconsistent");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function validateCommonOperand(operand, instruction, operandIndex) {
|
|
91
|
+
if (!operand || (operand.modifierName ?? "none") !== "none" || (operand.minPrecisionName ?? "default") !== "default" || operand.nonUniform === true) {
|
|
92
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} requires default uniform unmodified data`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function validateFixedIndex(operand, instruction, operandIndex) {
|
|
96
|
+
const index = operand.indices?.[0];
|
|
97
|
+
if (!Number.isInteger(operand.registerIndex) || operand.registerIndex < 0 || operand.indices?.length !== 1 || index?.relative || index?.values?.length !== 1 || index.values[0] !== operand.registerIndex) {
|
|
98
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} has an invalid fixed register identity`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function validateDestination(operand, instruction, operandIndex) {
|
|
102
|
+
validateCommonOperand(operand, instruction, operandIndex);
|
|
103
|
+
validateFixedIndex(operand, instruction, operandIndex);
|
|
104
|
+
if (operand.typeName !== "temp" || operand.registerIndex > 9 || operand.componentCount !== 4 || !/^(?:x|y|z|w|xy|xz|yz|zw|xw|xyzw)$/u.test(operand.mask) || operand.swizzle || operand.selected) {
|
|
105
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} has an unsupported temp destination`);
|
|
106
|
+
}
|
|
107
|
+
return Array.from(operand.mask);
|
|
108
|
+
}
|
|
109
|
+
function validateScalarSource(operand, instruction, operandIndex, typeName = null) {
|
|
110
|
+
validateCommonOperand(operand, instruction, operandIndex);
|
|
111
|
+
if (typeName && operand.typeName !== typeName) {
|
|
112
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} requires ${typeName}`);
|
|
113
|
+
}
|
|
114
|
+
if (!COMPONENTS.includes(operand.selected) || operand.mask || operand.swizzle) {
|
|
115
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} requires one selected scalar lane`);
|
|
116
|
+
}
|
|
117
|
+
if (operand.typeName === "temp") {
|
|
118
|
+
validateFixedIndex(operand, instruction, operandIndex);
|
|
119
|
+
if (operand.registerIndex > 9 || operand.componentCount !== 4) {
|
|
120
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} has an invalid temp source`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return operand;
|
|
124
|
+
}
|
|
125
|
+
function immediateValues(operand, instruction, operandIndex) {
|
|
126
|
+
validateCommonOperand(operand, instruction, operandIndex);
|
|
127
|
+
if (operand.typeName !== "immediate32" || operand.registerIndex !== null || operand.indices?.length || operand.mask || operand.swizzle || operand.selected || ![1, 4].includes(operand.componentCount) || operand.immediateValues?.length !== operand.componentCount || operand.immediateValues.some(value => !Number.isInteger(value?.uint32))) {
|
|
128
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} requires canonical immediate32 data`);
|
|
129
|
+
}
|
|
130
|
+
return operand.immediateValues.map(value => value.uint32 >>> 0);
|
|
131
|
+
}
|
|
132
|
+
function operandSignature(operand) {
|
|
133
|
+
const index = (operand.indices || []).map(entry => entry.values?.join(":") || "?").join(",");
|
|
134
|
+
const immediate = (operand.immediateValues || []).map(entry => `#${entry.uint32 >>> 0}`).join(",");
|
|
135
|
+
return [operand.typeName, Number.isInteger(operand.registerIndex) ? operand.registerIndex : "", operand.mask || operand.swizzle || operand.selected || "", index, immediate].join(":");
|
|
136
|
+
}
|
|
137
|
+
function instructionOperandSignature(instruction) {
|
|
138
|
+
return (instruction.operands || []).map(operandSignature).join(" | ");
|
|
139
|
+
}
|
|
140
|
+
function validateSource(operand, instruction, operandIndex) {
|
|
141
|
+
validateCommonOperand(operand, instruction, operandIndex);
|
|
142
|
+
if (operand.mask || operand.selected && operand.swizzle) {
|
|
143
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} has an invalid source selector`);
|
|
144
|
+
}
|
|
145
|
+
if (operand.typeName === "temp") {
|
|
146
|
+
validateFixedIndex(operand, instruction, operandIndex);
|
|
147
|
+
if (operand.registerIndex > 9 || operand.componentCount !== 4 || !COMPONENTS.includes(operand.selected) && !/^[xyzw]{4}$/u.test(operand.swizzle)) {
|
|
148
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} has an invalid temp source`);
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (operand.typeName === "constant_buffer") {
|
|
153
|
+
const [bufferIndex, rowIndex] = operand.indices || [];
|
|
154
|
+
if (operand.registerIndex !== 3 || operand.componentCount !== 4 || operand.indices?.length !== 2 || bufferIndex?.relative || bufferIndex?.values?.length !== 1 || bufferIndex.values[0] !== 3 || rowIndex?.relative || rowIndex?.values?.length !== 1 || !Number.isInteger(rowIndex.values[0]) || rowIndex.values[0] < 0 || rowIndex.values[0] > 2 || !COMPONENTS.includes(operand.selected) && !/^[xyzw]{4}$/u.test(operand.swizzle)) {
|
|
155
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} has an invalid cb3 source`);
|
|
156
|
+
}
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (operand.typeName === "input_thread_id") {
|
|
160
|
+
if (operand.registerIndex !== null || operand.indices?.length || operand.componentCount !== 4 || !COMPONENTS.includes(operand.selected) && !/^[xyzw]{4}$/u.test(operand.swizzle) || Array.from(operand.selected || operand.swizzle).some(component => component !== "x")) {
|
|
161
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} may read only input_thread_id.x`);
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
if (operand.typeName === "immediate32") {
|
|
166
|
+
immediateValues(operand, instruction, operandIndex);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} operand ${operandIndex} has unsupported source ${operand.typeName || "unknown"}`);
|
|
170
|
+
}
|
|
171
|
+
function selectedComponents(operand, activeComponents) {
|
|
172
|
+
if (operand.selected) return activeComponents.map(() => operand.selected);
|
|
173
|
+
const swizzle = operand.swizzle || "xyzw";
|
|
174
|
+
return activeComponents.map(component => swizzle[COMPONENTS.indexOf(component)]);
|
|
175
|
+
}
|
|
176
|
+
function uintLiteral(value) {
|
|
177
|
+
return `0x${(value >>> 0).toString(16).padStart(8, "0")}u`;
|
|
178
|
+
}
|
|
179
|
+
function sourceParts(instruction, operandIndex, activeComponents) {
|
|
180
|
+
const operand = instruction.operands[operandIndex];
|
|
181
|
+
validateSource(operand, instruction, operandIndex);
|
|
182
|
+
const components = selectedComponents(operand, activeComponents);
|
|
183
|
+
if (operand.typeName === "temp") {
|
|
184
|
+
return components.map(component => `r${operand.registerIndex}.${component}`);
|
|
185
|
+
}
|
|
186
|
+
if (operand.typeName === "constant_buffer") {
|
|
187
|
+
const row = operand.indices[1].values[0];
|
|
188
|
+
return components.map(component => `bitcast<u32>(cb3[${row}].${component})`);
|
|
189
|
+
}
|
|
190
|
+
if (operand.typeName === "input_thread_id") {
|
|
191
|
+
return components.map(component => `dispatch_thread_id.${component}`);
|
|
192
|
+
}
|
|
193
|
+
const values = immediateValues(operand, instruction, operandIndex);
|
|
194
|
+
return components.map((component, index) => {
|
|
195
|
+
const sourceIndex = values.length === 1 ? 0 : COMPONENTS.indexOf(component);
|
|
196
|
+
return uintLiteral(values[sourceIndex] ?? values[index]);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function rawVector(parts) {
|
|
200
|
+
return parts.length === 1 ? parts[0] : `vec${parts.length}<u32>(${parts.join(", ")})`;
|
|
201
|
+
}
|
|
202
|
+
function floatVector(parts) {
|
|
203
|
+
const values = parts.map(part => `bitcast<f32>(${part})`);
|
|
204
|
+
return values.length === 1 ? values[0] : `vec${values.length}<f32>(${values.join(", ")})`;
|
|
205
|
+
}
|
|
206
|
+
function rawFloatExpression(code, count) {
|
|
207
|
+
return `bitcast<${"u32" }>(${code})`;
|
|
208
|
+
}
|
|
209
|
+
function assignment(instruction, destination, parts) {
|
|
210
|
+
return {
|
|
211
|
+
kind: "value-assignment",
|
|
212
|
+
instructionIndex: instruction.index,
|
|
213
|
+
dxbcOffset: instruction.dxbcOffset,
|
|
214
|
+
name: `r${destination.registerIndex}.${destination.mask}`,
|
|
215
|
+
type: destination.mask.length === 1 ? "u32" : `vec${destination.mask.length}<u32>`,
|
|
216
|
+
expression: {
|
|
217
|
+
code: rawVector(parts),
|
|
218
|
+
type: destination.mask.length === 1 ? "u32" : `vec${destination.mask.length}<u32>`
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
function bindingForHandle(bindings, kind, operand, instruction, operandIndex) {
|
|
223
|
+
validateCommonOperand(operand, instruction, operandIndex);
|
|
224
|
+
validateFixedIndex(operand, instruction, operandIndex);
|
|
225
|
+
const typeName = kind === "sampled-resource" ? "resource" : "uav";
|
|
226
|
+
if (operand.typeName !== typeName || operand.componentCount !== 4) {
|
|
227
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} has an invalid ${typeName} handle`);
|
|
228
|
+
}
|
|
229
|
+
const binding = bindings.find(entry => entry.resourceKind === kind && entry.registerIndex === operand.registerIndex && entry.registerSpace === 0);
|
|
230
|
+
if (!binding) {
|
|
231
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} has an unresolved ${kind} binding`);
|
|
232
|
+
}
|
|
233
|
+
return binding;
|
|
234
|
+
}
|
|
235
|
+
function safeStructuredLoad(program, instruction, bindings) {
|
|
236
|
+
if (instruction.operands.length !== 4) {
|
|
237
|
+
throw new Error(`WGSL structured skinning load ${instruction.index} requires four operands`);
|
|
238
|
+
}
|
|
239
|
+
const destination = instruction.operands[0];
|
|
240
|
+
const active = validateDestination(destination, instruction, 0);
|
|
241
|
+
validateScalarSource(instruction.operands[1], instruction, 1, "temp");
|
|
242
|
+
const address = sourceParts(instruction, 1, ["x"])[0];
|
|
243
|
+
const byteOffsets = immediateValues(instruction.operands[2], instruction, 2);
|
|
244
|
+
if (byteOffsets.length !== 1 || byteOffsets[0] % 4 !== 0) {
|
|
245
|
+
throw new Error(`WGSL structured skinning load ${instruction.index} requires one immediate DWORD byte offset`);
|
|
246
|
+
}
|
|
247
|
+
const resource = instruction.operands[3];
|
|
248
|
+
if (!/^[xyzw]{4}$/u.test(resource.swizzle) || resource.mask || resource.selected) {
|
|
249
|
+
throw new Error(`WGSL structured skinning load ${instruction.index} requires a four-lane resource swizzle`);
|
|
250
|
+
}
|
|
251
|
+
const binding = bindingForHandle(bindings, "sampled-resource", resource, instruction, 3);
|
|
252
|
+
const strideWords = binding.structureStride / 4;
|
|
253
|
+
const firstWord = byteOffsets[0] / 4;
|
|
254
|
+
if (binding.registerIndex === 0 && ![0, 4, 8].includes(firstWord) || binding.registerIndex === 1 && firstWord !== 0) {
|
|
255
|
+
throw new Error(`WGSL structured skinning load ${instruction.index} uses an unexpected structured byte offset`);
|
|
256
|
+
}
|
|
257
|
+
const wordCount = `arrayLength(&${binding.generatedSymbol})`;
|
|
258
|
+
const addressInRange = `${address} < (${wordCount} / ${strideWords}u)`;
|
|
259
|
+
const resourceComponents = selectedComponents(resource, active);
|
|
260
|
+
const parts = resourceComponents.map(component => {
|
|
261
|
+
const word = firstWord + COMPONENTS.indexOf(component);
|
|
262
|
+
if (word < 0 || word >= strideWords) {
|
|
263
|
+
throw new Error(`WGSL structured skinning load ${instruction.index} exceeds its ${binding.structureStride}-byte stride`);
|
|
264
|
+
}
|
|
265
|
+
const wordAddress = `((${address}) * ${strideWords}u) + ${word}u`;
|
|
266
|
+
const safeWordAddress = `min(${wordAddress}, ${wordCount} - 1u)`;
|
|
267
|
+
return `select(0u, ${binding.generatedSymbol}[${safeWordAddress}], ${addressInRange})`;
|
|
268
|
+
});
|
|
269
|
+
return assignment(instruction, destination, parts);
|
|
270
|
+
}
|
|
271
|
+
function structuredStore(program, instruction, bindings) {
|
|
272
|
+
if (instruction.operands.length !== 4) {
|
|
273
|
+
throw new Error(`WGSL structured skinning store ${instruction.index} requires four operands`);
|
|
274
|
+
}
|
|
275
|
+
const uav = instruction.operands[0];
|
|
276
|
+
if (uav.mask !== "x" || uav.swizzle || uav.selected) {
|
|
277
|
+
throw new Error(`WGSL structured skinning store ${instruction.index} requires the scalar x UAV mask`);
|
|
278
|
+
}
|
|
279
|
+
const binding = bindingForHandle(bindings, "storage-resource", uav, instruction, 0);
|
|
280
|
+
if (binding.structureStride !== 4 || binding.type !== "array<u32>") {
|
|
281
|
+
throw new Error(`WGSL structured skinning store ${instruction.index} requires a stride-4 raw-word UAV`);
|
|
282
|
+
}
|
|
283
|
+
validateScalarSource(instruction.operands[1], instruction, 1, "temp");
|
|
284
|
+
const address = sourceParts(instruction, 1, ["x"])[0];
|
|
285
|
+
const byteOffsets = immediateValues(instruction.operands[2], instruction, 2);
|
|
286
|
+
if (byteOffsets.length !== 1 || byteOffsets[0] !== 0) {
|
|
287
|
+
throw new Error(`WGSL structured skinning store ${instruction.index} requires byte offset zero`);
|
|
288
|
+
}
|
|
289
|
+
validateScalarSource(instruction.operands[3], instruction, 3, "temp");
|
|
290
|
+
const value = sourceParts(instruction, 3, ["x"])[0];
|
|
291
|
+
return {
|
|
292
|
+
kind: "if",
|
|
293
|
+
instructionIndex: instruction.index,
|
|
294
|
+
dxbcOffset: instruction.dxbcOffset,
|
|
295
|
+
condition: {
|
|
296
|
+
code: `${address} < arrayLength(&${binding.generatedSymbol})`,
|
|
297
|
+
type: "bool"
|
|
298
|
+
},
|
|
299
|
+
statements: [{
|
|
300
|
+
kind: "call",
|
|
301
|
+
instructionIndex: instruction.index,
|
|
302
|
+
dxbcOffset: instruction.dxbcOffset,
|
|
303
|
+
expression: {
|
|
304
|
+
code: `${binding.generatedSymbol}[${address}] = ${value}`,
|
|
305
|
+
type: "void"
|
|
306
|
+
}
|
|
307
|
+
}]
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function aluStatement(instruction) {
|
|
311
|
+
const destination = instruction.operands[0];
|
|
312
|
+
const active = validateDestination(destination, instruction, 0);
|
|
313
|
+
const count = active.length;
|
|
314
|
+
const source = operandIndex => sourceParts(instruction, operandIndex, active);
|
|
315
|
+
let parts;
|
|
316
|
+
switch (instruction.opcodeName) {
|
|
317
|
+
case "ult":
|
|
318
|
+
case "ine":
|
|
319
|
+
{
|
|
320
|
+
if (instruction.operands.length !== 3) break;
|
|
321
|
+
const left = source(1);
|
|
322
|
+
const right = source(2);
|
|
323
|
+
const operator = instruction.opcodeName === "ult" ? "<" : "!=";
|
|
324
|
+
parts = left.map((part, index) => `select(0u, 0xffffffffu, ${part} ${operator} ${right[index]})`);
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
case "imad":
|
|
328
|
+
{
|
|
329
|
+
if (instruction.operands.length !== 4) break;
|
|
330
|
+
const left = source(1);
|
|
331
|
+
const right = source(2);
|
|
332
|
+
const addend = source(3);
|
|
333
|
+
parts = left.map((part, index) => `((${part} * ${right[index]}) + ${addend[index]})`);
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
case "iadd":
|
|
337
|
+
case "and":
|
|
338
|
+
case "ushr":
|
|
339
|
+
{
|
|
340
|
+
if (instruction.operands.length !== 3) break;
|
|
341
|
+
const left = source(1);
|
|
342
|
+
const right = source(2);
|
|
343
|
+
const operator = {
|
|
344
|
+
iadd: "+",
|
|
345
|
+
and: "&",
|
|
346
|
+
ushr: ">>"
|
|
347
|
+
}[instruction.opcodeName];
|
|
348
|
+
parts = left.map((part, index) => `(${part} ${operator} ${right[index]})`);
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
case "ubfe":
|
|
352
|
+
{
|
|
353
|
+
if (instruction.operands.length !== 4) break;
|
|
354
|
+
const widths = immediateValues(instruction.operands[1], instruction, 1);
|
|
355
|
+
const offsets = immediateValues(instruction.operands[2], instruction, 2);
|
|
356
|
+
const values = source(3);
|
|
357
|
+
const lanes = selectedComponents(instruction.operands[1], active);
|
|
358
|
+
parts = lanes.map((component, index) => {
|
|
359
|
+
const lane = COMPONENTS.indexOf(component);
|
|
360
|
+
const width = widths.length === 1 ? widths[0] : widths[lane];
|
|
361
|
+
const offset = offsets.length === 1 ? offsets[0] : offsets[lane];
|
|
362
|
+
if (width !== 8 || ![8, 16].includes(offset)) {
|
|
363
|
+
throw new Error(`WGSL structured skinning ubfe ${instruction.index} requires the bounded 8-bit packed fields`);
|
|
364
|
+
}
|
|
365
|
+
return `((${values[index]} >> ${uintLiteral(offset)}) & 0x000000ffu)`;
|
|
366
|
+
});
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
369
|
+
case "utof":
|
|
370
|
+
{
|
|
371
|
+
if (instruction.operands.length !== 2) break;
|
|
372
|
+
parts = source(1).map(part => `bitcast<u32>(f32(${part}))`);
|
|
373
|
+
break;
|
|
374
|
+
}
|
|
375
|
+
case "mul":
|
|
376
|
+
case "mad":
|
|
377
|
+
{
|
|
378
|
+
const expected = instruction.opcodeName === "mul" ? 3 : 4;
|
|
379
|
+
if (instruction.operands.length !== expected) break;
|
|
380
|
+
const left = source(1);
|
|
381
|
+
const right = source(2);
|
|
382
|
+
const addend = instruction.opcodeName === "mad" ? source(3) : null;
|
|
383
|
+
parts = left.map((part, index) => {
|
|
384
|
+
const product = `(bitcast<f32>(${part}) * bitcast<f32>(${right[index]}))`;
|
|
385
|
+
const code = addend ? `(${product} + bitcast<f32>(${addend[index]}))` : product;
|
|
386
|
+
return `bitcast<u32>(${code})`;
|
|
387
|
+
});
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
case "mov":
|
|
391
|
+
if (instruction.operands.length === 2) parts = source(1);
|
|
392
|
+
break;
|
|
393
|
+
case "dp4":
|
|
394
|
+
{
|
|
395
|
+
if (instruction.operands.length !== 3 || count !== 1) break;
|
|
396
|
+
const left = sourceParts(instruction, 1, COMPONENTS);
|
|
397
|
+
const right = sourceParts(instruction, 2, COMPONENTS);
|
|
398
|
+
parts = [rawFloatExpression(`dot(${floatVector(left)}, ${floatVector(right)})`)];
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (!parts) {
|
|
403
|
+
throw new Error(`WGSL structured skinning ${instruction.opcodeName} instruction ${instruction.index} has an unsupported operand shape`);
|
|
404
|
+
}
|
|
405
|
+
return assignment(instruction, destination, parts);
|
|
406
|
+
}
|
|
407
|
+
function validateDeclarationOperand(declaration, typeName, registerIndex) {
|
|
408
|
+
const operand = declaration.operands?.[0];
|
|
409
|
+
validateCommonOperand(operand, {
|
|
410
|
+
index: `declaration@${declaration.dxbcOffset}`
|
|
411
|
+
}, 0);
|
|
412
|
+
validateFixedIndex(operand, {
|
|
413
|
+
index: `declaration@${declaration.dxbcOffset}`
|
|
414
|
+
}, 0);
|
|
415
|
+
if (declaration.operands.length !== 1 || operand.typeName !== typeName || operand.registerIndex !== registerIndex || operand.componentCount !== 0 || operand.mask || operand.swizzle || operand.selected) {
|
|
416
|
+
throw new Error(`WGSL structured skinning declaration ${declaration.opcodeName} has a malformed handle`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
function validateDeclarations(program) {
|
|
420
|
+
if (program?.format !== "CJS_SHADER_IR" || program.formatVersion !== 1 || program.stage !== "compute" || program.shaderModel?.major !== 5 || program.shaderModel.minor !== 0) {
|
|
421
|
+
throw new TypeError("WGSL structured skinning compute profile requires CJS SM5.0 compute IR");
|
|
422
|
+
}
|
|
423
|
+
if ((program.signatures?.input || []).length || (program.signatures?.output || []).length || (program.signatures?.patch || []).length || program.immediateConstantBuffer || program.constTables) {
|
|
424
|
+
throw new Error("WGSL structured skinning compute profile does not support signatures or constant tables");
|
|
425
|
+
}
|
|
426
|
+
if (!isSkinVerticesComputeProfile(program)) {
|
|
427
|
+
throw new Error("WGSL structured skinning compute declaration shape is not supported");
|
|
428
|
+
}
|
|
429
|
+
requireRefactoringAllowed(program, "structured skinning compute");
|
|
430
|
+
const [global, cb, bone, input, output, builtin, temps, group] = program.declarations;
|
|
431
|
+
if (global.data?.globalFlags !== 1 << 11 || global.data.refactoringAllowed !== true || global.operands?.length) {
|
|
432
|
+
throw new Error("WGSL structured skinning compute requires only the refactoring-allowed global flag");
|
|
433
|
+
}
|
|
434
|
+
if (cb.data?.registerIndex !== 3 || cb.data.sizeInVec4 !== 3 || cb.data.accessPattern !== "immediate_indexed") {
|
|
435
|
+
throw new Error("WGSL structured skinning compute requires immediate cb3 with three vec4 rows");
|
|
436
|
+
}
|
|
437
|
+
const cbOperand = cb.operands?.[0];
|
|
438
|
+
validateCommonOperand(cbOperand, {
|
|
439
|
+
index: `declaration@${cb.dxbcOffset}`
|
|
440
|
+
}, 0);
|
|
441
|
+
if (cb.operands?.length !== 1 || cbOperand.typeName !== "constant_buffer" || cbOperand.registerIndex !== 3 || cbOperand.componentCount !== 4 || cbOperand.swizzle !== "xyzw" || cbOperand.mask || cbOperand.selected || cbOperand.indices?.length !== 2 || cbOperand.indices.some(index => index.relative || index.values?.length !== 1 || index.values[0] !== 3)) {
|
|
442
|
+
throw new Error("WGSL structured skinning compute requires the canonical cb3[3] declaration operand");
|
|
443
|
+
}
|
|
444
|
+
for (const [declaration, typeName, registerIndex, stride] of [[bone, "resource", 0, 48], [input, "resource", 1, 4], [output, "uav", 0, 4]]) {
|
|
445
|
+
if (declaration.data?.registerIndex !== registerIndex || declaration.data.structureStride !== stride || typeName === "uav" && declaration.data.globallyCoherent !== false) {
|
|
446
|
+
throw new Error(`WGSL structured skinning compute requires ${typeName}${registerIndex} stride ${stride}`);
|
|
447
|
+
}
|
|
448
|
+
validateDeclarationOperand(declaration, typeName, registerIndex);
|
|
449
|
+
}
|
|
450
|
+
const inputOperand = builtin.operands?.[0];
|
|
451
|
+
validateCommonOperand(inputOperand, {
|
|
452
|
+
index: `declaration@${builtin.dxbcOffset}`
|
|
453
|
+
}, 0);
|
|
454
|
+
if (builtin.data?.operandTypeName !== "input_thread_id" || builtin.data.registerIndex !== null || builtin.operands?.length !== 1 || inputOperand.typeName !== "input_thread_id" || inputOperand.componentCount !== 4 || inputOperand.mask !== "x" || inputOperand.registerIndex !== null || inputOperand.indices?.length || inputOperand.selected || inputOperand.swizzle) {
|
|
455
|
+
throw new Error("WGSL structured skinning compute requires exactly input_thread_id.x");
|
|
456
|
+
}
|
|
457
|
+
if (temps.data?.tempCount !== 10 || group.data?.threadGroupX !== 64 || group.data?.threadGroupY !== 1 || group.data?.threadGroupZ !== 1 || temps.operands?.length || group.operands?.length) {
|
|
458
|
+
throw new Error("WGSL structured skinning compute requires ten temps and dcl_thread_group 64,1,1");
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function validateBindings(bindings) {
|
|
462
|
+
const expected = [["uniform-buffer", 3, "cb3", "array<vec4<f32>, 3>", null, "uniform", 48], ["sampled-resource", 0, "t0", "array<u32>", 48, "read-only-storage", 48], ["sampled-resource", 1, "t1", "array<u32>", 4, "read-only-storage", 4], ["storage-resource", 0, "u0", "array<u32>", 4, "storage", 4]];
|
|
463
|
+
if (bindings.length !== expected.length || expected.some(([kind, registerIndex, symbol, type, stride, bufferType, minSize], index) => {
|
|
464
|
+
const binding = bindings[index];
|
|
465
|
+
return binding?.resourceKind !== kind || binding.registerIndex !== registerIndex || binding.registerSpace !== 0 || binding.generatedSymbol !== symbol || binding.type !== type || (binding.structureStride ?? null) !== stride || binding.buffer?.type !== bufferType || binding.buffer.hasDynamicOffset !== false || binding.buffer.minBindingSize !== minSize;
|
|
466
|
+
})) {
|
|
467
|
+
throw new Error("WGSL structured skinning compute binding layout does not match cb3/t0/t1/u0");
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
function validateBody(program) {
|
|
471
|
+
if (program.instructions?.length !== BODY_OPCODES.length || BODY_OPCODES.some((opcodeName, index) => program.instructions[index]?.opcodeName !== opcodeName || instructionOperandSignature(program.instructions[index]) !== BODY_OPERANDS[index])) {
|
|
472
|
+
throw new Error("WGSL structured skinning compute requires the exact bounded body opcode and operand sequence");
|
|
473
|
+
}
|
|
474
|
+
for (const [index, instruction] of program.instructions.entries()) {
|
|
475
|
+
const expectedControl = CONTROL_KIND[instruction.opcodeName] || null;
|
|
476
|
+
const extensions = instruction.extensions || [];
|
|
477
|
+
const resourceIndex = instruction.operands?.[3]?.registerIndex;
|
|
478
|
+
const expectedStride = resourceIndex === 0 ? 48 : resourceIndex === 1 ? 4 : null;
|
|
479
|
+
const hasValidExtensions = instruction.opcodeName === "ld_structured" ? validateSm50ResourceExtensions(extensions, {
|
|
480
|
+
resourceDimension: 12,
|
|
481
|
+
resourceDimensionName: "structured_buffer",
|
|
482
|
+
structureStride: expectedStride,
|
|
483
|
+
resourceReturnTypes: [6, 6, 6, 6]
|
|
484
|
+
}, `WGSL structured skinning instruction ${index}`) : extensions.length === 0;
|
|
485
|
+
if (instruction.index !== index || index > 0 && instruction.dxbcOffset <= program.instructions[index - 1].dxbcOffset || instruction.controlKind !== expectedControl || instruction.testBoolean !== (instruction.opcodeName === "if" ? "nonzero" : null) || instruction.saturate || instruction.preciseMask !== "" || !hasValidExtensions) {
|
|
486
|
+
throw new Error(`WGSL structured skinning instruction ${index} has inconsistent envelope metadata`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
validateAnalysisMetadata(program);
|
|
490
|
+
const values = new Map(program.values.map(value => [value.id, value]));
|
|
491
|
+
for (const instruction of program.instructions) {
|
|
492
|
+
for (const ref of instruction.dataflow.reads.flatMap(read => read.refs)) {
|
|
493
|
+
if (values.get(ref.valueId)?.origin === "undefined-register") {
|
|
494
|
+
throw new Error(`WGSL structured skinning instruction ${instruction.index} reads undefined register data`);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
const plans = buildSelectionPlans(program, "structured skinning compute");
|
|
499
|
+
if (plans.size !== 2 || plans.get(1)?.kind !== "selection" || plans.get(1).hasElse || plans.get(1).merges.length || plans.get(9)?.kind !== "selection" || !plans.get(9).hasElse || plans.get(9).merges.length !== 12) {
|
|
500
|
+
throw new Error("WGSL structured skinning compute requires the canonical nested selection and live merges");
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
function lowerBody(program, bindings) {
|
|
504
|
+
const statements = Array.from({
|
|
505
|
+
length: 10
|
|
506
|
+
}, (_, registerIndex) => ({
|
|
507
|
+
kind: "var",
|
|
508
|
+
name: `r${registerIndex}`,
|
|
509
|
+
type: "vec4<u32>",
|
|
510
|
+
expression: {
|
|
511
|
+
code: "vec4<u32>(0u)",
|
|
512
|
+
type: "vec4<u32>"
|
|
513
|
+
}
|
|
514
|
+
}));
|
|
515
|
+
const stack = [];
|
|
516
|
+
let current = statements;
|
|
517
|
+
for (const instruction of program.instructions) {
|
|
518
|
+
if (instruction.opcodeName === "if") {
|
|
519
|
+
if (instruction.operands.length !== 1) {
|
|
520
|
+
throw new Error(`WGSL structured skinning if ${instruction.index} requires one condition`);
|
|
521
|
+
}
|
|
522
|
+
validateScalarSource(instruction.operands[0], instruction, 0, "temp");
|
|
523
|
+
const condition = sourceParts(instruction, 0, ["x"])[0];
|
|
524
|
+
const statement = {
|
|
525
|
+
kind: "if",
|
|
526
|
+
instructionIndex: instruction.index,
|
|
527
|
+
dxbcOffset: instruction.dxbcOffset,
|
|
528
|
+
condition: {
|
|
529
|
+
code: `${condition} != 0u`,
|
|
530
|
+
type: "bool"
|
|
531
|
+
},
|
|
532
|
+
statements: []
|
|
533
|
+
};
|
|
534
|
+
current.push(statement);
|
|
535
|
+
stack.push({
|
|
536
|
+
parent: current,
|
|
537
|
+
statement
|
|
538
|
+
});
|
|
539
|
+
current = statement.statements;
|
|
540
|
+
continue;
|
|
541
|
+
}
|
|
542
|
+
if (instruction.opcodeName === "else") {
|
|
543
|
+
if (instruction.operands.length || !stack.length || stack.at(-1).statement.elseStatements) {
|
|
544
|
+
throw new Error(`WGSL structured skinning else ${instruction.index} has malformed nesting`);
|
|
545
|
+
}
|
|
546
|
+
stack.at(-1).statement.elseStatements = [];
|
|
547
|
+
current = stack.at(-1).statement.elseStatements;
|
|
548
|
+
continue;
|
|
549
|
+
}
|
|
550
|
+
if (instruction.opcodeName === "endif") {
|
|
551
|
+
if (instruction.operands.length || !stack.length) {
|
|
552
|
+
throw new Error(`WGSL structured skinning endif ${instruction.index} has malformed nesting`);
|
|
553
|
+
}
|
|
554
|
+
current = stack.pop().parent;
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
if (instruction.opcodeName === "ret") {
|
|
558
|
+
if (instruction.operands.length || stack.length) {
|
|
559
|
+
throw new Error(`WGSL structured skinning return ${instruction.index} has malformed nesting`);
|
|
560
|
+
}
|
|
561
|
+
current.push({
|
|
562
|
+
kind: "return",
|
|
563
|
+
instructionIndex: instruction.index,
|
|
564
|
+
dxbcOffset: instruction.dxbcOffset
|
|
565
|
+
});
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
const statement = instruction.opcodeName === "ld_structured" ? safeStructuredLoad(program, instruction, bindings) : instruction.opcodeName === "store_structured" ? structuredStore(program, instruction, bindings) : aluStatement(instruction);
|
|
569
|
+
current.push(statement);
|
|
570
|
+
}
|
|
571
|
+
if (stack.length) {
|
|
572
|
+
throw new Error("WGSL structured skinning compute contains unterminated selection nesting");
|
|
573
|
+
}
|
|
574
|
+
return statements;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Whether declarations select the isolated structured skinning compute
|
|
579
|
+
* profile. Detailed declaration/body validation belongs to the selected
|
|
580
|
+
* profile and never falls through to another lowerer.
|
|
581
|
+
*
|
|
582
|
+
* @param {object} program CJS shader IR program.
|
|
583
|
+
* @returns {boolean} True for the structured skinning declaration family.
|
|
584
|
+
*/
|
|
585
|
+
function isSkinVerticesComputeProfile(program) {
|
|
586
|
+
return program?.stage === "compute" && program.declarations?.length === DECLARATION_OPCODES.length && DECLARATION_OPCODES.every((opcodeName, index) => program.declarations[index]?.opcodeName === opcodeName);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Lowers the bounded structured skinning compute profile.
|
|
591
|
+
*
|
|
592
|
+
* @param {object} program CJS shader IR program.
|
|
593
|
+
* @param {object} [options] Exact compute-only binding options.
|
|
594
|
+
* @returns {object} Typed compute program.
|
|
595
|
+
*/
|
|
596
|
+
function lowerSkinVerticesComputeProgram(program, options = {}) {
|
|
597
|
+
validateDeclarations(program);
|
|
598
|
+
validateBody(program);
|
|
599
|
+
const bindings = lowerBindingLayout(program, options.bindingPlan ?? null);
|
|
600
|
+
validateBindings(bindings);
|
|
601
|
+
const statements = lowerBody(program, bindings);
|
|
602
|
+
return deepFreeze({
|
|
603
|
+
kind: "typed-shader-program",
|
|
604
|
+
format: "CJS_TYPED_SHADER",
|
|
605
|
+
formatVersion: 1,
|
|
606
|
+
source: program.source,
|
|
607
|
+
stage: "compute",
|
|
608
|
+
entryPoint: "main",
|
|
609
|
+
builtinInputs: [{
|
|
610
|
+
builtin: "global_invocation_id",
|
|
611
|
+
name: "dispatch_thread_id",
|
|
612
|
+
type: "vec3<u32>"
|
|
613
|
+
}],
|
|
614
|
+
threadGroupSize: [64, 1, 1],
|
|
615
|
+
bindings,
|
|
616
|
+
statements
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
export { isSkinVerticesComputeProfile, lowerSkinVerticesComputeProgram };
|
|
621
|
+
//# sourceMappingURL=lowerSkinVerticesComputeProgram.js.map
|