@carbonenginejs/runtime 0.1.0-alpha.2 → 0.1.0-alpha.3

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.
Files changed (45) hide show
  1. package/dist/global/model/CjsModel.js +3 -1
  2. package/dist/global/model/CjsModel.js.map +1 -1
  3. package/dist/global/model/document/CjsDocumentHydrator.js +5 -1
  4. package/dist/global/model/document/CjsDocumentHydrator.js.map +1 -1
  5. package/dist/global/schema/CjsSchema.js +98 -18
  6. package/dist/global/schema/CjsSchema.js.map +1 -1
  7. package/dist/global/schema/hydration.js +10 -8
  8. package/dist/global/schema/hydration.js.map +1 -1
  9. package/dist/index.js +2 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/resource/CjsResMan.js +177 -4
  12. package/dist/resource/CjsResMan.js.map +1 -1
  13. package/dist/resource/format/CjsBlueReader.js +8 -1
  14. package/dist/resource/format/CjsBlueReader.js.map +1 -1
  15. package/dist/resource/formats/webgl/core/glsl/DxbcGlslEmitter.js +7 -1
  16. package/dist/resource/formats/webgl/core/glsl/DxbcGlslEmitter.js.map +1 -1
  17. package/dist/resource/index.js +2 -0
  18. package/dist/resource/index.js.map +1 -1
  19. package/dist/resource/texture/SolidColorTextureConstructor.js +46 -0
  20. package/dist/resource/texture/SolidColorTextureConstructor.js.map +1 -0
  21. package/dist/resource/texture/TriTextureRes.js +43 -0
  22. package/dist/resource/texture/TriTextureRes.js.map +1 -1
  23. package/dist/resource/texture/index.js +2 -0
  24. package/dist/resource/texture/index.js.map +1 -1
  25. package/dist/resource/texture/solidColorTexture.js +111 -0
  26. package/dist/resource/texture/solidColorTexture.js.map +1 -0
  27. package/dist/trinity/eve/attachment/decal/EveSpaceObjectDecal.js +19 -8
  28. package/dist/trinity/eve/attachment/decal/EveSpaceObjectDecal.js.map +1 -1
  29. package/dist/trinity/eve/child/EveChildMesh.js +17 -3
  30. package/dist/trinity/eve/child/EveChildMesh.js.map +1 -1
  31. package/dist/trinity/eve/locator/EveLocatorSets.js +12 -3
  32. package/dist/trinity/eve/locator/EveLocatorSets.js.map +1 -1
  33. package/dist/trinity/eve/spaceObject/EveSpaceObject2.js +15 -2
  34. package/dist/trinity/eve/spaceObject/EveSpaceObject2.js.map +1 -1
  35. package/dist/trinity/eve/spaceObject/IEveSpaceObject2ParentData.js +44 -52
  36. package/dist/trinity/eve/spaceObject/IEveSpaceObject2ParentData.js.map +1 -1
  37. package/docs/resource/concepts/resource-lifecycle.md +10 -8
  38. package/docs/resource/formats/geometry-interchange.md +50 -0
  39. package/docs/resource/formats/webgl/decl-io.md +241 -397
  40. package/docs/resource/formats/webgl/memory-structured.md +91 -128
  41. package/docs/resource/formats/webgl/texture-sample.md +306 -469
  42. package/docs/resource/reference/classes/texture.md +11 -1
  43. package/docs/resource/reference/motherlode-cache.md +24 -11
  44. package/docs/resource/reference/queues.md +23 -1
  45. package/package.json +1 -1
@@ -2,12 +2,16 @@
2
2
 
3
3
  Status: Evolving
4
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`),
5
+ Audience: Shader translator maintainers and reviewers
6
+ Summary: Defines DXBC texture sampling behavior and WebGL2 target adaptations.
7
+
8
+ Historical lowering study: the target and register convention below describe
9
+ the studied configuration, not today's full emitter support. Confidence ratings
10
+ and unresolved qualifications are retained; this condensation is not shader validation.
11
+
12
+ Target: GLSL ES 3.00 (WebGL2), vertex + pixel stages, no SSBO/compute.
13
+ Register storage model: every register is a float `vec4`; typed reads/writes bitcast at
14
+ the use site (`floatBitsToInt`, `floatBitsToUint`, `intBitsToFloat`, `uintBitsToFloat`),
11
15
  mirroring HLSLcc's own behavior when reflected data-type analysis is unavailable
12
16
  (`ShaderInfo::GetTextureDataType` returns `SVT_FLOAT` when no `RDEF` binding is found —
13
17
  `vendor/HLSLcc/src/ShaderInfo.cpp:10-18`).
@@ -89,85 +93,63 @@ Ground truth: `toGLSLOperand.cpp:1738-1882` (`ResourceName`, `TextureSamplerName
89
93
  `ui32ReturnType = RETURN_TYPE_FLOAT`, matching the fork's stripped-`RDEF` fallback policy.
90
94
 
91
95
  ---
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
96
+
97
+ ## 1. `sample` (3064 occurrences)
98
+
99
+ Filtered sampling with sampler-controlled wrap/filter state and implicit,
100
+ derivative-based LOD. DXBC operands: `dest, address, resource, sampler`.
101
+ `TranslateTextureSample(psInst, TEXSMP_FLAG_NONE)` dispatches at
102
+ `toGLSLInstruction.cpp:3161-3170` into `:1131-1459`:
103
+
104
+ `dest = texture(<TextureSamplerName>, <coord>)<returnSwizzle>;`
105
+
106
+ ### Shared sampling machinery
107
+
108
+ Variants below inherit this machinery except where their sections name a delta.
109
+
110
+ - ES300 uses overloaded `texture`, not legacy `texture2D`/`textureCube`:
111
+ `iHaveOverloadedTexFuncs` excludes only `LANG_ES_100`/`LANG_120`
112
+ (`languages.h:37-44`). Dimension selects `funcName`, `offset`,
113
+ `gradSwizzle`, `ui32NumOffsets` (`:1172-1251`). The study's
114
+ cubemap-array qualification remains with its dimension/depth paths.
115
+ - `TranslateTexCoord` (`:985-1031`) selects/expands leading address
116
+ components; the coordinate table below owns the mapping. It reads
117
+ `TO_AUTO_BITCAST_TO_FLOAT` (`:989`), including integer-produced registers.
118
+ - `bAddressOffset` adds the `Offset` suffix and literal integer/vector
119
+ argument (`:1391-1411`); the sample-controls section owns this rule.
120
+ - Result swizzle belongs to the **texture operand**, not the destination.
121
+ Re-enable its `iWriteMaskEnabled`, then
122
+ `TranslateOperandSwizzleWithMask(psContext, psSrcTex, psDest->GetAccessMask(), 0)`
123
+ (`:1451-1457`) intersects that RGBA permutation with the destination mask.
124
+ - `_sat` is applied **after** the sampling function by the general
125
+ instruction epilogue (`:4821-4844`): `dst = clamp(dst, 0.0, 1.0);`,
126
+ with the `UNITY_ADRENO_ES3`-guarded `min(max(x,0.0),1.0)` form.
127
+ This epilogue applies throughout the family, not inside `TranslateTextureSample`.
128
+
129
+ **Types:** `ShaderInfo::GetTextureDataType(texRegNo)`
130
+ (`ShaderInfo.cpp:10-18`) maps reflected return type to float/int/uint,
131
+ defaulting to `SVT_FLOAT` without RDEF. `AddAssignToDest`
132
+ (`toGLSLInstruction.cpp:1281`, `:155-171`) wraps mismatches between
133
+ texture result and declared destination type using the appropriate bitcast.
134
+ The historical float-register proposal treats results as float storage and
135
+ defers integer reinterpretation to consuming instructions; it is not a new
136
+ qualification of current integer handling.
137
+
138
+ Sampler type is selected at declaration by `GetSamplerType`
139
+ (`toGLSLDeclaration.cpp:1388-1551`); unreflected fallback is float
140
+ (`sampler2D` at `:1550` and per-dimension defaults). Core bitcast
141
+ builtins require no custom helpers: `HaveBitEncodingOps` excludes only
142
+ `LANG_ES_100`/`LANG_120` (`languages.h:169-180`).
143
+
144
+ **Edge cases**: Out-of-range coordinates follow the sampler's wrap mode (not a DXBC
145
+ concern — GLSL `texture()` handles it per the WebGL2 sampler state, which is set at the
159
146
  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
