@carbonenginejs/runtime-resource 0.11.1 → 0.12.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/CjsResMan.js +4 -4
- package/dist/CjsResMan.js.map +1 -1
- package/dist/_virtual/_rollupPluginBabelHelpers.js +1 -4
- package/dist/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
- package/dist/format/CjsByteReader.js +310 -0
- package/dist/format/CjsByteReader.js.map +1 -0
- package/dist/format/CjsByteWriter.js +242 -0
- package/dist/format/CjsByteWriter.js.map +1 -0
- package/dist/format/CjsFormatError.js +41 -0
- package/dist/format/CjsFormatError.js.map +1 -0
- package/dist/format/CjsStringTable.js +268 -0
- package/dist/format/CjsStringTable.js.map +1 -0
- package/dist/format/carbonEffect/CjsCarbonEffectReader.js +361 -0
- package/dist/format/carbonEffect/CjsCarbonEffectReader.js.map +1 -0
- package/dist/format/carbonEffect/CjsCarbonEffectWriter.js +373 -0
- package/dist/format/carbonEffect/CjsCarbonEffectWriter.js.map +1 -0
- package/dist/format/carbonEffect/carbonDescriptionFromPortable.js +372 -0
- package/dist/format/carbonEffect/carbonDescriptionFromPortable.js.map +1 -0
- package/dist/format/carbonEffect/carbonEffectBackendBlock.js +427 -0
- package/dist/format/carbonEffect/carbonEffectBackendBlock.js.map +1 -0
- package/dist/format/carbonEffect/carbonEffectRecords.js +955 -0
- package/dist/format/carbonEffect/carbonEffectRecords.js.map +1 -0
- package/dist/format/compareUtf8.js +36 -0
- package/dist/format/compareUtf8.js.map +1 -0
- package/dist/format/index.js +11 -0
- package/dist/format/index.js.map +1 -0
- package/dist/formats/bnk/CjsBnkFormat.js +18 -2
- package/dist/formats/bnk/CjsBnkFormat.js.map +1 -1
- package/dist/formats/bnk/core/eventAction.js +305 -0
- package/dist/formats/bnk/core/eventAction.js.map +1 -0
- package/dist/formats/bnk/core/graph.js +3 -6
- package/dist/formats/bnk/core/graph.js.map +1 -1
- package/dist/formats/bnk/core/helpers.js +62 -11
- package/dist/formats/bnk/core/helpers.js.map +1 -1
- package/dist/formats/bnk/core/nodeBase.js +532 -0
- package/dist/formats/bnk/core/nodeBase.js.map +1 -0
- package/dist/formats/bnk/core/sfxNodes.js +632 -0
- package/dist/formats/bnk/core/sfxNodes.js.map +1 -0
- package/dist/formats/bnk/core/soundbanksInfo.js +59 -51
- package/dist/formats/bnk/core/soundbanksInfo.js.map +1 -1
- package/dist/formats/gr2/CjsGr2Format.js +256 -13
- package/dist/formats/gr2/CjsGr2Format.js.map +1 -1
- package/dist/formats/gr2/core/helpers.js +15 -15
- package/dist/formats/gr2/core/helpers.js.map +1 -1
- package/dist/formats/gr2/core/json.js +1 -1
- package/dist/formats/gr2/core/json.js.map +1 -1
- package/dist/formats/gr2/core/targets.js +1 -1
- package/dist/formats/gr2/core/targets.js.map +1 -1
- package/dist/formats/gr2/index.js +0 -1
- package/dist/formats/gr2/index.js.map +1 -1
- package/dist/formats/hlsl/core/HlslReader.js +7 -257
- package/dist/formats/hlsl/core/HlslReader.js.map +1 -1
- package/dist/formats/hlsl/core/analysis.js +1 -1
- package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js +781 -0
- package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js.map +1 -0
- package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js +21 -1
- package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js.map +1 -1
- package/dist/formats/hlsl/index.js +1 -0
- package/dist/formats/hlsl/index.js.map +1 -1
- package/dist/formats/index.js +3 -6
- package/dist/formats/index.js.map +1 -1
- package/dist/formats/webgl/core/cewg/CewgPackage.js +2 -1
- package/dist/formats/webgl/core/cewg/CewgPackage.js.map +1 -1
- package/dist/formats/webgl/core/cewg/binary.js +11 -93
- package/dist/formats/webgl/core/cewg/binary.js.map +1 -1
- package/dist/formats/webgl/core/effectPackage.js +4 -1
- package/dist/formats/webgl/core/effectPackage.js.map +1 -1
- package/dist/formats/webgl/core/errors.js +3 -3
- package/dist/formats/webgl/core/errors.js.map +1 -1
- package/dist/formats/webgpu/CjsWebgpuFormat.js +4 -23
- package/dist/formats/webgpu/CjsWebgpuFormat.js.map +1 -1
- package/dist/formats/webgpu/core/buildCarbonEffectContainer.js +197 -0
- package/dist/formats/webgpu/core/buildCarbonEffectContainer.js.map +1 -0
- package/dist/formats/webgpu/core/cewgpu/CewgpuContainer.js +368 -0
- package/dist/formats/webgpu/core/cewgpu/CewgpuContainer.js.map +1 -0
- package/dist/formats/webgpu/core/cewgpu/containerViews.js +355 -0
- package/dist/formats/webgpu/core/cewgpu/containerViews.js.map +1 -0
- package/dist/formats/webgpu/core/cewgpu/validateContainer.js +90 -0
- package/dist/formats/webgpu/core/cewgpu/validateContainer.js.map +1 -0
- package/dist/formats/webgpu/core/effectBackendBodySet.js +21 -20
- package/dist/formats/webgpu/core/effectBackendBodySet.js.map +1 -1
- package/dist/formats/webgpu/core/helpers.js +87 -92
- package/dist/formats/webgpu/core/helpers.js.map +1 -1
- package/dist/formats/webgpu/core/ir/analyzeRegisterValues.js +14 -13
- package/dist/formats/webgpu/core/ir/analyzeRegisterValues.js.map +1 -1
- package/dist/formats/webgpu/core/ir/inferValueTypes.js +10 -8
- package/dist/formats/webgpu/core/ir/inferValueTypes.js.map +1 -1
- package/dist/formats/webgpu/core/packageEffect.js +94 -9
- package/dist/formats/webgpu/core/packageEffect.js.map +1 -1
- package/dist/formats/webgpu/core/packageMetadata.js +10 -1
- package/dist/formats/webgpu/core/packageMetadata.js.map +1 -1
- package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js +17 -15
- package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js.map +1 -1
- package/dist/formats/webgpu/core/wgsl/buildWgslBindingPlan.js +13 -12
- package/dist/formats/webgpu/core/wgsl/buildWgslBindingPlan.js.map +1 -1
- package/dist/formats/webgpu/core/wgsl/buildWgslSet.js +9 -8
- package/dist/formats/webgpu/core/wgsl/buildWgslSet.js.map +1 -1
- package/dist/formats/webgpu/core/wgsl/lowerComputeProgram.js +23 -22
- package/dist/formats/webgpu/core/wgsl/lowerComputeProgram.js.map +1 -1
- package/dist/formats/webgpu/core/wgsl/selectionPlans.js +46 -44
- package/dist/formats/webgpu/core/wgsl/selectionPlans.js.map +1 -1
- package/dist/resource/CjsResource.js +700 -684
- package/dist/resource/CjsResource.js.map +1 -1
- package/dist/resource/Tr2LightProfileRes.js +18 -27
- package/dist/resource/Tr2LightProfileRes.js.map +1 -1
- package/dist/resource/audio/CjsAudioBufferRes.js +2 -2
- package/dist/resource/audio/CjsAudioBufferRes.js.map +1 -1
- package/dist/resource/audio/CjsAudioRes.js +2 -2
- package/dist/resource/audio/CjsAudioRes.js.map +1 -1
- package/dist/resource/geometry/TriGeometryRes.js +605 -586
- package/dist/resource/geometry/TriGeometryRes.js.map +1 -1
- package/dist/resource/geometry/granny/Tr2GrannyStateRes.js +21 -30
- package/dist/resource/geometry/granny/Tr2GrannyStateRes.js.map +1 -1
- package/dist/resource/geometry/granny/TriGrannyRes.js +21 -30
- package/dist/resource/geometry/granny/TriGrannyRes.js.map +1 -1
- package/dist/resource/shader/Tr2EffectRes.js +9 -7
- package/dist/resource/shader/Tr2EffectRes.js.map +1 -1
- package/dist/resource/shader/Tr2MaterialArea.js +5 -3
- package/dist/resource/shader/Tr2MaterialArea.js.map +1 -1
- package/dist/resource/shader/Tr2MaterialMesh.js +4 -2
- package/dist/resource/shader/Tr2MaterialMesh.js.map +1 -1
- package/dist/resource/shader/Tr2MaterialRes.js +5 -3
- package/dist/resource/shader/Tr2MaterialRes.js.map +1 -1
- package/dist/resource/shader/Tr2Shader.js +26 -21
- package/dist/resource/shader/Tr2Shader.js.map +1 -1
- package/dist/resource/shader/Tr2ShaderPermutation.js +8 -6
- package/dist/resource/shader/Tr2ShaderPermutation.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectDefine.js +5 -3
- package/dist/resource/shader/reflection/Tr2EffectDefine.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectDescription.js +5 -3
- package/dist/resource/shader/reflection/Tr2EffectDescription.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectLibrary.js +17 -15
- package/dist/resource/shader/reflection/Tr2EffectLibrary.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js +11 -9
- package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectResource.js +8 -6
- package/dist/resource/shader/reflection/Tr2EffectResource.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectStageInput.js +15 -13
- package/dist/resource/shader/reflection/Tr2EffectStageInput.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2EffectTechnique.js +7 -5
- package/dist/resource/shader/reflection/Tr2EffectTechnique.js.map +1 -1
- package/dist/resource/shader/reflection/Tr2Pass.js +11 -9
- package/dist/resource/shader/reflection/Tr2Pass.js.map +1 -1
- package/dist/resource/shader/sampler/Tr2SamplerSetup.js +8 -6
- package/dist/resource/shader/sampler/Tr2SamplerSetup.js.map +1 -1
- package/dist/resource/texture/CjsTextureArrayRes.js +400 -411
- package/dist/resource/texture/CjsTextureArrayRes.js.map +1 -1
- package/dist/resource/texture/Tr2ImageRes.js +99 -95
- package/dist/resource/texture/Tr2ImageRes.js.map +1 -1
- package/dist/resource/texture/TriTextureRes.js +312 -273
- package/dist/resource/texture/TriTextureRes.js.map +1 -1
- package/docs/README.md +13 -1
- package/docs/architecture.md +3 -3
- package/docs/concepts/resource-lifecycle.md +9 -2
- package/docs/concepts/shader-resource-model.md +114 -0
- package/docs/concepts/writing-an-engine-adapter.md +115 -0
- package/docs/formats/README.md +24 -1
- package/docs/formats/carbon-effect-container.md +452 -0
- package/docs/formats/dxbc/README.md +68 -0
- package/docs/formats/dxbc/architecture.md +80 -0
- package/docs/formats/dxbc/reference/api.md +77 -0
- package/docs/formats/dxbc/reference/classes/README.md +9 -0
- package/docs/formats/dxbc/reference/decoded-output.md +122 -0
- package/docs/formats/gr2.md +3 -4
- package/docs/formats/hlsl/README.md +54 -0
- package/docs/formats/hlsl/architecture.md +67 -0
- package/docs/formats/hlsl/guides/hydrating-json-output.md +62 -0
- package/docs/formats/hlsl/guides/reading-effects.md +64 -0
- package/docs/formats/hlsl/reference/advanced-analysis.md +66 -0
- package/docs/formats/hlsl/reference/api.md +98 -0
- package/docs/formats/hlsl/reference/classes/README.md +11 -0
- package/docs/formats/hlsl/reference/json-graph.md +100 -0
- package/docs/formats/hlsl/reference/portable-reflection.md +141 -0
- package/docs/formats/provenance.md +32 -17
- package/docs/formats/webgl/README.md +57 -0
- package/docs/formats/webgl/architecture.md +70 -0
- package/docs/formats/webgl/carbon-constant-layouts.md +326 -0
- package/docs/formats/webgl/decl-io.md +1234 -0
- package/docs/formats/webgl/effect-reflection.md +127 -0
- package/docs/formats/webgl/memory-structured.md +871 -0
- package/docs/formats/webgl/reference/classes/README.md +9 -0
- package/docs/formats/webgl/texture-sample.md +964 -0
- package/docs/formats/webgpu/README.md +84 -0
- package/docs/formats/webgpu/architecture.md +96 -0
- package/docs/formats/webgpu/formats/cewgpu.md +216 -0
- package/docs/formats/webgpu/guides/effect-packaging.md +191 -0
- package/docs/formats/webgpu/reference/api.md +197 -0
- package/docs/formats/webgpu/reference/classes/README.md +9 -0
- package/docs/formats/webgpu/reference/wgsl-compatibility.md +1543 -0
- package/docs/formats/wwise.md +45 -4
- package/docs/reference/classes/core.md +80 -0
- package/docs/reference/classes/formats.md +24 -34
- package/docs/reference/events.md +25 -0
- package/docs/reference/motherlode-cache.md +22 -8
- package/docs/reference/workers.md +5 -5
- package/docs/roadmap.md +61 -41
- package/format-notices/bnk/NOTICE +5 -4
- package/format-notices/webgl/NOTICE +1 -1
- package/package.json +2 -1
- package/dist/formats/gr2/core/CjsFormatGr2.js +0 -273
- package/dist/formats/gr2/core/CjsFormatGr2.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/CewgpuPackage.js +0 -415
- package/dist/formats/webgpu/core/cewgpu/CewgpuPackage.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/CewgpuPackageBuilder.js +0 -100
- package/dist/formats/webgpu/core/cewgpu/CewgpuPackageBuilder.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/binary.js +0 -93
- package/dist/formats/webgpu/core/cewgpu/binary.js.map +0 -1
- package/dist/formats/webgpu/core/cewgpu/tags.js +0 -17
- package/dist/formats/webgpu/core/cewgpu/tags.js.map +0 -1
- package/dist/formats/webgpu/core/effectPackageValidation.js +0 -1078
- package/dist/formats/webgpu/core/effectPackageValidation.js.map +0 -1
|
@@ -0,0 +1,1234 @@
|
|
|
1
|
+
# DXBC -> GLSL ES 3.00 Lowering Spec: `decl-io` Family
|
|
2
|
+
|
|
3
|
+
Status: Evolving
|
|
4
|
+
Scope: `@carbonenginejs/runtime-resource/formats/webgl` declaration and stage-I/O lowering
|
|
5
|
+
Audience: Shader translator maintainers and reviewers
|
|
6
|
+
Summary: Defines the DXBC declaration and I/O rules used by the GLSL emitter.
|
|
7
|
+
|
|
8
|
+
Target: GLSL ES 3.00 (WebGL2), vertex + pixel stages only. No SSBOs, no compute, no
|
|
9
|
+
tessellation/geometry stages (facts for those stages are cited where they explain
|
|
10
|
+
*why* a code path in the authority source is skipped, never as things this emitter
|
|
11
|
+
must implement).
|
|
12
|
+
|
|
13
|
+
Register model for this emitter (differs from stock HLSLcc, stated once here so every
|
|
14
|
+
section below can just say "the float vec4 register file"): every DXBC temp/output
|
|
15
|
+
register is stored as a `vec4` of floats. Instructions that need int or uint semantics
|
|
16
|
+
bitcast at the use site with `floatBitsToInt` / `floatBitsToUint` on read and
|
|
17
|
+
`intBitsToFloat` / `uintBitsToFloat` on write, exactly mirroring the bitcast operator
|
|
18
|
+
names HLSLcc itself uses when it emits its own (non-register-collapsed) integer path
|
|
19
|
+
(`GetBitcastOp`, `vendor/HLSLcc/src/toGLSLOperand.cpp:327-353`). Stock HLSLcc instead
|
|
20
|
+
runs `DataTypeAnalysis` and gives each temp register a native-typed shadow variable
|
|
21
|
+
(`u_xlatN` float, `u_xlatiN` int, `u_xlatuN` uint, ...). This spec calls out every
|
|
22
|
+
place our float-only convention diverges from that stock behavior.
|
|
23
|
+
|
|
24
|
+
Corpus counts (450k-instruction sweep, 1611 EVE Online DX11 effects), used to order
|
|
25
|
+
sections by real-world impact:
|
|
26
|
+
|
|
27
|
+
| Opcode | Count |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `dcl_output` | 15197 |
|
|
30
|
+
| `dcl_input` | 11726 |
|
|
31
|
+
| `dcl_constant_buffer` | 10160 |
|
|
32
|
+
| `dcl_input_ps` | 6995 |
|
|
33
|
+
| `dcl_resource` | 6317 |
|
|
34
|
+
| `dcl_global_flags` | 5848 |
|
|
35
|
+
| `dcl_temps` | 5035 |
|
|
36
|
+
| `dcl_sampler` | 3277 |
|
|
37
|
+
| `dcl_output_siv` | 2825 |
|
|
38
|
+
| `dcl_resource_structured` | 684 |
|
|
39
|
+
| `dcl_input_ps_siv` | 538 |
|
|
40
|
+
| `dcl_input_ps_sgv` | 42 |
|
|
41
|
+
| `dcl_input_sgv` | 18 |
|
|
42
|
+
| `dcl_indexable_temp` | 16 |
|
|
43
|
+
| `dcl_input_siv` | 3 |
|
|
44
|
+
| `customdata` | 159 |
|
|
45
|
+
|
|
46
|
+
All line numbers below refer to `vendor/HLSLcc/src/toGLSLDeclaration.cpp`
|
|
47
|
+
unless another file is named.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Emission order and `#version` boilerplate
|
|
52
|
+
|
|
53
|
+
Authority: `vendor/HLSLcc/src/toGLSL.cpp`.
|
|
54
|
+
|
|
55
|
+
HLSLcc builds the final GLSL text as two bstrings that get concatenated at the very
|
|
56
|
+
end (`toGLSL.cpp:1039` region: `// Concat extensions and glsl for the final shader
|
|
57
|
+
code.`):
|
|
58
|
+
|
|
59
|
+
1. `extensions` — seeded with the version string (`toGLSL.cpp:617`,
|
|
60
|
+
`GetVersionString(LANG_ES_300)` returns `"#version 300 es\n"` at `toGLSL.cpp:387`),
|
|
61
|
+
then every `#extension ... : require|enable` line added by `RequireExtension` /
|
|
62
|
+
`EnableExtension` calls made while walking declarations and instructions.
|
|
63
|
+
2. `glsl` — populated in this order:
|
|
64
|
+
a. `AddVersionDependentCode` (`toGLSL.cpp:93`, called at `toGLSL.cpp:647`) emits,
|
|
65
|
+
for pixel shaders on an ES target (`toGLSL.cpp:307-328`):
|
|
66
|
+
```
|
|
67
|
+
precision highp float;
|
|
68
|
+
precision highp int;
|
|
69
|
+
```
|
|
70
|
+
(int precision is forced to `highp` "to avoid issues on platforms that
|
|
71
|
+
actually implement mediump" — comment at `toGLSL.cpp:326`). Vertex shaders get
|
|
72
|
+
no default-precision block from this path.
|
|
73
|
+
b. If the shader has any constant buffers or textures, two `#define` blocks for
|
|
74
|
+
`UNITY_LOCATION`/`UNITY_BINDING`/`HLSLCC_ENABLE_UNIFORM_BUFFERS` macros
|
|
75
|
+
(`toGLSL.cpp:667-691`). These are Unity-build plumbing; a from-scratch JS
|
|
76
|
+
emitter does not need the macro indirection, only the concrete
|
|
77
|
+
`layout(std140) uniform ... { vec4 data[N]; } cbN;` text it expands to when the
|
|
78
|
+
macros are defined to `1` (the emitter should hardcode the "enabled" expansion,
|
|
79
|
+
not restate the `#if`/`#else` machinery, since WebGL2 has no runtime toggle for
|
|
80
|
+
it).
|
|
81
|
+
c. `TranslateDeclaration` for every `Declaration` in bytecode order — this is the
|
|
82
|
+
entire `decl-io` family plus every other declaration opcode.
|
|
83
|
+
d. `void main() { ... }` with early-main redirect code, then translated
|
|
84
|
+
instructions.
|
|
85
|
+
|
|
86
|
+
**WebGL2 note**: emit exactly `#version 300 es` as line 1, nothing before it (WebGL2
|
|
87
|
+
rejects any non-comment/non-whitespace token before `#version`). Do not emit the
|
|
88
|
+
`GL_FRAGMENT_PRECISION_HIGH` `#ifdef` dance used for `LANG_ES_100`
|
|
89
|
+
(`toGLSL.cpp:311-320`) — that branch is ES 2.0-only; ES 3.00 always has `highp`
|
|
90
|
+
fragment-shader float support and HLSLcc itself only takes the unconditional
|
|
91
|
+
`precision highp float;` branch for `LANG_ES_300` (`toGLSL.cpp:321-324`).
|
|
92
|
+
|
|
93
|
+
**Confidence: high** — this is a straight read of the concatenation order in
|
|
94
|
+
`toGLSL.cpp`, not a translated instruction whose semantics could be ambiguous.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## `dcl_global_flags` (5848)
|
|
99
|
+
|
|
100
|
+
**Semantics**: DXBC global shader flags (`D3D10_SB_GLOBAL_FLAGS`) declared once per
|
|
101
|
+
shader: refactoring-allowed, force-early-depth-stencil, enable double-precision float
|
|
102
|
+
ops, skip-optimization, enable raw/structured buffers, etc. Purely a compiler-hint
|
|
103
|
+
bitfield, not a register declaration.
|
|
104
|
+
|
|
105
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:2781-2809`. Only two bits produce any GLSL
|
|
106
|
+
text in our target subset:
|
|
107
|
+
- `GLOBAL_FLAG_FORCE_EARLY_DEPTH_STENCIL` on a pixel shader emits
|
|
108
|
+
`layout(early_fragment_tests) in;\n` (`2785-2789`) unconditionally — no target
|
|
109
|
+
language gate in the C++ source.
|
|
110
|
+
- `GLOBAL_FLAG_REFACTORING_ALLOWED` combined with `HavePreciseQualifier` emits four
|
|
111
|
+
`precise <type> u_xlat_precise_<type>;` globals (`2790-2802`) — desktop-only
|
|
112
|
+
qualifier gate, unreachable for `LANG_ES_300`.
|
|
113
|
+
- `GLOBAL_FLAG_ENABLE_DOUBLE_PRECISION_FLOAT_OPS` requires
|
|
114
|
+
`GL_ARB_gpu_shader_fp64` (`2803-2807`) — desktop-only, unreachable for ES targets.
|
|
115
|
+
|
|
116
|
+
All other flag bits (skip-optimization, minimum-precision, enable-raw-and-structured,
|
|
117
|
+
force-early-*, all-resources-bound, etc.) are read by the decoder for correctness of
|
|
118
|
+
other lowering decisions but emit no GLSL text here.
|
|
119
|
+
|
|
120
|
+
**Type rules**: n/a — no operands, no register.
|
|
121
|
+
|
|
122
|
+
**Helpers needed**: none.
|
|
123
|
+
|
|
124
|
+
**Edge cases**: this instruction fires on almost every real shader (5848/1611 files ≈
|
|
125
|
+
one per shader stage), but the `FORCE_EARLY_DEPTH_STENCIL` bit itself is set on only a
|
|
126
|
+
minority of those. **WebGL2 note (important deviation from stock HLSLcc)**:
|
|
127
|
+
`layout(early_fragment_tests) in;` is a GLSL ES 3.10 / desktop-4.20 feature
|
|
128
|
+
(`GL_ARB_shader_image_load_store` era) and is **not part of GLSL ES 3.00** — WebGL2
|
|
129
|
+
will fail to compile a fragment shader containing this qualifier. Since the C++
|
|
130
|
+
source emits it unconditionally whenever the flag bit is set and the stage is a
|
|
131
|
+
pixel shader, this JS emitter must add a language gate stock HLSLcc does not have:
|
|
132
|
+
suppress the `layout(early_fragment_tests) in;` line entirely when targeting ES 3.00
|
|
133
|
+
(early-fragment-tests is a depth-test-ordering optimization hint only; skipping it is
|
|
134
|
+
always semantically safe, just potentially slower).
|
|
135
|
+
|
|
136
|
+
**Confidence: medium** — the flag-to-GLSL mapping is a direct source read (high
|
|
137
|
+
confidence), but whether any EVE shader in the corpus actually sets
|
|
138
|
+
`FORCE_EARLY_DEPTH_STENCIL` (making the WebGL2 gate load-bearing) was not verified
|
|
139
|
+
against the corpus in this pass.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## `dcl_temps` (5035)
|
|
144
|
+
|
|
145
|
+
**Semantics**: declares the count of general-purpose temporary registers (`r0..r{N-1}`)
|
|
146
|
+
used by the current shader phase (`D3D10_SB_OPCODE_DCL_TEMPS`, one dword: `ui32NumTemps`).
|
|
147
|
+
|
|
148
|
+
**GLSL lowering (stock HLSLcc)**: `toGLSLDeclaration.cpp:2425-2523`. For each temp
|
|
149
|
+
index `i`, HLSLcc's `DataTypeAnalysis` pass has already recorded which *native* GLSL
|
|
150
|
+
types that register was ever read/written as (`psFloatTempSizes[i]`,
|
|
151
|
+
`psIntTempSizes[i]`, `psUIntTempSizes[i]`, `psBoolTempSizes[i]`, plus 16/12/10-bit
|
|
152
|
+
minimum-precision and `fp64` variants), and HLSLcc declares one shadow variable per
|
|
153
|
+
type actually used, e.g.:
|
|
154
|
+
```
|
|
155
|
+
vec4 u_xlat0;
|
|
156
|
+
int u_xlati0; // only if r0 was ever read/written as int
|
|
157
|
+
uint u_xlatu0; // only if r0 was ever read/written as uint
|
|
158
|
+
```
|
|
159
|
+
(prefix macro `HLSLCC_TEMP_PREFIX` = `"u_xlat"`, `vendor/HLSLcc/include/hlslcc.h:127`).
|
|
160
|
+
On Switch targets only, each gets a `= <ctor>(0)` default initializer
|
|
161
|
+
(`2436-2498`) to dodge a false-positive uninitialized-variable compiler warning;
|
|
162
|
+
non-Switch targets declare with no initializer (`2501-2521`).
|
|
163
|
+
|
|
164
|
+
**GLSL lowering (this emitter's float-only register file — required deviation)**:
|
|
165
|
+
because this project does not run `DataTypeAnalysis` (that pass requires full
|
|
166
|
+
def/use dataflow over the instruction stream, ref: project brief), declare exactly
|
|
167
|
+
one `vec4` per temp index, unconditionally:
|
|
168
|
+
```
|
|
169
|
+
vec4 r0;
|
|
170
|
+
vec4 r1;
|
|
171
|
+
...
|
|
172
|
+
vec4 r{N-1};
|
|
173
|
+
```
|
|
174
|
+
Every instruction that consumes `rN` as int/uint wraps the read in
|
|
175
|
+
`floatBitsToInt(rN)` / `floatBitsToUint(rN)`; every instruction that produces an
|
|
176
|
+
int/uint result destined for `rN` wraps the write in `intBitsToFloat(...)` /
|
|
177
|
+
`uintBitsToFloat(...)` before assigning. This is the single largest structural
|
|
178
|
+
deviation from the stock HLSLcc temp-register model in this whole family — flag it
|
|
179
|
+
prominently to the instruction-family authors, since every arithmetic/logic opcode's
|
|
180
|
+
lowering depends on this convention holding for `dcl_temps`-declared registers.
|
|
181
|
+
|
|
182
|
+
**Type rules**: declared type is always `vec4` (float). Actual read/write type is
|
|
183
|
+
determined per-instruction by the consuming/producing opcode, not by this
|
|
184
|
+
declaration.
|
|
185
|
+
|
|
186
|
+
**Helpers needed**: none beyond the four bitcast builtins (already core GLSL ES 3.00,
|
|
187
|
+
not user-defined helpers).
|
|
188
|
+
|
|
189
|
+
**Edge cases**: initializing temps to zero (as HLSLcc does only for Switch) is *not*
|
|
190
|
+
required for GLSL ES 3.00/WebGL2 correctness in general, but this project's
|
|
191
|
+
`vec4(0.0)` fallback convention for signature-only outputs (see `dcl_output` below)
|
|
192
|
+
suggests the same defensive default-init could be applied here too if any code path
|
|
193
|
+
is ever found reading a temp before it is written; no corpus evidence of that has
|
|
194
|
+
been found (`TRANSPILING-GAPS.md` "Already handled" section reports 0 instruction
|
|
195
|
+
blockers). Recommend leaving temps uninitialized (matches non-Switch stock
|
|
196
|
+
behavior) unless a specific shader is found to depend on zero-init.
|
|
197
|
+
|
|
198
|
+
**Confidence: high** for the *stock* semantics (direct source read); **medium** for
|
|
199
|
+
the float-only deviation's completeness, since it depends on every opcode in the
|
|
200
|
+
sibling instruction-lowering families correctly bitcasting at every read/write site —
|
|
201
|
+
a single missed bitcast silently corrupts values without a compile error.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## `dcl_indexable_temp` (16)
|
|
206
|
+
|
|
207
|
+
**Semantics**: declares a dynamically-indexable local array of temp registers
|
|
208
|
+
(`x0[i]`-style addressing, as opposed to the flat `r#` file), used when HLSL source
|
|
209
|
+
has to write to computed indices (e.g. unrolled small loops writing into a local
|
|
210
|
+
array). Encodes register index, element count, and per-element component width.
|
|
211
|
+
|
|
212
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:3085-3092`:
|
|
213
|
+
```cpp
|
|
214
|
+
bformata(glsl, "vec%d TempArray%d[%d];\n", ui32RegComponentSize, ui32RegIndex, ui32RegCount);
|
|
215
|
+
```
|
|
216
|
+
i.e. `vec{ComponentSize} TempArray{RegIndex}[{RegCount}];` — component width (1-4)
|
|
217
|
+
comes directly from the DXBC declaration's `sIdxTemp.ui32RegComponentSize`, not from
|
|
218
|
+
signature/DataTypeAnalysis lookups.
|
|
219
|
+
|
|
220
|
+
**Type rules**: always declared as `float`-family vector (`vecN`), never `ivecN`/
|
|
221
|
+
`uvecN`, even in stock HLSLcc — indexable temps are HLSL-source local arrays, whose
|
|
222
|
+
element type is resolved by the DXBC compiler down to float storage before emission
|
|
223
|
+
in every observed case in this authority source. This emitter should mirror that:
|
|
224
|
+
declare `vecN TempArray{RegIndex}[RegCount];` where `N` is exactly the decoded
|
|
225
|
+
`ui32RegComponentSize` (do not force to `vec4` — unlike the flat temp-register file,
|
|
226
|
+
indexable-temp width is a hard DXBC-encoded fact, not a convention this project
|
|
227
|
+
gets to choose). Bitcast at use sites the same way as regular temps if any consumer
|
|
228
|
+
reads/writes it as int/uint.
|
|
229
|
+
|
|
230
|
+
**Helpers needed**: none.
|
|
231
|
+
|
|
232
|
+
**Edge cases**: rare (16 total instructions across the whole corpus) — low priority,
|
|
233
|
+
but get the declared width right since a mismatched vector size is a hard GLSL
|
|
234
|
+
compile error, not a silent bug.
|
|
235
|
+
|
|
236
|
+
**WebGL2 notes**: none beyond standard array declaration syntax, which GLSL ES 3.00
|
|
237
|
+
supports natively.
|
|
238
|
+
|
|
239
|
+
**Confidence: high** — single unconditional code path, no branching on target
|
|
240
|
+
language or shader stage.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## `dcl_constant_buffer` (10160)
|
|
245
|
+
|
|
246
|
+
**Semantics**: declares a constant-buffer binding (`cb#`) and its total `vec4`-slot
|
|
247
|
+
count, used by later `mov`/arithmetic instructions that read `cb#[i].component`.
|
|
248
|
+
Authoritative source for constant *names/offsets/layout* is Carbon/Trinity RDEF-derived
|
|
249
|
+
metadata, not this fork (`CARBONENGINEJS-FORK.md`: "Carbon/Trinity metadata remains
|
|
250
|
+
authoritative for ... per-frame and per-object constant buffer layout"); this fork's
|
|
251
|
+
job is only to keep the register-stable `cb#` GLSL symbol emitting correctly when that
|
|
252
|
+
reflection metadata is present *or stripped*.
|
|
253
|
+
|
|
254
|
+
**GLSL lowering — stripped-RDEF fallback (the path this project actually depends on)**:
|
|
255
|
+
`toGLSLDeclaration.cpp:2530-2559`. When `GetConstantBufferFromBindingPoint` returns
|
|
256
|
+
`nullptr` (no RDEF, or RDEF present but missing this specific buffer — the CarbonEngineJS
|
|
257
|
+
fork's stripped-reflection case, `CARBONENGINEJS-FORK.md` "Constant-buffer operands
|
|
258
|
+
emit fallback register access such as `cb3.data[0]`"), HLSLcc emits:
|
|
259
|
+
```cpp
|
|
260
|
+
bformata(glsl, "layout(std140) uniform %s {\n\tvec4 data[%d];\n} cb%d;\n",
|
|
261
|
+
name, psOperand->aui32ArraySizes[1], ui32BindingPoint);
|
|
262
|
+
```
|
|
263
|
+
i.e. exactly:
|
|
264
|
+
```glsl
|
|
265
|
+
layout(std140) uniform ConstantBuffer3 {
|
|
266
|
+
vec4 data[200];
|
|
267
|
+
} cb3;
|
|
268
|
+
```
|
|
269
|
+
where `ConstantBuffer{N}` is a synthesized block-type name (`name` built at
|
|
270
|
+
`2541-2542`, `sprintf(name, "ConstantBuffer%d", ui32BindingPoint)`), the instance
|
|
271
|
+
name is always `cb{N}` (`ui32BindingPoint`), and the array size is
|
|
272
|
+
`psOperand->aui32ArraySizes[1]` — the DXBC declaration's own encoded slot count, read
|
|
273
|
+
directly off the `dcl_constant_buffer` instruction, independent of any reflection
|
|
274
|
+
data. This `cbN.data[i]` register-stable access convention is the ABI this whole
|
|
275
|
+
project is built to preserve (`CARBONENGINEJS-FORK.md` "Runtime Contract";
|
|
276
|
+
`TRANSPILING-GAPS.md` records the cross-stage `ConstantBuffer0` size-mismatch bug
|
|
277
|
+
this produces when VS/PS declare different slot counts for the same `cb#` — normalize
|
|
278
|
+
to the maximum observed size across stages sharing a binding point before emitting).
|
|
279
|
+
If `UNITY_LOCATION`/binding macros are relevant (`2550-2555`) they add a
|
|
280
|
+
`UNITY_LOCATION(%d)` prefix, which this emitter should expand directly to
|
|
281
|
+
`layout(location = N)` text (WebGL2 has no runtime macro toggle, so skip the
|
|
282
|
+
`#if`/`#else` indirection described above).
|
|
283
|
+
|
|
284
|
+
**GLSL lowering — named/reflected path**: when RDEF metadata for the named cbuffer
|
|
285
|
+
*is* present, HLSLcc instead calls `DeclareUBOConstants`
|
|
286
|
+
(`877-997`, used when `HLSLCC_FLAG_UNIFORM_BUFFER_OBJECT` is set) or
|
|
287
|
+
`DeclareStructConstants` (`1094+`) to emit one named `float`/`vecN`/matrix member per
|
|
288
|
+
reflected constant, inside `uniform {CBufferName} { ... };`. This path is **not** the
|
|
289
|
+
ABI this project keeps stable end-to-end (Carbon metadata is the source of truth for
|
|
290
|
+
per-constant names/offsets, per `CARBONENGINEJS-FORK.md`); treat the fallback
|
|
291
|
+
`cbN.data[i]` form above as the primary target shape for this emitter, and the named
|
|
292
|
+
path as background context only.
|
|
293
|
+
|
|
294
|
+
**Type rules**: every `data[i]` slot is a `vec4` of floats; a `mov` or arithmetic
|
|
295
|
+
instruction reading `cb3.data[5].x` as an int/uint bitcasts with `floatBitsToInt` /
|
|
296
|
+
`floatBitsToUint` exactly like a temp register read (this project's cbuffers are
|
|
297
|
+
`vec4`-slot float storage regardless of the HLSL source's cbuffer member types,
|
|
298
|
+
mirroring how the fallback path above has no member-type information at all).
|
|
299
|
+
|
|
300
|
+
**Helpers needed**: none for the declaration itself.
|
|
301
|
+
|
|
302
|
+
**Edge cases**:
|
|
303
|
+
- Cross-stage size mismatch: VS and PS `dcl_constant_buffer` for the same binding
|
|
304
|
+
point can carry different `aui32ArraySizes[1]` if each stage only reads a prefix of
|
|
305
|
+
the buffer (`TRANSPILING-GAPS.md`, "AB hull test-set blockers" — `boostervolumetric`
|
|
306
|
+
and `planeglow` failed WebGL2 *linking* because of this, not compilation). Emit the
|
|
307
|
+
**max** slot count seen for a given `cb#` across the linked program's stages.
|
|
308
|
+
- Vulkan-subpass-input (`2561-2636`) and `OVR_multiview` (`2638-2664`) special cases
|
|
309
|
+
are Vulkan/Unity-specific and out of scope for this project's DX11→WebGL2 EVE
|
|
310
|
+
corpus. **Correction**: these two are the only special cases actually in the
|
|
311
|
+
`2561-2670` range; the `"$Globals"` name check is a *different* piece of code, not
|
|
312
|
+
located there. There are two distinct `$Globals`-related checks elsewhere in this
|
|
313
|
+
file: (1) `psCBuf->name[0] == '$'` at `2674`, inside the *named/reflected* path
|
|
314
|
+
(`2672-2687`), which chooses `DeclareStructConstants` over `DeclareUBOConstants`
|
|
315
|
+
when `HLSLCC_FLAG_GLOBAL_CONSTS_NEVER_IN_UBO` is also set; and (2) the `"$Globals"`
|
|
316
|
+
string checks inside `DeclareUBOConstants`/`DeclareStructConstants` themselves
|
|
317
|
+
(`883`, `888`, `1105`, `1142`). None of this is reached by the stripped-RDEF
|
|
318
|
+
fallback path this project depends on (that path returns at `2558` before any of
|
|
319
|
+
`2561` onward runs) — so the conclusion ("$Globals is out of scope, handled
|
|
320
|
+
generically by the synthesized `ConstantBufferN` name") still holds, just not for
|
|
321
|
+
the reason/line-range originally cited.
|
|
322
|
+
|
|
323
|
+
**WebGL2 notes**: `layout(std140) uniform` blocks are core GLSL ES 3.00 — no
|
|
324
|
+
extension required. `std140` layout rules (16-byte vec4 alignment, `vec4 data[]`
|
|
325
|
+
array) mean every array element is a full 16 bytes regardless of the HLSL source
|
|
326
|
+
type, which is exactly why the flat `vec4 data[N]` fallback shape is both simple and
|
|
327
|
+
correct for any packed constant layout.
|
|
328
|
+
|
|
329
|
+
**Confidence: high** for the stripped-RDEF fallback shape (this is exactly what
|
|
330
|
+
`CARBONENGINEJS-FORK.md` documents as the load-bearing convention and what
|
|
331
|
+
`toGLSLDeclaration.cpp:2557` literally emits); **medium** on the cross-stage
|
|
332
|
+
normalization requirement, since that is a package/link-time policy documented in
|
|
333
|
+
`TRANSPILING-GAPS.md` as a known bug rather than something already fixed in
|
|
334
|
+
`toGLSLDeclaration.cpp` itself.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## `dcl_resource_structured` (684)
|
|
339
|
+
|
|
340
|
+
**Semantics**: declares a structured-buffer shader resource (`t#`) with a known
|
|
341
|
+
per-element byte stride, read via `ld_structured`. In EVE's skinned space-object
|
|
342
|
+
shaders this is `BoneTransforms` (a `Buffer<float4x3>`-shaped structured resource of
|
|
343
|
+
joint matrices), always paired with `ld_structured` in the instruction stream.
|
|
344
|
+
|
|
345
|
+
**GLSL lowering (stock HLSLcc)**: `toGLSLDeclaration.cpp:3680-3684` calls
|
|
346
|
+
`DeclareBufferVariable(..., isRaw=0, isUAV=0, ...)` (`1027-1092`), which emits an
|
|
347
|
+
SSBO. **Correction to the exact emitted text** (verified against `1042-1088`): the
|
|
348
|
+
struct member uses GLSL's `type[size] name;` array-declarator ordering, not
|
|
349
|
+
`type name[size];`, and the buffer *block* name is plain `t0` (`BufName`), not a
|
|
350
|
+
synthesized `t0_type_block_name` — the block's *member* variable is `t0_buf`:
|
|
351
|
+
```glsl
|
|
352
|
+
struct t0_type {
|
|
353
|
+
uint[3] value; // stride/4, via bformata("...\t%s[%d] value;\n...", typeStr, stride/4)
|
|
354
|
+
};
|
|
355
|
+
layout(std430, binding = N) readonly buffer t0 {
|
|
356
|
+
t0_type t0_buf[];
|
|
357
|
+
};
|
|
358
|
+
```
|
|
359
|
+
(exact struct/instance naming per `1035-1088`; `readonly` is unconditional for
|
|
360
|
+
non-UAV structured buffers, `1069-1070`; on Switch targets only, the block name gets
|
|
361
|
+
an `hlslcc_readonly` prefix instead, `1073`).
|
|
362
|
+
|
|
363
|
+
**Stripped-RDEF fallback**: `CARBONENGINEJS-FORK.md` — "Structured-buffer
|
|
364
|
+
declarations tolerate missing `RDEF` bindings by using the stride encoded in the DXBC
|
|
365
|
+
declaration extension" — i.e. `psDecl->ui32BufferStride` is read directly off the
|
|
366
|
+
`dcl_resource_structured` instruction's declaration-extension dword rather than off
|
|
367
|
+
reflection metadata, so the struct-element count (`stride/4`) is always available
|
|
368
|
+
even with `RDEF` stripped (decision shard
|
|
369
|
+
`022-dxbc-dcl-resource-declaration-tails.md` covers the sibling `dcl_resource`
|
|
370
|
+
one-word-tail decoding that established this pattern).
|
|
371
|
+
|
|
372
|
+
**Type rules**: SSBO element type is `uint[]` (raw dwords); the consuming
|
|
373
|
+
`ld_structured` instruction bitcasts each loaded dword to float/int/uint as needed
|
|
374
|
+
at the read site (out of this family's scope — instruction family territory).
|
|
375
|
+
|
|
376
|
+
**Helpers needed**: none for the declaration text itself.
|
|
377
|
+
|
|
378
|
+
**Edge cases / WebGL2 notes (hard blocker, not a lowering detail)**: **GLSL ES 3.00
|
|
379
|
+
has no shader storage buffers** — `buffer` blocks require GLSL ES 3.10+ or desktop
|
|
380
|
+
`GL_ARB_shader_storage_buffer_object`. This emitter **must not** emit the SSBO form
|
|
381
|
+
above for a WebGL2 target; it will not compile. The proven working path for this
|
|
382
|
+
project is a **package-time ABI rewrite**, not a change to this opcode's GLSL
|
|
383
|
+
lowering:
|
|
384
|
+
- `CARBONENGINEJS-FORK.md` / `016-cewg-skinning-abi-lowering-for-ccpwgl-2026-06-30.md`
|
|
385
|
+
/ `TRANSPILING-GAPS.md`: drop the `t0` SSBO declaration entirely, grow the
|
|
386
|
+
paired `ConstantBuffer3` (`cb3`) to at least `vec4 data[200]`, and rewrite every
|
|
387
|
+
`ld_structured` row load against `t0` into `cb3.data[26 + blendIndex * 3 + row]`
|
|
388
|
+
(the ccpwgl `EveShip2` `JointMat` uniform-block projection, `58` joints × `12`
|
|
389
|
+
floats/joint = `696` floats appended at `cb3[26..199]`).
|
|
390
|
+
- This rewrite is package/runtime-ABI policy for the current ccpwgl compatibility
|
|
391
|
+
target, **not** a native CarbonEngineJS/Trinity representation
|
|
392
|
+
(`016-...md`, "Boundary" section) — a future non-ccpwgl consumer may want a real
|
|
393
|
+
buffer-texture or uniform-array representation of `BoneTransforms` instead of this
|
|
394
|
+
specific `cb3` splice.
|
|
395
|
+
- Validated: `skinned_quadv5.sm_converted_hi` 75/75 shaders translate, 336/336
|
|
396
|
+
WebGL2 programs link after the rewrite; `skinned_quadheatv5` 63/63 / 240/240.
|
|
397
|
+
|
|
398
|
+
**Confidence: high** on both "stock HLSLcc emits an SSBO" and "WebGL2 cannot use
|
|
399
|
+
SSBOs" (directly cited, unambiguous); **medium** on the exact `cb3.data[26 + ...]`
|
|
400
|
+
offset formula for any *other* structured buffer this family's opcode might describe
|
|
401
|
+
in a shader outside the skinned space-object set — this is proven only for
|
|
402
|
+
`BoneTransforms` specifically, not as a general `dcl_resource_structured` policy.
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## `dcl_resource` (6317)
|
|
407
|
+
|
|
408
|
+
**Semantics**: declares a texture shader-resource-view binding (`t#`) with a resource
|
|
409
|
+
dimension (1D/2D/3D/Cube/arrays/MS variants/buffer) and a 4-nibble per-component
|
|
410
|
+
return type (float/unorm/snorm/int/uint), consumed later by `sample*`/`ld`/`resinfo`
|
|
411
|
+
instructions.
|
|
412
|
+
|
|
413
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:2689-2758`. Non-Vulkan path:
|
|
414
|
+
1. Optional `UNITY_LOCATION(%d)` prefix (`2700-2718`) — expand directly to
|
|
415
|
+
`layout(location = N)` for this project (see cbuffer section's note on macro
|
|
416
|
+
indirection).
|
|
417
|
+
2. `RESOURCE_DIMENSION_BUFFER` → `uniform samplerBuffer`/`isamplerBuffer`/
|
|
418
|
+
`usamplerBuffer` (`2722-2733`, requires `GL_EXT_texture_buffer` on ES targets,
|
|
419
|
+
`1404-1405` inside `GetSamplerType`) — not expected in this project's vertex/pixel
|
|
420
|
+
corpus (texel buffers are rare in EVE effects; treat as low-priority).
|
|
421
|
+
3. All 2D/1D/Cube/array-of-those dimensions → `TranslateResourceTexture(..., 1)`
|
|
422
|
+
(`1597-1687`), which emits:
|
|
423
|
+
```glsl
|
|
424
|
+
uniform <precision> <samplerType> t{N};
|
|
425
|
+
```
|
|
426
|
+
and, only if the resource is a shadow-comparison texture
|
|
427
|
+
(`psDecl->ui32IsShadowTex`), an *additional* `<samplerType>Shadow t{N}_shadow`-style
|
|
428
|
+
binding (`1668-1686`) — this second declaration is **unconditional** on
|
|
429
|
+
`ui32IsShadowTex`/`samplerCanDoShadowCmp` and fires regardless of whether
|
|
430
|
+
`HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS` is set (that flag is not tested anywhere in
|
|
431
|
+
this code path). What the combine flag actually gates is a *separate*, earlier
|
|
432
|
+
block (`1632-1657`, inside `TranslateResourceTexture`): when
|
|
433
|
+
`HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS` is set, HLSLcc emits one *additional*
|
|
434
|
+
`uniform <samplerType> <name>;` per (texture, sampler) pair actually used together
|
|
435
|
+
(name from `TextureSamplerName`, iterating `psDecl->samplersUsed`) — on top of, not
|
|
436
|
+
instead of, the plain `t{N}` declaration at `1659-1666`. Since this project's
|
|
437
|
+
`dcl_sampler` section concludes the combine flag is required for any GLSL-ES
|
|
438
|
+
target, expect these extra per-combo uniforms to be emitted too, and confirm which
|
|
439
|
+
name (`t{N}` vs. the combo name) the consuming `sample`/`sample_c` instruction
|
|
440
|
+
family actually references before assuming plain `t{N}` is the only symbol that
|
|
441
|
+
matters.
|
|
442
|
+
4. `TEXTURE2DMS`/`TEXTURE3D`/`TEXTURE2DMSARRAY` → `TranslateResourceTexture(..., 0)`
|
|
443
|
+
(same emission, `samplerCanDoShadowCmp=0`, i.e. never a comparison sampler).
|
|
444
|
+
|
|
445
|
+
**Sampler-type selection** (`GetSamplerType`, `1388-1551`): base type name keyed on
|
|
446
|
+
`RESOURCE_DIMENSION` (`sampler2D`, `sampler3D`, `samplerCube`, `sampler2DArray`,
|
|
447
|
+
`samplerCubeArray`, `sampler2DMS`, `sampler2DMSArray`, `sampler1D`/`1DArray`,
|
|
448
|
+
`samplerBuffer`), then prefixed `i`/`u` if the resource's reflected
|
|
449
|
+
`RESOURCE_RETURN_TYPE` is `RETURN_TYPE_SINT`/`RETURN_TYPE_UINT` (`1406-1544`); every
|
|
450
|
+
other return type (`UNORM`/`SNORM`/`FLOAT`/`TYPELESS`) maps to the plain (float)
|
|
451
|
+
sampler. Return type comes from `ResourceBinding::ui32ReturnType`
|
|
452
|
+
(RDEF-reflected) when available; when RDEF is stripped, this fork's
|
|
453
|
+
`dcl_resource` one-word declaration-tail decoding
|
|
454
|
+
(`022-dxbc-dcl-resource-declaration-tails.md`) supplies the same fact from the raw
|
|
455
|
+
DXBC declaration instead: the trailing dword is four 4-bit return-type nibbles,
|
|
456
|
+
preserved as `declarationData.resourceReturnType` — decode return type from there
|
|
457
|
+
when no RDEF binding is found, rather than defaulting to float/unorm blindly.
|
|
458
|
+
|
|
459
|
+
**Texture type 3 == native 3D** (`027-texture-type-3-is-native-3d-not-legacy-atlas.md`):
|
|
460
|
+
DXBC/Carbon resource type `3` (`RESOURCE_DIMENSION_TEXTURE3D`) is an authoritative
|
|
461
|
+
native volume texture, not a legacy packed-2D-atlas convention some older ccpwgl code
|
|
462
|
+
assumed — lower it to `sampler3D`/`texture3D`-family calls, never collapse it into
|
|
463
|
+
`sampler2D`.
|
|
464
|
+
|
|
465
|
+
**Type rules**: the sampler's *component* return type (float vs int vs uint) governs
|
|
466
|
+
which `texture()`/`texelFetch()` overload the consuming instruction must call
|
|
467
|
+
(`vec4`- vs `ivec4`- vs `uvec4`-returning) — declaration-time fact, consumed by the
|
|
468
|
+
`sample`/`ld` instruction family (out of scope here beyond noting the dependency).
|
|
469
|
+
|
|
470
|
+
**Helpers needed**: none for the declaration; sampler precision comes from
|
|
471
|
+
`GetSamplerPrecision` (`1553-1569`) — **not** `highp` by default. The function only
|
|
472
|
+
returns `"highp "` when the resource's reflected precision is explicitly
|
|
473
|
+
`REFLECT_RESOURCE_PRECISION_HIGHP`; the `default`/`UNKNOWN`/`LOWP` case (`1560-1563`,
|
|
474
|
+
the path this project's stripped-RDEF fallback always hits, since there is no
|
|
475
|
+
reflected `ResourceBinding::ePrecision` to consult) returns `EmitLowp(...) ? "lowp "
|
|
476
|
+
: "mediump "`, and `EmitLowp` (`languages.h:69-73`) is `true` only for `LANG_ES_100` —
|
|
477
|
+
so for this project's `LANG_ES_300` target the *actual* default sampler precision
|
|
478
|
+
emitted is **`mediump`**, not `highp`. (WebGL2 does support `highp` samplers in
|
|
479
|
+
fragment shaders, unlike GLSL ES 1.00, but stock HLSLcc does not default to
|
|
480
|
+
requesting it — this project must decide separately whether to request `highp`
|
|
481
|
+
samplers, rather than assuming the stock lowering already does.)
|
|
482
|
+
|
|
483
|
+
**Edge cases**: MSAA resource dimensions (`TEXTURE2DMS`/`TEXTURE2DMSARRAY`) need
|
|
484
|
+
`GL_OES_texture_storage_multisample_2d_array` on ES targets for the array variant
|
|
485
|
+
(`1516-1519`) — WebGL2 exposes multisample textures but **not** `texelFetch` on them
|
|
486
|
+
from a fragment shader in the same way desktop does; treat multisample resources as
|
|
487
|
+
out-of-scope/low-confidence for this corpus unless a specific EVE effect is proven to
|
|
488
|
+
need them. Cube-array (`TEXTURECUBEARRAY`) needs
|
|
489
|
+
`GL_OES_texture_cube_map_array`/`GL_EXT_texture_cube_map_array` (`1608-1619`) — **not
|
|
490
|
+
core in GLSL ES 3.00**, only in 3.20/desktop or via those extensions, which are not
|
|
491
|
+
universally available on WebGL2 (`OES_texture_cube_map_array` is an optional WebGL2
|
|
492
|
+
extension) — flag as a target blocker if any EVE effect requires it without checking
|
|
493
|
+
extension availability at runtime.
|
|
494
|
+
|
|
495
|
+
**WebGL2 notes**: combined texture+sampler objects (GLSL `sampler2D` as a single
|
|
496
|
+
opaque uniform) are exactly WebGL2's own texture model — no separate texture/sampler
|
|
497
|
+
descriptor split is needed for this target (that split only matters for the Vulkan
|
|
498
|
+
backend in `TranslateVulkanResource`, out of scope).
|
|
499
|
+
|
|
500
|
+
**Confidence: high** for 2D/Cube/array dimension mapping (heavily used, directly
|
|
501
|
+
cited); **medium** for MS/cube-array/buffer dimensions (low corpus incidence, GLSL ES
|
|
502
|
+
3.00 extension availability not verified per-device).
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## `dcl_sampler` (3277)
|
|
507
|
+
|
|
508
|
+
**Semantics**: declares a sampler-state binding (`s#`) — filter mode, address mode,
|
|
509
|
+
comparison mode, LOD clamp/bias — consumed by `sample`/`sample_c`/`sample_l`
|
|
510
|
+
instructions when combined with a `t#` resource via `dcl_resource`'s
|
|
511
|
+
`samplersUsed` set.
|
|
512
|
+
|
|
513
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:3348-3365`. For **non-Vulkan** targets (this
|
|
514
|
+
project's WebGL2 target), the entire case body is gated behind
|
|
515
|
+
`if (psContext->IsVulkan()) { ...; break; }` — falling through to `break;` with **no
|
|
516
|
+
GLSL text emitted at all** for OpenGL/GLSL/GLSL-ES targets. The separate sampler
|
|
517
|
+
object is *not* represented as its own GLSL declaration on this target; it is folded
|
|
518
|
+
into the combined `uniform sampler2D t{N};` declaration emitted by `dcl_resource`
|
|
519
|
+
above (`HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS`-style combined texture+sampler model,
|
|
520
|
+
the only model GLSL ES 3.00 supports). The one piece of state this instruction does
|
|
521
|
+
carry into codegen is whether the sampler is a comparison sampler
|
|
522
|
+
(`D3D10_SB_SAMPLER_MODE_COMPARISON`) — that fact reaches
|
|
523
|
+
`TranslateResourceTexture`'s shadow-texture branch (`ui32IsShadowTex`, decided
|
|
524
|
+
upstream at declaration-plan time from which `s#`/`t#` pairs get used together in
|
|
525
|
+
`sample_c`-family instructions, not from this opcode's own GLSL emission path).
|
|
526
|
+
|
|
527
|
+
**Type rules**: n/a — no GLSL variable is produced for this opcode on WebGL2/GLSL
|
|
528
|
+
targets.
|
|
529
|
+
|
|
530
|
+
**Helpers needed**: none.
|
|
531
|
+
|
|
532
|
+
**Edge cases**: DX11 sampler-state fields that have no WebGL2 shader-side
|
|
533
|
+
representation at all (address mode, filter mode, LOD bias/clamp, anisotropy,
|
|
534
|
+
border color) are **runtime binding-state policy**, not shader text — they must be
|
|
535
|
+
applied via `gl.texParameteri`/`gl.samplerParameteri` from Carbon/Trinity sampler
|
|
536
|
+
metadata at draw time, entirely outside this translator
|
|
537
|
+
(`TRANSPILING-GAPS.md`, "Exporter and runtime policy": "WebGL sampler-state
|
|
538
|
+
application" is explicitly listed as deferred/out-of-scope for the DXBC reader and
|
|
539
|
+
draft transpiler).
|
|
540
|
+
|
|
541
|
+
**WebGL2 notes**: this is the single opcode in the family whose stock-HLSLcc-for-our-
|
|
542
|
+
target lowering is "emit nothing" — worth flagging clearly to the implementing
|
|
543
|
+
engineer so they don't go looking for a `s0` GLSL symbol; the register-stable name
|
|
544
|
+
`s0` only shows up in Carbon binding-manifest metadata (`CARBONENGINEJS-FORK.md`:
|
|
545
|
+
"`s0`" is one of the register-stable symbols this fork preserves for
|
|
546
|
+
`Tr2EffectBindingManifest`), not in the GLSL source text itself.
|
|
547
|
+
|
|
548
|
+
**Confidence: high** — the Vulkan/non-Vulkan branch is unconditional and
|
|
549
|
+
unambiguous; the only judgment call is confirming this project always wants
|
|
550
|
+
`HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS`-style combined sampling (yes — required for
|
|
551
|
+
any WebGL2/GLSL-ES target, since GLSL ES 3.00 has no separate sampler-object type).
|
|
552
|
+
|
|
553
|
+
---
|
|
554
|
+
|
|
555
|
+
## `dcl_input` (11726)
|
|
556
|
+
|
|
557
|
+
**Semantics**: declares a shader-stage input register (vertex-shader per-vertex
|
|
558
|
+
attribute, or any non-pixel stage's plain input) bound to an input-signature (ISGN)
|
|
559
|
+
row: semantic name/index, component mask, component type (float/sint/uint),
|
|
560
|
+
interpolation mode (non-VS stages).
|
|
561
|
+
|
|
562
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:2061-2186`. Several early-outs
|
|
563
|
+
(`2070-2105`) skip declaration for control-flow/thread-ID-style pseudo-inputs and
|
|
564
|
+
already-declared-as-array registers — none apply to plain vertex-shader attributes,
|
|
565
|
+
the dominant case in this corpus. For a normal vertex input:
|
|
566
|
+
1. Name: `GetDeclaredInputName` → `inputPrefix + semanticName + semanticIndex`
|
|
567
|
+
(`HLSLCrossCompilerContext.cpp:169-211`); for a vertex shader `inputPrefix =
|
|
568
|
+
"in_"` (`toGLSL.cpp:33`) — i.e. **`in_POSITION0`, `in_NORMAL0`, `in_TEXCOORD3`,
|
|
569
|
+
`in_BLENDINDICES0`**, etc. This `in_<SEMANTIC><index>` naming is the register-
|
|
570
|
+
stable vertex-attribute ABI surface Carbon metadata and package/runtime tooling
|
|
571
|
+
bind against.
|
|
572
|
+
2. Storage qualifier: `"in"` for any target where `InOutSupported` is true
|
|
573
|
+
(`2121-2127`) — true for `LANG_ES_300` (WebGL2's `in`/`out` keyword model, not the
|
|
574
|
+
legacy `attribute`/`varying` GLSL ES 1.00 keywords).
|
|
575
|
+
3. Precision: `highp` unless the operand carries a `OPERAND_MIN_PRECISION_*` hint
|
|
576
|
+
(`2129-2159`) — DXBC minimum-precision annotations are rare in this corpus; default
|
|
577
|
+
to `highp` for all vertex attributes absent contrary evidence.
|
|
578
|
+
4. Component type/count (`DeclareInput`, `232-390`, using the ISGN row's
|
|
579
|
+
`eComponentType` and `GetNumberBitsSet(ui32Mask)` for element count, **not** the
|
|
580
|
+
operand's own write mask) → `float`/`vecN` (`INOUT_COMPONENT_FLOAT32`),
|
|
581
|
+
`int`/`ivecN` (`SINT32`), or `uint`/`uvecN` (`UINT32`) (`265-291`).
|
|
582
|
+
5. Final text: `in <precision> <type> in_<SEMANTIC><index>;` (`362-388` default
|
|
583
|
+
branch, non-array case — the common case for VS attributes).
|
|
584
|
+
|
|
585
|
+
**Attribute naming / BINORMAL→BITANGENT alias (load-bearing for this project)**:
|
|
586
|
+
HLSLcc derives the attribute name purely from the DXBC ISGN semantic string, which
|
|
587
|
+
for EVE's split-tangent-space vertex format is literally `BINORMAL` (`in_BINORMAL0`)
|
|
588
|
+
— but Carbon/Trinity per-vertex-stream metadata for that exact same GR2 mesh channel
|
|
589
|
+
calls it `BITANGENT`
|
|
590
|
+
(`../shaderdiscovery/knowledge/trinity-metadata/shader-discovery-truths.md:126-133`,
|
|
591
|
+
`../shaderdiscovery/knowledge/carbon-metadata-contract/hlslcc-transpile-spike.md:195-201`).
|
|
592
|
+
This is a **naming alias, not a semantic difference** — same vertex buffer channel,
|
|
593
|
+
two different names used by two different authorities. The proven fix is a
|
|
594
|
+
package-time rewrite, *after* HLSLcc emission, not a change to this opcode's GLSL
|
|
595
|
+
lowering itself: `scripts/packageTr2WebglEffect.js` normalizes every
|
|
596
|
+
`in_BINORMAL{n} -> in_BITANGENT{n}` for a vertex shader whose stage contract
|
|
597
|
+
declares a `BITANGENT` pipeline input, so the runtime's metadata-driven attribute
|
|
598
|
+
binder (which looks up attributes by the Carbon name) finds the symbol it expects.
|
|
599
|
+
Validated: `unpackedskinned_quadv5`/`unpackedskinned_quadheatv5` regenerated with no
|
|
600
|
+
`in_BINORMAL*` symbols remaining, still link (336/336, 80/80 WebGL2 programs).
|
|
601
|
+
**This emitter should keep emitting `in_BINORMALn`** (matching HLSLcc/DXBC ISGN
|
|
602
|
+
truth) **and rely on the package-time rewrite step**, not bake a BINORMAL→BITANGENT
|
|
603
|
+
special case into the opcode lowering itself — the alias is a runtime-ABI fact, not a
|
|
604
|
+
DXBC-to-GLSL translation fact.
|
|
605
|
+
|
|
606
|
+
**Type rules**: component type/count are ISGN facts (declaration-time), independent
|
|
607
|
+
of this project's float-register-file convention for `r#` temps — a vertex attribute
|
|
608
|
+
declared `uvec4` really is a GLSL `uvec4`-typed `in` variable at declaration time (see
|
|
609
|
+
next paragraph for why that is still a problem at the runtime-binding layer).
|
|
610
|
+
|
|
611
|
+
**Helpers needed**: `HandleInputRedirect` (`toGLSLDeclaration.cpp:1689-1806`) is an
|
|
612
|
+
HLSLcc-internal hull/domain-shader phase-input staging mechanism (`phase{N}_Input...`
|
|
613
|
+
temporaries) — out of scope for this project's vertex/pixel-only target; no
|
|
614
|
+
equivalent helper is needed here.
|
|
615
|
+
|
|
616
|
+
**Edge cases — the uvec/ivec attribute problem (required deviation, highest-priority
|
|
617
|
+
item in this family)**: stock HLSLcc, run as designed, declares integer-semantic
|
|
618
|
+
vertex inputs with their true GLSL integer vector type, e.g. `in uvec4
|
|
619
|
+
in_BLENDINDICES0;` for a `BLENDINDICES` stream reflected as `UINT32` component type
|
|
620
|
+
(`DeclareInput`, `270-274`). **This project's runtime (ccpwgl) binds all mesh
|
|
621
|
+
attribute channels, including blend indices, as float vertex attributes via
|
|
622
|
+
`gl.vertexAttribPointer` (not `vertexAttribIPointer`)** — a real `uvec4 in_...`
|
|
623
|
+
declaration either fails to link against that float-typed buffer binding, or links
|
|
624
|
+
but silently produces garbage/invisible geometry
|
|
625
|
+
(`028-cewg-skinned-blend-index-abi-lowering.md`: "Raw CEWG validation can link
|
|
626
|
+
integer attributes, but ccpwgl runtime binding can still fail or produce invisible
|
|
627
|
+
geometry if the source reaches compile as `uvec4`."). The proven, validated fix
|
|
628
|
+
(`028-...md`; `TRANSPILING-GAPS.md` "Ranked helper action plan" documents the general
|
|
629
|
+
version of this class of bug): **lower every integer-component-type `dcl_input`
|
|
630
|
+
vertex attribute to its float-vector equivalent at declaration time** —
|
|
631
|
+
```glsl
|
|
632
|
+
in vec4 in_BLENDINDICES0; // not uvec4
|
|
633
|
+
```
|
|
634
|
+
and bitcast at every *use* site instead: any instruction reading `in_BLENDINDICES0`
|
|
635
|
+
as an index wraps it in `floatBitsToUint(in_BLENDINDICES0)` (or, if the actual buffer
|
|
636
|
+
data was uploaded as plain float index values rather than bit-pattern-encoded uints —
|
|
637
|
+
verify per-attribute — a plain `uint(in_BLENDINDICES0.x)` truncating conversion
|
|
638
|
+
instead of a bitcast; the CEWG lowering evidence describes casting at use sites but
|
|
639
|
+
does not pin down which of these two forms every producer used, see Confidence
|
|
640
|
+
below). This is the **general form** of the family-level "every register is a float
|
|
641
|
+
vec4" convention applied specifically to `dcl_input`: unlike the `r#` temp file
|
|
642
|
+
(where float-only storage is this project's own choice), for vertex attributes it is
|
|
643
|
+
required by a concrete runtime constraint (float-only `vertexAttribPointer` binding),
|
|
644
|
+
proven necessary by regression (skinned geometry disappearing) and proven sufficient
|
|
645
|
+
(336/336 and 240/240 WebGL2 programs pass after the rewrite) in the corpus evidence
|
|
646
|
+
cited above.
|
|
647
|
+
|
|
648
|
+
**WebGL2 notes**: GLSL ES 3.00 does support genuine integer vertex attributes
|
|
649
|
+
(`in uvec4`/`in ivec4` with `vertexAttribIPointer`) — the float-only lowering above is
|
|
650
|
+
not a GLSL-ES-3.00 *language* limitation, it is a **runtime binding-layer**
|
|
651
|
+
limitation specific to this project's current ccpwgl consumer. A future
|
|
652
|
+
CarbonEngineJS-native consumer that binds attributes with `vertexAttribIPointer`
|
|
653
|
+
could use the stock HLSLcc `uvec4`/`ivec4` declarations directly and should not
|
|
654
|
+
inherit this workaround by default.
|
|
655
|
+
|
|
656
|
+
**Confidence: medium** — the *requirement* to avoid integer vertex-attribute types is
|
|
657
|
+
high confidence (proven by a specific regression + fix with before/after link
|
|
658
|
+
counts); the *exact* per-attribute cast convention (bitcast-reinterpret vs.
|
|
659
|
+
truncating-convert at the use site) is not nailed down to opcode-level precision in
|
|
660
|
+
the cited evidence and should be confirmed against the actual uploaded vertex-buffer
|
|
661
|
+
encoding for each integer semantic (`BLENDINDICES` specifically is documented;
|
|
662
|
+
generalize cautiously to any other integer-typed vertex semantic found in the corpus).
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
## `dcl_input_ps` (6995)
|
|
667
|
+
|
|
668
|
+
**Semantics**: declares a pixel-shader input register (an interpolated varying from
|
|
669
|
+
the previous stage) bound to an ISGN row, carrying an explicit DXBC interpolation
|
|
670
|
+
mode (`INTERPOLATION_CONSTANT`/`LINEAR`/`LINEAR_CENTROID`/`LINEAR_NOPERSPECTIVE`/etc.)
|
|
671
|
+
that this instruction's own `value.eInterpolation` field encodes (distinct from plain
|
|
672
|
+
`dcl_input`, which has no interpolation-mode payload).
|
|
673
|
+
|
|
674
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:2217-2423`. Name via `GetDeclaredInputName`
|
|
675
|
+
with `inputPrefix = "vs_"` (when the previous stage is a vertex shader, the common
|
|
676
|
+
case for this corpus — `toGLSL.cpp:59-79`) → **`vs_<SEMANTIC><index>`**, matching the
|
|
677
|
+
vertex shader's `outputPrefix = "vs_"` output name exactly (`toGLSL.cpp:34`), which is
|
|
678
|
+
how HLSLcc keeps VS-output/PS-input varying names paired across the two independently
|
|
679
|
+
compiled GLSL stage sources. Storage qualifier `"in"` (`2228-2231`, `InOutSupported`
|
|
680
|
+
true for ES 300). Interpolation qualifier:
|
|
681
|
+
- integer component type (`UINT32`/`SINT32`) forces `flat ` regardless of the DXBC
|
|
682
|
+
interpolation mode (`2238-2242`) — **GLSL spec requirement**, not a DXBC fact:
|
|
683
|
+
integer varyings must be flat-interpolated in any GLSL version.
|
|
684
|
+
- otherwise, map `psDecl->value.eInterpolation` (`2245-2284`): `INTERPOLATION_CONSTANT`
|
|
685
|
+
→ `"flat "`; `LINEAR` → `""`; `LINEAR_CENTROID` → `"centroid "`;
|
|
686
|
+
`LINEAR_NOPERSPECTIVE` → `"noperspective "` **only if** `hasNoPerspective` (true for
|
|
687
|
+
`eTargetLanguage > LANG_ES_310`, i.e. **false for `LANG_ES_300`** — `2225`,
|
|
688
|
+
`2263-2265`); `LINEAR_SAMPLE`/`LINEAR_NOPERSPECTIVE_SAMPLE` → `"sample "`/
|
|
689
|
+
`"noperspective sample "` similarly gated.
|
|
690
|
+
- Precision: same `highp`/`mediump`/`lowp` mapping from `OPERAND_MIN_PRECISION_*` as
|
|
691
|
+
`dcl_input` (`2287-2317`).
|
|
692
|
+
- Final text: `DeclareInput(...)` (`2418`) → same underlying emitter as `dcl_input`,
|
|
693
|
+
producing `<interp>in <precision> <type> vs_<SEMANTIC><index>;`.
|
|
694
|
+
|
|
695
|
+
**Type rules**: identical component-type derivation to `dcl_input` (ISGN
|
|
696
|
+
`eComponentType` → `float`/`int`/`uint` base, `GetNumberBitsSet(mask)` → vector
|
|
697
|
+
width). The **integer-varying-must-be-flat** rule is a hard GLSL requirement in every
|
|
698
|
+
GLSL version, not a WebGL2-specific quirk — always emit `flat` for integer pixel
|
|
699
|
+
inputs regardless of the source DXBC interpolation mode field.
|
|
700
|
+
|
|
701
|
+
**Helpers needed**: none beyond core-language `flat`/`centroid` qualifiers (both core
|
|
702
|
+
in GLSL ES 3.00).
|
|
703
|
+
|
|
704
|
+
**Edge cases — framebuffer-fetch special case**: `2319-2416` handles reading back a
|
|
705
|
+
previously-written render target value (`SV_TargetN` bound both as PS input and PS
|
|
706
|
+
output, gated on `EXT_shader_framebuffer_fetch` + `HLSLCC_FLAG_SHADER_FRAMEBUFFER_FETCH`)
|
|
707
|
+
via `#define vs_SV_TargetN gl_LastFragData[N]` or a `layout(location=N) inout`
|
|
708
|
+
declaration. `GL_EXT_shader_framebuffer_fetch` **is not universally available in
|
|
709
|
+
WebGL2** and this project's target is standard WebGL2 fragment shaders reading only
|
|
710
|
+
their own current-fragment inputs — treat this branch as out of scope / not expected
|
|
711
|
+
to trigger in the EVE corpus; if it ever does, it is a target blocker requiring the
|
|
712
|
+
extension's presence to be verified at runtime, not silently assumed.
|
|
713
|
+
|
|
714
|
+
**WebGL2 notes**: `centroid`/`sample` interpolation qualifiers are core GLSL ES 3.00
|
|
715
|
+
keywords (no extension needed). `noperspective` is **not** — GLSL ES 3.00's spec does
|
|
716
|
+
not include `noperspective` as a keyword at all (it was added later, e.g. via
|
|
717
|
+
`NV_shader_noperspective_interpolation` for ES 3.0/3.1, and core only from ES 3.20);
|
|
718
|
+
WebGL2/ES 3.00 has no standard `noperspective` qualifier. The C++ source's own
|
|
719
|
+
`hasNoPerspective` gate (`eTargetLanguage <= LANG_ES_310 ? 0 : 1`, `2225`) is
|
|
720
|
+
therefore **correct as written, not stale or overly conservative** — it already
|
|
721
|
+
disables `noperspective` for `LANG_ES_300` (and `LANG_ES_310`) and only enables it for
|
|
722
|
+
targets above `LANG_ES_310`. This emitter should simply mirror that gate rather than
|
|
723
|
+
second-guess it: if any EVE pixel shader declares `INTERPOLATION_LINEAR_NOPERSPECTIVE`,
|
|
724
|
+
drop the qualifier for a `LANG_ES_300` target (falls back to perspective-correct
|
|
725
|
+
interpolation, a visible but non-fatal quality difference, vs. a hard compile error
|
|
726
|
+
from an unrecognized qualifier).
|
|
727
|
+
|
|
728
|
+
**Confidence: high** — the name-prefix pairing and integer-flat rule are high
|
|
729
|
+
confidence (direct source read, universal GLSL requirement); the
|
|
730
|
+
`noperspective`-in-ES-3.00 gate was re-checked directly against the GLSL ES 3.00
|
|
731
|
+
language facts (no `noperspective` keyword until ES 3.20 core / the
|
|
732
|
+
`NV_shader_noperspective_interpolation` extension) and confirmed correct as written,
|
|
733
|
+
so this is no longer an open question for this opcode.
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
## `dcl_output` (15197) — highest-frequency opcode in this family
|
|
738
|
+
|
|
739
|
+
**Semantics**: declares a vertex/pixel-shader output register (`o#`) bound to an
|
|
740
|
+
OSGN row (semantic name/index, component mask, component type), or (hull-shader
|
|
741
|
+
control-point phase only, not in this project's scope) routed to `gl_Position`.
|
|
742
|
+
|
|
743
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:2760-2779` → `AddUserOutput`
|
|
744
|
+
(`594-854`), gated by `OutputNeedsDeclaring` (`HLSLCrossCompilerContext.cpp:279-330`)
|
|
745
|
+
which dedups repeated partial-mask declarations of the same register via an
|
|
746
|
+
`acOutputDeclared` bitmask (a register can legally receive several `dcl_output`
|
|
747
|
+
instructions each covering a different component subset; only undeclared components
|
|
748
|
+
trigger new text).
|
|
749
|
+
- Component type/count: OSGN `eComponentType`/`GetNumberBitsSet(mask)` →
|
|
750
|
+
`float`/`vecN` (`FLOAT32`), `int`/`ivecN` (`SINT32`), `uint`/`uvecN` (`UINT32`)
|
|
751
|
+
(`622-655`) — identical derivation pattern to `dcl_input`.
|
|
752
|
+
- Precision: `highp`/`mediump`/`lowp` from `OPERAND_MIN_PRECISION_*` (`657-689`).
|
|
753
|
+
- **Pixel shader** (`691-795`): special output types first —
|
|
754
|
+
`OPERAND_TYPE_OUTPUT_DEPTH` → plain `gl_FragDepth` (built-in, no declaration
|
|
755
|
+
needed on GL/ES targets, `701-708`; the `EXT_frag_depth` `#define` shim at `703-706`
|
|
756
|
+
is `LANG_ES_100`-only, irrelevant for ES 300 where `gl_FragDepth` is core).
|
|
757
|
+
`OUTPUT_DEPTH_GREATER_EQUAL`/`OUTPUT_DEPTH_LESS_EQUAL` → `GL_ARB_conservative_depth`
|
|
758
|
+
layout qualifiers (`709-723`) — **desktop-only extension, not available in GLSL ES
|
|
759
|
+
3.00**; if an EVE pixel shader uses conditional depth output, this project must fall
|
|
760
|
+
back to plain unconstrained `gl_FragDepth` writes (drop the `depth_greater`/
|
|
761
|
+
`depth_less` hint — it is a performance hint only, never required for correctness).
|
|
762
|
+
Otherwise (`725-793`, the common `SV_TargetN` case): name =
|
|
763
|
+
`outputPrefix("") + semanticName + renderTargetIndex` i.e. plain `SV_TargetN`, and
|
|
764
|
+
an explicit `layout(location = N) out <precision><type> SV_TargetN;` the first time
|
|
765
|
+
render target `N` is seen (`748-789`). **Correction to the gating fact**: the
|
|
766
|
+
`layout(location=N)` here is *not* gated by `HaveInOutLocationQualifier` — that
|
|
767
|
+
function (`languages.h:102-109`) is `false` for `LANG_ES_300` (only `true` for
|
|
768
|
+
`>=LANG_410` or `LANG_ES_310`). The actual gate at `752-753` is
|
|
769
|
+
`HaveInOutLocationQualifier(...) || HaveLimitedInOutLocationQualifier(...)`, and it
|
|
770
|
+
is `HaveLimitedInOutLocationQualifier` (`languages.h:93-100`, explicitly commented
|
|
771
|
+
"Only on vertex inputs and pixel outputs") that returns `true` for `LANG_ES_300`,
|
|
772
|
+
satisfying the `||` and producing the explicit location. Net behavior is unchanged
|
|
773
|
+
(ES 300 pixel outputs do get `layout(location=N)`), but the responsible function is
|
|
774
|
+
`HaveLimitedInOutLocationQualifier`, not `HaveInOutLocationQualifier` — worth getting
|
|
775
|
+
right since the two gates diverge for other declarations in this same family (see
|
|
776
|
+
`dcl_input`'s vertex-attribute declaration below, which tests
|
|
777
|
+
`HaveInOutLocationQualifier` alone and therefore does *not* get an explicit location
|
|
778
|
+
on `LANG_ES_300`). WebGL2 **requires** explicit `layout(location=N)` for any
|
|
779
|
+
multi-render-target fragment shader (no implicit `gl_FragData[N]` indexing in the
|
|
780
|
+
ES 3.00 core profile; `WriteToFragData` is true only for legacy/ES 100 targets).
|
|
781
|
+
- **Vertex shader** (`796-846`, the common case here since this project has no
|
|
782
|
+
geometry/hull/domain stages): name =
|
|
783
|
+
`outputPrefix("vs_") + semanticName + semanticIndex` → **`vs_<SEMANTIC><index>`**
|
|
784
|
+
(`804`), matching the pixel shader's `vs_`-prefixed input names described above.
|
|
785
|
+
Interpolation: integer types forced `flat` (`810-814`), float types resolved from
|
|
786
|
+
cross-stage dependency data (`GetInterpolationMode`, `815-818`) — in practice this
|
|
787
|
+
project should resolve interpolation per-varying from the **pixel shader's**
|
|
788
|
+
`dcl_input_ps` `value.eInterpolation` for the same semantic, since that is the only
|
|
789
|
+
side that actually encodes an interpolation mode in DXBC (vertex-shader outputs
|
|
790
|
+
carry no interpolation-mode field of their own). `layout(location=N)` from
|
|
791
|
+
`GetVaryingLocation` (`821-825`) — WebGL2 requires **matching** explicit varying
|
|
792
|
+
locations between the two independently compiled VS/PS GLSL programs when using
|
|
793
|
+
explicit locations, or (simpler, and what this project should default to) omit
|
|
794
|
+
`layout(location=...)` for varyings entirely and let the GLSL **linker** match by
|
|
795
|
+
name — WebGL2/GLSL ES 3.00 supports both; matching by name avoids a whole class of
|
|
796
|
+
location-numbering bugs across independently emitted VS/PS sources and is
|
|
797
|
+
recommended here. Final text: `<interp>out <precision><type> vs_<SEMANTIC><index>;`
|
|
798
|
+
(`838`).
|
|
799
|
+
- Early-out: register 0 with legacy `"POS"` semantic name in a vertex shader returns
|
|
800
|
+
without declaring anything (`619-620`) — that register is expected to be routed to
|
|
801
|
+
`gl_Position` via a separate `dcl_output_siv` `NAME_POSITION` declaration elsewhere
|
|
802
|
+
in the same instruction stream (see next section); do not double-declare it.
|
|
803
|
+
|
|
804
|
+
**Type rules**: identical component-type/count derivation to `dcl_input`/
|
|
805
|
+
`dcl_input_ps` (OSGN-driven, not write-mask-driven). The destination write mask on
|
|
806
|
+
the *declaration* itself only ever narrows which components get declared this pass
|
|
807
|
+
(merged across multiple partial declarations via `acOutputDeclared`); it has no
|
|
808
|
+
`_sat` concept — `saturate` only applies to the *instructions* that write the
|
|
809
|
+
register, never to a `dcl_output` declaration itself.
|
|
810
|
+
|
|
811
|
+
**Helpers needed**: `HandleOutputRedirect` — like `HandleInputRedirect`, this is
|
|
812
|
+
HLSLcc's hull-shader phase-output staging machinery; out of scope for this project's
|
|
813
|
+
vertex/pixel-only target.
|
|
814
|
+
|
|
815
|
+
**Edge cases — signature-only vertex outputs**: `023-signature-only-vertex-output-fallback.md`
|
|
816
|
+
documents `starmapnew`/`ubershader3d` variants whose OSGN declares outputs (`o3
|
|
817
|
+
-> COLOR2`, `o4 -> TEXCOORD1`, etc. for `starmapnew`; `o2 -> COLOR1`, `o7 ->
|
|
818
|
+
TEXCOORD4` for `ubershader3d`) with **no corresponding bytecode write** anywhere in
|
|
819
|
+
the instruction stream (audited: `references: 0`). GLSL ES 3.00 does not guarantee
|
|
820
|
+
zero-initialization of `out` varyings, and reading an unwritten varying downstream is
|
|
821
|
+
undefined/implementation-defined — this project's proven, adopted policy is to emit
|
|
822
|
+
an explicit deterministic zero-fill in early-main for any declared-but-never-written
|
|
823
|
+
output: `vs_COLOR2 = vec4(0.0);` before the translated instruction stream runs. Treat
|
|
824
|
+
this as expected, not a parser bug, for any output register with zero write
|
|
825
|
+
references.
|
|
826
|
+
|
|
827
|
+
**WebGL2 notes**: `layout(location=N)` for fragment-shader color outputs is
|
|
828
|
+
mandatory when more than one is declared (no implicit indexing); prefer
|
|
829
|
+
name-based linking (no `layout(location=...)`) for VS→PS varyings specifically,
|
|
830
|
+
per the recommendation above, to avoid cross-stage location-numbering mismatches.
|
|
831
|
+
|
|
832
|
+
**Confidence: high** for the SV_Target/varying declaration shape and naming
|
|
833
|
+
convention (heavily used, directly cited, corpus-validated linking counts exist
|
|
834
|
+
elsewhere in this family for related opcodes); **medium** for the
|
|
835
|
+
"resolve VS-output interpolation from the paired PS-input's `dcl_input_ps` mode"
|
|
836
|
+
policy recommendation, since that is this spec's own synthesis of how to handle
|
|
837
|
+
cross-stage interpolation resolution for a from-scratch JS emitter, not a literal
|
|
838
|
+
restatement of an already-proven CarbonEngineJS-fork behavior.
|
|
839
|
+
|
|
840
|
+
---
|
|
841
|
+
|
|
842
|
+
## `dcl_output_siv` (2825)
|
|
843
|
+
|
|
844
|
+
**Semantics**: declares a vertex/geometry/domain-shader output register bound to a
|
|
845
|
+
**system-value** semantic (`SV_Position`, `SV_RenderTargetArrayIndex`,
|
|
846
|
+
`SV_ClipDistance`, `SV_CullDistance`, `SV_ViewportArrayIndex`, `SV_PrimitiveID`, plus
|
|
847
|
+
tessellation-factor system values not relevant to this project's VS/PS-only scope)
|
|
848
|
+
rather than an arbitrary user semantic.
|
|
849
|
+
|
|
850
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:1899-2058`, switch on
|
|
851
|
+
`psDecl->asOperands[0].eSpecialName`:
|
|
852
|
+
- `NAME_POSITION` → `AddBuiltinOutput(psDecl, 0, "gl_Position")` (`1903-1907`) — the
|
|
853
|
+
**only** system value this project's vertex-shader corpus needs. `gl_Position` is
|
|
854
|
+
built-in in every GLSL version; no declaration text at all is emitted for it (the
|
|
855
|
+
register's read/write sites are simply redirected to the literal string
|
|
856
|
+
`gl_Position` instead of a synthesized varying name — see `AddBuiltinOutput`,
|
|
857
|
+
`413-...`, and note it early-returns immediately for any special name other than
|
|
858
|
+
`NAME_CLIP_DISTANCE`/`NAME_CULL_DISTANCE`, `419-420`, meaning **for `NAME_POSITION`
|
|
859
|
+
specifically this call is a pure no-op**: the redirection to `gl_Position` as an
|
|
860
|
+
operand string happens entirely in the instruction-translation/operand layer, not
|
|
861
|
+
here).
|
|
862
|
+
- `NAME_RENDER_TARGET_ARRAY_INDEX` → `gl_Layer`, requiring
|
|
863
|
+
`GL_AMD_vertex_shader_layer` on a vertex shader (`1908-1928`) — **not standard in
|
|
864
|
+
GLSL ES 3.00/WebGL2**; this is a desktop-GL vendor extension. Multi-layer
|
|
865
|
+
rendering from a vertex shader is out of scope for this project's target; treat as
|
|
866
|
+
a target blocker if encountered, not a silently-degraded feature.
|
|
867
|
+
- `NAME_CLIP_DISTANCE`/`NAME_CULL_DISTANCE` → `gl_ClipDistance`/`gl_CullDistance`
|
|
868
|
+
(`1929-1938`), requiring `GL_EXT_clip_cull_distance` on ES targets
|
|
869
|
+
(`449` inside `AddBuiltinOutput`) — this is a **real, available WebGL2 extension**
|
|
870
|
+
(`EXT_clip_cull_distance`), but is optional/not universally supported; treat as
|
|
871
|
+
conditionally available, verify at runtime before relying on it.
|
|
872
|
+
- `NAME_VIEWPORT_ARRAY_INDEX` → `gl_ViewportIndex` (`1939-1943`) — desktop-only
|
|
873
|
+
(`GL_ARB_shader_viewport_layer_array`/`GL_NV_viewport_array2`), no WebGL2
|
|
874
|
+
equivalent; out of scope.
|
|
875
|
+
- `NAME_PRIMITIVE_ID` → `gl_PrimitiveID` (`1949-1953`) — vertex shaders cannot write
|
|
876
|
+
`SV_PrimitiveID` in D3D (it is a geometry-shader-only output there); this branch is
|
|
877
|
+
reached only for geometry shaders, out of this project's scope.
|
|
878
|
+
- `NAME_VERTEX_ID`/`NAME_INSTANCE_ID`/`NAME_IS_FRONT_FACE` → `ASSERT(0)` (`1944-1963`,
|
|
879
|
+
these are never legal *outputs*, only inputs — DXBC-level invariant, not a lowering
|
|
880
|
+
choice).
|
|
881
|
+
- Tessellation-factor names (`NAME_FINAL_*_TESSFACTOR`, `1964-2047`) → hull-shader-only
|
|
882
|
+
`gl_TessLevelOuter`/`gl_TessLevelInner` array slots; entirely out of this project's
|
|
883
|
+
vertex/pixel-only scope.
|
|
884
|
+
|
|
885
|
+
**Type rules**: `gl_Position` is always `vec4`; the `_siv` declaration itself carries
|
|
886
|
+
no separate component-type fact beyond what the built-in GLSL variable already
|
|
887
|
+
mandates.
|
|
888
|
+
|
|
889
|
+
**Helpers needed**: none — every reachable case in this project's scope
|
|
890
|
+
(`NAME_POSITION`) redirects to a language built-in with zero emitted declaration
|
|
891
|
+
text.
|
|
892
|
+
|
|
893
|
+
**Edge cases**: the DXBC-level invariant that `SV_Position` is always written in a
|
|
894
|
+
vertex shader means this opcode should appear at least once per vertex-shader stage
|
|
895
|
+
in the corpus (2825 occurrences across 1611 files' vertex + pixel-adjacent stages is
|
|
896
|
+
consistent with "roughly one per vertex/domain/geometry stage, most of which are
|
|
897
|
+
plain VS-only stages here").
|
|
898
|
+
|
|
899
|
+
**WebGL2 notes**: of the system values this opcode can carry, only `SV_Position` (no
|
|
900
|
+
extension) and, conditionally, `SV_ClipDistance`/`SV_CullDistance`
|
|
901
|
+
(`EXT_clip_cull_distance`, optional) have any real WebGL2 story; every other branch
|
|
902
|
+
listed above is a target blocker for this project's WebGL2 scope, not a lowering
|
|
903
|
+
detail to implement.
|
|
904
|
+
|
|
905
|
+
**Confidence: high** for `NAME_POSITION` (dominant case, direct source read,
|
|
906
|
+
`TRANSPILING-GAPS.md` "Already handled": "`SV_Position`... [is] handled"); **low**
|
|
907
|
+
for every other branch, since none of them are exercised in this project's proven
|
|
908
|
+
VS/PS-only WebGL2 validation runs.
|
|
909
|
+
|
|
910
|
+
---
|
|
911
|
+
|
|
912
|
+
## `dcl_input_ps_siv` (538)
|
|
913
|
+
|
|
914
|
+
**Semantics**: declares a pixel-shader input bound to a system-value semantic
|
|
915
|
+
(`SV_Position` as `gl_FragCoord`, or `SV_RenderTargetArrayIndex` as `gl_Layer`).
|
|
916
|
+
|
|
917
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:2188-2207`:
|
|
918
|
+
- `NAME_POSITION` → `AddBuiltinInput(psDecl, "gl_FragCoord")` (built-in, no
|
|
919
|
+
declaration text — `gl_FragCoord` is core GLSL ES 3.00), **plus** an early-main
|
|
920
|
+
statement:
|
|
921
|
+
```glsl
|
|
922
|
+
vec4 hlslcc_FragCoord = vec4(gl_FragCoord.xyz, 1.0/gl_FragCoord.w);
|
|
923
|
+
```
|
|
924
|
+
(`2195`) — every read of the DXBC `SV_Position` pixel-shader input must be
|
|
925
|
+
redirected to `hlslcc_FragCoord`, **not** raw `gl_FragCoord`: the literal C++
|
|
926
|
+
text takes `gl_FragCoord.xyz` unchanged but replaces the `.w` component with
|
|
927
|
+
`1.0/gl_FragCoord.w`, reconciling a difference between what HLSL's
|
|
928
|
+
`SV_Position.w` and GLSL's `gl_FragCoord.w` each store in the 4th component.
|
|
929
|
+
Treat `hlslcc_FragCoord` as the mandatory redirect target for any
|
|
930
|
+
`SV_Position`-as-input read in a pixel shader, not `gl_FragCoord` directly — do
|
|
931
|
+
not attempt to re-derive or "simplify" the `1.0/gl_FragCoord.w` swap, just
|
|
932
|
+
reproduce the line as emitted.
|
|
933
|
+
- `NAME_RENDER_TARGET_ARRAY_INDEX` → `gl_Layer` (`2198-2201`) — reading back which
|
|
934
|
+
array layer/cubemap face the primitive rasterized into; requires geometry-shader
|
|
935
|
+
layered rendering upstream, out of this project's scope.
|
|
936
|
+
- Anything else → `ASSERT(0)` (`2203-2205`) — DXBC-level invariant, no other system
|
|
937
|
+
value is legal as a pixel-shader `_siv` input.
|
|
938
|
+
|
|
939
|
+
**Type rules**: `gl_FragCoord`/`hlslcc_FragCoord` is always `vec4`.
|
|
940
|
+
|
|
941
|
+
**Helpers needed**: the `hlslcc_FragCoord` early-main redirect line above — declare
|
|
942
|
+
it as a **named helper convention** (a fixed early-main statement emitted whenever a
|
|
943
|
+
`dcl_input_ps_siv NAME_POSITION` is seen), not a callable function, since it is a
|
|
944
|
+
local variable substitution rather than a reusable GLSL function.
|
|
945
|
+
|
|
946
|
+
**Edge cases**: `1.0/gl_FragCoord.w` divides by the fragment's window-space `w`
|
|
947
|
+
reciprocal — if `gl_FragCoord.w` is ever exactly `0.0` (a fragment at infinite
|
|
948
|
+
depth/degenerate clip-space w), this produces `inf`; no corpus evidence this occurs
|
|
949
|
+
in practice (fragments with `w=0` do not typically survive clipping), but note it as
|
|
950
|
+
a theoretical NaN/inf source worth being aware of, not one this project needs to
|
|
951
|
+
guard defensively against absent contrary evidence.
|
|
952
|
+
|
|
953
|
+
**WebGL2 notes**: `gl_FragCoord` is core; no extension needed. `gl_Layer` requires
|
|
954
|
+
geometry-shader support, out of scope for this project.
|
|
955
|
+
|
|
956
|
+
**Confidence: high** for `NAME_POSITION` (directly cited, dominant case — 538
|
|
957
|
+
occurrences is consistent with "most pixel shaders read `SV_Position`"); **low** for
|
|
958
|
+
`gl_Layer` (unreachable without geometry shaders in this project's stage set).
|
|
959
|
+
|
|
960
|
+
---
|
|
961
|
+
|
|
962
|
+
## `dcl_input_ps_sgv` (42) / `dcl_input_sgv` (18)
|
|
963
|
+
|
|
964
|
+
**Semantics**: declares a pixel-shader (`_ps_sgv`) or vertex/other-stage (`_sgv`)
|
|
965
|
+
input bound to a **system-generated-value** semantic — the DXBC category for values
|
|
966
|
+
the *rasterizer/assembler* synthesizes rather than values passed through the
|
|
967
|
+
interpolator pipeline: `SV_IsFrontFace`, `SV_SampleIndex`, `SV_VertexID`,
|
|
968
|
+
`SV_InstanceID`, `SV_PrimitiveID`, plus the same position/layer/clip/cull/viewport
|
|
969
|
+
names `_siv` also carries (both opcodes share one switch statement in the source).
|
|
970
|
+
|
|
971
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:1815-1896` (both opcodes dispatch to this
|
|
972
|
+
single `case` block). The branches relevant to this project's VS/PS-only scope:
|
|
973
|
+
- `NAME_IS_FRONT_FACE` (pixel-shader-only in practice — `SV_IsFrontFace` is a PS
|
|
974
|
+
input) → `gl_FrontFacing`, with an explicit **cast trick**
|
|
975
|
+
(`1856-1869`):
|
|
976
|
+
```cpp
|
|
977
|
+
if (HaveUnsignedTypes(psContext->psShader->eTargetLanguage))
|
|
978
|
+
AddBuiltinInput(psDecl, "(gl_FrontFacing ? 0xffffffffu : uint(0))");
|
|
979
|
+
else
|
|
980
|
+
AddBuiltinInput(psDecl, "(gl_FrontFacing ? 1 : 0)");
|
|
981
|
+
```
|
|
982
|
+
The comment explains why: `if(gl_FrontFacing != 0)` failed to compile on Intel HD
|
|
983
|
+
4000 — no implicit bool↔int conversion on that driver — so HLSLcc always
|
|
984
|
+
materializes the DXBC **comparison-mask convention** explicitly at the point of
|
|
985
|
+
use: `SV_IsFrontFace` in DXBC is an integer that reads as `0xFFFFFFFF` (true) or
|
|
986
|
+
`0x00000000` (false), **not** a GLSL `bool`. For GLSL ES 3.00 (`HaveUnsignedTypes`
|
|
987
|
+
true), every read of this input must produce `0xffffffffu`/`uint(0)`, then get
|
|
988
|
+
bitcast with `uintBitsToFloat(...)` if the register file stores it as a float (per
|
|
989
|
+
this project's register convention) — i.e. the declaration-time substitution text
|
|
990
|
+
for `in_IS_FRONT_FACE`-style reads should literally be
|
|
991
|
+
`(gl_FrontFacing ? uintBitsToFloat(0xffffffffu) : uintBitsToFloat(uint(0)))` when
|
|
992
|
+
materializing it into this project's float register file, or equivalently
|
|
993
|
+
`uintBitsToFloat(gl_FrontFacing ? 0xffffffffu : 0u)` (matches the JS draft
|
|
994
|
+
transpiler's own hypothesis at
|
|
995
|
+
`../shaderdiscovery/src/core/transpiler/gles/Dx11GlesDraftTranspiler.js:1405`:
|
|
996
|
+
`splatScalarExpression("uintBitsToFloat(gl_FrontFacing ? 0xffffffffu : 0u)", count)`
|
|
997
|
+
— cross-checked against `toGLSLDeclaration.cpp:1864-1867` and confirmed
|
|
998
|
+
consistent).
|
|
999
|
+
- `NAME_SAMPLE_INDEX` → `gl_SampleID`, requiring `GL_OES_sample_variables` on ES
|
|
1000
|
+
targets (`1870-1876`) — this **is** a real, available WebGL2 extension
|
|
1001
|
+
(`OES_sample_variables`), but optional; treat as conditionally available.
|
|
1002
|
+
- `NAME_VERTEX_ID` → `gl_VertexID` (`1878-1881`) — core in GLSL ES 3.00 for vertex
|
|
1003
|
+
shaders, no extension needed. `TRANSPILING-GAPS.md` "Already handled":
|
|
1004
|
+
"`SV_VertexID`... [is] handled."
|
|
1005
|
+
- `NAME_INSTANCE_ID` → `gl_InstanceID` (`1851-1854`) — core in GLSL ES 3.00, no
|
|
1006
|
+
extension needed.
|
|
1007
|
+
- `NAME_PRIMITIVE_ID` → `gl_PrimitiveID`/`gl_PrimitiveIDIn` (`1883-1889`) — requires a
|
|
1008
|
+
geometry shader upstream in practice, out of scope.
|
|
1009
|
+
- `NAME_RENDER_TARGET_ARRAY_INDEX`/`NAME_CLIP_DISTANCE`/`NAME_CULL_DISTANCE`/
|
|
1010
|
+
`NAME_VIEWPORT_ARRAY_INDEX` (`1826-1850`) — same extension caveats as the `_siv`
|
|
1011
|
+
output section above.
|
|
1012
|
+
- `default` (`1891-1894`) — falls back to a plain `in vec4 %s;` declaration using the
|
|
1013
|
+
DXBC-provided special-name string directly, for any system-generated value this
|
|
1014
|
+
switch doesn't special-case.
|
|
1015
|
+
|
|
1016
|
+
**Type rules**: `gl_FrontFacing` is GLSL `bool`; every other value in this list is
|
|
1017
|
+
`int` (`gl_VertexID`, `gl_InstanceID`, `gl_SampleID`, `gl_PrimitiveID`). None of these
|
|
1018
|
+
match DXBC's `0xFFFFFFFF`/`0x00000000` mask convention natively except
|
|
1019
|
+
`SV_IsFrontFace`, which is why it alone gets the explicit ternary-to-mask
|
|
1020
|
+
materialization above; `gl_VertexID`/`gl_InstanceID`/etc. are read as plain signed
|
|
1021
|
+
`int` and bitcast with `intBitsToFloat` when stored into this project's float
|
|
1022
|
+
register file (not `uintBitsToFloat` — these are genuinely signed-int builtins in the
|
|
1023
|
+
GLSL spec, unlike the synthesized front-facing mask).
|
|
1024
|
+
|
|
1025
|
+
**Helpers needed**: none beyond the inline ternary-to-mask expression for
|
|
1026
|
+
`SV_IsFrontFace` (a fixed substitution text, not a callable helper function).
|
|
1027
|
+
|
|
1028
|
+
**Edge cases**: `SV_IsFrontFace`'s `0/0xFFFFFFFF` convention is exactly the
|
|
1029
|
+
**comparison-mask convention** called out at the top level of this spec family — even
|
|
1030
|
+
though this is a *declaration*-family opcode rather than an instruction, it is one of
|
|
1031
|
+
the few `decl-io` opcodes where the DXBC 0/0xFFFFFFFF-vs-GLSL-bool boundary has to be
|
|
1032
|
+
crossed at declaration time rather than left to a later comparison instruction.
|
|
1033
|
+
|
|
1034
|
+
**WebGL2 notes**: `gl_VertexID`/`gl_InstanceID`/`gl_FrontFacing` are all core GLSL ES
|
|
1035
|
+
3.00 (no extension) — the dominant, high-confidence cases for this project.
|
|
1036
|
+
`gl_SampleID` needs an optional extension; primitive-ID/layer/clip/cull/viewport
|
|
1037
|
+
branches need geometry-shader support this project's target does not have.
|
|
1038
|
+
|
|
1039
|
+
**Confidence: high** for `NAME_IS_FRONT_FACE`/`NAME_VERTEX_ID`/`NAME_INSTANCE_ID`
|
|
1040
|
+
(directly cited, corpus-relevant, `TRANSPILING-GAPS.md`-confirmed); **low** for every
|
|
1041
|
+
other branch (geometry-shader-dependent or low corpus incidence: 42+18=60 total
|
|
1042
|
+
instances is small next to the 15k+ `dcl_output` count, and most of that 60 is
|
|
1043
|
+
plausibly `SV_IsFrontFace`/`SV_VertexID` given this corpus is VS/PS-dominated).
|
|
1044
|
+
|
|
1045
|
+
---
|
|
1046
|
+
|
|
1047
|
+
## `dcl_input_siv` (3)
|
|
1048
|
+
|
|
1049
|
+
**Semantics**: declares a non-pixel-shader input bound to a system-value semantic
|
|
1050
|
+
(shares the `NAME_*` enum with `dcl_output_siv`/`dcl_input_ps_siv`/`dcl_input_sgv`,
|
|
1051
|
+
but with its own narrow handling).
|
|
1052
|
+
|
|
1053
|
+
**GLSL lowering**: `toGLSLDeclaration.cpp:2209-2215`:
|
|
1054
|
+
```cpp
|
|
1055
|
+
case OPCODE_DCL_INPUT_SIV:
|
|
1056
|
+
{
|
|
1057
|
+
if (psShader->eShaderType == PIXEL_SHADER && psContext->psDependencies)
|
|
1058
|
+
{
|
|
1059
|
+
psContext->psDependencies->SetInterpolationMode(psDecl->asOperands[0].ui32RegisterNumber, psDecl->value.eInterpolation);
|
|
1060
|
+
}
|
|
1061
|
+
break;
|
|
1062
|
+
}
|
|
1063
|
+
```
|
|
1064
|
+
This opcode emits **no GLSL text of its own** in this project's scope. Its only
|
|
1065
|
+
effect is recording an interpolation-mode fact for a later `dcl_input_ps`/
|
|
1066
|
+
`dcl_input` declaration of the *same register* to consume when choosing that
|
|
1067
|
+
declaration's interpolation qualifier — and only when the current shader is itself
|
|
1068
|
+
the pixel shader (unreachable in the VS/PS pair unless this specific opcode is
|
|
1069
|
+
emitted for a PS input, which is unusual — `dcl_input_ps`/`dcl_input_ps_siv` normally
|
|
1070
|
+
carry that role for pixel shaders; `dcl_input_siv` proper is more commonly a
|
|
1071
|
+
non-pixel-stage opcode in the wider HLSLcc target matrix, e.g. domain/geometry-shader
|
|
1072
|
+
inputs receiving a previous stage's system value as an ordinary interpolated input).
|
|
1073
|
+
|
|
1074
|
+
**Type rules**: n/a — no declaration text, no operand type conversion here.
|
|
1075
|
+
|
|
1076
|
+
**Helpers needed**: none.
|
|
1077
|
+
|
|
1078
|
+
**Edge cases**: only 3 occurrences in the entire 450k-instruction/1611-file corpus —
|
|
1079
|
+
lowest-frequency opcode in this family by a wide margin. Given this project has no
|
|
1080
|
+
geometry/domain/hull stages, verify what these 3 instances actually are before
|
|
1081
|
+
assuming the pixel-shader branch above is even the relevant one; they may be
|
|
1082
|
+
vertex-shader-side declarations that fall through this `case` doing nothing
|
|
1083
|
+
observable at all (the `if` guard requires `PIXEL_SHADER`, so a vertex-shader
|
|
1084
|
+
occurrence of this opcode is a complete no-op).
|
|
1085
|
+
|
|
1086
|
+
**WebGL2 notes**: none — no GLSL is emitted.
|
|
1087
|
+
|
|
1088
|
+
**Confidence: low** — three instances is too small a sample to be confident which
|
|
1089
|
+
concrete DXBC pattern in the EVE corpus produces this opcode versus its much more
|
|
1090
|
+
common `_ps_siv`/`_sgv`/`_ps_sgv` siblings; implement the no-op/interpolation-mode-
|
|
1091
|
+
recording behavior above as written in the source, but do not assume it is
|
|
1092
|
+
exercised meaningfully by this project's corpus.
|
|
1093
|
+
|
|
1094
|
+
---
|
|
1095
|
+
|
|
1096
|
+
## `customdata` (159, encodes an Immediate Constant Buffer)
|
|
1097
|
+
|
|
1098
|
+
**Semantics**: DXBC `customdata` with subtype `ICB` (Immediate Constant Buffer) —
|
|
1099
|
+
an inline array of literal `vec4`-shaped constant data baked directly into the
|
|
1100
|
+
bytecode (as opposed to `dcl_constant_buffer`'s externally-bound `cb#`), addressed
|
|
1101
|
+
either directly by a fixed index or dynamically (`x0[aL]`-style) from instructions
|
|
1102
|
+
later in the stream.
|
|
1103
|
+
|
|
1104
|
+
**GLSL lowering (non-Vulkan, non-Switch — this project's target)**:
|
|
1105
|
+
`toGLSLDeclaration.cpp:3007-3076`. HLSLcc walks `m_ConstantArrayInfo.m_Chunks`
|
|
1106
|
+
(pre-computed groupings of same-component-width, contiguously-accessed ICB slices)
|
|
1107
|
+
and, per chunk:
|
|
1108
|
+
1. Declares an array: `float ImmCB_{phase}_{chunkFirst}_{rebase}[{size}];` (scalar
|
|
1109
|
+
chunk) or `vec{N} ImmCB_{phase}_{chunkFirst}_{rebase}[{size}];` (`N`-wide chunk)
|
|
1110
|
+
(`3017-3020`).
|
|
1111
|
+
2. If the target lacks dynamic indexing support, additionally registers a
|
|
1112
|
+
`DeclareDynamicIndexWrapper` (`3022-3029`) — irrelevant here since GLSL ES 3.00
|
|
1113
|
+
(`HaveDynamicIndexing` true for ES 300) supports genuine dynamic array indexing
|
|
1114
|
+
natively; this project should skip the wrapper machinery entirely and always emit
|
|
1115
|
+
a real GLSL array.
|
|
1116
|
+
3. Populates each array element in **early-main** (not as a `const` initializer list
|
|
1117
|
+
— note this is a *mutable* global-scope-declared, early-main-assigned array in
|
|
1118
|
+
stock HLSLcc, not a `const` array), one assignment per element per component
|
|
1119
|
+
(`3032-3074`):
|
|
1120
|
+
```glsl
|
|
1121
|
+
ImmCB_0_0_0[0] = 1.5;
|
|
1122
|
+
ImmCB_0_0_0[1] = uintBitsToFloat(uint(0x7FC00000u)); // NaN literal, bit-pattern form
|
|
1123
|
+
```
|
|
1124
|
+
Float literals that are themselves NaN/Inf bit patterns
|
|
1125
|
+
(`fpcheck(val[...])`, `3045-3048`, `3067-3070`) are re-encoded as
|
|
1126
|
+
`uintBitsToFloat(uint(0x{hex}u))` rather than a literal `nan`/`inf` token (which
|
|
1127
|
+
GLSL cannot parse directly) — **this bit-pattern-preserving encoding is the
|
|
1128
|
+
correct/required approach for any ICB constant that is NaN or ±Inf, and this
|
|
1129
|
+
project's emitter must replicate it**, since a plain decimal float literal cannot
|
|
1130
|
+
represent those bit patterns exactly and GLSL has no `nan`/`inf` literal syntax.
|
|
1131
|
+
4. Vulkan target (`2975-2990`, background only — not this project's target):
|
|
1132
|
+
`const uvec4 ImmCB_{phase}[] = uvec4[{count}](uvec4(0x..., ...), ...);` — a true
|
|
1133
|
+
`const` array of raw-bit `uvec4`s.
|
|
1134
|
+
5. Switch target (`2991-3006`, background only): a `const vec4
|
|
1135
|
+
ImmCB_{phase}[]` initialized with a `vec4[{count}]` array constructor whose
|
|
1136
|
+
elements preserve raw bits with `uintBitsToFloat`; this is the
|
|
1137
|
+
shape closest to "a `const vec4 array`" as the family brief describes, and is a
|
|
1138
|
+
**better model for this project's emitter to imitate** than the non-Vulkan/
|
|
1139
|
+
non-Switch mutable-early-main-array path above: declare
|
|
1140
|
+
```glsl
|
|
1141
|
+
const vec4 ImmCB_{phase}[{count}] = vec4[{count}](
|
|
1142
|
+
vec4(uintBitsToFloat(0x3FC00000u), uintBitsToFloat(0x00000000u), ...),
|
|
1143
|
+
...
|
|
1144
|
+
);
|
|
1145
|
+
```
|
|
1146
|
+
at global scope (every raw dword reinterpreted through `uintBitsToFloat`
|
|
1147
|
+
uniformly, whether or not it happens to be a "nice" float, sidestepping the
|
|
1148
|
+
`fpcheck`-conditional branching the CPU-target path uses) — simpler to implement
|
|
1149
|
+
correctly in a from-scratch JS emitter and avoids the early-main mutable-global
|
|
1150
|
+
pattern (which exists in stock HLSLcc mainly to support per-chunk dynamic-array
|
|
1151
|
+
splitting this project doesn't need, since `HaveDynamicIndexing` is true and a
|
|
1152
|
+
single flat `const vec4[]` can be indexed directly).
|
|
1153
|
+
|
|
1154
|
+
**Type rules**: every ICB element is exactly 4 raw dwords; **always reinterpret via
|
|
1155
|
+
`uintBitsToFloat`** rather than trusting a decimal float re-parse of the DXBC literal
|
|
1156
|
+
value, to guarantee exact bit-for-bit reproduction of the original constant
|
|
1157
|
+
(including denormals/NaNs/Infs the HLSL compiler folded in). Consumers needing an
|
|
1158
|
+
int/uint view of an ICB element bitcast again at the use site
|
|
1159
|
+
(`floatBitsToInt`/`floatBitsToUint`) exactly like any other float-register-file read.
|
|
1160
|
+
|
|
1161
|
+
**Helpers needed**: none — `uintBitsToFloat` is core GLSL ES 3.00.
|
|
1162
|
+
|
|
1163
|
+
**Edge cases**: NaN/Inf constants are the primary edge case, handled correctly by
|
|
1164
|
+
the bit-pattern-preserving encoding above — do not let a JS `JSON.stringify`/decimal
|
|
1165
|
+
round-trip of the float value silently normalize a NaN payload or lose an Inf's
|
|
1166
|
+
sign bit; carry the raw `uint32` dword through to the emitted GLSL untouched.
|
|
1167
|
+
Dynamic indexing of the ICB (`x0[aL]`-style reads) is a plain GLSL array-index
|
|
1168
|
+
expression on this project's target (`HaveDynamicIndexing` true for ES 300),
|
|
1169
|
+
needing none of stock HLSLcc's non-dynamic-indexing wrapper-function fallback.
|
|
1170
|
+
|
|
1171
|
+
**WebGL2 notes**: dynamic (non-constant-expression) array indexing of a global
|
|
1172
|
+
array is supported in GLSL ES 3.00's core profile (unlike GLSL ES 1.00, where it was
|
|
1173
|
+
restricted) — this project's target does not need the
|
|
1174
|
+
`DeclareDynamicIndexWrapper` fallback stock HLSLcc carries for older targets.
|
|
1175
|
+
|
|
1176
|
+
**Confidence: medium** — the NaN/Inf bit-pattern-preserving requirement and the
|
|
1177
|
+
"prefer the Switch-shaped `const vec4[]` over the non-Vulkan/non-Switch mutable
|
|
1178
|
+
early-main array" recommendation are both this spec's own synthesis reasoned from
|
|
1179
|
+
reading three different target branches in the same source function, not a literal
|
|
1180
|
+
restatement of a single already-proven CarbonEngineJS-fork code path — validate the
|
|
1181
|
+
`const vec4[]` shape compiles and links correctly on an actual WebGL2 context before
|
|
1182
|
+
treating it as final.
|
|
1183
|
+
|
|
1184
|
+
---
|
|
1185
|
+
|
|
1186
|
+
## Helpers summary
|
|
1187
|
+
|
|
1188
|
+
Every helper function/macro/convention this family requires the JS emitter to
|
|
1189
|
+
provide, in one place:
|
|
1190
|
+
|
|
1191
|
+
| Helper | Kind | Used by | Definition |
|
|
1192
|
+
|---|---|---|---|
|
|
1193
|
+
| `floatBitsToInt` | core GLSL ES 3.00 builtin | any int-typed read of a float-register-file value (`dcl_temps`, `dcl_indexable_temp`, `dcl_constant_buffer` fallback slots, `customdata`, integer-lowered `dcl_input`) | built-in, no definition needed |
|
|
1194
|
+
| `floatBitsToUint` | core GLSL ES 3.00 builtin | same as above, uint-typed reads (also the `SV_IsFrontFace` mask materialization, `dcl_input_ps_sgv`/`dcl_input_sgv`) | built-in |
|
|
1195
|
+
| `intBitsToFloat` | core GLSL ES 3.00 builtin | writing an int-typed result into a float register (`gl_VertexID`/`gl_InstanceID`/`gl_PrimitiveID`/`gl_SampleID` materialization into the float register file) | built-in |
|
|
1196
|
+
| `uintBitsToFloat` | core GLSL ES 3.00 builtin | writing a uint-typed result into a float register; ICB literal decoding (`customdata`); `SV_IsFrontFace` mask materialization | built-in |
|
|
1197
|
+
| `hlslcc_FragCoord` early-main redirect | fixed substitution statement, not a function | `dcl_input_ps_siv` (`NAME_POSITION`) | `vec4 hlslcc_FragCoord = vec4(gl_FragCoord.xyz, 1.0/gl_FragCoord.w);` — every `SV_Position`-as-PS-input read must use this name, not raw `gl_FragCoord` |
|
|
1198
|
+
| `SV_IsFrontFace` mask expression | fixed substitution expression, not a function | `dcl_input_ps_sgv`/`dcl_input_sgv` (`NAME_IS_FRONT_FACE`) | `uintBitsToFloat(gl_FrontFacing ? 0xffffffffu : 0u)` materialized wherever the DXBC 0/0xFFFFFFFF mask value is read |
|
|
1199
|
+
| Integer-vertex-attribute float lowering | declaration-shape convention, not a function | `dcl_input` for any `INOUT_COMPONENT_UINT32`/`SINT32` vertex attribute (proven for `BLENDINDICES`; generalize cautiously) | declare `vec4`/`vecN` instead of `uvecN`/`ivecN`; bitcast at every use site |
|
|
1200
|
+
| `in_BINORMALn -> in_BITANGENTn` rename | package-time post-process, not a GLSL-emission-time helper | `dcl_input` split-tangent-space vertex shaders | applied by `scripts/packageTr2WebglEffect.js`-equivalent tooling **after** this family's GLSL text is emitted, keyed off the stage's Carbon metadata contract — do not bake into the opcode lowering itself |
|
|
1201
|
+
| Cross-stage `cbN` size normalization | package/link-time policy, not a per-shader GLSL-emission helper | `dcl_constant_buffer` | emit the **max** `data[]` slot count observed for a given `cb#` across every stage sharing that binding point in one linked program |
|
|
1202
|
+
| `BoneTransforms` SSBO→`cb3` splice | package-time ABI rewrite, not a GLSL-emission-time helper | `dcl_resource_structured` (skinned space-object shaders specifically) | drop the `t0` SSBO decl; grow `cb3` to `vec4 data[200]`; rewrite `ld_structured` row reads to `cb3.data[26 + blendIndex*3 + row]` |
|
|
1203
|
+
| `layout(early_fragment_tests) in;` suppression | emission-time language gate (not present in stock HLSLcc) | `dcl_global_flags` (`FORCE_EARLY_DEPTH_STENCIL`) | drop the qualifier entirely when targeting GLSL ES 3.00 |
|
|
1204
|
+
|
|
1205
|
+
---
|
|
1206
|
+
|
|
1207
|
+
## Cross-cutting risks (lowest-confidence areas across this whole family)
|
|
1208
|
+
|
|
1209
|
+
1. **`dcl_input_siv`** (3 corpus instances) — sample too small to be confident the
|
|
1210
|
+
documented no-op/interpolation-recording behavior is even the path exercised;
|
|
1211
|
+
verify against the actual 3 instances before trusting this section.
|
|
1212
|
+
2. ~~`noperspective` on `dcl_input_ps`~~ — resolved during review: the C++ source's
|
|
1213
|
+
`hasNoPerspective` gate (`>LANG_ES_310`) is correct, not stale — GLSL ES 3.00
|
|
1214
|
+
genuinely has no `noperspective` keyword, so the gate should be mirrored as-is
|
|
1215
|
+
rather than second-guessed. `sample`/`centroid` remain core ES 3.00 keywords with
|
|
1216
|
+
no gating concern.
|
|
1217
|
+
3. **Integer-vertex-attribute float-lowering generalization** — proven and validated
|
|
1218
|
+
specifically for `BLENDINDICES`/`uvec4`; whether the same treatment is correct for
|
|
1219
|
+
every other `INOUT_COMPONENT_UINT32`/`SINT32` vertex semantic in the corpus (and
|
|
1220
|
+
whether the use-site cast should be a bit-pattern `floatBitsToUint` reinterpret vs.
|
|
1221
|
+
a value-preserving `uint(...)` truncating convert) has not been separately proven
|
|
1222
|
+
per-semantic.
|
|
1223
|
+
4. **`customdata` emission shape** — this spec recommends the Switch-target's
|
|
1224
|
+
`const vec4[]` shape over the stock non-Vulkan/non-Switch mutable-early-main-array
|
|
1225
|
+
shape as simpler and sufficient for this project's ES-300-with-dynamic-indexing
|
|
1226
|
+
target; this recommendation is this document's own synthesis, not a literally
|
|
1227
|
+
cited already-proven CarbonEngineJS-fork code path, and should be validated by an
|
|
1228
|
+
actual WebGL2 compile before being treated as settled.
|
|
1229
|
+
5. **`dcl_global_flags` / `layout(early_fragment_tests) in;`** — whether any EVE
|
|
1230
|
+
effect in the corpus actually sets `FORCE_EARLY_DEPTH_STENCIL` (making the WebGL2
|
|
1231
|
+
suppression gate load-bearing rather than theoretical) was not verified in this
|
|
1232
|
+
pass.
|
|
1233
|
+
|
|
1234
|
+
|