@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,964 @@
|
|
|
1
|
+
# DXBC -> GLSL ES 3.00 Lowering Spec: texture-sample family
|
|
2
|
+
|
|
3
|
+
Status: Evolving
|
|
4
|
+
Scope: `@carbonenginejs/runtime-resource/formats/webgl` texture and sampling lowering
|
|
5
|
+
Audience: Shader translator maintainers and reviewers
|
|
6
|
+
Summary: Defines DXBC texture sampling behavior and WebGL2 target adaptations.
|
|
7
|
+
|
|
8
|
+
Target: GLSL ES 3.00 (WebGL2), vertex + pixel stages, no SSBO/compute.
|
|
9
|
+
Register storage model: every register is a float `vec4`; typed reads/writes bitcast at
|
|
10
|
+
the use site (`floatBitsToInt`, `floatBitsToUint`, `intBitsToFloat`, `uintBitsToFloat`),
|
|
11
|
+
mirroring HLSLcc's own behavior when reflected data-type analysis is unavailable
|
|
12
|
+
(`ShaderInfo::GetTextureDataType` returns `SVT_FLOAT` when no `RDEF` binding is found —
|
|
13
|
+
`vendor/HLSLcc/src/ShaderInfo.cpp:10-18`).
|
|
14
|
+
|
|
15
|
+
Authority order used below: (1) `toGLSLInstruction.cpp` / `toGLSLOperand.cpp` /
|
|
16
|
+
`toGLSLDeclaration.cpp` / `HLSLccToolkit.cpp`, (2) `CARBONENGINEJS-FORK.md`, (3)
|
|
17
|
+
`TRANSPILING-GAPS.md`, (4) `AGENT-FINDINGS/decisions/*.md`, (5) `Dx11GlesDraftTranspiler.js`
|
|
18
|
+
(hints only, cross-checked, never trusted standalone).
|
|
19
|
+
|
|
20
|
+
**Correction (verification pass, 2026-07-05)**: sources (3) and (4) above —
|
|
21
|
+
`TRANSPILING-GAPS.md`, `AGENT-FINDINGS/decisions/*.md` — and source (5),
|
|
22
|
+
`Dx11GlesDraftTranspiler.js`, do not exist anywhere in this repository: neither in the
|
|
23
|
+
working tree nor in `git log --all` history, under any path (checked repo-wide, not just
|
|
24
|
+
under `docs/` or `vendor/`). Only `CARBONENGINEJS-FORK.md`
|
|
25
|
+
(`vendor/HLSLcc/CARBONENGINEJS-FORK.md`) and the `toGLSLInstruction.cpp`/`toGLSLOperand.cpp`/
|
|
26
|
+
`toGLSLDeclaration.cpp`/`HLSLccToolkit.cpp` C++ sources actually exist and were readable for
|
|
27
|
+
this review. Every citation to `TRANSPILING-GAPS.md:*`, `decisions/*.md`, or
|
|
28
|
+
`Dx11GlesDraftTranspiler.js` elsewhere in this document is therefore **unverifiable** and
|
|
29
|
+
must not be treated as independent corroboration until those files are located or
|
|
30
|
+
reconstructed — treat any "Confidence" rating that leaned on them as resting on the C++
|
|
31
|
+
citations alone (which were independently re-verified line-by-line for this pass and, apart
|
|
32
|
+
from the corrections called out below, held up).
|
|
33
|
+
|
|
34
|
+
This project's own `hlsl2webgl` CLI tool is the concrete configuration this spec targets:
|
|
35
|
+
`LANG_ES_300` with `HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS | HLSLCC_FLAG_UNIFORM_BUFFER_OBJECT |
|
|
36
|
+
HLSLCC_FLAG_INOUT_SEMANTIC_NAMES | HLSLCC_FLAG_INCLUDE_INSTRUCTIONS_COMMENTS |
|
|
37
|
+
HLSLCC_FLAG_KEEP_VARYING_LOCATIONS` (`vendor/HLSLcc/tools/hlsl2webgl/hlsl2webgl.cpp:38-44`).
|
|
38
|
+
So the combined-texture-sampler path (single opaque GLSL `samplerND` per t#/s# pair) is
|
|
39
|
+
this CLI tool's **default** configuration (both `hlsl2webgl.cpp`'s `--flags`/
|
|
40
|
+
`--no-default-flags` options and `scripts/packageTr2WebglEffect.js`'s `--flags` passthrough
|
|
41
|
+
can override it), not a hardcoded, unconditional invariant — but it is the configuration
|
|
42
|
+
this spec targets and the one assumed throughout.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 0. Register-stable ABI: how t#/s# become GLSL names
|
|
47
|
+
|
|
48
|
+
Ground truth: `toGLSLOperand.cpp:1738-1882` (`ResourceName`, `TextureSamplerName`),
|
|
49
|
+
`toGLSLDeclaration.cpp:1597-1686` (`TranslateResourceTexture`), and
|
|
50
|
+
`CARBONENGINEJS-FORK.md`.
|
|
51
|
+
|
|
52
|
+
- **Plain resource name** (`ResourceName`, `toGLSLOperand.cpp:1738-1810`): if the register
|
|
53
|
+
has a resolved `RDEF`/reflection binding, the name is the reflected identifier (with `[`/`]`
|
|
54
|
+
array syntax rewritten to `_`, and an array-offset suffix appended if the register is not
|
|
55
|
+
the base of its binding). If no binding is found (stripped `RDEF` — the documented
|
|
56
|
+
`CARBONENGINEJS-FORK.md` scenario), the fallback is the literal register-stable symbol:
|
|
57
|
+
`"t" + regNo` for textures, `"s" + regNo` for samplers (prefixed with the literal string
|
|
58
|
+
`sampler` if it doesn't already start with it — so unresolved sampler `s3` becomes
|
|
59
|
+
`samplers3`), `"cb" + regNo` for constant buffers, `"u" + regNo` for UAVs
|
|
60
|
+
(`toGLSLOperand.cpp:1780-1799`).
|
|
61
|
+
- **Combined texture+sampler name** (`TextureSamplerName`, `toGLSLOperand.cpp:1819-1876`):
|
|
62
|
+
built independently of `ResourceName`. If either the texture or the sampler binding is
|
|
63
|
+
unresolved, the fallback is literally `"t" + texRegNo + "TEX_with_SMPs" + smpRegNo`
|
|
64
|
+
(e.g. `t0TEX_with_SMPs0`) — the `t#`/`s#` symbols survive intact inside the combined name.
|
|
65
|
+
If both bindings resolve, the name is `<textureName>[arrayOffset]TEX_with_SMP<samplerName>`.
|
|
66
|
+
A `bZCompare` flag prefixes `hlslcc_zcmp` onto either name for the shadow-sampler variant
|
|
67
|
+
used by depth-compare ops (see `sample_c` below).
|
|
68
|
+
- **Declaration duplication**: `TranslateResourceTexture` (`toGLSLDeclaration.cpp:1632-1666`)
|
|
69
|
+
emits **both** symbols as separate `uniform` declarations when
|
|
70
|
+
`HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS` is set: one `uniform sampler2D <TextureSamplerName>`
|
|
71
|
+
per (texture, sampler) pair actually used together in the shader, **and** a plain
|
|
72
|
+
`uniform sampler2D <ResourceName>` (the bare `t#` symbol) that is declared but not
|
|
73
|
+
referenced by instruction bodies (instruction bodies call `TextureSamplerName`, not
|
|
74
|
+
`ResourceName`, when `useCombinedTextureSamplers` is true — `toGLSLInstruction.cpp:1332-1336`).
|
|
75
|
+
This is deliberate register-identity preservation per `CARBONENGINEJS-FORK.md`
|
|
76
|
+
("emitting deterministic register-stable GLSL symbols such as `cb3`, `t0`, and `s0`" /
|
|
77
|
+
"preserving enough register identity for `Tr2EffectBindingManifest`... and eventual
|
|
78
|
+
trinityjs binding work"): the emitter must keep declaring the bare `t#` uniform even
|
|
79
|
+
though the sampling calls use the combined name, so downstream tooling can still find a
|
|
80
|
+
`t#`-named uniform to correlate against Carbon metadata.
|
|
81
|
+
- **Texture/sampler pairing is register-based, not name-based**
|
|
82
|
+
(`AGENT-FINDINGS/decisions/003-texture-sampler-translation-boundary-2026-06-26.md`):
|
|
83
|
+
do not infer texture ownership from a sampler's metadata label; the (t#, s#) pair observed
|
|
84
|
+
on the actual instruction operands is the only truth.
|
|
85
|
+
- **Samplerless resource access is real** (`decisions/005-samplerless-texture-access-evidence-2026-06-26.md`):
|
|
86
|
+
`ld` and `resinfo` carry no sampler operand at all. `TranslateTexelFetch` handles a
|
|
87
|
+
missing reflected binding by synthesizing a `fallbackBinding` from the `SHEX`-derived
|
|
88
|
+
resource dimension (`toGLSLInstruction.cpp:825-870`), defaulting
|
|
89
|
+
`ui32ReturnType = RETURN_TYPE_FLOAT`, matching the fork's stripped-`RDEF` fallback policy.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## 1. `sample` (3064 occurrences)
|
|
94
|
+
|
|
95
|
+
**Semantics**: Standard filtered texture sample using the sampler's declared filter/wrap
|
|
96
|
+
state and an implicitly-computed LOD (derivative-based, like a normal pixel-shader texture
|
|
97
|
+
fetch). D3D11 `SAMPLE` opcode: `dest, address, resource, sampler`.
|
|
98
|
+
|
|
99
|
+
**GLSL lowering**: `TranslateTextureSample(psInst, TEXSMP_FLAG_NONE)`
|
|
100
|
+
(`toGLSLInstruction.cpp:3161-3170`, dispatch into `toGLSLInstruction.cpp:1131-1459`).
|
|
101
|
+
Template (combined-sampler, ES 3.00, dimension = 2D):
|
|
102
|
+
|
|
103
|
+
```glsl
|
|
104
|
+
dest = texture(<TextureSamplerName>, <coord>)<returnSwizzle>;
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- Function name defaults to `"texture"` (`iHaveOverloadedTexFuncs` is true for every
|
|
108
|
+
language except `LANG_ES_100`/`LANG_120`, `languages.h:37-44`, so ES 3.00 always uses the
|
|
109
|
+
overloaded `texture()` builtin, never legacy `texture2D`/`textureCube`/etc.).
|
|
110
|
+
`funcName`/`offset`/`gradSwizzle`/`ui32NumOffsets` are chosen per resource dimension at
|
|
111
|
+
`toGLSLInstruction.cpp:1172-1251`.
|
|
112
|
+
- Coordinate build is `TranslateTexCoord(eResDim, psDestAddr)` (`:985-1031`), which selects
|
|
113
|
+
and expands the address operand's leading components per dimension — see the coordinate
|
|
114
|
+
table in section "Coordinate component selection" below.
|
|
115
|
+
- If `psInst->bAddressOffset` (immediate texel offset present, see section on
|
|
116
|
+
`sample_controls` below), `offset = "Offset"` is appended to the function name and an
|
|
117
|
+
`ivec2`/`ivec3`/int offset literal argument is appended (`:1391-1411`).
|
|
118
|
+
- After the call closes, the **return-channel swizzle** is applied by re-reading the
|
|
119
|
+
swizzle encoded on the **texture (`t#`) operand itself** (not the destination): DXBC
|
|
120
|
+
texture instructions carry a component swizzle on the resource operand describing how the
|
|
121
|
+
hardware's raw fetched RGBA maps onto the instruction's result vector before the
|
|
122
|
+
destination write mask applies. HLSLcc re-enables the write mask on that operand
|
|
123
|
+
(`iWriteMaskEnabled = 1`) and calls `TranslateOperandSwizzleWithMask(psContext, psSrcTex,
|
|
124
|
+
psDest->GetAccessMask(), 0)` (`:1451-1457`) to append e.g. `.yzwx` intersected with the
|
|
125
|
+
destination's write mask.
|
|
126
|
+
- Saturate (`_sat`) is **not** applied inside `TranslateTextureSample`; it is a uniform
|
|
127
|
+
post-processing step applied by the general instruction-loop epilogue
|
|
128
|
+
(`toGLSLInstruction.cpp:4821-4844`): after any instruction with `bSaturate` set, the
|
|
129
|
+
destination register is re-emitted as `dst = clamp(dst, 0.0, 1.0);` (with an
|
|
130
|
+
`#ifdef UNITY_ADRENO_ES3` `min(max(x,0.0),1.0)` variant guard). This applies identically
|
|
131
|
+
to every opcode in this family.
|
|
132
|
+
|
|
133
|
+
**Type rules**: destination type comes from `ShaderInfo::GetTextureDataType(texRegNo)`
|
|
134
|
+
(`ShaderInfo.cpp:10-18`) — `SVT_FLOAT`, `SVT_INT`, or `SVT_UINT` from the reflected
|
|
135
|
+
`RESOURCE_RETURN_TYPE`, or `SVT_FLOAT` if unreflected. `AddAssignToDest`
|
|
136
|
+
(`toGLSLInstruction.cpp:1281`, `:155-171`) wraps the whole call in `floatBitsToInt(...)`/
|
|
137
|
+
`floatBitsToUint(...)`/`intBitsToFloat(...)`/`uintBitsToFloat(...)` only if the destination's
|
|
138
|
+
*declared register type* (from prior data-type analysis) disagrees with the texture's
|
|
139
|
+
return type — since this project stores everything as float vec4 and skips full data-type
|
|
140
|
+
analysis, the safe default is to always treat the texture-op result as float and defer any
|
|
141
|
+
int/uint reinterpretation to the consuming instruction's own bitcast (matches the "bitcast
|
|
142
|
+
at use site" policy stated in the task, and matches `GetSamplerType`'s int/uint sampler
|
|
143
|
+
selection below). Coordinates are read with `TO_AUTO_BITCAST_TO_FLOAT` (`TranslateTexCoord`
|
|
144
|
+
always sets this flag, `:989`) — i.e. address components are reinterpreted as float via
|
|
145
|
+
`intBitsToFloat`/`uintBitsToFloat` if the source register was produced as int/uint.
|
|
146
|
+
The **sampler variant type** (`sampler2D` vs `isampler2D` vs `usampler2D`) is chosen once,
|
|
147
|
+
at declaration time, from the reflected return type via `GetSamplerType`
|
|
148
|
+
(`toGLSLDeclaration.cpp:1388-1551`); if unreflected it falls back to `default: return
|
|
149
|
+
"sampler2D"` (float) at `:1550` and per-dimension `default:` cases, again matching the
|
|
150
|
+
stripped-`RDEF` fallback.
|
|
151
|
+
|
|
152
|
+
**Helpers needed**: none beyond the coordinate-assembly and bitcast machinery already
|
|
153
|
+
required by every opcode family (`floatBitsToInt`/`intBitsToFloat`/etc. are native GLSL ES
|
|
154
|
+
3.00 builtins, not custom helpers — `HaveBitEncodingOps` is true for every language except
|
|
155
|
+
`LANG_ES_100`/`LANG_120`, `languages.h:169-180`).
|
|
156
|
+
|
|
157
|
+
**Edge cases**: Out-of-range coordinates follow the sampler's wrap mode (not a DXBC
|
|
158
|
+
concern — GLSL `texture()` handles it per the WebGL2 sampler state, which is set at the
|
|
159
|
+
JS/WebGL layer, outside this translator's scope). NaN/Inf in coordinates is
|
|
160
|
+
undefined/implementation-defined per GLSL ES spec, same as native GLSL; HLSLcc does not
|
|
161
|
+
special-case it.
|
|
162
|
+
|
|
163
|
+
**WebGL2 notes**: `texture()` (the "vec form" overloaded builtin) is core GLSL ES 3.00 —
|
|
164
|
+
no extension needed for 1D/2D/3D/Cube/array textures except cubemap arrays (see below).
|
|
165
|
+
Legacy `texture2D`/`textureCube`/etc. names are never emitted because `iHaveOverloadedTexFuncs`
|
|
166
|
+
is true for ES 3.00.
|
|
167
|
+
|
|
168
|
+
**Confidence**: high — this is the highest-volume opcode in the corpus and the core
|
|
169
|
+
`TranslateTextureSample` path is fully read and directly cited line-by-line.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 2. `sample_l` (9124 occurrences — highest volume in family)
|
|
174
|
+
|
|
175
|
+
**Semantics**: Texture sample with an explicit, caller-supplied LOD (mip level), no
|
|
176
|
+
derivative computation. D3D11 `SAMPLE_L`: `dest, address, resource, sampler, LOD`. Used
|
|
177
|
+
heavily for skinned/environment/UI shaders that need deterministic mip selection outside a
|
|
178
|
+
derivative-having stage (this is also the *only* sampling form legal in a vertex shader,
|
|
179
|
+
which cannot compute screen-space derivatives).
|
|
180
|
+
|
|
181
|
+
**GLSL lowering**: `TranslateTextureSample(psInst, TEXSMP_FLAG_LOD)`
|
|
182
|
+
(`toGLSLInstruction.cpp:3171-3180`). LOD operand is `psInst->asOperands[4]`
|
|
183
|
+
(`:1144`). Template:
|
|
184
|
+
|
|
185
|
+
```glsl
|
|
186
|
+
dest = textureLod(<TextureSamplerName>, <coord>, <lod>)<returnSwizzle>;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
or with an immediate texel offset: `textureLodOffset(<sampler>, <coord>, <lod>, <offsetVec>)`
|
|
190
|
+
(`:1308-1309`, offset suffix logic `:1163-1170`).
|
|
191
|
+
|
|
192
|
+
- LOD argument: `TranslateOperand(psSrcLOD, TO_AUTO_BITCAST_TO_FLOAT)` (`:1361-1372`); if
|
|
193
|
+
`psContext->psShader->ui32MajorVersion < 4` (SM1–3 legacy bytecode) a `.w` swizzle is
|
|
194
|
+
appended, but for DX11/SM5 bytecode (the corpus target) this branch does not apply — the
|
|
195
|
+
scalar LOD operand is used directly.
|
|
196
|
+
- **2D-array shadow-sampler LOD workaround** (`needsLodWorkaround`,
|
|
197
|
+
`toGLSLInstruction.cpp:1284,1297-1300,1357-1360`): GLSL has no `textureLod()` overload for
|
|
198
|
+
`sampler2DArrayShadow`. When `eResDim == RESOURCE_DIMENSION_TEXTURE2DARRAY` **and**
|
|
199
|
+
`TEXSMP_FLAG_DEPTHCOMPARE` is set (i.e. this is really a `sample_c`/`sample_c_lz` case on
|
|
200
|
+
a 2D-array depth resource, not plain `sample_l`), HLSLcc substitutes
|
|
201
|
+
`textureGrad(sampler, coord, vec2(0.0,0.0), vec2(0.0,0.0))` — zero gradients approximate
|
|
202
|
+
LOD 0. This is a correctness approximation, not exact LOD selection, and only fires for
|
|
203
|
+
the depth-compare + 2D-array combination.
|
|
204
|
+
|
|
205
|
+
**Type rules**: identical destination-type rule to `sample` (texture reflected return
|
|
206
|
+
type, `SVT_FLOAT` fallback). LOD operand is bitcast to float via `TO_AUTO_BITCAST_TO_FLOAT`
|
|
207
|
+
regardless of the DXBC register's nominal type, because DXBC LOD is always a float value
|
|
208
|
+
even when stored in an otherwise-integer temp register.
|
|
209
|
+
|
|
210
|
+
**Helpers needed**: none beyond core bitcast machinery.
|
|
211
|
+
|
|
212
|
+
**Edge cases**: LOD is clamped to `[0, textureQueryLevels-1]` by the GL implementation
|
|
213
|
+
itself, per GLSL spec — HLSLcc emits no explicit clamp. A negative or out-of-range LOD is
|
|
214
|
+
implementation-defined-clamped, not a translator concern.
|
|
215
|
+
|
|
216
|
+
**WebGL2 notes**: `textureLod` is core GLSL ES 3.00 for all sampler types except
|
|
217
|
+
`sampler2DArrayShadow`/`samplerCubeShadow` (no such overload exists at all — hence the
|
|
218
|
+
grad workaround above). `textureLodOffset` is also core ES 3.00 (`texelFetchOffset`-family
|
|
219
|
+
functions, GLSL ES 3.00 spec section 8.9) — no extension required.
|
|
220
|
+
|
|
221
|
+
**Confidence**: high — dominant opcode, full lowering path read directly, workaround logic
|
|
222
|
+
explicitly commented in source.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 3. `sample_b` (3312 occurrences)
|
|
227
|
+
|
|
228
|
+
**Semantics**: Texture sample with a LOD **bias** added to the automatically computed
|
|
229
|
+
(derivative-based) LOD. D3D11 `SAMPLE_B`: `dest, address, resource, sampler, bias`.
|
|
230
|
+
Pixel-shader only (requires derivatives to compute the base LOD before biasing).
|
|
231
|
+
|
|
232
|
+
**GLSL lowering**: `TranslateTextureSample(psInst, TEXSMP_FLAG_BIAS)`
|
|
233
|
+
(`toGLSLInstruction.cpp:3211-3220`). Bias operand is `psInst->asOperands[4]` (`:1147`).
|
|
234
|
+
Template:
|
|
235
|
+
|
|
236
|
+
```glsl
|
|
237
|
+
dest = texture(<TextureSamplerName>, <coord>, <bias>)<returnSwizzle>;
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
The bias is appended as the GLSL `texture()` builtin's optional trailing `bias` parameter
|
|
241
|
+
(`:1426-1430`, appended after any offset/gather-component arguments) — **not** a separate
|
|
242
|
+
function name (`textureBias` does not exist; core `texture()` already accepts an optional
|
|
243
|
+
bias argument in both desktop GLSL and GLSL ES 3.00 for non-shadow, non-array-shadow
|
|
244
|
+
samplers in fragment shaders).
|
|
245
|
+
|
|
246
|
+
**Type rules**: same destination-type rule as `sample`. Bias is
|
|
247
|
+
`TranslateOperand(psSrcBias, TO_AUTO_BITCAST_TO_FLOAT)` — always read/bitcast as float.
|
|
248
|
+
|
|
249
|
+
**Helpers needed**: none.
|
|
250
|
+
|
|
251
|
+
**Edge cases**: per GLSL ES 3.00 spec, the optional bias parameter to `texture()` is **only
|
|
252
|
+
legal in fragment shaders**; DXBC `sample_b` cannot legally appear in a vertex shader
|
|
253
|
+
either (no derivatives), so this is a non-issue in practice, but the emitter should assert
|
|
254
|
+
stage == pixel for `sample_b` rather than silently emit invalid vertex-shader GLSL.
|
|
255
|
+
|
|
256
|
+
**WebGL2 notes**: the bias-argument overload of `texture()` is core GLSL ES 3.00 (unlike
|
|
257
|
+
GLSL ES 1.00/`LANG_ES_100`, which required the `GL_OES_shader_texture_lod`-style `EXT`
|
|
258
|
+
suffix handled by the `ext = "EXT"` branch at `:1303-1306` — that branch only triggers for
|
|
259
|
+
`LANG_ES_100`, never for ES 3.00, so no extension suffix is emitted for this target).
|
|
260
|
+
|
|
261
|
+
**Confidence**: high — straightforward, fully read lowering path.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## 4. `sample_d` (153 occurrences)
|
|
266
|
+
|
|
267
|
+
**Semantics**: Texture sample with explicit user-supplied screen-space gradients
|
|
268
|
+
(`ddx`, `ddy`) instead of automatically-computed derivatives — used to avoid derivative
|
|
269
|
+
discontinuities across non-uniform control flow, or to sample from a vertex/geometry-style
|
|
270
|
+
context with manually supplied gradients. D3D11 `SAMPLE_D`: `dest, address, resource,
|
|
271
|
+
sampler, xDerivatives, yDerivatives`.
|
|
272
|
+
|
|
273
|
+
**GLSL lowering**: `TranslateTextureSample(psInst, TEXSMP_FLAG_GRAD)`
|
|
274
|
+
(`toGLSLInstruction.cpp:3201-3210`). `psSrcDx = operands[4]`, `psSrcDy = operands[5]`
|
|
275
|
+
(`:1145-1146`). Template:
|
|
276
|
+
|
|
277
|
+
```glsl
|
|
278
|
+
dest = textureGrad(<TextureSamplerName>, <coord>, vec4(<dx>)<gradSwizzle>, vec4(<dy>)<gradSwizzle>)<returnSwizzle>;
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
- Gradient arguments are always wrapped `vec4(...)` then swizzled down to the dimension's
|
|
282
|
+
`gradSwizzle` (`.x`/`.xy`/`.xyz` per resource dimension, `:1177,1192,1207,1218,1229,1236,1242`)
|
|
283
|
+
— i.e. the DXBC gradient operand is always a full 4-component register, and only the
|
|
284
|
+
dimension-appropriate leading components are kept (`:1378-1388`).
|
|
285
|
+
- With an immediate offset, `textureGradOffset(sampler, coord, dx, dy, offsetVec)` is used
|
|
286
|
+
instead (`offset = "Offset"`, `:1311`).
|
|
287
|
+
|
|
288
|
+
**Type rules**: same destination-type rule as `sample`. Gradient operands are
|
|
289
|
+
`TranslateOperand(psSrcDx/Dy, TO_AUTO_BITCAST_TO_FLOAT)` — always bitcast to float.
|
|
290
|
+
|
|
291
|
+
**Helpers needed**: none.
|
|
292
|
+
|
|
293
|
+
**Edge cases**: the 2D-array-shadow LOD-workaround described under `sample_l` also applies
|
|
294
|
+
here in principle (`needsLodWorkaround` is dimension/depth-compare gated, not
|
|
295
|
+
opcode-gated) but `sample_d` is not itself a depth-compare opcode in this corpus (DXBC has
|
|
296
|
+
no `sample_d_c`), so it does not fire for plain `sample_d`.
|
|
297
|
+
|
|
298
|
+
**WebGL2 notes**: `textureGrad`/`textureGradOffset` are core GLSL ES 3.00 builtins for all
|
|
299
|
+
non-shadow sampler types plus `sampler2DShadow`/`samplerCubeShadow` (but not
|
|
300
|
+
`sampler2DArrayShadow`, consistent with the `sample_l` workaround note). Low corpus count
|
|
301
|
+
(153) means most usages likely target ordinary color textures, but if a Carbon effect ever
|
|
302
|
+
uses `sample_d` on a 2D-array depth resource, the same "no textureGrad-family overload"
|
|
303
|
+
class of gap could theoretically surface — unconfirmed in this corpus, flagged as a risk.
|
|
304
|
+
|
|
305
|
+
**Confidence**: medium — the lowering path is fully read and low-ambiguity, but the low
|
|
306
|
+
occurrence count (153) means it has had less indirect validation than `sample`/`sample_l`/
|
|
307
|
+
`sample_b` from the corpus-count-as-confidence-proxy perspective.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## 5. `gather4` (195 occurrences) — and `gather4_po` / `gather4_po_c` / `gather4_c`
|
|
312
|
+
|
|
313
|
+
**Semantics**: Fetches the same single component (selectable) from the 4 texels used in
|
|
314
|
+
bilinear filtering at the given coordinate, without applying the bilinear weights — one
|
|
315
|
+
`vec4` result where each component is that channel from one of the 4 neighboring texels
|
|
316
|
+
(D3D11 `GATHER4` family). `_PO` variants add a programmable integer texel offset operand;
|
|
317
|
+
`_C` variants add a depth-comparison reference (shadow gather).
|
|
318
|
+
|
|
319
|
+
**GLSL lowering**: dispatch at `toGLSLInstruction.cpp:3121-3160`:
|
|
320
|
+
- `gather4` -> `TranslateTextureSample(psInst, TEXSMP_FLAG_GATHER)`
|
|
321
|
+
- `gather4_po` -> `TEXSMP_FLAG_GATHER | TEXSMP_FLAG_PARAMOFFSET`
|
|
322
|
+
- `gather4_po_c` -> `TEXSMP_FLAG_GATHER | TEXSMP_FLAG_PARAMOFFSET | TEXSMP_FLAG_DEPTHCOMPARE`
|
|
323
|
+
- `gather4_c` -> `TEXSMP_FLAG_GATHER | TEXSMP_FLAG_DEPTHCOMPARE`
|
|
324
|
+
|
|
325
|
+
Inside `TranslateTextureSample`, `funcName` is forced to `"textureGather"`
|
|
326
|
+
(`:1253-1254`). Template:
|
|
327
|
+
|
|
328
|
+
```glsl
|
|
329
|
+
dest = textureGather(<TextureSamplerName>, <coord>[, <refZ>][, <offsetVec>][, <component>])<returnSwizzle>;
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
- Depth-compare reference (`gather4_c`/`gather4_po_c`): unlike ordinary depth-compare
|
|
333
|
+
sampling, the gather forms pass the reference as a **separate trailing argument**, never
|
|
334
|
+
embedded into the coordinate vector — the code explicitly special-cases
|
|
335
|
+
`!(ui32Flags & TEXSMP_FLAG_GATHER)` when deciding whether to build the `txVecN` embedded-
|
|
336
|
+
reference temp (`:1264-1265`, `:1341-1354`), matching real
|
|
337
|
+
`textureGather(sampler, coord, refZ)` GLSL signature for shadow samplers.
|
|
338
|
+
- Programmable offset (`gather4_po`/`gather4_po_c`): read via
|
|
339
|
+
`TranslateOperand(psSrcOff, TO_FLAG_INTEGER, mask)` and appended with a leading comma
|
|
340
|
+
(`:1412-1423`), mask width = `ui32NumOffsets` (1/2/3 per dimension).
|
|
341
|
+
Immediate (non-programmable) offsets on plain `gather4` follow the same
|
|
342
|
+
`bAddressOffset`/`iUAddrOffset` path as `sample`.
|
|
343
|
+
- **Gather component selection**: `gather4`/`gather4_po` may carry a 1-component swizzle on
|
|
344
|
+
the *sampler* (`s#`) operand selecting which of R/G/B/A to gather; if that swizzle is not
|
|
345
|
+
`X` (red, the GLSL default), the component index is appended as a trailing int argument
|
|
346
|
+
(`:1432-1447`). Component selection is explicitly **not supported** for the `_C` (depth
|
|
347
|
+
compare) gather variants — HLSLcc's comment states this outright (`:1442-1445`); shadow
|
|
348
|
+
gather always returns the comparison result, there is no channel to select.
|
|
349
|
+
- Switch-console-specific `GATHER4_PO` `Offset`-suffix quirk (`:1165-1170`) is not relevant
|
|
350
|
+
to this WebGL2-only target (`psContext->IsSwitch()` is always false here).
|
|
351
|
+
|
|
352
|
+
**Type rules**: destination type same rule as `sample` (reflected return type,
|
|
353
|
+
`SVT_FLOAT` fallback). Offset operand is read with `TO_FLAG_INTEGER` (never bitcast to
|
|
354
|
+
float) since GLSL's `ivec` offset parameters require true integer values, not a
|
|
355
|
+
reinterpreted float register.
|
|
356
|
+
|
|
357
|
+
**Helpers needed**: `hlslcc_textureGather4Emulated` (**mandatory for this target** — see
|
|
358
|
+
WebGL2 notes below). **Correction**: an earlier draft of this spec claimed "zero hits for
|
|
359
|
+
`HaveGather` outside `languages.h`" — that grep claim is false. `toGLSLInstruction.cpp`/
|
|
360
|
+
`toGLSLDeclaration.cpp`/`toGLSLOperand.cpp` (the instruction/declaration/operand lowering
|
|
361
|
+
proper) indeed never check `HaveGather`, but `toGLSL.cpp`'s `AddVersionDependentCode`
|
|
362
|
+
(`:163-172`) does: `if (!HaveGather(eLang)) { if (any gather4* opcode used)
|
|
363
|
+
EnableExtension("GL_ARB_texture_gather"); }`. `EnableExtension` (`HLSLCrossCompilerContext.cpp:157-167`)
|
|
364
|
+
emits a guarded pragma — `#ifdef GL_ARB_texture_gather` / `#extension GL_ARB_texture_gather
|
|
365
|
+
: enable` / `#endif` — so it never hard-fails on an unrecognized extension name; it is a
|
|
366
|
+
best-effort "enable it if the compiler happens to advertise it" pattern. For `LANG_ES_300`
|
|
367
|
+
this is a no-op in practice: `GL_ARB_texture_gather` is a **desktop**-only ARB extension
|
|
368
|
+
token with no ES/WebGL2-side branch (contrast the image-atomics case a few lines above at
|
|
369
|
+
`:154-160`, which does pick `GL_OES_shader_image_atomic` on `isES`) — no WebGL2 GLSL ES
|
|
370
|
+
preprocessor predefines that macro, so the `#ifdef` never fires, no `#extension` line is
|
|
371
|
+
emitted, and the instruction body's hardcoded `funcName = "textureGather"`
|
|
372
|
+
(`toGLSLInstruction.cpp:1253-1254`, still unconditional) is unaffected either way. So the
|
|
373
|
+
end conclusion is unchanged — this target still needs the emulation helper — but the
|
|
374
|
+
"HLSLcc never gates this at all" framing is wrong: it does attempt a gate, the gate is just
|
|
375
|
+
built for desktop GL and silently does nothing useful on `LANG_ES_300`. The JS emitter must
|
|
376
|
+
supply its own 4-tap emulation (four `textureOffset`/`texture` calls at the four
|
|
377
|
+
bilinear-neighbor texel centers, computed from `textureSize`) wherever the real
|
|
378
|
+
`textureGather` builtin is unavailable.
|
|
379
|
+
|
|
380
|
+
**Edge cases**: `textureGather` (where available) requires the four sampled texels to be
|
|
381
|
+
selected by hardware bilinear-neighbor rules that are implementation-defined at exact
|
|
382
|
+
texel boundaries; an emulated fallback needs to replicate the "texel below-left of the
|
|
383
|
+
sample point" neighbor-selection rule (typically via `floor(coord*size - 0.5)` and
|
|
384
|
+
`+ivec2(0/1,0/1)` taps) to match D3D `Gather4` semantics closely enough for typical
|
|
385
|
+
consumers (contact-hardening shadows, procedural blending). This emulation is
|
|
386
|
+
**not sourced from HLSLcc** (HLSLcc assumes `textureGather` exists) and is the single
|
|
387
|
+
highest-risk item in this spec.
|
|
388
|
+
|
|
389
|
+
**WebGL2 notes — critical gap**: `languages.h:220-227` defines
|
|
390
|
+
`HaveGather(eLang)` as true only for `eLang >= LANG_400` (desktop GL 4.0+) **or**
|
|
391
|
+
`eLang == LANG_ES_310`. **`LANG_ES_300` (this project's actual target) is excluded.**
|
|
392
|
+
`textureGather`/`textureGatherOffset` are GLSL ES 3.10 / desktop-GLSL-4.00 builtins; they
|
|
393
|
+
do not exist in GLSL ES 3.00 core and WebGL2 (which is GLSL ES 3.00-based) exposes no
|
|
394
|
+
extension that adds them. **Correction**: an earlier draft of this spec claimed "HLSLcc's
|
|
395
|
+
GLSL backend never checks `HaveGather` before emitting `textureGather(...)`" — that is not
|
|
396
|
+
quite right; see the "Helpers needed" correction above: `toGLSL.cpp` does check
|
|
397
|
+
`!HaveGather(eLang)` and attempts to `EnableExtension("GL_ARB_texture_gather")`, it's just
|
|
398
|
+
that the attempt is built for desktop GL and is a silent no-op on `LANG_ES_300`
|
|
399
|
+
(the `#ifdef`-guarded extension macro is never predefined by an ES/WebGL2 preprocessor, and
|
|
400
|
+
the instruction body's `funcName` is set unconditionally regardless of that check's
|
|
401
|
+
outcome). Net effect is unchanged: it will happily produce GLSL that fails to compile under
|
|
402
|
+
strict WebGL2/ES 3.00 validation. This spec's emitter must either (a) always emit the
|
|
403
|
+
`hlslcc_textureGather4Emulated` helper instead of raw `textureGather` for this family, or
|
|
404
|
+
(b) detect and reject `gather4*` shaders at translation time with an explicit diagnostic —
|
|
405
|
+
but silently trusting HLSLcc's literal `textureGather(...)` output will break at WebGL2
|
|
406
|
+
shader-compile time. This is the most important actionable finding in this spec for the
|
|
407
|
+
`gather4` opcodes.
|
|
408
|
+
|
|
409
|
+
**Confidence**: low for WebGL2 compilability, high for what HLSLcc *literally emits*
|
|
410
|
+
(fully read source, zero ambiguity in the C++, including the `toGLSL.cpp` extension-attempt
|
|
411
|
+
correction above) — the risk is entirely in the target capability mismatch documented
|
|
412
|
+
above, not in misreading HLSLcc's intent. An earlier draft cited `TRANSPILING-GAPS.md:188`
|
|
413
|
+
as corroboration for this being a known pending item; that file does not exist anywhere in
|
|
414
|
+
this repository (see the authority-order correction at the top of this document), so that
|
|
415
|
+
citation is withdrawn and this section's confidence rests solely on the C++ reading above.
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
## 6. `sample_c` (0 occurrences in corpus, spec required for depth paths)
|
|
420
|
+
|
|
421
|
+
**Semantics**: Depth-comparison ("shadow") sample: fetches from a depth-format resource
|
|
422
|
+
using a comparison sampler, compares the fetched depth against a supplied reference value,
|
|
423
|
+
and returns the hardware's percentage-closer-filtered (PCF) result — a **float in
|
|
424
|
+
`[0.0, 1.0]`**, not a 0/1 boolean and **not** the DXBC ALU integer comparison-mask
|
|
425
|
+
convention. D3D11 `SAMPLE_C`: `dest, address, resource, sampler, referenceValue`, implicit
|
|
426
|
+
(derivative-based) LOD like `sample`.
|
|
427
|
+
|
|
428
|
+
**Important — comparison-mask convention does NOT apply here**: DXBC's scalar/vector ALU
|
|
429
|
+
comparison opcodes (`eq`/`ne`/`lt`/`ge`, `ieq`/`ige`/etc., handled by `AddComparison`,
|
|
430
|
+
`toGLSLInstruction.cpp:173` and the `OPCODE_GE` comment "the result is a boolean but HLSL
|
|
431
|
+
asm returns 0xFFFFFFFF/0x0 instead", `:2689-2694`) produce a full-lane
|
|
432
|
+
`0xFFFFFFFF`/`0x00000000` integer mask per component. **`sample_c`/`sample_c_lz`/
|
|
433
|
+
`gather4_c` are unrelated to that convention** — hardware depth comparison sampling
|
|
434
|
+
returns a genuinely-filtered floating-point value (0.0, 1.0, or any PCF-blended value in
|
|
435
|
+
between when the sampler uses linear filtering across multiple depth texels), matching
|
|
436
|
+
standard D3D11 `SampleCmp`/`SampleCmpLevelZero` semantics that HLSLcc's GLSL backend
|
|
437
|
+
forwards unchanged (it applies no extra masking logic to the depth-compare result — the
|
|
438
|
+
value comes directly out of GLSL `texture(sampler2DShadow, ...)`, which itself returns a
|
|
439
|
+
filtered float per the GLSL spec).
|
|
440
|
+
|
|
441
|
+
**GLSL lowering**: `TranslateTextureSample(psInst, TEXSMP_FLAG_DEPTHCOMPARE)`
|
|
442
|
+
(`toGLSLInstruction.cpp:3181-3190`). `psSrcRef = operands[4 + hasParamOffset]` (`:1143`).
|
|
443
|
+
|
|
444
|
+
- For every resource dimension **except** `TEXTURECUBEARRAY` and non-gather ops, the
|
|
445
|
+
reference value is embedded as the **last component of the texture coordinate vector**
|
|
446
|
+
(this matches core GLSL's shadow-sampler convention, where `sampler2DShadow` takes a
|
|
447
|
+
`vec3(u, v, refZ)`): HLSLcc builds a temp,
|
|
448
|
+
```glsl
|
|
449
|
+
vec3 txVec<N> = vec3(<coord>, <refZ>);
|
|
450
|
+
```
|
|
451
|
+
(`:1264-1277`; `depthCmpCoordType` is `"vec2"`/`"vec3"`/`"vec4"` per dimension,
|
|
452
|
+
`:1176,1191,1206,1217,1228,1235`), then samples `texture(<sampler>, txVec<N>)`.
|
|
453
|
+
The temp exists "as Adrenos hate nonstandard swizzles in the texcoords" (source comment,
|
|
454
|
+
`:1269`).
|
|
455
|
+
- For `TEXTURECUBEARRAY` (no `depthCmpCoordType` case defined) the reference is passed as a
|
|
456
|
+
separate trailing argument instead (`:1349-1354`), matching GLSL's
|
|
457
|
+
`texture(samplerCubeArrayShadow, vec4(dir, arrayIdx), refZ)` signature, which has no room
|
|
458
|
+
in the coordinate vector for both array index and reference.
|
|
459
|
+
- Function name is plain `funcName` (`"texture"`, or `"textureLod"`/`"textureGrad"` variants
|
|
460
|
+
per other combined flags) — depth-compare does **not** change the function name, only the
|
|
461
|
+
sampler *type* (`sampler2DShadow` etc., chosen at declaration time from `ui32IsShadowTex`)
|
|
462
|
+
and the coordinate/argument shape.
|
|
463
|
+
- `ResourceName`/`TextureSamplerName` calls pass `bZCompare = 1` when
|
|
464
|
+
`TEXSMP_FLAG_DEPTHCOMPARE` is set (`:1333,1335`). **Correction**: because
|
|
465
|
+
`HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS` is always set for this fork (see section 0),
|
|
466
|
+
`useCombinedTextureSamplers` is always true, so the instruction body always takes the
|
|
467
|
+
`:1335` branch — `TextureSamplerName(..., bZCompare=1)` — never the `:1333` bare-
|
|
468
|
+
`ResourceName` branch. The declaration that actually matches what the instruction body
|
|
469
|
+
calls is therefore the **combined**-sampler shadow uniform emitted at
|
|
470
|
+
`toGLSLDeclaration.cpp:1634-1646` (`uniform <samplerType>Shadow <TextureSamplerName(...,
|
|
471
|
+
bZCompare=1)>`), **not** `toGLSLDeclaration.cpp:1668-1686` as an earlier draft of this spec
|
|
472
|
+
claimed — that `1668-1686` block declares the *bare* `ResourceName`-based shadow uniform
|
|
473
|
+
(`hlslcc_zcmp`-prefixed plain `t#` symbol), which is emitted unconditionally alongside the
|
|
474
|
+
combined one (regardless of the combine flag) purely for register-identity duplication
|
|
475
|
+
(the same "declared but not referenced by instruction bodies" pattern section 0 already
|
|
476
|
+
documents for the non-shadow case) and is never the symbol the instruction body's call
|
|
477
|
+
resolves to. Concretely, a shader that both plain-samples and depth-compares the same
|
|
478
|
+
`t#` texture with this fork's always-on combine flag gets **four** declared GLSL sampler
|
|
479
|
+
uniforms for that texture (combined non-shadow `TEX_with_SMP` name, combined shadow
|
|
480
|
+
`hlslcc_zcmp...TEX_with_SMP` name, bare non-shadow `t#`/reflected name, bare shadow
|
|
481
|
+
`hlslcc_zcmp`+`t#`/reflected name — `toGLSLDeclaration.cpp:1632-1686`), of which only the
|
|
482
|
+
two combined ones are ever referenced by instruction bodies.
|
|
483
|
+
|
|
484
|
+
**Type rules**: destination is always float (D3D `SampleCmp` result type is float;
|
|
485
|
+
`ui32ReturnType`/`GetTextureDataType` is not consulted for the shadow path's numeric
|
|
486
|
+
result — it stays float because depth formats reflect as float). Reference value:
|
|
487
|
+
`TranslateOperand(psSrcRef, TO_AUTO_BITCAST_TO_FLOAT)` (`:1275,1353`) — always float.
|
|
488
|
+
|
|
489
|
+
**Helpers needed**: none beyond the `txVecN` embedding pattern (a per-call-site local
|
|
490
|
+
`vec2/vec3/vec4` temp, not a shared function — the JS emitter should replicate this
|
|
491
|
+
inline-temp pattern rather than centralizing it, to match HLSLcc's numbering scheme
|
|
492
|
+
`m_NextTexCoordTemp` used to keep temp names unique per shader phase, `:1267`).
|
|
493
|
+
|
|
494
|
+
**Edge cases**: see `sample_l`'s 2D-array-shadow `textureLod`-unavailable workaround —
|
|
495
|
+
that workaround is keyed off `TEXSMP_FLAG_DEPTHCOMPARE` and fires for `sample_c` combined
|
|
496
|
+
with an explicit-LOD or LOD-zero flag on a `TEXTURE2DARRAY` resource; plain `sample_c`
|
|
497
|
+
(implicit LOD) does not need it because ordinary `texture(sampler2DArrayShadow, ...)`
|
|
498
|
+
(no explicit LOD) is legal GLSL.
|
|
499
|
+
|
|
500
|
+
**WebGL2 notes**: `sampler2DShadow`/`sampler2DArrayShadow`/`samplerCubeShadow` and the
|
|
501
|
+
`texture()` shadow-comparison overloads are core GLSL ES 3.00. `samplerCubeArrayShadow`
|
|
502
|
+
requires cubemap-array support, which itself needs `GL_OES_texture_cube_map_array`/
|
|
503
|
+
`GL_EXT_texture_cube_map_array` on ES targets (`HaveCubemapArray` is false for
|
|
504
|
+
`LANG_ES_300`, `languages.h:75-80`; `TranslateResourceTexture` enables both OES and EXT
|
|
505
|
+
extension strings for ES languages when a cubemap array is declared,
|
|
506
|
+
`toGLSLDeclaration.cpp:1608-1619`) — so a `sample_c` against a `TextureCubeArray` shadow
|
|
507
|
+
resource depends on a WebGL2 extension actually being available at runtime, which is not
|
|
508
|
+
guaranteed.
|
|
509
|
+
|
|
510
|
+
**Confidence**: medium — the lowering path itself is fully and unambiguously read from
|
|
511
|
+
source; the medium (not high) rating is solely because the corpus has 0 real-world
|
|
512
|
+
instances to cross-check the reading against, per the task's own instruction to still
|
|
513
|
+
document it for depth-path completeness.
|
|
514
|
+
|
|
515
|
+
---
|
|
516
|
+
|
|
517
|
+
## 7. `sample_c_lz` (12,640 Frontier occurrences; 0 in the EVE corpus)
|
|
518
|
+
|
|
519
|
+
**Semantics**: Identical to `sample_c` except the LOD is forced to `0` (no derivative
|
|
520
|
+
computation) — D3D11 `SampleCmpLevelZero`. Used for shadow-map lookups from a
|
|
521
|
+
non-derivative-having context (frequently a loop-unrolled PCF kernel where the compiler
|
|
522
|
+
wants to guarantee LOD-0 regardless of control flow uniformity).
|
|
523
|
+
|
|
524
|
+
**GLSL lowering**: `TranslateTextureSample(psInst, TEXSMP_FLAG_DEPTHCOMPARE |
|
|
525
|
+
TEXSMP_FLAG_FIRSTLOD)` (`toGLSLInstruction.cpp:3191-3200`). `TEXSMP_FLAG_FIRSTLOD` alone
|
|
526
|
+
(without `TEXSMP_FLAG_LOD`) selects the `...Lod...` function-name branch
|
|
527
|
+
(`:1308`, condition includes `TEXSMP_FLAG_FIRSTLOD`) but supplies a **literal `0.0`**
|
|
528
|
+
argument instead of reading an LOD operand (`:1373-1377`, `bcatcstr(glsl, ", 0.0")`) —
|
|
529
|
+
there is no LOD source operand for this opcode at all (DXBC `sample_c_lz` has no LOD field
|
|
530
|
+
in its operand list; zero is implied by the opcode itself).
|
|
531
|
+
Template (non-2D-array-shadow case):
|
|
532
|
+
|
|
533
|
+
```glsl
|
|
534
|
+
dest = textureLod(<sampler2DShadow>, vec3(<coord>, <refZ>), 0.0);
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
- **2D-array shadow workaround applies here directly and unconditionally** for
|
|
538
|
+
`RESOURCE_DIMENSION_TEXTURE2DARRAY` (`needsLodWorkaround` is true whenever
|
|
539
|
+
dimension is 2D-array **and** depth-compare is set — true for both `sample_c` with an
|
|
540
|
+
explicit/zero LOD and, notably, always true for `sample_c_lz` combined with a
|
|
541
|
+
`TEXTURE2DARRAY` resource, which is an extremely common real-world case: cascaded shadow
|
|
542
|
+
maps stored as a `Texture2DArray`). In that case the emitted call becomes:
|
|
543
|
+
```glsl
|
|
544
|
+
dest = textureGrad(<sampler2DArrayShadow>, txVecN, vec2(0.0,0.0), vec2(0.0,0.0));
|
|
545
|
+
```
|
|
546
|
+
(`:1297-1300,1357-1360`) — the literal `0.0` LOD argument is dropped entirely in this
|
|
547
|
+
branch (`!needsLodWorkaroundES2` gate at `:1375-1377` only affects the ES-1.00 pixel-
|
|
548
|
+
shader case, irrelevant here).
|
|
549
|
+
- A Nintendo-Switch-specific override exists (`:1287-1295`) that reverts this workaround
|
|
550
|
+
back to a plain fetch for `sample_c_lz` specifically, because `textureGrad` on shadow
|
|
551
|
+
samplers is software-emulated (slow) on that platform; this branch is gated by
|
|
552
|
+
`psContext->IsSwitch()` and never applies to this WebGL2-only target.
|
|
553
|
+
|
|
554
|
+
**Type rules**: same as `sample_c` (float result, float reference operand).
|
|
555
|
+
|
|
556
|
+
**Helpers needed**: none (same `txVecN` inline-temp pattern as `sample_c`).
|
|
557
|
+
|
|
558
|
+
**Edge cases**: because the LOD-zero constant is baked in at translation time (not read
|
|
559
|
+
from a register), there is no NaN/Inf risk from the LOD argument itself. The 2D-array
|
|
560
|
+
`textureGrad`-with-zero-gradients substitution is an *approximation* — it does not
|
|
561
|
+
guarantee literal mip level 0 selection the way a true `textureLod(..., 0.0)` would if
|
|
562
|
+
that overload existed; zero gradients make the implementation compute the coarsest
|
|
563
|
+
(or a very fine) LOD depending on its `dFdx`/`dFdy`-from-zero handling, which is
|
|
564
|
+
implementation-defined at the edges but converges to LOD 0 in practice on all GLES/ANGLE
|
|
565
|
+
implementations observed by upstream HLSLcc (this is HLSLcc's own accepted tradeoff;
|
|
566
|
+
Frontier's observed comparison samples are all 2D and therefore do not exercise it).
|
|
567
|
+
|
|
568
|
+
**WebGL2 notes**: identical to `sample_c`'s notes; the `textureGrad`-for-shadow-2D-array
|
|
569
|
+
substitution is specifically a WebGL2/GLSL-ES-3.00 accommodation (GLSL ES 3.00 core simply
|
|
570
|
+
has no `textureLod` overload for `sampler2DArrayShadow` — same restriction exists in
|
|
571
|
+
desktop GLSL, this is not an ES-only gap).
|
|
572
|
+
|
|
573
|
+
**Corpus evidence**: the cached Frontier Stillness high-tier catalog from 2026-07-10
|
|
574
|
+
contains 12,640 instructions across 784 unique pixel shaders and 99 effects. Every
|
|
575
|
+
observed instruction targets `texture2d`; no affected shader samples the same resource
|
|
576
|
+
through both comparison and ordinary filtered operations. The EVE build-3430261
|
|
577
|
+
high-tier corpus contains no `sample_c` or `sample_c_lz` instructions.
|
|
578
|
+
|
|
579
|
+
**Confidence**: high for the observed `texture2d` path — the full Frontier corpus emits,
|
|
580
|
+
and representative StandardPBR and QuadV5 programs compile/link in Chromium WebGL2.
|
|
581
|
+
Synthetic 2D, cube, and 2D-array shadow variants also compile/link; cube/array remain
|
|
582
|
+
lower-confidence semantically because Frontier does not exercise those dimensions.
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## 8. `ld` (667 occurrences)
|
|
587
|
+
|
|
588
|
+
**Semantics**: Direct, unfiltered texel fetch by **integer** coordinates plus an explicit
|
|
589
|
+
integer mip level — no sampler object involved at all (samplerless access, confirmed by
|
|
590
|
+
`decisions/005-samplerless-texture-access-evidence-2026-06-26.md`). D3D11 `LD`: `dest,
|
|
591
|
+
address(int), resource[, swizzle]`, where `address.w` (or `.a`) holds the mip level for
|
|
592
|
+
non-multisample resources.
|
|
593
|
+
|
|
594
|
+
**GLSL lowering**: dispatches through the shared `OPCODE_LD`/`OPCODE_LD_MS` case
|
|
595
|
+
(`toGLSLInstruction.cpp:4092-4109`) into `TranslateTexelFetch`
|
|
596
|
+
(`:819-980`). Per-dimension templates (`:896-976`):
|
|
597
|
+
|
|
598
|
+
| Resource dimension | Template |
|
|
599
|
+
|---|---|
|
|
600
|
+
| `TEXTURE1D` / `BUFFER` | `texelFetch(tex, int(coord.x), int(coord.w))` (buffer has no LOD arg) |
|
|
601
|
+
| `TEXTURE2D` / `TEXTURE1DARRAY` | `texelFetch(tex, ivec2(coord.xy), int(coord.w))` |
|
|
602
|
+
| `TEXTURE2DARRAY` / `TEXTURE3D` | `texelFetch(tex, ivec3(coord.xyz), int(coord.w))` |
|
|
603
|
+
| `TEXTURE2DMS` (`ld_ms` only) | `texelFetch(tex, ivec2(coord.xy), int(sampleIndexOperand.x))` — 3rd instruction operand, not `.w` |
|
|
604
|
+
| `TEXTURE2DMSARRAY` (`ld_ms`) | `texelFetch(tex, ivec3(coord.xyz), int(sampleIndexOperand.x))` |
|
|
605
|
+
| Cube / CubeArray / BufferEx | not possible in HLSL or GLSL — `ASSERT(0)` (`:970-974`) |
|
|
606
|
+
|
|
607
|
+
- `hasOffset` (`psInst->bAddressOffset`) swaps in `texelFetchOffset(...)` with a trailing
|
|
608
|
+
`ivec2`/`ivec3`/int offset literal (`:875,891-894,909-911,923-926,938-941`).
|
|
609
|
+
- **Source bug — malformed offset literal for `TEXTURE2D`/`TEXTURE2DARRAY`**: the
|
|
610
|
+
`TEXTURE1D` (`:909-910`, plain `int`) and `TEXTURE3D` (`:923-924`, `ivec3(%d, %d, %d)`,
|
|
611
|
+
3 args) offset literals are well-formed, but the `TEXTURE2DARRAY` (`:925-926`) and
|
|
612
|
+
`TEXTURE2D` (`:940-941`) cases both emit the literal text `ivec3(%d, %d)` —
|
|
613
|
+
labeled `ivec3` but with only **two** `%d` substitutions
|
|
614
|
+
(`bformata(glsl, ", ivec3(%d, %d)", psInst->iUAddrOffset, psInst->iVAddrOffset)`).
|
|
615
|
+
`ivec3(3, 5)` is not a legal GLSL constructor call (an `ivec3` needs 3 components, or a
|
|
616
|
+
single scalar to splat, not 2), so this is invalid GLSL that will fail to compile — this
|
|
617
|
+
looks like a copy-paste typo in the vendor source (should read `ivec2`, matching the
|
|
618
|
+
correct 2-arg, 2D offset shape used elsewhere, e.g. `sample`'s own offset-building code at
|
|
619
|
+
`toGLSLInstruction.cpp:1398-1402` which correctly emits `ivec2(%d, %d)` for 2 offsets).
|
|
620
|
+
Any Carbon effect that uses an immediate texel offset (`sample_controls`) on a `ld`/`ld_ms`
|
|
621
|
+
against a `Texture2D` or `Texture2DArray` resource will hit this bug and get
|
|
622
|
+
non-compiling GLSL; `Texture1D`/`Texture3D`/`Texture1DArray` immediate-offset `ld` is
|
|
623
|
+
unaffected. This is a real upstream HLSLcc defect (ground truth wins per this review's
|
|
624
|
+
brief), not a misreading — the JS emitter must special-case these two dimensions to emit
|
|
625
|
+
`ivec2` instead of replicating the literal `ivec3` text.
|
|
626
|
+
- Coordinates are read `TO_FLAG_INTEGER | TO_AUTO_EXPAND_TO_VEC2/VEC3` (`:903,920,935,950,961`)
|
|
627
|
+
— **integer**, not the `TO_AUTO_BITCAST_TO_FLOAT` used by filtered sampling; the mip/LOD
|
|
628
|
+
(or sample index for MS) is separately read with plain `TO_FLAG_INTEGER` on the `.w`/`.a`
|
|
629
|
+
mask or the dedicated 4th operand.
|
|
630
|
+
- Return-channel swizzle is applied the same way as `sample` (via the texture operand's
|
|
631
|
+
own swizzle re-enabled and masked by the destination access mask, `:978`).
|
|
632
|
+
- On Vulkan the texture name is wrapped `<samplerType>(<tex>, <dummySampler>)` because
|
|
633
|
+
SPIR-V requires every texel fetch to go through a combined-image-sampler even when HLSL
|
|
634
|
+
had none (`:872-886`) — **not applicable** to this non-Vulkan WebGL2 target; plain
|
|
635
|
+
`texelFetch(tex, ...)` is used directly with no dummy sampler wrapper.
|
|
636
|
+
|
|
637
|
+
**Type rules**: destination type comes from the (possibly synthesized-fallback) resource
|
|
638
|
+
binding's `ui32ReturnType` via `ResourceReturnTypeToFlag`/`TypeFlagsToSVTType`
|
|
639
|
+
(`:889`), defaulting to `RETURN_TYPE_FLOAT` when unreflected
|
|
640
|
+
(`fallbackBinding.ui32ReturnType = RETURN_TYPE_FLOAT`, `:830`) — this is the exact
|
|
641
|
+
`CARBONENGINEJS-FORK.md` "samplerless texture fetches synthesize a fallback resource
|
|
642
|
+
binding from `SHEX` declaration data" behavior. Coordinate and mip/sample-index operands
|
|
643
|
+
are always read as true integers (`TO_FLAG_INTEGER`), never bitcast-to-float — this is the
|
|
644
|
+
one texture opcode family where address components are genuinely integer, not
|
|
645
|
+
float-reinterpreted-as-address.
|
|
646
|
+
|
|
647
|
+
**Helpers needed**: none — `texelFetch`/`texelFetchOffset` are core GLSL ES 3.00 builtins
|
|
648
|
+
for all the dimensions DXBC `ld` legally targets.
|
|
649
|
+
|
|
650
|
+
**Edge cases**: out-of-range integer coordinates or mip level return `vec4(0)` per GLSL ES
|
|
651
|
+
3.00 spec (well-defined, unlike desktop GL's implementation-defined behavior in some
|
|
652
|
+
older versions) — no clamp needed from the translator. Buffer resources have no mip/LOD
|
|
653
|
+
argument at all (`:904-911` conditionally omits it).
|
|
654
|
+
|
|
655
|
+
**WebGL2 notes**: fully native, no gaps. This is one of the safest opcodes in the family
|
|
656
|
+
for WebGL2 portability.
|
|
657
|
+
|
|
658
|
+
**Confidence**: high — `TranslateTexelFetch` fully read, dimension table directly
|
|
659
|
+
transcribed from source, and its `SHEX`-fallback path is independently corroborated by
|
|
660
|
+
`CARBONENGINEJS-FORK.md`.
|
|
661
|
+
|
|
662
|
+
---
|
|
663
|
+
|
|
664
|
+
## 9. `resinfo` (247 occurrences)
|
|
665
|
+
|
|
666
|
+
**Semantics**: Queries a resource's dimensions (width/height/depth-or-array-size) at a
|
|
667
|
+
given mip level, plus the resource's total mip-chain length, with a caller-selectable
|
|
668
|
+
return-type encoding (float / reciprocal-float / uint) — D3D11 `RESINFO`, decoded
|
|
669
|
+
return-type control per `decisions/016...018-dxbc-instruction-controls...md`: bits 11-12 of
|
|
670
|
+
the opcode token, `0` = float, `1` = reciprocal float, `2` = uint
|
|
671
|
+
(`RESINFO_INSTRUCTION_RETURN_{FLOAT,RCPFLOAT,UINT}`).
|
|
672
|
+
|
|
673
|
+
**GLSL lowering**: dispatch loop iterates the destination write mask, calling
|
|
674
|
+
`GetResInfoData(psInst, swizzledComponentIndex, destElem)` once per live destination
|
|
675
|
+
component (`toGLSLInstruction.cpp:4734-4752`), implementation at `:1033-1129`:
|
|
676
|
+
|
|
677
|
+
- For `index` (post-swizzle component index) `< 3` — width/height/depth-or-arraysize:
|
|
678
|
+
```glsl
|
|
679
|
+
dest.<comp> = <returnCast>( <maybe 1.0/> textureSize(<tex>[, int(mipOperand)]) [.x|.y|.z] );
|
|
680
|
+
```
|
|
681
|
+
- `dim = GetNumTextureDimensions(eResDim)` (`HLSLccToolkit.cpp:437-458`: 1 for
|
|
682
|
+
`TEXTURE1D`; 2 for `TEXTURE2D`/`TEXTURE2DMS`/`TEXTURE1DARRAY`/`TEXTURECUBE`; 3 for
|
|
683
|
+
`TEXTURE3D`/`TEXTURE2DARRAY`/`TEXTURE2DMSARRAY`/`TEXTURECUBEARRAY`).
|
|
684
|
+
- If the requested `index` exceeds `dim` (e.g. asking for `.z` on a 2D texture), the
|
|
685
|
+
literal constant `0`/`0.0`/`uint(0)` is emitted instead of calling `textureSize`
|
|
686
|
+
(`:1064-1067`) — the source comment notes `0u` is mistreated as a const-int by "old
|
|
687
|
+
ES3.0 Adrenos", hence `uint(0)` is spelled out rather than a bare `0u`.
|
|
688
|
+
- Return-type wrapping: `RESINFO_INSTRUCTION_RETURN_UINT` → `uvec<dim>(...)` (or
|
|
689
|
+
`ivec<dim>` if `HaveUnsignedTypes` is false, not applicable to ES 3.00);
|
|
690
|
+
`RESINFO_INSTRUCTION_RETURN_RCPFLOAT` → `vec<dim>(1.0) / vec<dim>(textureSize(...))`;
|
|
691
|
+
else → `vec<dim>(textureSize(...))` (`:1070-1080`).
|
|
692
|
+
- MS resources (`isMS`) and UAVs (`isUAV`) omit the mip-level argument to
|
|
693
|
+
`textureSize`/`imageSize` entirely (`:1089-1093`; UAV uses `imageSize` instead of
|
|
694
|
+
`textureSize`, `:1082-1085` — not reachable via the pure `t#` `resinfo` path this family
|
|
695
|
+
documents, but present in the same function since `resinfo` can also target a UAV).
|
|
696
|
+
- For `index >= 3` (total mip-level count):
|
|
697
|
+
```glsl
|
|
698
|
+
dest.w = <int|uint|float>(textureQueryLevels(<tex>));
|
|
699
|
+
```
|
|
700
|
+
(`:1112-1127`) — **unconditionally emitted with no target-language capability check**
|
|
701
|
+
(see WebGL2 notes below).
|
|
702
|
+
|
|
703
|
+
**Type rules**: each live destination component is assigned independently via
|
|
704
|
+
`AddOpAssignToDestWithMask(..., eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ?
|
|
705
|
+
SVT_UINT : SVT_FLOAT, 1, ..., 1 << destElem)` (`:1057`) — i.e. `resinfo`'s destination type
|
|
706
|
+
per-component is uint only for the UINT return-type control, float for both FLOAT and
|
|
707
|
+
RCPFLOAT controls (RCPFLOAT is still a float result, just the reciprocal).
|
|
708
|
+
|
|
709
|
+
**Helpers needed**: `hlslcc_textureQueryLevels` (**mandatory for the 4th/mip-count
|
|
710
|
+
component on this target** — see WebGL2 notes). No helper needed for the width/height/
|
|
711
|
+
depth components (`textureSize` is fully core).
|
|
712
|
+
|
|
713
|
+
**Edge cases**: `textureSize` with an out-of-range `lod` argument returns `0` per GLSL ES
|
|
714
|
+
3.00 spec (well-defined). Buffer/`BUFFEX` resources are excluded from the `dim==0` default
|
|
715
|
+
path implicitly by never appearing in the `resinfo`-legal dimension set.
|
|
716
|
+
|
|
717
|
+
**WebGL2 notes — gap on the mip-count component**: `languages.h:247-254` defines
|
|
718
|
+
`HaveQueryLevels(eLang)` true only for `eLang >= LANG_430`. `LANG_ES_300` does **not**
|
|
719
|
+
qualify, and `GetResInfoData`'s `index >= 3` branch (`:1112-1127`) itself calls
|
|
720
|
+
`textureQueryLevels(...)` unconditionally, with no local `HaveQueryLevels` gate. **Correction**:
|
|
721
|
+
an earlier draft of this spec said this was "no gate at all" and contrasted it with `lod`'s
|
|
722
|
+
`HaveQueryLod` as the supposed sole gated case in the family — that contrast overstates the
|
|
723
|
+
difference. `toGLSL.cpp`'s `AddVersionDependentCode` **does** check `HaveQueryLevels`
|
|
724
|
+
(`:234-241`): `if (!HaveQueryLevels(eLang)) { if (OPCODE_RESINFO used)
|
|
725
|
+
{ EnableExtension("GL_ARB_texture_query_levels"); EnableExtension("GL_ARB_shader_image_size"); } }`.
|
|
726
|
+
As with `gather4`'s analogous `GL_ARB_texture_gather` attempt above, both are desktop-only
|
|
727
|
+
ARB extension tokens behind an `EnableExtension` `#ifdef` guard that is never true under a
|
|
728
|
+
GLSL ES/WebGL2 preprocessor, so on `LANG_ES_300` this is a no-op in practice: no
|
|
729
|
+
`#extension` line is emitted and `GetResInfoData`'s call site is unaffected. The practical
|
|
730
|
+
conclusion is therefore unchanged — `textureQueryLevels` does not exist in GLSL ES 3.00
|
|
731
|
+
core, has no WebGL2-exposed extension equivalent, and any Carbon effect that reads
|
|
732
|
+
`resinfo`'s 4th (`.w`, "total mip count") component on this target will receive GLSL that
|
|
733
|
+
fails to compile. Given 247 corpus occurrences of `resinfo`, this is a second actionable,
|
|
734
|
+
high-value gap for this spec (alongside `gather4`'s `textureGather` gap) — the emitter must
|
|
735
|
+
substitute `hlslcc_textureQueryLevels` (fallback strategy: accept the mip count as an
|
|
736
|
+
out-of-band uniform per texture, since there is no in-shader WebGL2-legal way to query it;
|
|
737
|
+
or hard-fail translation if this exact component is read). The first-3-components path
|
|
738
|
+
(`textureSize`) has no such gap.
|
|
739
|
+
|
|
740
|
+
**Confidence**: high on what HLSLcc emits (fully read, unambiguous, including the
|
|
741
|
+
`toGLSL.cpp` extension-attempt correction above), but explicitly flagged as a real WebGL2
|
|
742
|
+
compile-time risk for the mip-count component. The general opcode was previously described
|
|
743
|
+
as "corroborated by `TRANSPILING-GAPS.md:186,337`" — that file does not exist in this
|
|
744
|
+
repository (see the authority-order correction at the top of this document), so that
|
|
745
|
+
corroboration claim is withdrawn; this section's confidence now rests solely on the C++
|
|
746
|
+
reading above.
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## 10. `deriv_rtx_coarse` (209) and `deriv_rty_coarse` (215)
|
|
751
|
+
### (plus `deriv_rtx`/`deriv_rtx_fine`/`deriv_rty`/`deriv_rty_fine`, same lowering)
|
|
752
|
+
|
|
753
|
+
**Semantics**: Screen-space partial derivative of the source value with respect to
|
|
754
|
+
window-space X (`rtx`) or Y (`rty`). D3D11 distinguishes `_coarse` (may share a derivative
|
|
755
|
+
across a 2x2 quad, cheaper) from `_fine` (per-pixel) and from the plain (compiler's choice)
|
|
756
|
+
form, but **GLSL only exposes one derivative pair** (`dFdx`/`dFdy`), with precision
|
|
757
|
+
controlled by an optional `GL_OES_standard_derivatives`-style hint, not a distinct
|
|
758
|
+
coarse/fine builtin.
|
|
759
|
+
|
|
760
|
+
**GLSL lowering**: all six coarse/fine/plain DERIV opcodes collapse onto the same two
|
|
761
|
+
`case` blocks (`toGLSLInstruction.cpp:4579-4602`):
|
|
762
|
+
```glsl
|
|
763
|
+
dest = dFdx(src)<destSwizzleSubset>; // DERIV_RTX_COARSE / DERIV_RTX_FINE / DERIV_RTX
|
|
764
|
+
dest = dFdy(src)<destSwizzleSubset>; // DERIV_RTY_COARSE / DERIV_RTY_FINE / DERIV_RTY
|
|
765
|
+
```
|
|
766
|
+
via `CallHelper1("dFdx", psInst, 0, 1, 1)` / `CallHelper1("dFdy", psInst, 0, 1, 1)`.
|
|
767
|
+
`CallHelper1` (`:745-762`): destination is assigned `SVT_FLOAT` with the destination's own
|
|
768
|
+
swizzle-element count (`AddAssignToDest(dest, SVT_FLOAT, dstSwizCount, ...)`), the call is
|
|
769
|
+
`name(TranslateOperand(src0, TO_AUTO_BITCAST_TO_FLOAT, destMask))` where `destMask` is the
|
|
770
|
+
destination's own access mask (the 4th `CallHelper1` argument, `paramsShouldFollowWriteMask
|
|
771
|
+
= 1`, restricts the source read to the same components being written).
|
|
772
|
+
|
|
773
|
+
**Type rules**: always float in and float out; source is
|
|
774
|
+
`TO_AUTO_BITCAST_TO_FLOAT` (reinterpret as float if the register was produced as int/uint).
|
|
775
|
+
No int/uint derivative form exists in DXBC or GLSL.
|
|
776
|
+
|
|
777
|
+
**Helpers needed**: none — `dFdx`/`dFdy` are core GLSL ES 3.00 builtins (fragment-shader
|
|
778
|
+
only).
|
|
779
|
+
|
|
780
|
+
**Edge cases**: derivatives are **fragment-shader only** — DXBC guarantees `deriv_*` never
|
|
781
|
+
appears in a vertex shader (no rasterization quad exists there), so no stage guard is
|
|
782
|
+
needed beyond what DXBC itself enforces. Derivatives across non-uniform control flow
|
|
783
|
+
(diverging discard/branch within a 2x2 quad) are undefined-ish in both D3D and GLES —
|
|
784
|
+
HLSLcc adds no special handling; this is an inherent GPU behavior difference the
|
|
785
|
+
translator cannot paper over.
|
|
786
|
+
|
|
787
|
+
**WebGL2 notes**: `dFdx`/`dFdy` (and `fwidth`) are **core, unconditional** in GLSL ES 3.00
|
|
788
|
+
(unlike GLSL ES 1.00/WebGL1, where they required the `GL_OES_standard_derivatives`
|
|
789
|
+
extension — irrelevant here since target is ES 3.00). The coarse/fine distinction is
|
|
790
|
+
simply lost/unified; there is no GLSL ES 3.00 way to request coarse-only derivatives, so
|
|
791
|
+
`_fine` and `_coarse` and plain forms are indistinguishable in the output, matching
|
|
792
|
+
upstream HLSLcc behavior exactly (not a gap this project introduces).
|
|
793
|
+
|
|
794
|
+
**Confidence**: high — trivial, fully read, single-line-per-opcode lowering, high corpus
|
|
795
|
+
count (209+215 combined for the `_coarse` variants alone).
|
|
796
|
+
|
|
797
|
+
---
|
|
798
|
+
|
|
799
|
+
## 11. `lod` (0 occurrences in corpus, spec required per task)
|
|
800
|
+
|
|
801
|
+
**Semantics**: Computes the LOD the hardware *would* select for a given sample (both the
|
|
802
|
+
"clamped" and "unclamped" values), without actually sampling — D3D11 `LOD`: result is
|
|
803
|
+
`(ClampedLOD, NonClampedLOD, 0, 0)`. Distinct from every `sample_*` opcode: this one never
|
|
804
|
+
fetches texels.
|
|
805
|
+
|
|
806
|
+
**GLSL lowering**: `toGLSLInstruction.cpp:4161-4200`.
|
|
807
|
+
```glsl
|
|
808
|
+
dest = textureQueryLod(<tex>, <coord>)<returnSwizzle>; // core-language name, LANG>=400
|
|
809
|
+
// or
|
|
810
|
+
dest = textureQueryLOD(<tex>, <coord>)<returnSwizzle>; // extension name, otherwise
|
|
811
|
+
```
|
|
812
|
+
Function-name casing is chosen by `HaveQueryLod(eLang)` (`languages.h:238-245`, true only
|
|
813
|
+
for `eLang >= LANG_400`) — this is the one check in this family that gates a **function
|
|
814
|
+
name** directly inside the instruction-lowering switch itself (`gather4`'s `HaveGather` and
|
|
815
|
+
`resinfo`'s `HaveQueryLevels` are instead checked separately in `toGLSL.cpp`'s
|
|
816
|
+
`AddVersionDependentCode`, purely to attempt an `EnableExtension` pragma — see the
|
|
817
|
+
corrections in those sections above; `lod` gets an analogous, equally ES-3.00-ineffective
|
|
818
|
+
`EnableExtension("GL_ARB_texture_query_lod")` attempt there too, gated on the same
|
|
819
|
+
`!HaveQueryLod` check, at `toGLSL.cpp:226-231`).
|
|
820
|
+
|
|
821
|
+
**Correction — resource-name resolution bypasses the combined-sampler ABI**: unlike every
|
|
822
|
+
other opcode in this family, the texture operand here (`psInst->asOperands[2]`) is emitted
|
|
823
|
+
via a plain `TranslateOperand(&psInst->asOperands[2], TO_FLAG_NONE)` call (`:4185`), which
|
|
824
|
+
for an `OPERAND_TYPE_RESOURCE` operand routes into `toGLSLOperand.cpp:1271-1275`'s
|
|
825
|
+
`case OPERAND_TYPE_RESOURCE: ResourceName(glsl, psContext, RGROUP_TEXTURE,
|
|
826
|
+
psOperand->ui32RegisterNumber, 0);` — the **bare** `ResourceName` path, not
|
|
827
|
+
`TextureSamplerName`. `lod` never touches its sampler operand
|
|
828
|
+
(`psInst->asOperands[3]`) at all. So even though `HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS` is
|
|
829
|
+
always on for this fork, `lod` always references the bare, non-combined `t#`/reflected-name
|
|
830
|
+
sampler uniform (the one declared unconditionally at `toGLSLDeclaration.cpp:1659-1666`) —
|
|
831
|
+
a *different* GLSL uniform than the combined `TEX_with_SMP...` name that `sample`/
|
|
832
|
+
`sample_l`/etc. use to read the same DXBC texture register. This is architecturally
|
|
833
|
+
consistent (`textureQueryLod` only needs one sampler object, and a real one is always
|
|
834
|
+
declared), but it means `lod` is the one opcode in this family that does not follow
|
|
835
|
+
section 0's combined-sampler naming rule, which the earlier draft of this section did not
|
|
836
|
+
call out at all. Coordinates use the same `TranslateTexCoord` per-dimension selection as
|
|
837
|
+
`sample` (`:4187-4189`). Return-channel swizzle applied the same way as other texture ops
|
|
838
|
+
(`:4194-4197`).
|
|
839
|
+
|
|
840
|
+
**Type rules**: destination is always `SVT_FLOAT`, 4 components (`AddAssignToDest(dest,
|
|
841
|
+
SVT_FLOAT, 4, ...)`, `:4171`) — DXBC `lod` always produces float regardless of the
|
|
842
|
+
resource's reflected return type (this is a query result, not a texel fetch).
|
|
843
|
+
|
|
844
|
+
**Helpers needed**: `hlslcc_textureQueryLod` fallback (see WebGL2 notes — `LANG_ES_300`
|
|
845
|
+
falls into the `textureQueryLOD` extension-name branch, but that extension is not part of
|
|
846
|
+
WebGL2's guaranteed baseline).
|
|
847
|
+
|
|
848
|
+
**Edge cases**: none beyond standard coordinate range handling; no fetch occurs so no
|
|
849
|
+
wrap/border-color interaction applies.
|
|
850
|
+
|
|
851
|
+
**WebGL2 notes — gap**: `HaveQueryLod(LANG_ES_300)` is false, so HLSLcc emits the
|
|
852
|
+
extension-style name `textureQueryLOD(...)`. That name corresponds to
|
|
853
|
+
`GL_ARB_texture_query_lod` (desktop) / `GL_EXT_texture_query_lod`-equivalent — **not** a
|
|
854
|
+
function that exists in unextended WebGL2/GLSL ES 3.00, and no such extension is part of
|
|
855
|
+
the WebGL2 core extension set exposed by browsers. Since the corpus shows 0 real usages,
|
|
856
|
+
this is a low-priority gap in practice, but the emitter should either detect `lod`
|
|
857
|
+
opcode usage and fail translation explicitly, or provide a CPU-side/uniform-supplied LOD
|
|
858
|
+
approximation, rather than emit a GLSL call that will not link on any real WebGL2
|
|
859
|
+
implementation.
|
|
860
|
+
|
|
861
|
+
**Confidence**: low — zero corpus occurrences means this reading has no cross-check
|
|
862
|
+
against real Carbon effect output; the source reading itself (line-cited above) is
|
|
863
|
+
unambiguous, but "will this ever actually appear" is unverified.
|
|
864
|
+
|
|
865
|
+
---
|
|
866
|
+
|
|
867
|
+
## Coordinate component selection per resource dimension
|
|
868
|
+
|
|
869
|
+
Ground truth: `TranslateTexCoord` (`toGLSLInstruction.cpp:985-1031`), used by every
|
|
870
|
+
filtered-sample opcode (`sample`, `sample_l`, `sample_b`, `sample_d`, `sample_c`,
|
|
871
|
+
`sample_c_lz`, `gather4*`, `lod`) — **not** used by `ld`/`ld_ms` (integer path, see
|
|
872
|
+
`TranslateTexelFetch` table above) or `resinfo` (no coordinate operand for width/height
|
|
873
|
+
query; only an optional mip-level scalar).
|
|
874
|
+
|
|
875
|
+
| `eResDim` | Access mask kept | Auto-expand | Meaning of DXBC address components |
|
|
876
|
+
|---|---|---|---|
|
|
877
|
+
| `TEXTURE1D` | `.x` only | none (scalar) | `x` = u |
|
|
878
|
+
| `TEXTURE2D` | `.xy` | `vec2` | `xy` = (u, v) |
|
|
879
|
+
| `TEXTURE1DARRAY` | `.xy` | `vec2` | `x` = u, `y` = array slice |
|
|
880
|
+
| `TEXTURECUBE` | `.xyz` | `vec3` | `xyz` = direction vector |
|
|
881
|
+
| `TEXTURE3D` | `.xyz` | `vec3` | `xyz` = (u, v, w) |
|
|
882
|
+
| `TEXTURE2DARRAY` | `.xyz` | `vec3` | `xy` = (u, v), `z` = array slice |
|
|
883
|
+
| `TEXTURECUBEARRAY` | all 4 (`.xyzw`) | `vec4` | `xyz` = direction, `w` = array slice |
|
|
884
|
+
|
|
885
|
+
All texcoord operands are read with `TO_AUTO_BITCAST_TO_FLOAT` (`:989`) regardless of
|
|
886
|
+
dimension — the address register is always treated as float data (reinterpreted via
|
|
887
|
+
`intBitsToFloat`/`uintBitsToFloat` if it was produced by an integer-typed instruction),
|
|
888
|
+
consistent with DXBC's convention that sample-instruction addresses are always float even
|
|
889
|
+
though the same register file backs int/uint temps.
|
|
890
|
+
|
|
891
|
+
The depth-compare embedded-coordinate type (`depthCmpCoordType`, one dimension wider than
|
|
892
|
+
the plain coordinate type to make room for the reference value) is: `TEXTURE1D` → `vec2`,
|
|
893
|
+
`TEXTURE2D`/`TEXTURE1DARRAY` → `vec3`, `TEXTURECUBE`/`TEXTURE3D`/`TEXTURE2DARRAY` → `vec4`,
|
|
894
|
+
`TEXTURECUBEARRAY` → none (reference passed as a separate trailing argument instead, see
|
|
895
|
+
`sample_c` above).
|
|
896
|
+
|
|
897
|
+
---
|
|
898
|
+
|
|
899
|
+
## `sample_controls` extension: immediate texel offsets
|
|
900
|
+
|
|
901
|
+
Ground truth: `decisions/016-018-dxbc-instruction-controls-used-by-the-gles-draft-transpiler.md`
|
|
902
|
+
plus `toGLSLInstruction.cpp:1161-1170,1391-1423`.
|
|
903
|
+
|
|
904
|
+
- The extended-opcode-token field `sample_controls` (bits 0-5 of an extended token,
|
|
905
|
+
decoded per Microsoft DXC's `d3d12TokenizedProgramFormat.hpp`) carries three signed
|
|
906
|
+
immediate texel-offset values (U/V/W, each roughly -8..+7) attached to a `sample*`/`ld*`/
|
|
907
|
+
`gather4*` instruction. HLSLcc surfaces this as `psInst->bAddressOffset` +
|
|
908
|
+
`iUAddrOffset`/`iVAddrOffset`/`iWAddrOffset` on the `Instruction` struct.
|
|
909
|
+
- When present, every texture-op template in this family appends `"Offset"` to the GLSL
|
|
910
|
+
function name (`texture` → `textureOffset`, `textureLod` → `textureLodOffset`,
|
|
911
|
+
`textureGrad` → `textureGradOffset`, `texelFetch` → `texelFetchOffset`,
|
|
912
|
+
`textureGather` → `textureGatherOffset`) and appends a trailing integer/`ivecN` literal
|
|
913
|
+
argument built directly from the decoded immediate offset values — **not** a runtime
|
|
914
|
+
register read, since D3D11 requires these offsets to be compile-time immediates.
|
|
915
|
+
- `gather4_po`/`gather4_po_c` instead carry a **programmable** (runtime, register-valued)
|
|
916
|
+
offset via a distinct extra source operand (`psSrcOff`), read with
|
|
917
|
+
`TO_FLAG_INTEGER` and appended as a comma-separated argument rather than a function-name
|
|
918
|
+
suffix — this is the one offset form in the family that is not a literal.
|
|
919
|
+
- `TRANSPILING-GAPS.md:338` ("Already handled"): "DXBC sample offsets lower to WebGL2
|
|
920
|
+
offset texture calls where resource dimension supports it" — corroborates the
|
|
921
|
+
above from the draft-transpiler side.
|
|
922
|
+
- WebGL2 note: `textureOffset`/`textureLodOffset`/`textureGradOffset`/`texelFetchOffset`
|
|
923
|
+
are all core GLSL ES 3.00 (§8.9 of the spec) and impose a **compile-time-constant**
|
|
924
|
+
offset requirement — the offset argument must be a constant expression, matching DXBC's
|
|
925
|
+
own immediate-only restriction, so no runtime-variable-offset gap exists for the literal
|
|
926
|
+
(`bAddressOffset`) path. `textureGatherOffset` shares the `HaveGather`-gap noted for
|
|
927
|
+
`gather4` above (ES 3.00 does not have it at all, regardless of constant-offset support).
|
|
928
|
+
|
|
929
|
+
---
|
|
930
|
+
|
|
931
|
+
## Helpers summary
|
|
932
|
+
|
|
933
|
+
Helpers this family requires the JS emitter to define (native GLSL ES 3.00 builtins used
|
|
934
|
+
directly — `texture`, `textureLod`, `textureGrad`, `texelFetch`, `textureSize`,
|
|
935
|
+
`textureOffset`/`textureLodOffset`/`textureGradOffset`/`texelFetchOffset`, `dFdx`, `dFdy`,
|
|
936
|
+
`floatBitsToInt`/`floatBitsToUint`/`intBitsToFloat`/`uintBitsToFloat` — are **not** listed
|
|
937
|
+
here since they need no custom implementation):
|
|
938
|
+
|
|
939
|
+
1. **`hlslcc_textureGather4Emulated`** — mandatory. `textureGather`/`textureGatherOffset`
|
|
940
|
+
do not exist in GLSL ES 3.00 (`HaveGather` excludes `LANG_ES_300`,
|
|
941
|
+
`languages.h:220-227`), yet HLSLcc's GLSL backend emits them unconditionally for
|
|
942
|
+
`gather4`/`gather4_po`/`gather4_po_c`/`gather4_c`. Must emulate via four texel taps
|
|
943
|
+
(computed from `textureSize`) replicating D3D `Gather4`'s neighbor-selection order.
|
|
944
|
+
Needed for both the plain-channel-gather and (separately, since component selection is
|
|
945
|
+
unsupported there per source) the depth-compare gather variants.
|
|
946
|
+
2. **`hlslcc_textureQueryLevels`** — mandatory for `resinfo`'s 4th (mip-count) destination
|
|
947
|
+
component only. `textureQueryLevels` requires `LANG >= 430`
|
|
948
|
+
(`languages.h:247-254`) but `GetResInfoData` calls it with **no gate at all**
|
|
949
|
+
(`toGLSLInstruction.cpp:1112-1127`). No WebGL2/ES-3.00 extension provides an equivalent;
|
|
950
|
+
fallback strategy (out-of-band uniform, or explicit translation failure on this specific
|
|
951
|
+
component) must be decided by the emitter.
|
|
952
|
+
3. **`hlslcc_textureQueryLod`** — needed only if the (zero-occurrence-so-far) `lod` opcode
|
|
953
|
+
is ever exercised. `HaveQueryLod` correctly excludes `LANG_ES_300`
|
|
954
|
+
(`languages.h:238-245`), and the resulting `textureQueryLOD(...)` extension name has no
|
|
955
|
+
WebGL2-guaranteed equivalent either. Lowest priority of the three, but same class of gap.
|
|
956
|
+
4. **Depth-compare inline coordinate temp (`txVec<N>`)** — not a shared function, but a
|
|
957
|
+
per-call-site codegen pattern (`vecK txVecN = vecK(coord, refZ);`) the emitter must
|
|
958
|
+
replicate for `sample_c`/`sample_c_lz`/`gather4_po_c` on non-cube-array dimensions,
|
|
959
|
+
using a monotonically increasing per-phase counter matching HLSLcc's
|
|
960
|
+
`m_NextTexCoordTemp` (`toGLSLInstruction.cpp:1267`) to keep temp names collision-free.
|
|
961
|
+
|
|
962
|
+
No helper is needed for `sample`, `sample_l`, `sample_b`, `sample_d`, `ld`, or the
|
|
963
|
+
`deriv_rtx*`/`deriv_rty*` family — all of those map directly onto unconditional GLSL ES
|
|
964
|
+
3.00 core builtins.
|