-
147
+ undefined/implementation-defined per GLSL ES spec, same as native GLSL; HLSLcc does not
148
+ special-case it.
149
+
150
+ **Confidence**: high — this is the highest-volume opcode in the corpus and the core
151
+ `TranslateTextureSample` path is fully read and directly cited line-by-line.
152
+
171
153
  ---
172
154
 
173
155
  ## 2. `sample_l` (9124 occurrences — highest volume in family)
@@ -307,72 +289,56 @@ occurrence count (153) means it has had less indirect validation than `sample`/`
307
289
  `sample_b` from the corpus-count-as-confidence-proxy perspective.
308
290
 
309
291
  ---
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
358
- target**). The earlier claim of "zero hits for `HaveGather` outside
359
- `languages.h`" was false: instruction/declaration/operand lowering does not
360
- check it, but `toGLSL.cpp`'s `AddVersionDependentCode` (`:163-172`) checks
361
- `!HaveGather(eLang)` and, for any `gather4*`, calls
362
- `EnableExtension("GL_ARB_texture_gather")`.
363
-
364
- `EnableExtension` (`HLSLCrossCompilerContext.cpp:157-167`) emits a guarded
365
- `#ifdef GL_ARB_texture_gather` / `#extension GL_ARB_texture_gather : enable` /
366
- `#endif`, not a hard failure on an unknown extension. This desktop-only token
367
- is never predefined by an ES/WebGL2 preprocessor: the guard emits no extension
368
- and leaves the instruction's unconditional `funcName = "textureGather"`
369
- (`toGLSLInstruction.cpp:1253-1254`) unchanged. Unlike the image-atomics case
370
- at `:154-160`, it has no `isES` branch selecting
371
- `GL_OES_shader_image_atomic`.
372
-
373
- Thus HLSLcc attempts a gate, but it does nothing useful on `LANG_ES_300`.
374
- The JS emitter must supply four-tap emulation: four `textureOffset`/`texture`
375
- calls at the bilinear-neighbor texel centers, computed from `textureSize`.
292
+
293
+ ## 5. `gather4` (195 occurrences) — and `gather4_po` / `gather4_po_c` / `gather4_c`
294
+
295
+ Returns one selected channel from each of four bilinear-neighbor texels as a
296
+ `vec4`, without applying bilinear weights. `_PO` adds a programmable
297
+ integer offset; `_C` adds a comparison reference.
298
+ Dispatch (`toGLSLInstruction.cpp:3121-3160`) combines flags:
299
+
300
+ | Opcode | `TEXSMP_FLAG_*` |
301
+ |---|---|
302
+ | `gather4` | `GATHER` |
303
+ | `gather4_po` | `GATHER \| PARAMOFFSET` |
304
+ | `gather4_po_c` | `GATHER \| PARAMOFFSET \| DEPTHCOMPARE` |
305
+ | `gather4_c` | `GATHER \| DEPTHCOMPARE` |
306
+
307
+ `TranslateTextureSample` forces `textureGather` (`:1253-1254`):
308
+
309
+ `dest = textureGather(<TextureSamplerName>, <coord>[, <refZ>][, <offsetVec>][, <component>])<returnSwizzle>;`
310
+
311
+ Shared result-type/swizzle/mask machinery is in §1. Gather-specific arguments:
312
+
313
+ - Comparison reference is **separate**, never embedded in `txVecN`.
314
+ The temporary condition explicitly excludes `TEXSMP_FLAG_GATHER`
315
+ (`:1264-1265`, `:1341-1354`).
316
+ - Programmable offsets use `TranslateOperand(psSrcOff, TO_FLAG_INTEGER, mask)`
317
+ (`:1412-1423`), with `ui32NumOffsets` components (1/2/3).
318
+ Immediate offsets use the shared `bAddressOffset`/`iUAddrOffset` path.
319
+ The Switch-only `GATHER4_PO` suffix quirk (`:1165-1170`) is excluded.
320
+ - A one-component **sampler-operand** swizzle selects R/G/B/A; non-X appends
321
+ a trailing integer channel (`:1432-1447`). This is not result swizzling.
322
+ Comparison gathers have no selectable channel (`:1442-1445`).
323
+
324
+ ### Historical ES300 capability gap
325
+
326
+ `HaveGather` (`languages.h:220-227`) accepts `>=LANG_400` or
327
+ `LANG_ES_310`, not ES300. Instruction emission is unconditional, but
328
+ `AddVersionDependentCode` (`toGLSL.cpp:163-172`) tests `!HaveGather`
329
+ and attempts `GL_ARB_texture_gather` for `gather4*`.
330
+ `EnableExtension` (`HLSLCrossCompilerContext.cpp:157-167`) emits
331
+ an `#ifdef`-guarded pragma, not an unknown-extension failure. Under
332
+ ES/WebGL2 that desktop token is not predefined, so the call remains unchanged.
333
+ Unlike image atomics at `:154-160`, there is no `isES` branch choosing
334
+ `GL_OES_shader_image_atomic`. The earlier “no gate” claim was incorrect;
335
+ the attempted gate is ineffective for this target.
336
+
337
+ The study requires `hlslcc_textureGather4Emulated` (four
338
+ `textureOffset`/`texture` taps at centers derived from `textureSize`)
339
+ **or explicit translation rejection**, not literal unsupported
340
+ `textureGather`/`textureGatherOffset`. Neither is an ES300 builtin
341
+ or supplied by a WebGL2 extension. Emulation's ordering risk remains below.
376
342
 
377
343
  **Edge cases**: `textureGather` (where available) requires the four sampled texels to be
378
344
  selected by hardware bilinear-neighbor rules that are implementation-defined at exact
@@ -383,18 +349,6 @@ consumers (contact-hardening shadows, procedural blending). This emulation is
383
349
  **not sourced from HLSLcc** (HLSLcc assumes `textureGather` exists) and is the single
384
350
  highest-risk item in this spec.
385
351
 
386
- **WebGL2 notes — critical gap**: `languages.h:220-227` makes
387
- `HaveGather(eLang)` true only for `eLang >= LANG_400` or `LANG_ES_310`,
388
- excluding `LANG_ES_300`. `textureGather`/`textureGatherOffset` require
389
- GLSL ES 3.10 / desktop GLSL 4.00; WebGL2 exposes no extension adding them.
390
- The ineffective desktop extension attempt is described above, not "no gate".
391
-
392
- This spec's emitter must either (a) always emit the
393
- `hlslcc_textureGather4Emulated` helper instead of raw `textureGather` for this family, or
394
- (b) detect and reject `gather4*` shaders at translation time with an explicit diagnostic —
395
- but silently trusting HLSLcc's literal `textureGather(...)` output will break at WebGL2
396
- shader-compile time.
397
-
398
352
  **Confidence**: low for WebGL2 compilability, high for HLSLcc's literal output
399
353
  (fully read C++, including the global extension attempt). The risk is target
400
354
  capability mismatch. The earlier `TRANSPILING-GAPS.md:188` corroboration is
@@ -403,96 +357,63 @@ assessment rests solely on the cited C++ reading.
403
357
 
404
358
  ---
405
359
 
406
- ## 6. `sample_c` (0 occurrences in corpus, spec required for depth paths)
407
-
408
- **Semantics**: Depth-comparison ("shadow") sample: fetches from a depth-format resource
409
- using a comparison sampler, compares the fetched depth against a supplied reference value,
410
- and returns the hardware's percentage-closer-filtered (PCF) result — a **float in
411
- `[0.0, 1.0]`**, not a 0/1 boolean and **not** the DXBC ALU integer comparison-mask
412
- convention. D3D11 `SAMPLE_C`: `dest, address, resource, sampler, referenceValue`, implicit
413
- (derivative-based) LOD like `sample`.
414
-
415
- **Important — comparison-mask convention does NOT apply here**: ALU
416
- `eq`/`ne`/`lt`/`ge`, `ieq`/`ige`, etc. return per-lane
417
- `0xFFFFFFFF`/`0x00000000` masks (`AddComparison`,
418
- `toGLSLInstruction.cpp:173`; `OPCODE_GE` comment, `:2689-2694`).
419
- `sample_c`/`sample_c_lz`/`gather4_c` instead return filtered floats,
420
- including intermediate PCF values under linear filtering. HLSLcc forwards the
421
- GLSL shadow-sample result without extra masking, matching D3D11
422
- `SampleCmp`/`SampleCmpLevelZero` semantics.
423
-
424
- **GLSL lowering**: `TranslateTextureSample(psInst, TEXSMP_FLAG_DEPTHCOMPARE)`
425
- (`toGLSLInstruction.cpp:3181-3190`). `psSrcRef = operands[4 + hasParamOffset]` (`:1143`).
426
-
427
- - For every resource dimension **except** `TEXTURECUBEARRAY` and non-gather ops, the
428
- reference value is embedded as the **last component of the texture coordinate vector**
429
- (this matches core GLSL's shadow-sampler convention, where `sampler2DShadow` takes a
430
- `vec3(u, v, refZ)`): HLSLcc builds a temp,
431
- ```glsl
432
- vec3 txVec<N> = vec3(<coord>, <refZ>);
433
- ```
434
- (`:1264-1277`; `depthCmpCoordType` is `"vec2"`/`"vec3"`/`"vec4"` per dimension,
435
- `:1176,1191,1206,1217,1228,1235`), then samples `texture(<sampler>, txVec<N>)`.
436
- The temp exists "as Adrenos hate nonstandard swizzles in the texcoords" (source comment,
437
- `:1269`).
438
- - For `TEXTURECUBEARRAY` (no `depthCmpCoordType` case defined) the reference is passed as a
439
- separate trailing argument instead (`:1349-1354`), matching GLSL's
440
- `texture(samplerCubeArrayShadow, vec4(dir, arrayIdx), refZ)` signature, which has no room
441
- in the coordinate vector for both array index and reference.
442
- - Function name is plain `funcName` (`"texture"`, or `"textureLod"`/`"textureGrad"` variants
443
- per other combined flags) — depth-compare does **not** change the function name, only the
444
- sampler *type* (`sampler2DShadow` etc., chosen at declaration time from `ui32IsShadowTex`)
445
- and the coordinate/argument shape.
446
- - `ResourceName`/`TextureSamplerName` calls pass `bZCompare = 1` when
447
- `TEXSMP_FLAG_DEPTHCOMPARE` is set (`:1333,1335`). **Correction**: because
448
- `HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS` is always set for this fork (see section 0),
449
- `useCombinedTextureSamplers` is always true, so the instruction body always takes the
450
- `:1335` branch — `TextureSamplerName(..., bZCompare=1)` — never the `:1333` bare-
451
- `ResourceName` branch. The declaration that actually matches what the instruction body
452
- calls is therefore the **combined**-sampler shadow uniform emitted at
453
- `toGLSLDeclaration.cpp:1634-1646` (`uniform <samplerType>Shadow <TextureSamplerName(...,
454
- bZCompare=1)>`), **not** `toGLSLDeclaration.cpp:1668-1686` as an earlier draft of this spec
455
- claimed — that `1668-1686` block declares the *bare* `ResourceName`-based shadow uniform
456
- (`hlslcc_zcmp`-prefixed plain `t#` symbol), which is emitted unconditionally alongside the
457
- combined one (regardless of the combine flag) purely for register-identity duplication
458
- (the same "declared but not referenced by instruction bodies" pattern section 0 already
459
- documents for the non-shadow case) and is never the symbol the instruction body's call
460
- resolves to. Concretely, a shader that both plain-samples and depth-compares the same
461
- `t#` texture with this fork's always-on combine flag gets **four** declared GLSL sampler
462
- uniforms for that texture (combined non-shadow `TEX_with_SMP` name, combined shadow
463
- `hlslcc_zcmp...TEX_with_SMP` name, bare non-shadow `t#`/reflected name, bare shadow
464
- `hlslcc_zcmp`+`t#`/reflected name — `toGLSLDeclaration.cpp:1632-1686`), of which only the
465
- two combined ones are ever referenced by instruction bodies.
466
-
467
- **Type rules**: destination is always float (D3D `SampleCmp` result type is float;
468
- `ui32ReturnType`/`GetTextureDataType` is not consulted for the shadow path's numeric
469
- result — it stays float because depth formats reflect as float). Reference value:
470
- `TranslateOperand(psSrcRef, TO_AUTO_BITCAST_TO_FLOAT)` (`:1275,1353`) — always float.
471
-
472
- **Helpers needed**: none beyond the `txVecN` embedding pattern (a per-call-site local
473
- `vec2/vec3/vec4` temp, not a shared function — the JS emitter should replicate this
474
- inline-temp pattern rather than centralizing it, to match HLSLcc's numbering scheme
475
- `m_NextTexCoordTemp` used to keep temp names unique per shader phase, `:1267`).
476
-
477
- **Edge cases**: see `sample_l`'s 2D-array-shadow `textureLod`-unavailable workaround —
478
- that workaround is keyed off `TEXSMP_FLAG_DEPTHCOMPARE` and fires for `sample_c` combined
479
- with an explicit-LOD or LOD-zero flag on a `TEXTURE2DARRAY` resource; plain `sample_c`
480
- (implicit LOD) does not need it because ordinary `texture(sampler2DArrayShadow, ...)`
481
- (no explicit LOD) is legal GLSL.
482
-
483
- **WebGL2 notes**: `sampler2DShadow`/`sampler2DArrayShadow`/`samplerCubeShadow` and the
484
- `texture()` shadow-comparison overloads are core GLSL ES 3.00. `samplerCubeArrayShadow`
485
- requires cubemap-array support, which itself needs `GL_OES_texture_cube_map_array`/
486
- `GL_EXT_texture_cube_map_array` on ES targets (`HaveCubemapArray` is false for
487
- `LANG_ES_300`, `languages.h:75-80`; `TranslateResourceTexture` enables both OES and EXT
488
- extension strings for ES languages when a cubemap array is declared,
489
- `toGLSLDeclaration.cpp:1608-1619`) — so a `sample_c` against a `TextureCubeArray` shadow
490
- resource depends on a WebGL2 extension actually being available at runtime, which is not
491
- guaranteed.
492
-
493
- **Confidence**: medium — the lowering path itself is fully and unambiguously read from
494
- source; the medium (not high) rating is solely because the corpus has 0 real-world
495
- instances to cross-check the reading against, per the task's own instruction to still
360
+ ## 6. `sample_c` (0 occurrences in corpus, spec required for depth paths)
361
+
362
+ Implicit-LOD sampling of a depth-format resource using a comparison sampler:
363
+ `dest, address, resource, sampler, referenceValue`.
364
+ The percentage-closer-filtered (PCF) result is **float in [0,1]**, including
365
+ intermediate linear-filter values, not a Boolean or all-ones comparison mask.
366
+ This also applies to `sample_c_lz` and `gather4_c`. Contrast ALU
367
+ `eq/ne/lt/ge`, `ieq/ige` masks (`0xFFFFFFFF`/`0x00000000`; `AddComparison`,
368
+ `toGLSLInstruction.cpp:173`; `OPCODE_GE`, `:2689-2694`).
369
+ HLSLcc forwards the shadow result without additional masking.
370
+
371
+ `TranslateTextureSample(..., TEXSMP_FLAG_DEPTHCOMPARE)` dispatches at
372
+ `:3181-3190`; reference is `operands[4 + hasParamOffset]` (`:1143`).
373
+
374
+ - Non-gather, non-`TEXTURECUBEARRAY` calls embed reference in the last
375
+ coordinate component (`:1264-1277`), e.g.
376
+ `vec3 txVec<N> = vec3(<coord>, <refZ>);` then
377
+ `texture(<sampler>, txVec<N>)`. The coordinate table owns
378
+ `depthCmpCoordType` (`:1176,1191,1206,1217,1228,1235`).
379
+ The Adreno nonstandard-swizzle workaround motivates this local
380
+ (`:1269`); `m_NextTexCoordTemp` (`:1267`) keeps names unique per
381
+ shader phase. It is a per-call temporary, not a shared function.
382
+ - Cube arrays pass reference separately (`:1349-1354`):
383
+ `texture(samplerCubeArrayShadow, vec4(dir, arrayIdx), refZ)`.
384
+ Gather's separate-reference rule is in §5.
385
+ - Depth comparison changes sampler **type** and argument shape, not the
386
+ function name; `texture`/`textureLod`/`textureGrad` follows other flags.
387
+ Declaration selection uses `ui32IsShadowTex`.
388
+
389
+ **Names:** under the introduction's **overrideable combined-sampler default**,
390
+ `TextureSamplerName(..., bZCompare=1)` (`:1335`) references the
391
+ combined shadow uniform (`toGLSLDeclaration.cpp:1634-1646`), not the
392
+ bare `ResourceName` shadow declaration (`:1668-1686`). The latter
393
+ remains declared for register identity; §0 owns duplication. A texture used
394
+ for ordinary and comparison sampling has four declarations under that default:
395
+ combined plain/shadow and bare plain/shadow (`:1632-1686`), with the two
396
+ combined symbols used by these sampling calls. Without combination, the
397
+ `ResourceName(..., bZCompare=1)` branch is `:1333`.
398
+
399
+ **Types:** result stays float rather than using `GetTextureDataType` or
400
+ `ui32ReturnType` for a numeric conversion; depth formats reflect float.
401
+ Reference uses `TO_AUTO_BITCAST_TO_FLOAT` (`:1275,1353`).
402
+ 2D/2D-array/cube shadow `texture` overloads are the study's ES300 baseline.
403
+ Cube-array support is conditional: `HaveCubemapArray`
404
+ (`languages.h:75-80`) excludes ES300; declaration attempts
405
+ `GL_OES_texture_cube_map_array` and `GL_EXT_texture_cube_map_array`
406
+ (`toGLSLDeclaration.cpp:1608-1619`). Verify availability rather than assume it.
407
+
408
+ **Edge cases**: see `sample_l`'s 2D-array-shadow `textureLod`-unavailable workaround —
409
+ that workaround is keyed off `TEXSMP_FLAG_DEPTHCOMPARE` and fires for `sample_c` combined
410
+ with an explicit-LOD or LOD-zero flag on a `TEXTURE2DARRAY` resource; plain `sample_c`
411
+ (implicit LOD) does not need it because ordinary `texture(sampler2DArrayShadow, ...)`
412
+ (no explicit LOD) is legal GLSL.
413
+
414
+ **Confidence**: medium — the lowering path itself is fully and unambiguously read from
415
+ source; the medium (not high) rating is solely because the corpus has 0 real-world
416
+ instances to cross-check the reading against, per the task's own instruction to still
496
417
  document it for depth-path completeness.
497
418
 
498
419
  ---
@@ -637,80 +558,55 @@ transcribed from source, and its `SHEX`-fallback path is independently corrobora
637
558
  `CARBONENGINEJS-FORK.md`.
638
559
 
639
560
  ---
640
-
641
- ## 9. `resinfo` (247 occurrences)
642
-
643
- **Semantics**: Queries a resource's dimensions (width/height/depth-or-array-size) at a
644
- given mip level, plus the resource's total mip-chain length, with a caller-selectable
645
- return-type encoding (float / reciprocal-float / uint) — D3D11 `RESINFO`, decoded
646
- return-type control per `decisions/016...018-dxbc-instruction-controls...md`: bits 11-12 of
647
- the opcode token, `0` = float, `1` = reciprocal float, `2` = uint
648
- (`RESINFO_INSTRUCTION_RETURN_{FLOAT,RCPFLOAT,UINT}`).
649
-
650
- **GLSL lowering**: dispatch loop iterates the destination write mask, calling
651
- `GetResInfoData(psInst, swizzledComponentIndex, destElem)` once per live destination
652
- component (`toGLSLInstruction.cpp:4734-4752`), implementation at `:1033-1129`:
653
-
654
- - For `index` (post-swizzle component index) `< 3` — width/height/depth-or-arraysize:
655
- ```glsl
656
- dest.<comp> = <returnCast>( <maybe 1.0/> textureSize(<tex>[, int(mipOperand)]) [.x|.y|.z] );
657
- ```
658
- - `dim = GetNumTextureDimensions(eResDim)` (`HLSLccToolkit.cpp:437-458`: 1 for
659
- `TEXTURE1D`; 2 for `TEXTURE2D`/`TEXTURE2DMS`/`TEXTURE1DARRAY`/`TEXTURECUBE`; 3 for
660
- `TEXTURE3D`/`TEXTURE2DARRAY`/`TEXTURE2DMSARRAY`/`TEXTURECUBEARRAY`).
661
- - If the requested `index` exceeds `dim` (e.g. asking for `.z` on a 2D texture), the
662
- literal constant `0`/`0.0`/`uint(0)` is emitted instead of calling `textureSize`
663
- (`:1064-1067`) — the source comment notes `0u` is mistreated as a const-int by "old
664
- ES3.0 Adrenos", hence `uint(0)` is spelled out rather than a bare `0u`.
665
- - Return-type wrapping: `RESINFO_INSTRUCTION_RETURN_UINT` → `uvec<dim>(...)` (or
666
- `ivec<dim>` if `HaveUnsignedTypes` is false, not applicable to ES 3.00);
667
- `RESINFO_INSTRUCTION_RETURN_RCPFLOAT` → `vec<dim>(1.0) / vec<dim>(textureSize(...))`;
668
- else → `vec<dim>(textureSize(...))` (`:1070-1080`).
669
- - MS resources (`isMS`) and UAVs (`isUAV`) omit the mip-level argument to
670
- `textureSize`/`imageSize` entirely (`:1089-1093`; UAV uses `imageSize` instead of
671
- `textureSize`, `:1082-1085` — not reachable via the pure `t#` `resinfo` path this family
672
- documents, but present in the same function since `resinfo` can also target a UAV).
673
- - For `index >= 3` (total mip-level count):
674
- ```glsl
675
- dest.w = <int|uint|float>(textureQueryLevels(<tex>));
676
- ```
677
- (`:1112-1127`) — **unconditionally emitted with no target-language capability check**
678
- (see WebGL2 notes below).
679
-
680
- **Type rules**: each live destination component is assigned independently via
681
- `AddOpAssignToDestWithMask(..., eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ?
682
- SVT_UINT : SVT_FLOAT, 1, ..., 1 << destElem)` (`:1057`) — i.e. `resinfo`'s destination type
683
- per-component is uint only for the UINT return-type control, float for both FLOAT and
684
- RCPFLOAT controls (RCPFLOAT is still a float result, just the reciprocal).
685
-
686
- **Helpers needed**: `hlslcc_textureQueryLevels` (**mandatory for the 4th/mip-count
687
- component on this target** — see WebGL2 notes). No helper needed for the width/height/
688
- depth components (`textureSize` is fully core).
689
-
690
- **Edge cases**: `textureSize` with an out-of-range `lod` argument returns `0` per GLSL ES
561
+
562
+ ## 9. `resinfo` (247 occurrences)
563
+
564
+ Queries dimensions at a mip and total mip count. DXBC return control is
565
+ opcode bits11–12: 0=float, 1=reciprocal float, 2=uint
566
+ (`RESINFO_INSTRUCTION_RETURN_{FLOAT,RCPFLOAT,UINT}`;
567
+ `decisions/016...018-dxbc-instruction-controls...md`, subject to the
568
+ opening missing-evidence caveat).
569
+
570
+ Dispatch visits each destination-mask component, calling
571
+ `GetResInfoData(psInst, swizzledComponentIndex, destElem)`
572
+ (`toGLSLInstruction.cpp:4734-4752`, implementation `:1033-1129`).
573
+
574
+ | Post-swizzle component | Emission |
575
+ |---|---|
576
+ | index <3 | Dimension from `textureSize(tex[, int(mipOperand)])`, then selected component and return conversion. |
577
+ | Missing dimension | Literal `0`/`0.0`/`uint(0)` (`:1064-1067`); old ES3 Adrenos misread bare `0u` as const-int. |
578
+ | index >=3 | `dest.w = <int\|uint\|float>(textureQueryLevels(tex));` (`:1112-1127`). |
579
+
580
+ `GetNumTextureDimensions` (`HLSLccToolkit.cpp:437-458`):
581
+ 1D→1; 2D/2DMS/1DArray/Cube→2; 3D/2DArray/2DMSArray/CubeArray→3.
582
+ Conversions (`:1070-1080`): UINT→`uvec<dim>` (`ivec` only
583
+ without unsigned support); RCPFLOAT→`vec<dim>(1.0)/vec<dim>(textureSize(...))`;
584
+ FLOAT→`vec<dim>(textureSize(...))`. MS and UAV omit the mip argument
585
+ (`:1089-1093`); UAV uses `imageSize` (`:1082-1085`), outside the
586
+ pure-`t#` path studied here. `AddOpAssignToDestWithMask` (`:1057`)
587
+ assigns one component with `1 << destElem`: `SVT_UINT` only for UINT,
588
+ otherwise `SVT_FLOAT`, including reciprocal results.
589
+
590
+ ### Mip-count gap and global-gate correction
591
+
592
+ `HaveQueryLevels` (`languages.h:247-254`) requires `>=LANG_430`.
593
+ The instruction calls `textureQueryLevels` without a **local** gate, but
594
+ `AddVersionDependentCode` (`toGLSL.cpp:234-241`) tests
595
+ `!HaveQueryLevels` plus `OPCODE_RESINFO` and attempts
596
+ `GL_ARB_texture_query_levels` / `GL_ARB_shader_image_size`.
597
+ These guarded desktop pragmas are ineffective on ES/WebGL2, as in §5;
598
+ “no gate at all” was too broad.
599
+
600
+ Only total-mip-count access has this gap: `textureSize` dimensions need no
601
+ helper. With no ES300/WebGL2 equivalent for `textureQueryLevels`, the
602
+ study proposes `hlslcc_textureQueryLevels` backed by a per-texture
603
+ out-of-band mip-count uniform, **or explicit rejection when that component
604
+ is read**. It does not qualify today's implementation by the 247 opcode count.
605
+
606
+ **Edge cases**: `textureSize` with an out-of-range `lod` argument returns `0` per GLSL ES
691
607
  3.00 spec (well-defined). Buffer/`BUFFEX` resources are excluded from the `dim==0` default
692
608
  path implicitly by never appearing in the `resinfo`-legal dimension set.
693
609
 
694
- **WebGL2 notes — gap on the mip-count component**:
695
- `HaveQueryLevels(eLang)` requires `eLang >= LANG_430`
696
- (`languages.h:247-254`), excluding `LANG_ES_300`.
697
- `GetResInfoData`'s `index >= 3` branch (`:1112-1127`) calls
698
- `textureQueryLevels` without a local gate. The earlier "no gate at all"
699
- claim was too broad: `toGLSL.cpp`'s `AddVersionDependentCode`
700
- (`:234-241`) checks `!HaveQueryLevels` plus `OPCODE_RESINFO`, then
701
- attempts `GL_ARB_texture_query_levels` and `GL_ARB_shader_image_size`.
702
- Like the gather gate, these desktop-only tokens sit behind `EnableExtension`
703
- `#ifdef` guards that do nothing under ES/WebGL2; the call site is unchanged.
704
-
705
- `textureQueryLevels` has neither an ES 3.00 builtin nor a WebGL2 extension
706
- equivalent. Reading `resinfo`'s fourth (`.w`, total-mip-count) component
707
- therefore produces non-compiling GLSL. The 247 corpus occurrences make this
708
- an actionable risk; the first three `textureSize` components have no such gap.
709
- The emitter must
710
- substitute `hlslcc_textureQueryLevels` (fallback strategy: accept the mip count as an
711
- out-of-band uniform per texture, since there is no in-shader WebGL2-legal way to query it;
712
- or hard-fail translation if this exact component is read).
713
-
714
610
  **Confidence**: high on HLSLcc's literal output, including the global extension
715
611
  attempt; the mip-count path remains a WebGL2 compile risk. Corroboration by
716
612
  `TRANSPILING-GAPS.md:186,337` is withdrawn because that file is absent (see
@@ -718,120 +614,81 @@ the authority-order correction). Confidence rests on the C++ reading alone.
718
614
 
719
615
  ---
720
616
 
721
- ## 10. `deriv_rtx_coarse` (209) and `deriv_rty_coarse` (215)
722
- ### (plus `deriv_rtx`/`deriv_rtx_fine`/`deriv_rty`/`deriv_rty_fine`, same lowering)
723
-
724
- **Semantics**: Screen-space partial derivative of the source value with respect to
725
- window-space X (`rtx`) or Y (`rty`). D3D11 distinguishes `_coarse` (may share a derivative
726
- across a 2x2 quad, cheaper) from `_fine` (per-pixel) and from the plain (compiler's choice)
727
- form, but **GLSL only exposes one derivative pair** (`dFdx`/`dFdy`), with precision
728
- controlled by an optional `GL_OES_standard_derivatives`-style hint, not a distinct
729
- coarse/fine builtin.
730
-
731
- **GLSL lowering**: all six coarse/fine/plain DERIV opcodes collapse onto the same two
732
- `case` blocks (`toGLSLInstruction.cpp:4579-4602`):
733
- ```glsl
734
- dest = dFdx(src)<destSwizzleSubset>; // DERIV_RTX_COARSE / DERIV_RTX_FINE / DERIV_RTX
735
- dest = dFdy(src)<destSwizzleSubset>; // DERIV_RTY_COARSE / DERIV_RTY_FINE / DERIV_RTY
736
- ```
737
- via `CallHelper1("dFdx", psInst, 0, 1, 1)` / `CallHelper1("dFdy", psInst, 0, 1, 1)`.
738
- `CallHelper1` (`:745-762`): destination is assigned `SVT_FLOAT` with the destination's own
739
- swizzle-element count (`AddAssignToDest(dest, SVT_FLOAT, dstSwizCount, ...)`), the call is
740
- `name(TranslateOperand(src0, TO_AUTO_BITCAST_TO_FLOAT, destMask))` where `destMask` is the
741
- destination's own access mask (the 4th `CallHelper1` argument, `paramsShouldFollowWriteMask
742
- = 1`, restricts the source read to the same components being written).
743
-
744
- **Type rules**: always float in and float out; source is
745
- `TO_AUTO_BITCAST_TO_FLOAT` (reinterpret as float if the register was produced as int/uint).
746
- No int/uint derivative form exists in DXBC or GLSL.
747
-
748
- **Helpers needed**: none — `dFdx`/`dFdy` are core GLSL ES 3.00 builtins (fragment-shader
749
- only).
750
-
751
- **Edge cases**: derivatives are **fragment-shader only** — DXBC guarantees `deriv_*` never
752
- appears in a vertex shader (no rasterization quad exists there), so no stage guard is
617
+ ## 10. `deriv_rtx_coarse` (209) and `deriv_rty_coarse` (215)
618
+
619
+ ### (plus `deriv_rtx`/`deriv_rtx_fine`/`deriv_rty`/`deriv_rty_fine`, same lowering)
620
+
621
+ Window-space X/Y derivatives. D3D's coarse (may share across a 2×2 quad), fine (per-pixel)
622
+ and plain (compiler-chosen) distinction collapses to two ES300 builtins:
623
+
624
+ `dest = dFdx(src)<destSwizzleSubset>;` — all three RTX forms.
625
+ `dest = dFdy(src)<destSwizzleSubset>;` — all three RTY forms.
626
+
627
+ Source: `toGLSLInstruction.cpp:4579-4602`, calling
628
+ `CallHelper1("dFdx"/"dFdy", psInst, 0, 1, 1)` (`:745-762`).
629
+ `AddAssignToDest(dest, SVT_FLOAT, dstSwizCount, ...)` uses the destination
630
+ swizzle count. `paramsShouldFollowWriteMask=1` also limits the source
631
+ read to the destination access mask, through `TO_AUTO_BITCAST_TO_FLOAT`.
632
+ Input/output are float; there is no integer derivative form.
633
+
634
+ No helper or ES100 `GL_OES_standard_derivatives` extension is needed:
635
+ `dFdx`/`dFdy` (and `fwidth`) are fragment-stage ES300 builtins.
636
+ The study notes a derivative-quality hint rather than distinct coarse/fine
637
+ functions; output loses that DXBC distinction, matching the cited HLSLcc path.
638
+
639
+ **Edge cases**: derivatives are **fragment-shader only** — DXBC guarantees `deriv_*` never
640
+ appears in a vertex shader (no rasterization quad exists there), so no stage guard is
753
641
  needed beyond what DXBC itself enforces. Derivatives across non-uniform control flow
754
642
  (diverging discard/branch within a 2x2 quad) are undefined-ish in both D3D and GLES —
755
- HLSLcc adds no special handling; this is an inherent GPU behavior difference the
756
- translator cannot paper over.
757
-
758
- **WebGL2 notes**: `dFdx`/`dFdy` (and `fwidth`) are **core, unconditional** in GLSL ES 3.00
759
- (unlike GLSL ES 1.00/WebGL1, where they required the `GL_OES_standard_derivatives`
760
- extension — irrelevant here since target is ES 3.00). The coarse/fine distinction is
761
- simply lost/unified; there is no GLSL ES 3.00 way to request coarse-only derivatives, so
762
- `_fine` and `_coarse` and plain forms are indistinguishable in the output, matching
763
- upstream HLSLcc behavior exactly (not a gap this project introduces).
764
-
765
- **Confidence**: high — trivial, fully read, single-line-per-opcode lowering, high corpus
766
- count (209+215 combined for the `_coarse` variants alone).
767
-
643
+ HLSLcc adds no special handling; this is an inherent GPU behavior difference the
644
+ translator cannot paper over.
645
+
646
+ **Confidence**: high — trivial, fully read, single-line-per-opcode lowering, high corpus
647
+ count (209+215 combined for the `_coarse` variants alone).
648
+
768
649
  ---
769
-
770
- ## 11. `lod` (0 occurrences in corpus, spec required per task)
771
-
772
- **Semantics**: Computes the LOD the hardware *would* select for a given sample (both the
773
- "clamped" and "unclamped" values), without actually sampling — D3D11 `LOD`: result is
774
- `(ClampedLOD, NonClampedLOD, 0, 0)`. Distinct from every `sample_*` opcode: this one never
775
- fetches texels.
776
-
777
- **GLSL lowering**: `toGLSLInstruction.cpp:4161-4200`.
778
- ```glsl
779
- dest = textureQueryLod(<tex>, <coord>)<returnSwizzle>; // core-language name, LANG>=400
780
- // or
781
- dest = textureQueryLOD(<tex>, <coord>)<returnSwizzle>; // extension name, otherwise
782
- ```
783
- Function-name casing is chosen by `HaveQueryLod(eLang)` (`languages.h:238-245`, true only
784
- for `eLang >= LANG_400`) — this is the one check in this family that gates a **function
785
- name** directly inside the instruction-lowering switch itself (`gather4`'s `HaveGather` and
786
- `resinfo`'s `HaveQueryLevels` are instead checked separately in `toGLSL.cpp`'s
787
- `AddVersionDependentCode`, purely to attempt an `EnableExtension` pragma — see the
788
- corrections in those sections above; `lod` gets an analogous, equally ES-3.00-ineffective
789
- `EnableExtension("GL_ARB_texture_query_lod")` attempt there too, gated on the same
790
- `!HaveQueryLod` check, at `toGLSL.cpp:226-231`).
791
-
792
- **Correction — resource-name resolution bypasses the combined-sampler ABI**: unlike every
793
- other opcode in this family, the texture operand here (`psInst->asOperands[2]`) is emitted
794
- via a plain `TranslateOperand(&psInst->asOperands[2], TO_FLAG_NONE)` call (`:4185`), which
795
- for an `OPERAND_TYPE_RESOURCE` operand routes into `toGLSLOperand.cpp:1271-1275`'s
796
- `case OPERAND_TYPE_RESOURCE: ResourceName(glsl, psContext, RGROUP_TEXTURE,
797
- psOperand->ui32RegisterNumber, 0);` — the **bare** `ResourceName` path, not
798
- `TextureSamplerName`. `lod` never touches its sampler operand
799
- (`psInst->asOperands[3]`) at all. So even though `HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS` is
800
- always on for this fork, `lod` always references the bare, non-combined `t#`/reflected-name
801
- sampler uniform (the one declared unconditionally at `toGLSLDeclaration.cpp:1659-1666`) —
802
- a *different* GLSL uniform than the combined `TEX_with_SMP...` name that `sample`/
803
- `sample_l`/etc. use to read the same DXBC texture register. This is architecturally
804
- consistent (`textureQueryLod` only needs one sampler object, and a real one is always
805
- declared), but it means `lod` is the one opcode in this family that does not follow
806
- section 0's combined-sampler naming rule, which the earlier draft of this section did not
807
- call out at all. Coordinates use the same `TranslateTexCoord` per-dimension selection as
808
- `sample` (`:4187-4189`). Return-channel swizzle applied the same way as other texture ops
809
- (`:4194-4197`).
810
-
811
- **Type rules**: destination is always `SVT_FLOAT`, 4 components (`AddAssignToDest(dest,
812
- SVT_FLOAT, 4, ...)`, `:4171`) — DXBC `lod` always produces float regardless of the
813
- resource's reflected return type (this is a query result, not a texel fetch).
814
-
815
- **Helpers needed**: `hlslcc_textureQueryLod` fallback (see WebGL2 notes — `LANG_ES_300`
816
- falls into the `textureQueryLOD` extension-name branch, but that extension is not part of
817
- WebGL2's guaranteed baseline).
818
-
819
- **Edge cases**: none beyond standard coordinate range handling; no fetch occurs so no
820
- wrap/border-color interaction applies.
821
-
822
- **WebGL2 notes — gap**: `HaveQueryLod(LANG_ES_300)` is false, so HLSLcc emits the
823
- extension-style name `textureQueryLOD(...)`. That name corresponds to
824
- `GL_ARB_texture_query_lod` (desktop) / `GL_EXT_texture_query_lod`-equivalent — **not** a
825
- function that exists in unextended WebGL2/GLSL ES 3.00, and no such extension is part of
826
- the WebGL2 core extension set exposed by browsers. Since the corpus shows 0 real usages,
827
- this is a low-priority gap in practice, but the emitter should either detect `lod`
828
- opcode usage and fail translation explicitly, or provide a CPU-side/uniform-supplied LOD
829
- approximation, rather than emit a GLSL call that will not link on any real WebGL2
830
- implementation.
831
-
832
- **Confidence**: low — zero corpus occurrences means this reading has no cross-check
833
- against real Carbon effect output; the source reading itself (line-cited above) is
834
- unambiguous, but "will this ever actually appear" is unverified.
650
+
651
+ ## 11. `lod` (0 occurrences in corpus, spec required per task)
652
+
653
+ DXBC `LOD` returns `(ClampedLOD, NonClampedLOD, 0, 0)` without fetching
654
+ texels. `toGLSLInstruction.cpp:4161-4200` emits:
655
+
656
+ `dest = textureQueryLod(<tex>, <coord>)<returnSwizzle>;` for `LANG>=400`,
657
+ or extension spelling `textureQueryLOD` otherwise.
658
+
659
+ `HaveQueryLod` (`languages.h:238-245`) selects the function name
660
+ **inside instruction lowering**, unlike gather/resinfo's separate pragma
661
+ attempts. `AddVersionDependentCode` additionally tries the equally
662
+ ES300-ineffective `GL_ARB_texture_query_lod` extension
663
+ (`toGLSL.cpp:226-231`, gated by `!HaveQueryLod`).
664
+
665
+ **Bare-resource exception:** `TranslateOperand(&asOperands[2], TO_FLAG_NONE)`
666
+ (`:4185`) takes `OPERAND_TYPE_RESOURCE` through `ResourceName`
667
+ (`toGLSLOperand.cpp:1271-1275`), never `TextureSamplerName`.
668
+ Sampler operand `asOperands[3]` is unused. Even under the introduction's
669
+ combined-sampler default, `lod` therefore reads the bare `t#`/reflected
670
+ uniform (`toGLSLDeclaration.cpp:1659-1666`), not the paired sampling
671
+ symbol. Preserve this exception to §0; a bare sampler is declared, but it is
672
+ not the same uniform ordinary sampling calls use.
673
+
674
+ Coordinates share `TranslateTexCoord` (`:4187-4189`); result swizzling
675
+ is at `:4194-4197`. `AddAssignToDest(dest, SVT_FLOAT, 4, ...)`
676
+ (`:4171`) always declares a four-component float query result, independent
677
+ of texture return type.
678
+
679
+ For ES300, `HaveQueryLod` is false: the emitted extension-style name has
680
+ no unextended WebGL2 equivalent or browser core extension supplying it
681
+ (desktop `GL_ARB_texture_query_lod` / `GL_EXT_texture_query_lod` naming).
682
+ The study proposes `hlslcc_textureQueryLod` using a CPU/uniform-supplied
683
+ approximation, or explicit rejection. Zero observed uses makes this low priority,
684
+ not support evidence or permission to emit an un-linkable call.
685
+
686
+ **Edge cases**: none beyond standard coordinate range handling; no fetch occurs so no
687
+ wrap/border-color interaction applies.
688
+
689
+ **Confidence**: low — zero corpus occurrences means this reading has no cross-check
690
+ against real Carbon effect output; the source reading itself (line-cited above) is
691
+ unambiguous, but "will this ever actually appear" is unverified.
835
692
 
836
693
  ---
837
694
 
@@ -898,38 +755,18 @@ plus `toGLSLInstruction.cpp:1161-1170,1391-1423`.
898
755
  `gather4` above (ES 3.00 does not have it at all, regardless of constant-offset support).
899
756
 
900
757
  ---
901
-
902
- ## Helpers summary
903
-
904
- Helpers this family requires the JS emitter to define (native GLSL ES 3.00 builtins used
905
- directly — `texture`, `textureLod`, `textureGrad`, `texelFetch`, `textureSize`,
906
- `textureOffset`/`textureLodOffset`/`textureGradOffset`/`texelFetchOffset`, `dFdx`, `dFdy`,
907
- `floatBitsToInt`/`floatBitsToUint`/`intBitsToFloat`/`uintBitsToFloat` — are **not** listed
908
- here since they need no custom implementation):
909
-
910
- 1. **`hlslcc_textureGather4Emulated`** — mandatory. `textureGather`/`textureGatherOffset`
911
- do not exist in GLSL ES 3.00 (`HaveGather` excludes `LANG_ES_300`,
912
- `languages.h:220-227`), yet HLSLcc's GLSL backend emits them unconditionally for
913
- `gather4`/`gather4_po`/`gather4_po_c`/`gather4_c`. Must emulate via four texel taps
914
- (computed from `textureSize`) replicating D3D `Gather4`'s neighbor-selection order.
915
- Needed for both the plain-channel-gather and (separately, since component selection is
916
- unsupported there per source) the depth-compare gather variants.
917
- 2. **`hlslcc_textureQueryLevels`** — mandatory for `resinfo`'s 4th (mip-count) destination
918
- component only. `textureQueryLevels` requires `LANG >= 430`
919
- (`languages.h:247-254`) but `GetResInfoData` calls it with **no gate at all**
920
- (`toGLSLInstruction.cpp:1112-1127`). No WebGL2/ES-3.00 extension provides an equivalent;
921
- fallback strategy (out-of-band uniform, or explicit translation failure on this specific
922
- component) must be decided by the emitter.
923
- 3. **`hlslcc_textureQueryLod`** — needed only if the (zero-occurrence-so-far) `lod` opcode
924
- is ever exercised. `HaveQueryLod` correctly excludes `LANG_ES_300`
925
- (`languages.h:238-245`), and the resulting `textureQueryLOD(...)` extension name has no
926
- WebGL2-guaranteed equivalent either. Lowest priority of the three, but same class of gap.
927
- 4. **Depth-compare inline coordinate temp (`txVec<N>`)** — not a shared function, but a
928
- per-call-site codegen pattern (`vecK txVecN = vecK(coord, refZ);`) the emitter must
929
- replicate for `sample_c`/`sample_c_lz`/`gather4_po_c` on non-cube-array dimensions,
930
- using a monotonically increasing per-phase counter matching HLSLcc's
931
- `m_NextTexCoordTemp` (`toGLSLInstruction.cpp:1267`) to keep temp names collision-free.
932
-
933
- No helper is needed for `sample`, `sample_l`, `sample_b`, `sample_d`, `ld`, or the
934
- `deriv_rtx*`/`deriv_rty*` family — all of those map directly onto unconditional GLSL ES
935
- 3.00 core builtins.
758
+
759
+ ## Helpers summary
760
+
761
+ The opcode sections own these historical proposals and their qualification gates:
762
+
763
+ - §5: `hlslcc_textureGather4Emulated`, or explicit gather-family rejection.
764
+ - §9: `hlslcc_textureQueryLevels` for mip-count access only, or rejection.
765
+ - §11: `hlslcc_textureQueryLod` approximation or rejection; zero corpus uses.
766
+ - §6: per-call `txVec<N>`, numbered by `m_NextTexCoordTemp`; no shared
767
+ function. Gather forms never embed the reference in this temporary (§5).
768
+
769
+ This index replaces the old summary's conflicting “no gate at all” resinfo
770
+ claim and its inclusion of `gather4_po_c` in embedded-reference temporaries.
771
+ The corrected opcode descriptions govern; no fresh runtime support is implied.
772
+ Core sampling, derivative and bitcast builtins need no custom implementation.