@carbonenginejs/runtime 0.1.0-alpha.6 → 0.1.0-alpha.7
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.
Potentially problematic release.
This version of @carbonenginejs/runtime might be problematic. Click here for more details.
- package/dist/global/consts/effectPaths.js +4 -1
- package/dist/global/consts/effectPaths.js.map +1 -1
- package/dist/global/consts/index.js +1 -1
- package/dist/global/index.js +1 -1
- package/dist/index.js +3 -3
- package/dist/resource/format/carbonEffect/carbonEffectBackendBlock.js +19 -2
- package/dist/resource/format/carbonEffect/carbonEffectBackendBlock.js.map +1 -1
- package/dist/resource/format/index.js +1 -1
- package/dist/resource/formats/hlsl/core/carbonTypedViews.js +121 -65
- package/dist/resource/formats/hlsl/core/carbonTypedViews.js.map +1 -1
- package/dist/resource/formats/webgl/core/glsl/DxbcGlslEmitter.js +10 -7
- package/dist/resource/formats/webgl/core/glsl/DxbcGlslEmitter.js.map +1 -1
- package/dist/resource/formats/webgpu/core/effectBackendBodySet.js +3 -1
- package/dist/resource/formats/webgpu/core/effectBackendBodySet.js.map +1 -1
- package/dist/resource/formats/webgpu/core/packageEffect.js +5 -0
- package/dist/resource/formats/webgpu/core/packageEffect.js.map +1 -1
- package/dist/resource/formats/webgpu/core/wgsl/emitWgsl.js +20 -0
- package/dist/resource/formats/webgpu/core/wgsl/emitWgsl.js.map +1 -1
- package/dist/resource/formats/webgpu/core/wgsl/emulatedAddressing.js +93 -4
- package/dist/resource/formats/webgpu/core/wgsl/emulatedAddressing.js.map +1 -1
- package/dist/resource/formats/webgpu/core/wgsl/lowerBindingLayout.js +74 -64
- package/dist/resource/formats/webgpu/core/wgsl/lowerBindingLayout.js.map +1 -1
- package/dist/resource/formats/webgpu/core/wgsl/lowerFragmentProgram.js +16 -7
- package/dist/resource/formats/webgpu/core/wgsl/lowerFragmentProgram.js.map +1 -1
- package/dist/resource/formats/webgpu/core/wgsl/wgslTypedViews.js +69 -27
- package/dist/resource/formats/webgpu/core/wgsl/wgslTypedViews.js.map +1 -1
- package/dist/resource/geometry/registerGeometryResources.js +10 -1
- package/dist/resource/geometry/registerGeometryResources.js.map +1 -1
- package/dist/sof/EveSOFDNA.js +4 -2
- package/dist/sof/EveSOFDNA.js.map +1 -1
- package/dist/sof/EveSOFDataMgr.js +83 -69
- package/dist/sof/EveSOFDataMgr.js.map +1 -1
- package/dist/trinity/core/Tr2Denoiser.js +6 -1
- package/dist/trinity/core/Tr2Denoiser.js.map +1 -1
- package/dist/trinity/core/Tr2ShadowMap.js +7 -2
- package/dist/trinity/core/Tr2ShadowMap.js.map +1 -1
- package/dist/trinity/core/context/Tr2RenderContext.js +43 -0
- package/dist/trinity/core/context/Tr2RenderContext.js.map +1 -1
- package/dist/trinity/core/device/Tr2GpuStructuredBuffer.js +134 -0
- package/dist/trinity/core/device/Tr2GpuStructuredBuffer.js.map +1 -0
- package/dist/trinity/core/index.js +1 -0
- package/dist/trinity/core/index.js.map +1 -1
- package/dist/trinity/core/lighting/Tr2LightManager.js +410 -124
- package/dist/trinity/core/lighting/Tr2LightManager.js.map +1 -1
- package/dist/trinity/eve/effect/lensflare/EveLensflare.js +303 -312
- package/dist/trinity/eve/effect/lensflare/EveLensflare.js.map +1 -1
- package/dist/trinity/eve/effect/lensflare/EveOccluder.js +117 -0
- package/dist/trinity/eve/effect/lensflare/EveOccluder.js.map +1 -0
- package/dist/trinity/eve/index.js +1 -0
- package/dist/trinity/eve/index.js.map +1 -1
- package/dist/trinity/eve/scene/EveSpaceScene.js +286 -6
- package/dist/trinity/eve/scene/EveSpaceScene.js.map +1 -1
- package/dist/trinity/eve/scene/EveSpaceSceneRenderDriver.js +212 -32
- package/dist/trinity/eve/scene/EveSpaceSceneRenderDriver.js.map +1 -1
- package/dist/trinity/generated/eve/effect/index.js +0 -1
- package/dist/trinity/generated/eve/effect/index.js.map +1 -1
- package/dist/trinity/generated/eve/index.js +0 -1
- package/dist/trinity/generated/eve/index.js.map +1 -1
- package/dist/trinity/generated/index.js +0 -2
- package/dist/trinity/generated/index.js.map +1 -1
- package/dist/trinity/generated/trinityCore/index.js +0 -1
- package/dist/trinity/generated/trinityCore/index.js.map +1 -1
- package/dist/trinity/index.js +2 -2
- package/dist/trinity/postProcess/Tr2PostProcessRenderer.js +4 -1
- package/dist/trinity/postProcess/Tr2PostProcessRenderer.js.map +1 -1
- package/dist/trinity/postProcess/Tr2SSAO.js +282 -21
- package/dist/trinity/postProcess/Tr2SSAO.js.map +1 -1
- package/dist/trinity/shader/parameter/Tr2RuntimeTextureParameter.js +71 -53
- package/dist/trinity/shader/parameter/Tr2RuntimeTextureParameter.js.map +1 -1
- package/dist/trinityal/webgpu/CjsWebgpuRenderContextAL.js +81 -18
- package/dist/trinityal/webgpu/CjsWebgpuRenderContextAL.js.map +1 -1
- package/dist/trinityal/webgpu/CjsWebgpuResourceSetAL.js +46 -4
- package/dist/trinityal/webgpu/CjsWebgpuResourceSetAL.js.map +1 -1
- package/dist/trinityal/webgpu/CjsWebgpuShaderAL.js +32 -1
- package/dist/trinityal/webgpu/CjsWebgpuShaderAL.js.map +1 -1
- package/dist/trinityal/webgpu/CjsWebgpuShaderProgramAL.js +27 -0
- package/dist/trinityal/webgpu/CjsWebgpuShaderProgramAL.js.map +1 -1
- package/dist/trinityal/webgpu/CjsWebgpuTextureAL.js +29 -4
- package/dist/trinityal/webgpu/CjsWebgpuTextureAL.js.map +1 -1
- package/dist/trinityal/webgpu/core/CjsWebgpuPsoDescription.js +32 -2
- package/dist/trinityal/webgpu/core/CjsWebgpuPsoDescription.js.map +1 -1
- package/dist/trinityal/webgpu/core/CjsWebgpuUtils.js +57 -5
- package/dist/trinityal/webgpu/core/CjsWebgpuUtils.js.map +1 -1
- package/dist/trinityal/webgpu/core/CjsWebgpuWorkQueue.js +111 -5
- package/dist/trinityal/webgpu/core/CjsWebgpuWorkQueue.js.map +1 -1
- package/docs/trinity/reference/classes/generated.md +20 -20
- package/docs/trinity/reference/classes/post-process.md +1 -1
- package/package.json +1 -1
- package/dist/trinity/generated/eve/effect/EveOccluder.js +0 -38
- package/dist/trinity/generated/eve/effect/EveOccluder.js.map +0 -1
- package/dist/trinity/generated/trinityCore/Tr2GpuStructuredBuffer.js +0 -48
- package/dist/trinity/generated/trinityCore/Tr2GpuStructuredBuffer.js.map +0 -1
|
@@ -63,10 +63,16 @@ class CjsWebgpuResourceSetAL {
|
|
|
63
63
|
if (!description.m_registerMap.equals(program.GetRegisterMap())) return ALResult.E_INVALIDARG;
|
|
64
64
|
if (description.m_srv?.some(record => record.type === 3) || description.m_uav?.some(record => record.type === 3) || description.m_samplers?.some(record => record.type === 2)) return ALResult.E_FAIL;
|
|
65
65
|
const entries = new Map();
|
|
66
|
+
// The writable storage views bound so far, and the dummies handed out;
|
|
67
|
+
// see the storage-texture branch of _Resolve.
|
|
68
|
+
const storage = {
|
|
69
|
+
written: new Set(),
|
|
70
|
+
dummies: 0
|
|
71
|
+
};
|
|
66
72
|
for (const binding of program.GetBindings()) {
|
|
67
73
|
// Constant buffers are not the set's; see the head note.
|
|
68
74
|
if (binding.buffer && binding.buffer.type === "uniform") continue;
|
|
69
|
-
entries.set(`${binding.group}:${binding.binding}`, this._Resolve(description, binding, renderContext));
|
|
75
|
+
entries.set(`${binding.group}:${binding.binding}`, this._Resolve(description, binding, renderContext, storage));
|
|
70
76
|
}
|
|
71
77
|
this.m_entries = entries;
|
|
72
78
|
this.m_description = description;
|
|
@@ -77,7 +83,7 @@ class CjsWebgpuResourceSetAL {
|
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
/** One slot's resource, or the dummy Metal would put there. */
|
|
80
|
-
_Resolve(description, binding, renderContext) {
|
|
86
|
+
_Resolve(description, binding, renderContext, storage) {
|
|
81
87
|
if (binding.sampler) {
|
|
82
88
|
const slot = SlotFor(description, "sampler", binding);
|
|
83
89
|
const state = slot?.type === 1 ? slot.sampler : null;
|
|
@@ -94,15 +100,29 @@ class CjsWebgpuResourceSetAL {
|
|
|
94
100
|
|
|
95
101
|
// A storage texture is a UAV bound at one mip; the description keeps the mip
|
|
96
102
|
// in the slot's colour-space word (Tr2ResourceSetDescriptionAL.SetUav).
|
|
103
|
+
//
|
|
104
|
+
// WEBGPU REFUSES TWO WRITABLE BINDINGS OF ONE SUBRESOURCE in a dispatch or
|
|
105
|
+
// draw, where D3D allows them: Carbon binds CORTAO's pack slots past the
|
|
106
|
+
// last mip to the last mip (Tr2SSAO.cpp:659-665), and the kernel never
|
|
107
|
+
// writes those slots. A repeat takes a dummy instead, as an empty slot
|
|
108
|
+
// does, and each dummy is the slot's own, so no two dummies alias either.
|
|
109
|
+
// A texture's storage view is cached per mip, so the view is the
|
|
110
|
+
// subresource's identity.
|
|
97
111
|
if (binding.storageTexture) {
|
|
98
112
|
const slot = SlotFor(description, "uav", binding);
|
|
99
113
|
const texture = slot?.type === 2 ? slot.texture : null;
|
|
100
114
|
const {
|
|
101
115
|
format,
|
|
102
|
-
viewDimension
|
|
116
|
+
viewDimension,
|
|
117
|
+
access
|
|
103
118
|
} = binding.storageTexture;
|
|
104
119
|
const view = texture && typeof texture.GetDeviceStorageView === "function" ? texture.GetDeviceStorageView(viewDimension, slot.colorSpace) : null;
|
|
105
|
-
|
|
120
|
+
const writable = access !== "read-only";
|
|
121
|
+
if (view && !(writable && storage.written.has(view))) {
|
|
122
|
+
if (writable) storage.written.add(view);
|
|
123
|
+
return view;
|
|
124
|
+
}
|
|
125
|
+
return renderContext.GetDummyStorageTexture(format, viewDimension, storage.dummies++);
|
|
106
126
|
}
|
|
107
127
|
|
|
108
128
|
// A storage buffer: read-only ones are SRVs, writable ones UAVs.
|
|
@@ -115,6 +135,28 @@ class CjsWebgpuResourceSetAL {
|
|
|
115
135
|
};
|
|
116
136
|
}
|
|
117
137
|
|
|
138
|
+
/**
|
|
139
|
+
* The authored address modes of this set's pixel-stage sampler states, one
|
|
140
|
+
* `vec4` (U, V, W, 0) per sampler register, for the emulated-addressing
|
|
141
|
+
* modes buffer (`CARBON_BACKEND_ADDRESS_MODES_SYMBOL`). Zero where no state
|
|
142
|
+
* is bound, which the shader reads as "nothing to emulate".
|
|
143
|
+
*
|
|
144
|
+
* @param {number} registerCount How many sampler registers the buffer covers.
|
|
145
|
+
* @returns {Float32Array} The buffer's contents.
|
|
146
|
+
*/
|
|
147
|
+
GetAddressModes(registerCount) {
|
|
148
|
+
const modes = new Float32Array(registerCount * 4);
|
|
149
|
+
for (let registerIndex = 0; registerIndex < registerCount; registerIndex += 1) {
|
|
150
|
+
const slot = this.m_description ? SlotFor(this.m_description, "sampler", {
|
|
151
|
+
visibility: 2,
|
|
152
|
+
registerIndex
|
|
153
|
+
}) : null;
|
|
154
|
+
const description = slot?.type === 1 ? slot.sampler.GetDescription() : null;
|
|
155
|
+
if (description) modes.set([description.addressU, description.addressV, description.addressW, 0], registerIndex * 4);
|
|
156
|
+
}
|
|
157
|
+
return modes;
|
|
158
|
+
}
|
|
159
|
+
|
|
118
160
|
/** The resolved entries by `"group:binding"`. @returns {Map<string, object>} */
|
|
119
161
|
GetEntries() {
|
|
120
162
|
return this.m_entries;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CjsWebgpuResourceSetAL.js","sources":["../../../../src/trinityal/webgpu/CjsWebgpuResourceSetAL.js"],"sourcesContent":["// Source: trinity/trinityal/include/Tr2ResourceSetAL.h\r\n// trinity/trinityal/metal/Tr2ResourceSetALMetal.mm\r\n// trinity/trinityal/dx12/Tr2ResourceSetALDx12.cpp\r\n//\r\n// A `Tr2ResourceSetAL` for WebGPU: the description's textures, samplers and\r\n// buffers resolved against the program's bindings, ready to become bind groups.\r\n//\r\n// WHAT IT HOLDS AND WHAT IT DOES NOT. Carbon's description carries SRVs, UAVs\r\n// and samplers; constant buffers are NOT in it (`Tr2ResourceSetAL.h:57-65` has\r\n// no `SetConstantBuffer`) - they travel `SetConstants` and are bound beside the\r\n// set at the draw (DX12 root CBVs via `m_cbRegisters`, Metal's const-buffer\r\n// offset region). So this resolves every non-uniform slot of the program's\r\n// layout at Create, as Metal's `Create` fills its per-stage native arrays\r\n// (`Tr2ResourceSetALMetal.mm:57-279`), and the render context assembles each\r\n// `GPUBindGroup` from these entries plus the bound constant buffers when it\r\n// draws - a bind group being immutable, it can only exist once both halves are\r\n// known.\r\n//\r\n// UNFILLED SLOTS GET DUMMIES, AS METAL'S DO. Metal seeds its masks from the\r\n// program's requirements and fills what the description left empty with\r\n// `GetDummyTexture` / `GetDummySampler` (`:240-265`); DX12 substitutes null\r\n// views (`Tr2ResourceSetALDx12.cpp:145-146`). A WebGPU bind group with a hole\r\n// is a validation error, so the same substitution happens here.\r\n//\r\nimport { CjsSchema, impl } from \"#schema\";\r\nimport { ALResult, Tr2ALMemoryType } from \"#trinityal\";\r\nimport { ShaderType } from \"#consts/render-context\";\r\n\r\n/** GPUShaderStage bits to the Carbon stage whose description slot answers. */\r\nconst STAGE_OF_VISIBILITY = Object.freeze([\r\n [ 1, ShaderType.VERTEX_SHADER ],\r\n [ 2, ShaderType.PIXEL_SHADER ],\r\n [ 4, ShaderType.COMPUTE_SHADER ]\r\n]);\r\n\r\nlet nextResourceSetId = 1;\r\n\r\n\r\n/**\r\n * The description slot a binding reads, trying each stage it is visible to.\r\n *\r\n * A binding two stages share was merged by the container because both read\r\n * the same register; whichever stage the material filled answers.\r\n */\r\nfunction SlotFor(description, kind, binding)\r\n{\r\n for (const [ bit, stage ] of STAGE_OF_VISIBILITY)\r\n {\r\n if ((binding.visibility & bit) === 0) continue;\r\n\r\n const map = description.m_registerMap;\r\n const slots = kind === \"srv\" ? map.srvs : kind === \"uav\" ? map.uavs : map.samplers;\r\n const records = kind === \"srv\" ? description.m_srv : kind === \"uav\" ? description.m_uav : description.m_samplers;\r\n const slot = records?.[slots[stage][binding.registerIndex]];\r\n if (slot && slot.type !== 0) return slot;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n\r\n/**\r\n * A `Tr2ResourceSetAL` holding the resolved bindings a draw's bind groups are\r\n * assembled from.\r\n */\r\nexport class CjsWebgpuResourceSetAL\r\n{\r\n /** A process-unique identity, for the context's bind-group cache. Zero until Create. */\r\n m_id = 0;\r\n\r\n m_description = null;\r\n\r\n m_program = null;\r\n\r\n /** `\"group:binding\"` to the `GPUBindingResource` that fills it, non-uniform slots only. */\r\n m_entries = new Map();\r\n\r\n /**\r\n * Resolves the description against the program.\r\n *\r\n * @param {object} description A `Tr2ResourceSetDescriptionAL`.\r\n * @param {object} program The `CjsWebgpuShaderProgramAL` this set binds against.\r\n * @param {object} renderContext The WebGPU render context AL.\r\n * @returns {number} An `ALResult` value.\r\n */\r\n @impl.adapted\r\n @impl.reason(\"WebGPU resolves native dense records into bind-group entries, validates the program map and fills missing resources with dummies. Descriptor heap views have no WebGPU representation and return E_FAIL.\")\r\n Create(description, program, renderContext)\r\n {\r\n this.Destroy();\r\n\r\n if (!renderContext || !renderContext.IsValid()) return ALResult.E_INVALIDARG;\r\n if (!description) return ALResult.E_INVALIDARG;\r\n\r\n // DX12 refuses a description whose register map is not the program's\r\n // (`Tr2ResourceSetALDx12.cpp:78-81`); a program this backend did not link\r\n // has no bindings to lay out against, which is the same refusal.\r\n if (!program || typeof program.GetBindings !== \"function\" || !program.IsValid()) return ALResult.E_INVALIDARG;\r\n\r\n if (!description.m_registerMap.equals(program.GetRegisterMap())) return ALResult.E_INVALIDARG;\r\n\r\n if (description.m_srv?.some(record => record.type === 3)\r\n || description.m_uav?.some(record => record.type === 3)\r\n || description.m_samplers?.some(record => record.type === 2)) return ALResult.E_FAIL;\r\n\r\n const entries = new Map();\r\n\r\n for (const binding of program.GetBindings())\r\n {\r\n // Constant buffers are not the set's; see the head note.\r\n if (binding.buffer && binding.buffer.type === \"uniform\") continue;\r\n\r\n entries.set(`${binding.group}:${binding.binding}`, this._Resolve(description, binding, renderContext));\r\n }\r\n\r\n this.m_entries = entries;\r\n this.m_description = description;\r\n this.m_program = program;\r\n this.m_id = nextResourceSetId;\r\n nextResourceSetId += 1;\r\n\r\n return ALResult.S_OK;\r\n }\r\n\r\n /** One slot's resource, or the dummy Metal would put there. */\r\n @impl.adapted\r\n @impl.reason(\"Resolves dense native records to WebGPU views and buffers; a pending resource or empty slot uses the context dummy, following Metal.\")\r\n _Resolve(description, binding, renderContext)\r\n {\r\n if (binding.sampler)\r\n {\r\n const slot = SlotFor(description, \"sampler\", binding);\r\n const state = slot?.type === 1 ? slot.sampler : null;\r\n const sampler = state && typeof state.GetSampler === \"function\" ? state.GetSampler() : null;\r\n\r\n return sampler ?? renderContext.GetDummySampler();\r\n }\r\n\r\n if (binding.texture)\r\n {\r\n const slot = SlotFor(description, \"srv\", binding);\r\n const texture = slot?.type === 2 ? slot.texture : null;\r\n const dimension = binding.texture.viewDimension ?? \"2d\";\r\n const view = texture && typeof texture.GetDeviceTextureView === \"function\"\r\n ? texture.GetDeviceTextureView(dimension, slot.colorSpace)\r\n : null;\r\n\r\n return view ?? renderContext.GetDummyTexture(dimension);\r\n }\r\n\r\n // A storage texture is a UAV bound at one mip; the description keeps the mip\r\n // in the slot's colour-space word (Tr2ResourceSetDescriptionAL.SetUav).\r\n if (binding.storageTexture)\r\n {\r\n const slot = SlotFor(description, \"uav\", binding);\r\n const texture = slot?.type === 2 ? slot.texture : null;\r\n const { format, viewDimension } = binding.storageTexture;\r\n const view = texture && typeof texture.GetDeviceStorageView === \"function\"\r\n ? texture.GetDeviceStorageView(viewDimension, slot.colorSpace)\r\n : null;\r\n\r\n return view ?? renderContext.GetDummyStorageTexture(format, viewDimension);\r\n }\r\n\r\n // A storage buffer: read-only ones are SRVs, writable ones UAVs.\r\n const kind = binding.buffer && binding.buffer.type === \"storage\" ? \"uav\" : \"srv\";\r\n const slot = SlotFor(description, kind, binding);\r\n const resource = slot?.type === 1 ? slot.buffer : null;\r\n const buffer = resource && typeof resource.GetDeviceBuffer === \"function\" ? resource.GetDeviceBuffer() : null;\r\n\r\n return { buffer: buffer ?? renderContext.GetNullBuffer(binding.buffer?.minBindingSize ?? 16, \"STORAGE\") };\r\n }\r\n\r\n /** The resolved entries by `\"group:binding\"`. @returns {Map<string, object>} */\r\n GetEntries()\r\n {\r\n return this.m_entries;\r\n }\r\n\r\n /** The `Tr2ResourceSetDescriptionAL` it was created from, or null. */\r\n GetDescription()\r\n {\r\n return this.m_description;\r\n }\r\n\r\n /** The shader program whose bindings were resolved, or null. */\r\n GetProgram()\r\n {\r\n return this.m_program;\r\n }\r\n\r\n /** Whether the set has been created and carries an identity. */\r\n IsValid()\r\n {\r\n return this.m_id !== 0;\r\n }\r\n\r\n /** Drops the resolved entries, leaving the set invalid. */\r\n Destroy()\r\n {\r\n this.m_entries = new Map();\r\n this.m_description = null;\r\n this.m_program = null;\r\n this.m_id = 0;\r\n }\r\n\r\n /** Where the set lives, which is managed memory rather than the device. */\r\n GetMemoryClass()\r\n {\r\n return Tr2ALMemoryType.AL_MEMORY_MANAGED;\r\n }\r\n\r\n /**\r\n * Fills in a device-resource description.\r\n *\r\n * @param {object} description The description to fill.\r\n * @returns {object} The description, filled.\r\n */\r\n Describe(description)\r\n {\r\n if (!description) return description;\r\n\r\n description.memoryClass = this.GetMemoryClass();\r\n\r\n return description;\r\n }\r\n\r\n /**\r\n * Nothing here carries a label - the bind groups the context builds do.\r\n *\r\n * @returns {number} `S_OK`.\r\n */\r\n SetName(_name)\r\n {\r\n return ALResult.S_OK;\r\n }\r\n}\r\n\r\n// DECLARED AS A CALL, NOT A DECORATOR, for the reason recorded in\r\n// Tr2BitmapDimensions.js: the layer is imported straight from source by its\r\n// tests and raw Node cannot parse decorator syntax.\r\n//\r\n// The donor is NAMED rather than left to be derived from this class's name.\r\n// Carbon calls every backend's class the same thing and carries the backend in\r\n// the FILE name, because only one backend compiles at a time; we ship them\r\n// together, so the backend moves onto the class name. That divergence is the\r\n// author's to declare, never a checker's to guess.\r\nCjsSchema.define(CjsWebgpuResourceSetAL, { className: \"CjsWebgpuResourceSetAL\", carbon: \"Tr2ResourceSetAL\" });\r\n"],"names":["STAGE_OF_VISIBILITY","Object","freeze","ShaderType","VERTEX_SHADER","PIXEL_SHADER","COMPUTE_SHADER","nextResourceSetId","SlotFor","description","kind","binding","bit","stage","visibility","map","m_registerMap","slots","srvs","uavs","samplers","records","m_srv","m_uav","m_samplers","slot","registerIndex","type","CjsWebgpuResourceSetAL","_initProto","_applyDecs","impl","adapted","reason","e","m_id","m_description","m_program","m_entries","Map","Create","program","renderContext","Destroy","IsValid","ALResult","E_INVALIDARG","GetBindings","equals","GetRegisterMap","some","record","E_FAIL","entries","buffer","set","group","_Resolve","S_OK","sampler","state","GetSampler","GetDummySampler","texture","dimension","viewDimension","view","GetDeviceTextureView","colorSpace","GetDummyTexture","storageTexture","format","GetDeviceStorageView","GetDummyStorageTexture","resource","GetDeviceBuffer","GetNullBuffer","minBindingSize","GetEntries","GetDescription","GetProgram","GetMemoryClass","Tr2ALMemoryType","AL_MEMORY_MANAGED","Describe","memoryClass","SetName","_name","CjsSchema","define","className","carbon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CjsWebgpuResourceSetAL.js","sources":["../../../../src/trinityal/webgpu/CjsWebgpuResourceSetAL.js"],"sourcesContent":["// Source: trinity/trinityal/include/Tr2ResourceSetAL.h\r\n// trinity/trinityal/metal/Tr2ResourceSetALMetal.mm\r\n// trinity/trinityal/dx12/Tr2ResourceSetALDx12.cpp\r\n//\r\n// A `Tr2ResourceSetAL` for WebGPU: the description's textures, samplers and\r\n// buffers resolved against the program's bindings, ready to become bind groups.\r\n//\r\n// WHAT IT HOLDS AND WHAT IT DOES NOT. Carbon's description carries SRVs, UAVs\r\n// and samplers; constant buffers are NOT in it (`Tr2ResourceSetAL.h:57-65` has\r\n// no `SetConstantBuffer`) - they travel `SetConstants` and are bound beside the\r\n// set at the draw (DX12 root CBVs via `m_cbRegisters`, Metal's const-buffer\r\n// offset region). So this resolves every non-uniform slot of the program's\r\n// layout at Create, as Metal's `Create` fills its per-stage native arrays\r\n// (`Tr2ResourceSetALMetal.mm:57-279`), and the render context assembles each\r\n// `GPUBindGroup` from these entries plus the bound constant buffers when it\r\n// draws - a bind group being immutable, it can only exist once both halves are\r\n// known.\r\n//\r\n// UNFILLED SLOTS GET DUMMIES, AS METAL'S DO. Metal seeds its masks from the\r\n// program's requirements and fills what the description left empty with\r\n// `GetDummyTexture` / `GetDummySampler` (`:240-265`); DX12 substitutes null\r\n// views (`Tr2ResourceSetALDx12.cpp:145-146`). A WebGPU bind group with a hole\r\n// is a validation error, so the same substitution happens here.\r\n//\r\nimport { CjsSchema, impl } from \"#schema\";\r\nimport { ALResult, Tr2ALMemoryType } from \"#trinityal\";\r\nimport { ShaderType } from \"#consts/render-context\";\r\n\r\n/** GPUShaderStage bits to the Carbon stage whose description slot answers. */\r\nconst STAGE_OF_VISIBILITY = Object.freeze([\r\n [ 1, ShaderType.VERTEX_SHADER ],\r\n [ 2, ShaderType.PIXEL_SHADER ],\r\n [ 4, ShaderType.COMPUTE_SHADER ]\r\n]);\r\n\r\nlet nextResourceSetId = 1;\r\n\r\n\r\n/**\r\n * The description slot a binding reads, trying each stage it is visible to.\r\n *\r\n * A binding two stages share was merged by the container because both read\r\n * the same register; whichever stage the material filled answers.\r\n */\r\nfunction SlotFor(description, kind, binding)\r\n{\r\n for (const [ bit, stage ] of STAGE_OF_VISIBILITY)\r\n {\r\n if ((binding.visibility & bit) === 0) continue;\r\n\r\n const map = description.m_registerMap;\r\n const slots = kind === \"srv\" ? map.srvs : kind === \"uav\" ? map.uavs : map.samplers;\r\n const records = kind === \"srv\" ? description.m_srv : kind === \"uav\" ? description.m_uav : description.m_samplers;\r\n const slot = records?.[slots[stage][binding.registerIndex]];\r\n if (slot && slot.type !== 0) return slot;\r\n }\r\n\r\n return null;\r\n}\r\n\r\n\r\n/**\r\n * A `Tr2ResourceSetAL` holding the resolved bindings a draw's bind groups are\r\n * assembled from.\r\n */\r\nexport class CjsWebgpuResourceSetAL\r\n{\r\n /** A process-unique identity, for the context's bind-group cache. Zero until Create. */\r\n m_id = 0;\r\n\r\n m_description = null;\r\n\r\n m_program = null;\r\n\r\n /** `\"group:binding\"` to the `GPUBindingResource` that fills it, non-uniform slots only. */\r\n m_entries = new Map();\r\n\r\n /**\r\n * Resolves the description against the program.\r\n *\r\n * @param {object} description A `Tr2ResourceSetDescriptionAL`.\r\n * @param {object} program The `CjsWebgpuShaderProgramAL` this set binds against.\r\n * @param {object} renderContext The WebGPU render context AL.\r\n * @returns {number} An `ALResult` value.\r\n */\r\n @impl.adapted\r\n @impl.reason(\"WebGPU resolves native dense records into bind-group entries, validates the program map and fills missing resources with dummies. Descriptor heap views have no WebGPU representation and return E_FAIL.\")\r\n Create(description, program, renderContext)\r\n {\r\n this.Destroy();\r\n\r\n if (!renderContext || !renderContext.IsValid()) return ALResult.E_INVALIDARG;\r\n if (!description) return ALResult.E_INVALIDARG;\r\n\r\n // DX12 refuses a description whose register map is not the program's\r\n // (`Tr2ResourceSetALDx12.cpp:78-81`); a program this backend did not link\r\n // has no bindings to lay out against, which is the same refusal.\r\n if (!program || typeof program.GetBindings !== \"function\" || !program.IsValid()) return ALResult.E_INVALIDARG;\r\n\r\n if (!description.m_registerMap.equals(program.GetRegisterMap())) return ALResult.E_INVALIDARG;\r\n\r\n if (description.m_srv?.some(record => record.type === 3)\r\n || description.m_uav?.some(record => record.type === 3)\r\n || description.m_samplers?.some(record => record.type === 2)) return ALResult.E_FAIL;\r\n\r\n const entries = new Map();\r\n // The writable storage views bound so far, and the dummies handed out;\r\n // see the storage-texture branch of _Resolve.\r\n const storage = { written: new Set(), dummies: 0 };\r\n\r\n for (const binding of program.GetBindings())\r\n {\r\n // Constant buffers are not the set's; see the head note.\r\n if (binding.buffer && binding.buffer.type === \"uniform\") continue;\r\n\r\n entries.set(`${binding.group}:${binding.binding}`, this._Resolve(description, binding, renderContext, storage));\r\n }\r\n\r\n this.m_entries = entries;\r\n this.m_description = description;\r\n this.m_program = program;\r\n this.m_id = nextResourceSetId;\r\n nextResourceSetId += 1;\r\n\r\n return ALResult.S_OK;\r\n }\r\n\r\n /** One slot's resource, or the dummy Metal would put there. */\r\n @impl.adapted\r\n @impl.reason(\"Resolves dense native records to WebGPU views and buffers; a pending resource or empty slot uses the context dummy, following Metal.\")\r\n _Resolve(description, binding, renderContext, storage)\r\n {\r\n if (binding.sampler)\r\n {\r\n const slot = SlotFor(description, \"sampler\", binding);\r\n const state = slot?.type === 1 ? slot.sampler : null;\r\n const sampler = state && typeof state.GetSampler === \"function\" ? state.GetSampler() : null;\r\n\r\n return sampler ?? renderContext.GetDummySampler();\r\n }\r\n\r\n if (binding.texture)\r\n {\r\n const slot = SlotFor(description, \"srv\", binding);\r\n const texture = slot?.type === 2 ? slot.texture : null;\r\n const dimension = binding.texture.viewDimension ?? \"2d\";\r\n const view = texture && typeof texture.GetDeviceTextureView === \"function\"\r\n ? texture.GetDeviceTextureView(dimension, slot.colorSpace)\r\n : null;\r\n\r\n return view ?? renderContext.GetDummyTexture(dimension);\r\n }\r\n\r\n // A storage texture is a UAV bound at one mip; the description keeps the mip\r\n // in the slot's colour-space word (Tr2ResourceSetDescriptionAL.SetUav).\r\n //\r\n // WEBGPU REFUSES TWO WRITABLE BINDINGS OF ONE SUBRESOURCE in a dispatch or\r\n // draw, where D3D allows them: Carbon binds CORTAO's pack slots past the\r\n // last mip to the last mip (Tr2SSAO.cpp:659-665), and the kernel never\r\n // writes those slots. A repeat takes a dummy instead, as an empty slot\r\n // does, and each dummy is the slot's own, so no two dummies alias either.\r\n // A texture's storage view is cached per mip, so the view is the\r\n // subresource's identity.\r\n if (binding.storageTexture)\r\n {\r\n const slot = SlotFor(description, \"uav\", binding);\r\n const texture = slot?.type === 2 ? slot.texture : null;\r\n const { format, viewDimension, access } = binding.storageTexture;\r\n const view = texture && typeof texture.GetDeviceStorageView === \"function\"\r\n ? texture.GetDeviceStorageView(viewDimension, slot.colorSpace)\r\n : null;\r\n const writable = access !== \"read-only\";\r\n\r\n if (view && !(writable && storage.written.has(view)))\r\n {\r\n if (writable) storage.written.add(view);\r\n return view;\r\n }\r\n\r\n return renderContext.GetDummyStorageTexture(format, viewDimension, storage.dummies++);\r\n }\r\n\r\n // A storage buffer: read-only ones are SRVs, writable ones UAVs.\r\n const kind = binding.buffer && binding.buffer.type === \"storage\" ? \"uav\" : \"srv\";\r\n const slot = SlotFor(description, kind, binding);\r\n const resource = slot?.type === 1 ? slot.buffer : null;\r\n const buffer = resource && typeof resource.GetDeviceBuffer === \"function\" ? resource.GetDeviceBuffer() : null;\r\n\r\n return { buffer: buffer ?? renderContext.GetNullBuffer(binding.buffer?.minBindingSize ?? 16, \"STORAGE\") };\r\n }\r\n\r\n /**\r\n * The authored address modes of this set's pixel-stage sampler states, one\r\n * `vec4` (U, V, W, 0) per sampler register, for the emulated-addressing\r\n * modes buffer (`CARBON_BACKEND_ADDRESS_MODES_SYMBOL`). Zero where no state\r\n * is bound, which the shader reads as \"nothing to emulate\".\r\n *\r\n * @param {number} registerCount How many sampler registers the buffer covers.\r\n * @returns {Float32Array} The buffer's contents.\r\n */\r\n GetAddressModes(registerCount)\r\n {\r\n const modes = new Float32Array(registerCount * 4);\r\n\r\n for (let registerIndex = 0; registerIndex < registerCount; registerIndex += 1)\r\n {\r\n const slot = this.m_description ? SlotFor(this.m_description, \"sampler\", { visibility: 2, registerIndex }) : null;\r\n const description = slot?.type === 1 ? slot.sampler.GetDescription() : null;\r\n\r\n if (description) modes.set([ description.addressU, description.addressV, description.addressW, 0 ], registerIndex * 4);\r\n }\r\n\r\n return modes;\r\n }\r\n\r\n /** The resolved entries by `\"group:binding\"`. @returns {Map<string, object>} */\r\n GetEntries()\r\n {\r\n return this.m_entries;\r\n }\r\n\r\n /** The `Tr2ResourceSetDescriptionAL` it was created from, or null. */\r\n GetDescription()\r\n {\r\n return this.m_description;\r\n }\r\n\r\n /** The shader program whose bindings were resolved, or null. */\r\n GetProgram()\r\n {\r\n return this.m_program;\r\n }\r\n\r\n /** Whether the set has been created and carries an identity. */\r\n IsValid()\r\n {\r\n return this.m_id !== 0;\r\n }\r\n\r\n /** Drops the resolved entries, leaving the set invalid. */\r\n Destroy()\r\n {\r\n this.m_entries = new Map();\r\n this.m_description = null;\r\n this.m_program = null;\r\n this.m_id = 0;\r\n }\r\n\r\n /** Where the set lives, which is managed memory rather than the device. */\r\n GetMemoryClass()\r\n {\r\n return Tr2ALMemoryType.AL_MEMORY_MANAGED;\r\n }\r\n\r\n /**\r\n * Fills in a device-resource description.\r\n *\r\n * @param {object} description The description to fill.\r\n * @returns {object} The description, filled.\r\n */\r\n Describe(description)\r\n {\r\n if (!description) return description;\r\n\r\n description.memoryClass = this.GetMemoryClass();\r\n\r\n return description;\r\n }\r\n\r\n /**\r\n * Nothing here carries a label - the bind groups the context builds do.\r\n *\r\n * @returns {number} `S_OK`.\r\n */\r\n SetName(_name)\r\n {\r\n return ALResult.S_OK;\r\n }\r\n}\r\n\r\n// DECLARED AS A CALL, NOT A DECORATOR, for the reason recorded in\r\n// Tr2BitmapDimensions.js: the layer is imported straight from source by its\r\n// tests and raw Node cannot parse decorator syntax.\r\n//\r\n// The donor is NAMED rather than left to be derived from this class's name.\r\n// Carbon calls every backend's class the same thing and carries the backend in\r\n// the FILE name, because only one backend compiles at a time; we ship them\r\n// together, so the backend moves onto the class name. That divergence is the\r\n// author's to declare, never a checker's to guess.\r\nCjsSchema.define(CjsWebgpuResourceSetAL, { className: \"CjsWebgpuResourceSetAL\", carbon: \"Tr2ResourceSetAL\" });\r\n"],"names":["STAGE_OF_VISIBILITY","Object","freeze","ShaderType","VERTEX_SHADER","PIXEL_SHADER","COMPUTE_SHADER","nextResourceSetId","SlotFor","description","kind","binding","bit","stage","visibility","map","m_registerMap","slots","srvs","uavs","samplers","records","m_srv","m_uav","m_samplers","slot","registerIndex","type","CjsWebgpuResourceSetAL","_initProto","_applyDecs","impl","adapted","reason","e","m_id","m_description","m_program","m_entries","Map","Create","program","renderContext","Destroy","IsValid","ALResult","E_INVALIDARG","GetBindings","equals","GetRegisterMap","some","record","E_FAIL","entries","storage","written","Set","dummies","buffer","set","group","_Resolve","S_OK","sampler","state","GetSampler","GetDummySampler","texture","dimension","viewDimension","view","GetDeviceTextureView","colorSpace","GetDummyTexture","storageTexture","format","access","GetDeviceStorageView","writable","has","add","GetDummyStorageTexture","resource","GetDeviceBuffer","GetNullBuffer","minBindingSize","GetAddressModes","registerCount","modes","Float32Array","GetDescription","addressU","addressV","addressW","GetEntries","GetProgram","GetMemoryClass","Tr2ALMemoryType","AL_MEMORY_MANAGED","Describe","memoryClass","SetName","_name","CjsSchema","define","className","carbon"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CjsSchema } from '#schema';
|
|
2
2
|
import { ALResult, Tr2ALMemoryType } from '#trinityal';
|
|
3
3
|
import { ShaderType } from '#consts/render-context';
|
|
4
|
-
import { readBackendBlock } from '#resource/format';
|
|
4
|
+
import { readBackendBlock, CARBON_BACKEND_UNORM_TARGET_OVERRIDE } from '#resource/format';
|
|
5
5
|
|
|
6
6
|
// Source: trinity/trinityal/include/Tr2ShaderAL.h
|
|
7
7
|
// trinity/trinityal/stub/Tr2ShaderALStub.cpp
|
|
@@ -88,6 +88,19 @@ function FragmentOutputLocations(source) {
|
|
|
88
88
|
return direct ? [Number(direct[1])] : [];
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* The colour locations whose UNORM override a fragment stage declares
|
|
93
|
+
* (CARBON_BACKEND_UNORM_TARGET_OVERRIDE). A pipeline may set only overrides
|
|
94
|
+
* the module declares, so a hand-written stage without them gets none.
|
|
95
|
+
*
|
|
96
|
+
* @param {string} source The stage's WGSL.
|
|
97
|
+
* @returns {number[]} The locations, ascending.
|
|
98
|
+
*/
|
|
99
|
+
function UnormTargetOverrides(source) {
|
|
100
|
+
const pattern = new RegExp(`override\\s+${CARBON_BACKEND_UNORM_TARGET_OVERRIDE}(\\d+)\\s*:`, "gu");
|
|
101
|
+
return Array.from(source.matchAll(pattern), match => Number(match[1])).sort((a, b) => a - b);
|
|
102
|
+
}
|
|
103
|
+
|
|
91
104
|
/**
|
|
92
105
|
* The bind-group declarations visible to one stage, decoded from the block on
|
|
93
106
|
* its signature.
|
|
@@ -121,6 +134,9 @@ function StageBindings(type, signature) {
|
|
|
121
134
|
resourceKind: binding.resourceKind,
|
|
122
135
|
registerIndex: binding.registerIndex,
|
|
123
136
|
registerSpace: binding.registerSpace,
|
|
137
|
+
// The backend tells a binding it fills itself by its symbol: the
|
|
138
|
+
// emulated-addressing modes buffer (CARBON_BACKEND_ADDRESS_MODES_SYMBOL).
|
|
139
|
+
generatedSymbol: binding.generatedSymbol,
|
|
124
140
|
// Exactly one of these is present, already in GPUBindGroupLayoutEntry
|
|
125
141
|
// form - the reader derives it from the WGSL type text.
|
|
126
142
|
buffer: binding.buffer,
|
|
@@ -156,6 +172,9 @@ class CjsWebgpuShaderAL {
|
|
|
156
172
|
|
|
157
173
|
/** The colour locations a pixel stage writes (FragmentOutputLocations). */
|
|
158
174
|
m_outputs = [];
|
|
175
|
+
|
|
176
|
+
/** The colour locations whose UNORM override the stage declares. */
|
|
177
|
+
m_unormOverrides = [];
|
|
159
178
|
m_webgpu = null;
|
|
160
179
|
|
|
161
180
|
/**
|
|
@@ -216,9 +235,20 @@ class CjsWebgpuShaderAL {
|
|
|
216
235
|
this.m_bindings = bindings;
|
|
217
236
|
this.m_inputs = Array.isArray(signature?.pipelineInputs) ? signature.pipelineInputs.slice() : [];
|
|
218
237
|
this.m_outputs = type === ShaderType.PIXEL_SHADER ? FragmentOutputLocations(this.m_source) : [];
|
|
238
|
+
this.m_unormOverrides = type === ShaderType.PIXEL_SHADER ? UnormTargetOverrides(this.m_source) : [];
|
|
219
239
|
return ALResult.S_OK;
|
|
220
240
|
}
|
|
221
241
|
|
|
242
|
+
/**
|
|
243
|
+
* The colour locations whose UNORM override a pixel stage declares; empty
|
|
244
|
+
* for any other stage, and for a hand-written one without them.
|
|
245
|
+
*
|
|
246
|
+
* @returns {number[]} The locations, ascending.
|
|
247
|
+
*/
|
|
248
|
+
GetUnormTargetOverrides() {
|
|
249
|
+
return this.m_unormOverrides;
|
|
250
|
+
}
|
|
251
|
+
|
|
222
252
|
/**
|
|
223
253
|
* The colour locations a pixel stage writes; empty for any other stage.
|
|
224
254
|
*
|
|
@@ -282,6 +312,7 @@ class CjsWebgpuShaderAL {
|
|
|
282
312
|
this.m_bindings = [];
|
|
283
313
|
this.m_inputs = [];
|
|
284
314
|
this.m_outputs = [];
|
|
315
|
+
this.m_unormOverrides = [];
|
|
285
316
|
}
|
|
286
317
|
|
|
287
318
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CjsWebgpuShaderAL.js","sources":["../../../../src/trinityal/webgpu/CjsWebgpuShaderAL.js"],"sourcesContent":["// Source: trinity/trinityal/include/Tr2ShaderAL.h\n// trinity/trinityal/stub/Tr2ShaderALStub.cpp\n//\n// The device-backed half of Carbon's shader pair, and the second piece of the\n// immediate-draw route after `CjsWebgpuBufferAL`.\n//\n// WHY THESE EXIST. Carbon's draws all begin with `SetAllState`, which resolves a\n// pipeline from an incrementally described PSO (`Tr2RenderContextDx12.cpp:810`,\n// `:793-807`). The description's shader half is a `Tr2ShaderProgramAL` - a real\n// linked program, not a handle - so a backend that cannot produce one cannot\n// build a pipeline, and `SetStreamSource` + `DrawPrimitive` stay recording-only.\n// That is exactly where `Tr2Blitter` currently stops.\n//\n// BYTECODE HERE IS WGSL TEXT, NOT DXBC. Carbon hands its backends compiled\n// bytecode because its shaders are compiled offline for one API. Ours arrive as\n// translated WGSL from the effect container, so the \"bytecode\" a shader carries\n// is UTF-8 source. The AL contract does not care - it stores bytes and a\n// signature - and the divergence is here rather than in Trinity, which is where\n// Carbon puts every other API difference too.\n//\n// FIELDS ARE PUBLIC AND CARBON-NAMED, not private. Carbon's AL facade holds\n// exactly one private member - the `shared_ptr` to its impl - and the impl\n// class behind it carries public state, which is why Metal reads\n// `buffer.m_buffer->GetMetalBuffer()` and the stub swap chain declares\n// `m_backBuffer` public. We merge facade and impl into one class, so the merged\n// class carries the impl's fields.\n//\n// The whole layer is internal, so hiding inside it buys nothing - and it cost\n// something real: a program whose state was entirely private has no own\n// enumerable keys, canonicalised to an empty object, and would have collided\n// with every other program in the pipeline cache.\nimport { CjsSchema } from \"#schema\";\nimport { ALResult, Tr2ALMemoryType } from \"#trinityal\";\nimport { ShaderType } from \"#consts/render-context\";\nimport { readBackendBlock } from \"#resource/format\";\n\n/**\n * The entry point every stage in a Carbon WebGPU container has.\n *\n * The writer refuses any other name (`buildCarbonEffectContainer.js:45-50`), so\n * a module carries no entry-point record and this is the one value it can be.\n */\nexport const WEBGPU_ENTRY_POINT = \"main\";\n\n/**\n * Carbon's ShaderType to the stage name WebGPU's pipeline descriptor wants.\n *\n * The stage is carried as Carbon's INTEGER ENUM everywhere, and becomes a\n * string only here, at the one boundary that genuinely demands one.\n *\n * It used to be a string throughout, which was an unforced divergence: an\n * integer enum is perfectly expressible in JavaScript, Carbon's\n * `Tr2RenderContextEnum::ShaderType` is ALREADY ported in `global/consts`\n * (`renderContext/pipeline.js`) from that same header, and `layers.json`\n * explicitly permits `trinityal` to import `global/consts`. Carrying strings\n * also silently broke the duplicate-stage check, which Carbon writes as\n * `1 << GetType()` - shifting by a string puts every stage on bit 0.\n */\nexport const WEBGPU_STAGE_NAME = Object.freeze({\n [ShaderType.VERTEX_SHADER]: \"vertex\",\n [ShaderType.PIXEL_SHADER]: \"fragment\",\n [ShaderType.COMPUTE_SHADER]: \"compute\"\n});\n\n\n/** Decodes a shader's bytecode as WGSL source. */\nfunction wgslFrom(bytecode)\n{\n if (typeof bytecode === \"string\") return bytecode;\n\n const bytes = bytecode instanceof Uint8Array\n ? bytecode\n : new Uint8Array(bytecode.buffer, bytecode.byteOffset, bytecode.byteLength);\n\n return new TextDecoder().decode(bytes);\n}\n\n/**\n * The colour locations a fragment stage writes, from its WGSL: the\n * `@location(N)` members of the `FragmentOutput` struct our lowering emits\n * (`SV_TargetN` -> `@location(N)`). D3D keeps the same fact in the pixel\n * shader's OSGN; the WGSL is what this stage already holds.\n *\n * @param {string} source The stage's WGSL.\n * @returns {number[]} The written locations, ascending.\n */\nfunction FragmentOutputLocations(source)\n{\n const struct = /struct\\s+FragmentOutput\\s*\\{([^}]*)\\}/u.exec(source);\n\n if (struct) return Array.from(struct[1].matchAll(/@location\\((\\d+)\\)/gu), match => Number(match[1])).sort((a, b) => a - b);\n\n // A hand-written stage may return its one output directly: `-> @location(0) vec4f`.\n const direct = /@fragment[^{]*->\\s*@location\\((\\d+)\\)/u.exec(source);\n\n return direct ? [ Number(direct[1]) ] : [];\n}\n\n/**\n * The bind-group declarations visible to one stage, decoded from the block on\n * its signature.\n *\n * @param {number} type A Carbon `ShaderType`.\n * @param {object|null} signature The stage's signature.\n * @returns {object[]|null} The stage's bindings; an empty list when the\n * signature carries no block; null when the block is not this backend's.\n */\nfunction StageBindings(type, signature)\n{\n const block = signature?.backendBlock;\n\n if (!block || !block.size || !block.bytes) return [];\n\n const stageName = WEBGPU_STAGE_NAME[type];\n let decoded;\n\n try\n {\n decoded = readBackendBlock(block.bytes, { source: \"Tr2ShaderSignatureAL.backendBlock\" });\n }\n catch\n {\n return null;\n }\n\n const bindings = [];\n\n for (const group of decoded.bindGroups)\n {\n for (const binding of group.bindings)\n {\n if (!binding.visibility.includes(stageName)) continue;\n\n bindings.push({\n group: group.group,\n binding: binding.binding,\n identity: binding.identity,\n scopeIdentity: binding.scopeIdentity,\n resourceKind: binding.resourceKind,\n registerIndex: binding.registerIndex,\n registerSpace: binding.registerSpace,\n // Exactly one of these is present, already in GPUBindGroupLayoutEntry\n // form - the reader derives it from the WGSL type text.\n buffer: binding.buffer,\n texture: binding.texture,\n storageTexture: binding.storageTexture,\n sampler: binding.sampler\n });\n }\n }\n\n return bindings;\n}\n\n/**\n * A `Tr2ShaderAL` holding a real `GPUShaderModule`.\n *\n * Carbon's stub COPIES the bytecode so a shader stays readable after whatever\n * produced it moved on. This keeps the source for the same reason: a pipeline\n * built later needs the entry point and the module, and a compilation error\n * needs the text to report against.\n */\nexport class CjsWebgpuShaderAL\n{\n /** m_type - a Carbon `ShaderType`; `INVALID_SHADER` until Create succeeds. */\n m_type = ShaderType.INVALID_SHADER;\n\n /** m_signature */\n m_signature = null;\n\n /** The WGSL this module was compiled from. */\n m_source = \"\";\n\n /** The compiled module, or null before Create. */\n m_module = null;\n\n /** The colour locations a pixel stage writes (FragmentOutputLocations). */\n m_outputs = [];\n\n m_webgpu = null;\n\n /**\n * This stage's bind-group declarations, from the pass's backend block.\n *\n * METAL'S `m_resourceMask`, IN THIS BACKEND'S VOCABULARY. Metal derives a\n * per-stage binding table from `signature.registers` at Create\n * (`Tr2ShaderALMetal.mm:37-217`) and the program merges the stages' tables\n * (`Tr2ShaderProgramALMetal.mm:67`). A WGSL pipeline needs `(group, binding,\n * layout)` rather than a register mask, and Carbon's registers cannot say\n * that - so the container's per-pass block does, and it arrives here on the\n * signature. Only the bindings visible to THIS stage are kept: a stage's\n * table describes its own bindings, which is what lets two passes share an\n * identical vertex stage.\n */\n m_bindings = [];\n\n /** Carbon's `m_signature.pipelineInputs`, the vertex inputs this stage reads. */\n m_inputs = [];\n\n /**\n * Compiles the shader.\n *\n * @param {number} type A Carbon `ShaderType` value.\n * @param {ArrayBufferView|string} bytecode WGSL source.\n * @param {object|null} signature The reflected signature.\n * @param {string} shaderPath A debug label.\n * @param {object} renderContext The WebGPU render context AL.\n * @returns {number} An `ALResult` value.\n */\n Create(type, bytecode, signature, shaderPath, renderContext)\n {\n this.Destroy();\n\n // Carbon's stub reports OUT_OF_MEMORY for empty bytecode rather than\n // INVALIDARG (`Tr2ShaderALStub.cpp`), and the odd choice is transcribed\n // rather than tidied: a caller testing for it would not recognise a\n // different code.\n if (!bytecode || (bytecode.byteLength === 0 && bytecode.length === 0)) return ALResult.E_OUTOFMEMORY;\n\n if (!renderContext || !renderContext.IsValid()) return ALResult.E_INVALIDCALL;\n\n const webgpu = renderContext.GetWebgpu();\n if (!webgpu) return ALResult.E_INVALIDCALL;\n\n // REFUSED BEFORE COMPILING, AS METAL REFUSES A SIGNATURE IT CANNOT HONOUR\n // (`Tr2ShaderALMetal.mm:24-27`). A block that is not this backend's - a\n // WebGL2 container routed here - would otherwise compile a module whose\n // bindings nothing can lay out, and fail later with a message about the\n // pipeline.\n const bindings = StageBindings(type, signature);\n if (bindings === null) return ALResult.E_INVALIDARG;\n\n this.m_source = wgslFrom(bytecode);\n this.m_module = webgpu.GetDevice().createShaderModule({\n label: shaderPath || \"Tr2ShaderAL\",\n code: this.m_source\n });\n this.m_webgpu = webgpu;\n this.m_type = type;\n this.m_signature = signature;\n this.m_bindings = bindings;\n this.m_inputs = Array.isArray(signature?.pipelineInputs) ? signature.pipelineInputs.slice() : [];\n this.m_outputs = type === ShaderType.PIXEL_SHADER ? FragmentOutputLocations(this.m_source) : [];\n\n return ALResult.S_OK;\n }\n\n /**\n * The colour locations a pixel stage writes; empty for any other stage.\n *\n * @returns {number[]} The written locations, ascending.\n */\n GetOutputs()\n {\n return this.m_outputs;\n }\n\n /** This stage's bind-group declarations. @returns {object[]} */\n GetBindings()\n {\n return this.m_bindings;\n }\n\n /** The vertex inputs this stage reads. @returns {object[]} */\n GetInputs()\n {\n return this.m_inputs;\n }\n\n /**\n * Whether the shader compiled AND carries a stage.\n *\n * Carbon is `m_type != INVALID_SHADER && !m_bytecode.empty()`\n * (`Tr2ShaderALStub.cpp:48-51`) - both halves, on every backend. Testing the\n * module alone accepted a shader with no stage, which a program would then\n * link and resolve `GetModuleFor` against.\n */\n IsValid()\n {\n return this.m_module !== null && this.m_type !== ShaderType.INVALID_SHADER;\n }\n\n /** The stage this shader was created for. */\n GetType()\n {\n return this.m_type;\n }\n\n /** The WGSL this was compiled from, as bytes, matching the stub's contract. */\n GetBytecode()\n {\n return new TextEncoder().encode(this.m_source);\n }\n\n /** The reflected signature. */\n GetSignature()\n {\n return this.m_signature;\n }\n\n /** The `GPUShaderModule`, for a pipeline to reference. */\n GetModule()\n {\n return this.m_module;\n }\n\n /** Releases the module. */\n Destroy()\n {\n // A GPUShaderModule has no destroy(); it is released when nothing\n // references it. Dropping the reference is the whole of it.\n this.m_module = null;\n this.m_webgpu = null;\n this.m_type = ShaderType.INVALID_SHADER;\n this.m_signature = null;\n this.m_source = \"\";\n this.m_bindings = [];\n this.m_inputs = [];\n this.m_outputs = [];\n }\n\n /**\n * Claims a stage without bytecode, for a deliberately empty shader.\n *\n * The shader stays INVALID, which is the point: the pipeline must name the\n * stage, and nothing must try to reference a module for it.\n *\n * @param {number} type The pipeline stage.\n */\n SetNullShaderType(type)\n {\n this.m_type = type;\n }\n\n /**\n * Which memory class this shader occupies.\n *\n * @returns {number} A `Tr2ALMemoryType` value.\n */\n GetMemoryClass()\n {\n return Tr2ALMemoryType.AL_MEMORY_MANAGED;\n }\n\n /**\n * Fills in a device-resource description.\n *\n * @param {object} description The description to fill.\n * @returns {object} The description, filled.\n */\n Describe(description)\n {\n if (!description) return description;\n\n description.memoryClass = this.GetMemoryClass();\n\n return description;\n }\n\n /**\n * Names the shader for a debugger.\n *\n * `GPUShaderModule` carries a writable `label`, and it is what a WebGPU\n * compilation error quotes - so unlike the stub this keeps the name.\n *\n * @param {string} name The name to attach.\n * @returns {number} An `ALResult` value.\n */\n SetName(name)\n {\n if (this.m_module) this.m_module.label = String(name);\n\n return ALResult.S_OK;\n }\n}\n\n// DECLARED AS A CALL, NOT A DECORATOR, for the reason recorded in\n// Tr2BitmapDimensions.js: the layer is imported straight from source by its\n// tests and raw Node cannot parse decorator syntax.\n//\n// The donor is NAMED rather than left to be derived from this class's name.\n// Carbon calls every backend's class the same thing and carries the backend in\n// the FILE name, because only one backend compiles at a time; we ship them\n// together, so the backend moves onto the class name. That divergence is the\n// author's to declare, never a checker's to guess.\nCjsSchema.define(CjsWebgpuShaderAL, { className: \"CjsWebgpuShaderAL\", carbon: \"Tr2ShaderAL\" });\n"],"names":["WEBGPU_ENTRY_POINT","WEBGPU_STAGE_NAME","Object","freeze","ShaderType","VERTEX_SHADER","PIXEL_SHADER","COMPUTE_SHADER","wgslFrom","bytecode","bytes","Uint8Array","buffer","byteOffset","byteLength","TextDecoder","decode","FragmentOutputLocations","source","struct","exec","Array","from","matchAll","match","Number","sort","a","b","direct","StageBindings","type","signature","block","backendBlock","size","stageName","decoded","readBackendBlock","bindings","group","bindGroups","binding","visibility","includes","push","identity","scopeIdentity","resourceKind","registerIndex","registerSpace","texture","storageTexture","sampler","CjsWebgpuShaderAL","m_type","INVALID_SHADER","m_signature","m_source","m_module","m_outputs","m_webgpu","m_bindings","m_inputs","Create","shaderPath","renderContext","Destroy","length","ALResult","E_OUTOFMEMORY","IsValid","E_INVALIDCALL","webgpu","GetWebgpu","E_INVALIDARG","GetDevice","createShaderModule","label","code","isArray","pipelineInputs","slice","S_OK","GetOutputs","GetBindings","GetInputs","GetType","GetBytecode","TextEncoder","encode","GetSignature","GetModule","SetNullShaderType","GetMemoryClass","Tr2ALMemoryType","AL_MEMORY_MANAGED","Describe","description","memoryClass","SetName","name","String","CjsSchema","define","className","carbon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CjsWebgpuShaderAL.js","sources":["../../../../src/trinityal/webgpu/CjsWebgpuShaderAL.js"],"sourcesContent":["// Source: trinity/trinityal/include/Tr2ShaderAL.h\n// trinity/trinityal/stub/Tr2ShaderALStub.cpp\n//\n// The device-backed half of Carbon's shader pair, and the second piece of the\n// immediate-draw route after `CjsWebgpuBufferAL`.\n//\n// WHY THESE EXIST. Carbon's draws all begin with `SetAllState`, which resolves a\n// pipeline from an incrementally described PSO (`Tr2RenderContextDx12.cpp:810`,\n// `:793-807`). The description's shader half is a `Tr2ShaderProgramAL` - a real\n// linked program, not a handle - so a backend that cannot produce one cannot\n// build a pipeline, and `SetStreamSource` + `DrawPrimitive` stay recording-only.\n// That is exactly where `Tr2Blitter` currently stops.\n//\n// BYTECODE HERE IS WGSL TEXT, NOT DXBC. Carbon hands its backends compiled\n// bytecode because its shaders are compiled offline for one API. Ours arrive as\n// translated WGSL from the effect container, so the \"bytecode\" a shader carries\n// is UTF-8 source. The AL contract does not care - it stores bytes and a\n// signature - and the divergence is here rather than in Trinity, which is where\n// Carbon puts every other API difference too.\n//\n// FIELDS ARE PUBLIC AND CARBON-NAMED, not private. Carbon's AL facade holds\n// exactly one private member - the `shared_ptr` to its impl - and the impl\n// class behind it carries public state, which is why Metal reads\n// `buffer.m_buffer->GetMetalBuffer()` and the stub swap chain declares\n// `m_backBuffer` public. We merge facade and impl into one class, so the merged\n// class carries the impl's fields.\n//\n// The whole layer is internal, so hiding inside it buys nothing - and it cost\n// something real: a program whose state was entirely private has no own\n// enumerable keys, canonicalised to an empty object, and would have collided\n// with every other program in the pipeline cache.\nimport { CjsSchema } from \"#schema\";\nimport { ALResult, Tr2ALMemoryType } from \"#trinityal\";\nimport { ShaderType } from \"#consts/render-context\";\nimport { CARBON_BACKEND_UNORM_TARGET_OVERRIDE, readBackendBlock } from \"#resource/format\";\n\n/**\n * The entry point every stage in a Carbon WebGPU container has.\n *\n * The writer refuses any other name (`buildCarbonEffectContainer.js:45-50`), so\n * a module carries no entry-point record and this is the one value it can be.\n */\nexport const WEBGPU_ENTRY_POINT = \"main\";\n\n/**\n * Carbon's ShaderType to the stage name WebGPU's pipeline descriptor wants.\n *\n * The stage is carried as Carbon's INTEGER ENUM everywhere, and becomes a\n * string only here, at the one boundary that genuinely demands one.\n *\n * It used to be a string throughout, which was an unforced divergence: an\n * integer enum is perfectly expressible in JavaScript, Carbon's\n * `Tr2RenderContextEnum::ShaderType` is ALREADY ported in `global/consts`\n * (`renderContext/pipeline.js`) from that same header, and `layers.json`\n * explicitly permits `trinityal` to import `global/consts`. Carrying strings\n * also silently broke the duplicate-stage check, which Carbon writes as\n * `1 << GetType()` - shifting by a string puts every stage on bit 0.\n */\nexport const WEBGPU_STAGE_NAME = Object.freeze({\n [ShaderType.VERTEX_SHADER]: \"vertex\",\n [ShaderType.PIXEL_SHADER]: \"fragment\",\n [ShaderType.COMPUTE_SHADER]: \"compute\"\n});\n\n\n/** Decodes a shader's bytecode as WGSL source. */\nfunction wgslFrom(bytecode)\n{\n if (typeof bytecode === \"string\") return bytecode;\n\n const bytes = bytecode instanceof Uint8Array\n ? bytecode\n : new Uint8Array(bytecode.buffer, bytecode.byteOffset, bytecode.byteLength);\n\n return new TextDecoder().decode(bytes);\n}\n\n/**\n * The colour locations a fragment stage writes, from its WGSL: the\n * `@location(N)` members of the `FragmentOutput` struct our lowering emits\n * (`SV_TargetN` -> `@location(N)`). D3D keeps the same fact in the pixel\n * shader's OSGN; the WGSL is what this stage already holds.\n *\n * @param {string} source The stage's WGSL.\n * @returns {number[]} The written locations, ascending.\n */\nfunction FragmentOutputLocations(source)\n{\n const struct = /struct\\s+FragmentOutput\\s*\\{([^}]*)\\}/u.exec(source);\n\n if (struct) return Array.from(struct[1].matchAll(/@location\\((\\d+)\\)/gu), match => Number(match[1])).sort((a, b) => a - b);\n\n // A hand-written stage may return its one output directly: `-> @location(0) vec4f`.\n const direct = /@fragment[^{]*->\\s*@location\\((\\d+)\\)/u.exec(source);\n\n return direct ? [ Number(direct[1]) ] : [];\n}\n\n/**\n * The colour locations whose UNORM override a fragment stage declares\n * (CARBON_BACKEND_UNORM_TARGET_OVERRIDE). A pipeline may set only overrides\n * the module declares, so a hand-written stage without them gets none.\n *\n * @param {string} source The stage's WGSL.\n * @returns {number[]} The locations, ascending.\n */\nfunction UnormTargetOverrides(source)\n{\n const pattern = new RegExp(`override\\\\s+${CARBON_BACKEND_UNORM_TARGET_OVERRIDE}(\\\\d+)\\\\s*:`, \"gu\");\n\n return Array.from(source.matchAll(pattern), match => Number(match[1])).sort((a, b) => a - b);\n}\n\n/**\n * The bind-group declarations visible to one stage, decoded from the block on\n * its signature.\n *\n * @param {number} type A Carbon `ShaderType`.\n * @param {object|null} signature The stage's signature.\n * @returns {object[]|null} The stage's bindings; an empty list when the\n * signature carries no block; null when the block is not this backend's.\n */\nfunction StageBindings(type, signature)\n{\n const block = signature?.backendBlock;\n\n if (!block || !block.size || !block.bytes) return [];\n\n const stageName = WEBGPU_STAGE_NAME[type];\n let decoded;\n\n try\n {\n decoded = readBackendBlock(block.bytes, { source: \"Tr2ShaderSignatureAL.backendBlock\" });\n }\n catch\n {\n return null;\n }\n\n const bindings = [];\n\n for (const group of decoded.bindGroups)\n {\n for (const binding of group.bindings)\n {\n if (!binding.visibility.includes(stageName)) continue;\n\n bindings.push({\n group: group.group,\n binding: binding.binding,\n identity: binding.identity,\n scopeIdentity: binding.scopeIdentity,\n resourceKind: binding.resourceKind,\n registerIndex: binding.registerIndex,\n registerSpace: binding.registerSpace,\n // The backend tells a binding it fills itself by its symbol: the\n // emulated-addressing modes buffer (CARBON_BACKEND_ADDRESS_MODES_SYMBOL).\n generatedSymbol: binding.generatedSymbol,\n // Exactly one of these is present, already in GPUBindGroupLayoutEntry\n // form - the reader derives it from the WGSL type text.\n buffer: binding.buffer,\n texture: binding.texture,\n storageTexture: binding.storageTexture,\n sampler: binding.sampler\n });\n }\n }\n\n return bindings;\n}\n\n/**\n * A `Tr2ShaderAL` holding a real `GPUShaderModule`.\n *\n * Carbon's stub COPIES the bytecode so a shader stays readable after whatever\n * produced it moved on. This keeps the source for the same reason: a pipeline\n * built later needs the entry point and the module, and a compilation error\n * needs the text to report against.\n */\nexport class CjsWebgpuShaderAL\n{\n /** m_type - a Carbon `ShaderType`; `INVALID_SHADER` until Create succeeds. */\n m_type = ShaderType.INVALID_SHADER;\n\n /** m_signature */\n m_signature = null;\n\n /** The WGSL this module was compiled from. */\n m_source = \"\";\n\n /** The compiled module, or null before Create. */\n m_module = null;\n\n /** The colour locations a pixel stage writes (FragmentOutputLocations). */\n m_outputs = [];\n\n /** The colour locations whose UNORM override the stage declares. */\n m_unormOverrides = [];\n\n m_webgpu = null;\n\n /**\n * This stage's bind-group declarations, from the pass's backend block.\n *\n * METAL'S `m_resourceMask`, IN THIS BACKEND'S VOCABULARY. Metal derives a\n * per-stage binding table from `signature.registers` at Create\n * (`Tr2ShaderALMetal.mm:37-217`) and the program merges the stages' tables\n * (`Tr2ShaderProgramALMetal.mm:67`). A WGSL pipeline needs `(group, binding,\n * layout)` rather than a register mask, and Carbon's registers cannot say\n * that - so the container's per-pass block does, and it arrives here on the\n * signature. Only the bindings visible to THIS stage are kept: a stage's\n * table describes its own bindings, which is what lets two passes share an\n * identical vertex stage.\n */\n m_bindings = [];\n\n /** Carbon's `m_signature.pipelineInputs`, the vertex inputs this stage reads. */\n m_inputs = [];\n\n /**\n * Compiles the shader.\n *\n * @param {number} type A Carbon `ShaderType` value.\n * @param {ArrayBufferView|string} bytecode WGSL source.\n * @param {object|null} signature The reflected signature.\n * @param {string} shaderPath A debug label.\n * @param {object} renderContext The WebGPU render context AL.\n * @returns {number} An `ALResult` value.\n */\n Create(type, bytecode, signature, shaderPath, renderContext)\n {\n this.Destroy();\n\n // Carbon's stub reports OUT_OF_MEMORY for empty bytecode rather than\n // INVALIDARG (`Tr2ShaderALStub.cpp`), and the odd choice is transcribed\n // rather than tidied: a caller testing for it would not recognise a\n // different code.\n if (!bytecode || (bytecode.byteLength === 0 && bytecode.length === 0)) return ALResult.E_OUTOFMEMORY;\n\n if (!renderContext || !renderContext.IsValid()) return ALResult.E_INVALIDCALL;\n\n const webgpu = renderContext.GetWebgpu();\n if (!webgpu) return ALResult.E_INVALIDCALL;\n\n // REFUSED BEFORE COMPILING, AS METAL REFUSES A SIGNATURE IT CANNOT HONOUR\n // (`Tr2ShaderALMetal.mm:24-27`). A block that is not this backend's - a\n // WebGL2 container routed here - would otherwise compile a module whose\n // bindings nothing can lay out, and fail later with a message about the\n // pipeline.\n const bindings = StageBindings(type, signature);\n if (bindings === null) return ALResult.E_INVALIDARG;\n\n this.m_source = wgslFrom(bytecode);\n this.m_module = webgpu.GetDevice().createShaderModule({\n label: shaderPath || \"Tr2ShaderAL\",\n code: this.m_source\n });\n this.m_webgpu = webgpu;\n this.m_type = type;\n this.m_signature = signature;\n this.m_bindings = bindings;\n this.m_inputs = Array.isArray(signature?.pipelineInputs) ? signature.pipelineInputs.slice() : [];\n this.m_outputs = type === ShaderType.PIXEL_SHADER ? FragmentOutputLocations(this.m_source) : [];\n this.m_unormOverrides = type === ShaderType.PIXEL_SHADER ? UnormTargetOverrides(this.m_source) : [];\n\n return ALResult.S_OK;\n }\n\n /**\n * The colour locations whose UNORM override a pixel stage declares; empty\n * for any other stage, and for a hand-written one without them.\n *\n * @returns {number[]} The locations, ascending.\n */\n GetUnormTargetOverrides()\n {\n return this.m_unormOverrides;\n }\n\n /**\n * The colour locations a pixel stage writes; empty for any other stage.\n *\n * @returns {number[]} The written locations, ascending.\n */\n GetOutputs()\n {\n return this.m_outputs;\n }\n\n /** This stage's bind-group declarations. @returns {object[]} */\n GetBindings()\n {\n return this.m_bindings;\n }\n\n /** The vertex inputs this stage reads. @returns {object[]} */\n GetInputs()\n {\n return this.m_inputs;\n }\n\n /**\n * Whether the shader compiled AND carries a stage.\n *\n * Carbon is `m_type != INVALID_SHADER && !m_bytecode.empty()`\n * (`Tr2ShaderALStub.cpp:48-51`) - both halves, on every backend. Testing the\n * module alone accepted a shader with no stage, which a program would then\n * link and resolve `GetModuleFor` against.\n */\n IsValid()\n {\n return this.m_module !== null && this.m_type !== ShaderType.INVALID_SHADER;\n }\n\n /** The stage this shader was created for. */\n GetType()\n {\n return this.m_type;\n }\n\n /** The WGSL this was compiled from, as bytes, matching the stub's contract. */\n GetBytecode()\n {\n return new TextEncoder().encode(this.m_source);\n }\n\n /** The reflected signature. */\n GetSignature()\n {\n return this.m_signature;\n }\n\n /** The `GPUShaderModule`, for a pipeline to reference. */\n GetModule()\n {\n return this.m_module;\n }\n\n /** Releases the module. */\n Destroy()\n {\n // A GPUShaderModule has no destroy(); it is released when nothing\n // references it. Dropping the reference is the whole of it.\n this.m_module = null;\n this.m_webgpu = null;\n this.m_type = ShaderType.INVALID_SHADER;\n this.m_signature = null;\n this.m_source = \"\";\n this.m_bindings = [];\n this.m_inputs = [];\n this.m_outputs = [];\n this.m_unormOverrides = [];\n }\n\n /**\n * Claims a stage without bytecode, for a deliberately empty shader.\n *\n * The shader stays INVALID, which is the point: the pipeline must name the\n * stage, and nothing must try to reference a module for it.\n *\n * @param {number} type The pipeline stage.\n */\n SetNullShaderType(type)\n {\n this.m_type = type;\n }\n\n /**\n * Which memory class this shader occupies.\n *\n * @returns {number} A `Tr2ALMemoryType` value.\n */\n GetMemoryClass()\n {\n return Tr2ALMemoryType.AL_MEMORY_MANAGED;\n }\n\n /**\n * Fills in a device-resource description.\n *\n * @param {object} description The description to fill.\n * @returns {object} The description, filled.\n */\n Describe(description)\n {\n if (!description) return description;\n\n description.memoryClass = this.GetMemoryClass();\n\n return description;\n }\n\n /**\n * Names the shader for a debugger.\n *\n * `GPUShaderModule` carries a writable `label`, and it is what a WebGPU\n * compilation error quotes - so unlike the stub this keeps the name.\n *\n * @param {string} name The name to attach.\n * @returns {number} An `ALResult` value.\n */\n SetName(name)\n {\n if (this.m_module) this.m_module.label = String(name);\n\n return ALResult.S_OK;\n }\n}\n\n// DECLARED AS A CALL, NOT A DECORATOR, for the reason recorded in\n// Tr2BitmapDimensions.js: the layer is imported straight from source by its\n// tests and raw Node cannot parse decorator syntax.\n//\n// The donor is NAMED rather than left to be derived from this class's name.\n// Carbon calls every backend's class the same thing and carries the backend in\n// the FILE name, because only one backend compiles at a time; we ship them\n// together, so the backend moves onto the class name. That divergence is the\n// author's to declare, never a checker's to guess.\nCjsSchema.define(CjsWebgpuShaderAL, { className: \"CjsWebgpuShaderAL\", carbon: \"Tr2ShaderAL\" });\n"],"names":["WEBGPU_ENTRY_POINT","WEBGPU_STAGE_NAME","Object","freeze","ShaderType","VERTEX_SHADER","PIXEL_SHADER","COMPUTE_SHADER","wgslFrom","bytecode","bytes","Uint8Array","buffer","byteOffset","byteLength","TextDecoder","decode","FragmentOutputLocations","source","struct","exec","Array","from","matchAll","match","Number","sort","a","b","direct","UnormTargetOverrides","pattern","RegExp","CARBON_BACKEND_UNORM_TARGET_OVERRIDE","StageBindings","type","signature","block","backendBlock","size","stageName","decoded","readBackendBlock","bindings","group","bindGroups","binding","visibility","includes","push","identity","scopeIdentity","resourceKind","registerIndex","registerSpace","generatedSymbol","texture","storageTexture","sampler","CjsWebgpuShaderAL","m_type","INVALID_SHADER","m_signature","m_source","m_module","m_outputs","m_unormOverrides","m_webgpu","m_bindings","m_inputs","Create","shaderPath","renderContext","Destroy","length","ALResult","E_OUTOFMEMORY","IsValid","E_INVALIDCALL","webgpu","GetWebgpu","E_INVALIDARG","GetDevice","createShaderModule","label","code","isArray","pipelineInputs","slice","S_OK","GetUnormTargetOverrides","GetOutputs","GetBindings","GetInputs","GetType","GetBytecode","TextEncoder","encode","GetSignature","GetModule","SetNullShaderType","GetMemoryClass","Tr2ALMemoryType","AL_MEMORY_MANAGED","Describe","description","memoryClass","SetName","name","String","CjsSchema","define","className","carbon"],"mappings":"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"}
|
|
@@ -22,6 +22,12 @@ const STAGE_VISIBILITY = Object.freeze({
|
|
|
22
22
|
compute: 4
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* WebGPU's per-stage binding limits, each with the layout entries that count
|
|
27
|
+
* toward it (the WebGPU spec's "exceeds the binding slot limits").
|
|
28
|
+
*/
|
|
29
|
+
const PER_STAGE_LIMITS = Object.freeze([["maxSampledTexturesPerShaderStage", binding => Boolean(binding.texture)], ["maxSamplersPerShaderStage", binding => Boolean(binding.sampler)], ["maxStorageTexturesPerShaderStage", binding => Boolean(binding.storageTexture)], ["maxStorageBuffersPerShaderStage", binding => binding.buffer?.type === "storage" || binding.buffer?.type === "read-only-storage"], ["maxUniformBuffersPerShaderStage", binding => Boolean(binding.buffer) && (binding.buffer.type ?? "uniform") === "uniform"]]);
|
|
30
|
+
|
|
25
31
|
/** A monotonic program identity, for the pipeline cache. */
|
|
26
32
|
let nextProgramId = 1;
|
|
27
33
|
|
|
@@ -149,6 +155,16 @@ class CjsWebgpuShaderProgramAL {
|
|
|
149
155
|
const webgpu = renderContext.GetWebgpu();
|
|
150
156
|
if (!webgpu) return ALResult.E_INVALIDCALL;
|
|
151
157
|
const device = webgpu.GetDevice();
|
|
158
|
+
|
|
159
|
+
// A LAYOUT THE DEVICE CANNOT HOLD IS REFUSED HERE. WebGPU would make an
|
|
160
|
+
// invalid bind group layout, and every command buffer holding a pipeline
|
|
161
|
+
// built on it fails to submit: the whole frame, not the one draw.
|
|
162
|
+
for (const stage of Object.values(STAGE_VISIBILITY)) {
|
|
163
|
+
for (const [limit, counts] of PER_STAGE_LIMITS) {
|
|
164
|
+
const used = bindings.filter(binding => (binding.visibility & stage) !== 0 && counts(binding)).length;
|
|
165
|
+
if (used > device.limits[limit]) return ALResult.E_INVALIDARG;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
152
168
|
const bindGroupLayouts = [];
|
|
153
169
|
for (let group = 0; group < groupCount; group += 1) {
|
|
154
170
|
bindGroupLayouts.push(device.createBindGroupLayout({
|
|
@@ -231,6 +247,17 @@ class CjsWebgpuShaderProgramAL {
|
|
|
231
247
|
return pixel ? pixel.GetOutputs() : null;
|
|
232
248
|
}
|
|
233
249
|
|
|
250
|
+
/**
|
|
251
|
+
* The colour locations whose UNORM override the pixel stage declares
|
|
252
|
+
* (CjsWebgpuShaderAL.GetUnormTargetOverrides), empty without a pixel stage.
|
|
253
|
+
*
|
|
254
|
+
* @returns {number[]} The locations.
|
|
255
|
+
*/
|
|
256
|
+
GetUnormTargetOverrides() {
|
|
257
|
+
const pixel = this.m_shaders.find(shader => shader.GetType() === ShaderType.PIXEL_SHADER);
|
|
258
|
+
return pixel ? pixel.GetUnormTargetOverrides() : [];
|
|
259
|
+
}
|
|
260
|
+
|
|
234
261
|
/** One `GPUBindGroupLayout` per group, contiguous from zero. */
|
|
235
262
|
GetBindGroupLayouts() {
|
|
236
263
|
return this.m_bindGroupLayouts;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CjsWebgpuShaderProgramAL.js","sources":["../../../../src/trinityal/webgpu/CjsWebgpuShaderProgramAL.js"],"sourcesContent":["// Source: trinity/trinityal/include/Tr2ShaderProgramAL.h\n//\n// The linked-program half of Carbon's shader pair. The rationale shared with\n// its partner - why these exist at all, why bytecode here is WGSL text rather\n// than DXBC, and why fields are public and Carbon-named - is recorded in the\n// head comment of CjsWebgpuShaderAL.js, which several other files already cite.\nimport { CjsSchema } from \"#schema\";\nimport { ALResult, Tr2ALMemoryType, Tr2RegisterMapAL } from \"#trinityal\";\nimport { ShaderType } from \"#consts/render-context\";\nimport { WEBGPU_STAGE_NAME } from \"./CjsWebgpuShaderAL.js\";\n\n/**\n * WebGPU's `GPUShaderStage` bit for each stage name the backend block uses.\n *\n * Spelled out rather than read from `globalThis.GPUShaderStage` because a\n * headless test has no such global and the values are spec constants.\n */\nconst STAGE_VISIBILITY = Object.freeze({ vertex: 1, fragment: 2, compute: 4 });\n\n/** A monotonic program identity, for the pipeline cache. */\nlet nextProgramId = 1;\n\n/**\n * The layout half of a binding, the part two stages must agree on.\n *\n * @param {object} binding A stage binding.\n * @returns {string} A comparable key.\n */\nfunction LayoutKey(binding)\n{\n return JSON.stringify([\n binding.resourceKind,\n binding.registerSpace,\n binding.registerIndex,\n binding.buffer ?? null,\n binding.texture ?? null,\n binding.storageTexture ?? null,\n binding.sampler ?? null\n ]);\n}\n\n/**\n * A `Tr2ShaderProgramAL` linking compiled stages.\n *\n * Carbon's program is what a PSO description names, and its stub records which\n * stages were supplied as a mask. WebGPU has no link step - a render pipeline\n * takes the vertex and fragment modules directly - so this holds the stages and\n * answers for them, which is the part the pipeline description needs.\n *\n * THE PIPELINE LAYOUT IS BUILT HERE, AT CREATE, FROM THE STAGES. That is\n * DX12's shape exactly: `Tr2ShaderProgramAL::Create` walks each stage's\n * signature and merges its registers into one root signature\n * (`dx12/Tr2ShaderProgramALDx12.cpp:220-252`), and Metal's merges each stage's\n * resource mask the same way (`Tr2ShaderProgramALMetal.mm:67`). WebGPU's root\n * signature is a `GPUPipelineLayout`, and its per-stage input is the binding\n * list each `CjsWebgpuShaderAL` decoded from the block on its signature.\n *\n * This is what lets a draw resolve a pipeline from BOUND STATE: a bound program\n * carries its own layout, so nothing downstream needs the effect package the\n * program was read from. Before this the program held modules and nothing else,\n * and the layout lived only in a package the abstraction layer had no route to.\n *\n * Register maps retain signature order before physical WebGPU bindings merge.\n */\nexport class CjsWebgpuShaderProgramAL\n{\n /** m_shaders, in the order given. */\n m_shaders = [];\n\n m_registerMap = new Tr2RegisterMapAL();\n\n /** Returns the dense register map built from the linked shader signatures. */\n GetRegisterMap()\n {\n return this.m_registerMap;\n }\n\n /**\n * A process-unique identity, which is what the pipeline cache keys on.\n *\n * Metal hashes the function POINTERS into its pipeline key\n * (`MetalWorkQueue.mm:1610-1611`); an id is the same thing in a language\n * without addresses. Zero until Create.\n */\n m_id = 0;\n\n /** The merged bindings, one entry per `(group, binding)` slot. */\n m_bindings = [];\n\n /** `GPUBindGroupLayout` per group, contiguous from group zero. */\n m_bindGroupLayouts = [];\n\n /** The `GPUPipelineLayout`, this backend's root signature; null until Create. */\n m_pipelineLayout = null;\n\n /** Metal's `m_iaInputs`: the vertex stage's pipeline inputs. */\n m_inputs = [];\n\n /**\n * Links the shaders into a program.\n *\n * @param {object[]} shaders The `CjsWebgpuShaderAL`s to link.\n * @param {object} renderContext The context to link against.\n * @returns {number} An `ALResult` value.\n */\n Create(shaders, renderContext)\n {\n this.Destroy();\n\n if (!renderContext || !renderContext.IsValid()) return ALResult.E_INVALIDCALL;\n if (!shaders || shaders.length === 0) return ALResult.E_INVALIDARG;\n\n // A program with an uncompiled stage would fail at pipeline creation with a\n // message about the pipeline, not the shader. Refuse where the cause is.\n //\n // Two shaders of the SAME stage are refused for the same reason, and every\n // Carbon backend does it: the stub and Metal by bitmask\n // (`Tr2ShaderProgramALStub.cpp:35-48`, `Tr2ShaderProgramALMetal.mm:40-53`),\n // DX11 per slot. Without it a duplicate linked silently and `GetModuleFor`\n // returned whichever `find` reached first - unpredictable, and invisible\n // until a pipeline drew with the wrong stage.\n let stages = 0;\n for (const shader of shaders)\n {\n if (!shader || !shader.IsValid()) return ALResult.E_INVALIDARG;\n\n const bit = 1 << shader.GetType();\n if ((stages & bit) !== 0) return ALResult.E_INVALIDARG;\n stages |= bit;\n }\n\n // MERGE BY SLOT, AS DX12 MERGES BY REGISTER. A binding two stages both\n // read appears in both stage lists; it becomes ONE layout entry visible to\n // both. Two stages claiming one slot with different layouts is a container\n // defect, refused here where the cause is rather than at pipeline creation.\n const merged = new Map();\n\n for (const shader of shaders)\n {\n const visibility = STAGE_VISIBILITY[WEBGPU_STAGE_NAME[shader.GetType()]] ?? 0;\n\n for (const binding of shader.GetBindings())\n {\n const slot = `${binding.group}:${binding.binding}`;\n const existing = merged.get(slot);\n\n if (existing)\n {\n if (existing.layoutKey !== LayoutKey(binding)) return ALResult.E_INVALIDARG;\n existing.visibility |= visibility;\n continue;\n }\n\n merged.set(slot, { ...binding, visibility, layoutKey: LayoutKey(binding) });\n }\n }\n\n const bindings = Array.from(merged.values())\n .sort((left, right) => left.group - right.group || left.binding - right.binding);\n const groupCount = bindings.length ? bindings[bindings.length - 1].group + 1 : 0;\n\n // THE DEVICE OBJECTS ARE MADE HERE, as DX12 serialises and creates its root\n // signature inside Create (`:262-289`). An absent group index gets an\n // empty layout: WebGPU pipeline layouts are positional.\n const webgpu = renderContext.GetWebgpu();\n if (!webgpu) return ALResult.E_INVALIDCALL;\n\n const device = webgpu.GetDevice();\n\n const bindGroupLayouts = [];\n\n for (let group = 0; group < groupCount; group += 1)\n {\n bindGroupLayouts.push(device.createBindGroupLayout({\n label: `Tr2ShaderProgramAL.group${group}`,\n entries: bindings\n .filter(binding => binding.group === group)\n .map(binding => ({\n binding: binding.binding,\n visibility: binding.visibility,\n // A UNIFORM SLOT IS DYNAMIC, by the backend's decision and not the\n // container's. Constant buffers are bound out of a per-frame arena\n // at (page, offset), as Metal's are (`MetalWorkQueue.mm:2656-2659`,\n // `setVertexBufferOffset:`), and WebGPU spells a per-draw offset as\n // a dynamic offset on the layout. The container's `hasDynamicOffset`\n // is not consulted: it describes nothing the AL does not decide.\n ...(binding.buffer\n ? { buffer: binding.buffer.type === \"uniform\" ? { ...binding.buffer, hasDynamicOffset: true } : binding.buffer }\n : {}),\n ...(binding.texture ? { texture: binding.texture } : {}),\n ...(binding.storageTexture ? { storageTexture: binding.storageTexture } : {}),\n ...(binding.sampler ? { sampler: binding.sampler } : {})\n }))\n }));\n }\n\n this.m_pipelineLayout = device.createPipelineLayout({\n label: \"Tr2ShaderProgramAL.layout\",\n bindGroupLayouts\n });\n this.m_bindGroupLayouts = bindGroupLayouts;\n this.m_bindings = bindings;\n this.m_shaders = shaders.slice();\n this.m_registerMap = new Tr2RegisterMapAL({ shaders });\n this.m_inputs = shaders\n .find(shader => shader.GetType() === ShaderType.VERTEX_SHADER)\n ?.GetInputs() ?? [];\n this.m_id = nextProgramId;\n nextProgramId += 1;\n\n return ALResult.S_OK;\n }\n\n /** Whether the program linked. */\n IsValid()\n {\n return this.m_shaders.length > 0;\n }\n\n /**\n * The identity a pipeline cache keys this program under.\n *\n * @returns {string|null} A stable string, or null before Create.\n */\n GetIdentity()\n {\n return this.m_id ? `program:${this.m_id}` : null;\n }\n\n /** The merged bind-group declarations, sorted by group then binding. */\n GetBindings()\n {\n return this.m_bindings;\n }\n\n /** Metal's `GetInputs`: the vertex stage's pipeline inputs. */\n GetInputs()\n {\n return this.m_inputs;\n }\n\n /**\n * The colour locations the pixel stage writes, or null without a pixel\n * stage (a depth-only program has no fragment targets at all).\n *\n * @returns {number[]|null} The written locations.\n */\n GetFragmentOutputs()\n {\n const pixel = this.m_shaders.find(shader => shader.GetType() === ShaderType.PIXEL_SHADER);\n\n return pixel ? pixel.GetOutputs() : null;\n }\n\n /** One `GPUBindGroupLayout` per group, contiguous from zero. */\n GetBindGroupLayouts()\n {\n return this.m_bindGroupLayouts;\n }\n\n /** The `GPUPipelineLayout` a pipeline built from this program takes. */\n GetPipelineLayout()\n {\n return this.m_pipelineLayout;\n }\n\n /** The linked shaders, in the order they were given. */\n GetShaders()\n {\n return this.m_shaders;\n }\n\n /**\n * The module for one stage, or null when the program has no such stage.\n *\n * @param {*} type The stage to find.\n * @returns {GPUShaderModule|null} Its module.\n */\n GetModuleFor(type)\n {\n const shader = this.m_shaders.find(candidate => candidate.GetType() === type);\n\n return shader ? shader.GetModule() : null;\n }\n\n /** Releases the linked shaders and the layout built from them. */\n Destroy()\n {\n // Layout objects have no destroy(); dropping the references releases them.\n this.m_shaders = [];\n this.m_registerMap = new Tr2RegisterMapAL();\n this.m_bindings = [];\n this.m_bindGroupLayouts = [];\n this.m_pipelineLayout = null;\n this.m_inputs = [];\n this.m_id = 0;\n }\n\n /**\n * Builds D3D12 indirect-command signatures.\n *\n * REFUSES, WHICH IS CARBON'S OWN NON-DX12 ANSWER rather than an omission.\n * The shared facade defines it for every other backend as `return E_FAIL`\n * (`src/Tr2ShaderProgramAL.cpp:34-42`), so the method is on the contract\n * everywhere and only its implementation is DX12's.\n *\n * It was recorded as an accepted divergence on the grounds that it is\n * \"DX12-only\". That was a misreading: leaving it out produces a TypeError at\n * the call site, which is the defect class this backend's surface work was\n * written to remove.\n *\n * @param {object} _bufferLayout A `Tr2IndirectBufferLayoutAL`.\n * @param {object} _renderContext The primary render context.\n * @returns {boolean} False.\n */\n CreateCommandSignatures(_bufferLayout, _renderContext)\n {\n return false;\n }\n\n /**\n * Which memory class this program occupies.\n *\n * @returns {number} A `Tr2ALMemoryType` value.\n */\n GetMemoryClass()\n {\n return Tr2ALMemoryType.AL_MEMORY_MANAGED;\n }\n\n /**\n * Fills in a device-resource description.\n *\n * @param {object} description The description to fill.\n * @returns {object} The description, filled.\n */\n Describe(description)\n {\n if (!description) return description;\n\n description.memoryClass = this.GetMemoryClass();\n\n return description;\n }\n\n /**\n * Names the program for a debugger, and every stage under it.\n *\n * WebGPU has no program object to label - there is no link step - so the name\n * reaches the modules, which is where it can actually appear in an error.\n *\n * @param {string} name The name to attach.\n * @returns {number} An `ALResult` value.\n */\n SetName(name)\n {\n for (const shader of this.m_shaders) shader.SetName(name);\n\n return ALResult.S_OK;\n }\n}\n\n// DECLARED AS A CALL, NOT A DECORATOR, for the reason recorded in\n// Tr2BitmapDimensions.js: the layer is imported straight from source by its\n// tests and raw Node cannot parse decorator syntax.\n//\n// The donor is NAMED rather than left to be derived from this class's name.\n// Carbon calls every backend's class the same thing and carries the backend in\n// the FILE name, because only one backend compiles at a time; we ship them\n// together, so the backend moves onto the class name. That divergence is the\n// author's to declare, never a checker's to guess.\nCjsSchema.define(CjsWebgpuShaderProgramAL, { className: \"CjsWebgpuShaderProgramAL\", carbon: \"Tr2ShaderProgramAL\" });\n"],"names":["STAGE_VISIBILITY","Object","freeze","vertex","fragment","compute","nextProgramId","LayoutKey","binding","JSON","stringify","resourceKind","registerSpace","registerIndex","buffer","texture","storageTexture","sampler","CjsWebgpuShaderProgramAL","m_shaders","m_registerMap","Tr2RegisterMapAL","GetRegisterMap","m_id","m_bindings","m_bindGroupLayouts","m_pipelineLayout","m_inputs","Create","shaders","renderContext","Destroy","IsValid","ALResult","E_INVALIDCALL","length","E_INVALIDARG","stages","shader","bit","GetType","merged","Map","visibility","WEBGPU_STAGE_NAME","GetBindings","slot","group","existing","get","layoutKey","set","bindings","Array","from","values","sort","left","right","groupCount","webgpu","GetWebgpu","device","GetDevice","bindGroupLayouts","push","createBindGroupLayout","label","entries","filter","map","type","hasDynamicOffset","createPipelineLayout","slice","find","ShaderType","VERTEX_SHADER","GetInputs","S_OK","GetIdentity","GetFragmentOutputs","pixel","PIXEL_SHADER","GetOutputs","GetBindGroupLayouts","GetPipelineLayout","GetShaders","GetModuleFor","candidate","GetModule","CreateCommandSignatures","_bufferLayout","_renderContext","GetMemoryClass","Tr2ALMemoryType","AL_MEMORY_MANAGED","Describe","description","memoryClass","SetName","name","CjsSchema","define","className","carbon"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CjsWebgpuShaderProgramAL.js","sources":["../../../../src/trinityal/webgpu/CjsWebgpuShaderProgramAL.js"],"sourcesContent":["// Source: trinity/trinityal/include/Tr2ShaderProgramAL.h\n//\n// The linked-program half of Carbon's shader pair. The rationale shared with\n// its partner - why these exist at all, why bytecode here is WGSL text rather\n// than DXBC, and why fields are public and Carbon-named - is recorded in the\n// head comment of CjsWebgpuShaderAL.js, which several other files already cite.\nimport { CjsSchema } from \"#schema\";\nimport { ALResult, Tr2ALMemoryType, Tr2RegisterMapAL } from \"#trinityal\";\nimport { ShaderType } from \"#consts/render-context\";\nimport { WEBGPU_STAGE_NAME } from \"./CjsWebgpuShaderAL.js\";\n\n/**\n * WebGPU's `GPUShaderStage` bit for each stage name the backend block uses.\n *\n * Spelled out rather than read from `globalThis.GPUShaderStage` because a\n * headless test has no such global and the values are spec constants.\n */\nconst STAGE_VISIBILITY = Object.freeze({ vertex: 1, fragment: 2, compute: 4 });\n\n/**\n * WebGPU's per-stage binding limits, each with the layout entries that count\n * toward it (the WebGPU spec's \"exceeds the binding slot limits\").\n */\nconst PER_STAGE_LIMITS = Object.freeze([\n [ \"maxSampledTexturesPerShaderStage\", binding => Boolean(binding.texture) ],\n [ \"maxSamplersPerShaderStage\", binding => Boolean(binding.sampler) ],\n [ \"maxStorageTexturesPerShaderStage\", binding => Boolean(binding.storageTexture) ],\n [ \"maxStorageBuffersPerShaderStage\", binding => binding.buffer?.type === \"storage\" || binding.buffer?.type === \"read-only-storage\" ],\n [ \"maxUniformBuffersPerShaderStage\", binding => Boolean(binding.buffer) && (binding.buffer.type ?? \"uniform\") === \"uniform\" ]\n]);\n\n/** A monotonic program identity, for the pipeline cache. */\nlet nextProgramId = 1;\n\n/**\n * The layout half of a binding, the part two stages must agree on.\n *\n * @param {object} binding A stage binding.\n * @returns {string} A comparable key.\n */\nfunction LayoutKey(binding)\n{\n return JSON.stringify([\n binding.resourceKind,\n binding.registerSpace,\n binding.registerIndex,\n binding.buffer ?? null,\n binding.texture ?? null,\n binding.storageTexture ?? null,\n binding.sampler ?? null\n ]);\n}\n\n/**\n * A `Tr2ShaderProgramAL` linking compiled stages.\n *\n * Carbon's program is what a PSO description names, and its stub records which\n * stages were supplied as a mask. WebGPU has no link step - a render pipeline\n * takes the vertex and fragment modules directly - so this holds the stages and\n * answers for them, which is the part the pipeline description needs.\n *\n * THE PIPELINE LAYOUT IS BUILT HERE, AT CREATE, FROM THE STAGES. That is\n * DX12's shape exactly: `Tr2ShaderProgramAL::Create` walks each stage's\n * signature and merges its registers into one root signature\n * (`dx12/Tr2ShaderProgramALDx12.cpp:220-252`), and Metal's merges each stage's\n * resource mask the same way (`Tr2ShaderProgramALMetal.mm:67`). WebGPU's root\n * signature is a `GPUPipelineLayout`, and its per-stage input is the binding\n * list each `CjsWebgpuShaderAL` decoded from the block on its signature.\n *\n * This is what lets a draw resolve a pipeline from BOUND STATE: a bound program\n * carries its own layout, so nothing downstream needs the effect package the\n * program was read from. Before this the program held modules and nothing else,\n * and the layout lived only in a package the abstraction layer had no route to.\n *\n * Register maps retain signature order before physical WebGPU bindings merge.\n */\nexport class CjsWebgpuShaderProgramAL\n{\n /** m_shaders, in the order given. */\n m_shaders = [];\n\n m_registerMap = new Tr2RegisterMapAL();\n\n /** Returns the dense register map built from the linked shader signatures. */\n GetRegisterMap()\n {\n return this.m_registerMap;\n }\n\n /**\n * A process-unique identity, which is what the pipeline cache keys on.\n *\n * Metal hashes the function POINTERS into its pipeline key\n * (`MetalWorkQueue.mm:1610-1611`); an id is the same thing in a language\n * without addresses. Zero until Create.\n */\n m_id = 0;\n\n /** The merged bindings, one entry per `(group, binding)` slot. */\n m_bindings = [];\n\n /** `GPUBindGroupLayout` per group, contiguous from group zero. */\n m_bindGroupLayouts = [];\n\n /** The `GPUPipelineLayout`, this backend's root signature; null until Create. */\n m_pipelineLayout = null;\n\n /** Metal's `m_iaInputs`: the vertex stage's pipeline inputs. */\n m_inputs = [];\n\n /**\n * Links the shaders into a program.\n *\n * @param {object[]} shaders The `CjsWebgpuShaderAL`s to link.\n * @param {object} renderContext The context to link against.\n * @returns {number} An `ALResult` value.\n */\n Create(shaders, renderContext)\n {\n this.Destroy();\n\n if (!renderContext || !renderContext.IsValid()) return ALResult.E_INVALIDCALL;\n if (!shaders || shaders.length === 0) return ALResult.E_INVALIDARG;\n\n // A program with an uncompiled stage would fail at pipeline creation with a\n // message about the pipeline, not the shader. Refuse where the cause is.\n //\n // Two shaders of the SAME stage are refused for the same reason, and every\n // Carbon backend does it: the stub and Metal by bitmask\n // (`Tr2ShaderProgramALStub.cpp:35-48`, `Tr2ShaderProgramALMetal.mm:40-53`),\n // DX11 per slot. Without it a duplicate linked silently and `GetModuleFor`\n // returned whichever `find` reached first - unpredictable, and invisible\n // until a pipeline drew with the wrong stage.\n let stages = 0;\n for (const shader of shaders)\n {\n if (!shader || !shader.IsValid()) return ALResult.E_INVALIDARG;\n\n const bit = 1 << shader.GetType();\n if ((stages & bit) !== 0) return ALResult.E_INVALIDARG;\n stages |= bit;\n }\n\n // MERGE BY SLOT, AS DX12 MERGES BY REGISTER. A binding two stages both\n // read appears in both stage lists; it becomes ONE layout entry visible to\n // both. Two stages claiming one slot with different layouts is a container\n // defect, refused here where the cause is rather than at pipeline creation.\n const merged = new Map();\n\n for (const shader of shaders)\n {\n const visibility = STAGE_VISIBILITY[WEBGPU_STAGE_NAME[shader.GetType()]] ?? 0;\n\n for (const binding of shader.GetBindings())\n {\n const slot = `${binding.group}:${binding.binding}`;\n const existing = merged.get(slot);\n\n if (existing)\n {\n if (existing.layoutKey !== LayoutKey(binding)) return ALResult.E_INVALIDARG;\n existing.visibility |= visibility;\n continue;\n }\n\n merged.set(slot, { ...binding, visibility, layoutKey: LayoutKey(binding) });\n }\n }\n\n const bindings = Array.from(merged.values())\n .sort((left, right) => left.group - right.group || left.binding - right.binding);\n const groupCount = bindings.length ? bindings[bindings.length - 1].group + 1 : 0;\n\n // THE DEVICE OBJECTS ARE MADE HERE, as DX12 serialises and creates its root\n // signature inside Create (`:262-289`). An absent group index gets an\n // empty layout: WebGPU pipeline layouts are positional.\n const webgpu = renderContext.GetWebgpu();\n if (!webgpu) return ALResult.E_INVALIDCALL;\n\n const device = webgpu.GetDevice();\n\n // A LAYOUT THE DEVICE CANNOT HOLD IS REFUSED HERE. WebGPU would make an\n // invalid bind group layout, and every command buffer holding a pipeline\n // built on it fails to submit: the whole frame, not the one draw.\n for (const stage of Object.values(STAGE_VISIBILITY))\n {\n for (const [ limit, counts ] of PER_STAGE_LIMITS)\n {\n const used = bindings.filter(binding => (binding.visibility & stage) !== 0 && counts(binding)).length;\n\n if (used > device.limits[limit]) return ALResult.E_INVALIDARG;\n }\n }\n\n const bindGroupLayouts = [];\n\n for (let group = 0; group < groupCount; group += 1)\n {\n bindGroupLayouts.push(device.createBindGroupLayout({\n label: `Tr2ShaderProgramAL.group${group}`,\n entries: bindings\n .filter(binding => binding.group === group)\n .map(binding => ({\n binding: binding.binding,\n visibility: binding.visibility,\n // A UNIFORM SLOT IS DYNAMIC, by the backend's decision and not the\n // container's. Constant buffers are bound out of a per-frame arena\n // at (page, offset), as Metal's are (`MetalWorkQueue.mm:2656-2659`,\n // `setVertexBufferOffset:`), and WebGPU spells a per-draw offset as\n // a dynamic offset on the layout. The container's `hasDynamicOffset`\n // is not consulted: it describes nothing the AL does not decide.\n ...(binding.buffer\n ? { buffer: binding.buffer.type === \"uniform\" ? { ...binding.buffer, hasDynamicOffset: true } : binding.buffer }\n : {}),\n ...(binding.texture ? { texture: binding.texture } : {}),\n ...(binding.storageTexture ? { storageTexture: binding.storageTexture } : {}),\n ...(binding.sampler ? { sampler: binding.sampler } : {})\n }))\n }));\n }\n\n this.m_pipelineLayout = device.createPipelineLayout({\n label: \"Tr2ShaderProgramAL.layout\",\n bindGroupLayouts\n });\n this.m_bindGroupLayouts = bindGroupLayouts;\n this.m_bindings = bindings;\n this.m_shaders = shaders.slice();\n this.m_registerMap = new Tr2RegisterMapAL({ shaders });\n this.m_inputs = shaders\n .find(shader => shader.GetType() === ShaderType.VERTEX_SHADER)\n ?.GetInputs() ?? [];\n this.m_id = nextProgramId;\n nextProgramId += 1;\n\n return ALResult.S_OK;\n }\n\n /** Whether the program linked. */\n IsValid()\n {\n return this.m_shaders.length > 0;\n }\n\n /**\n * The identity a pipeline cache keys this program under.\n *\n * @returns {string|null} A stable string, or null before Create.\n */\n GetIdentity()\n {\n return this.m_id ? `program:${this.m_id}` : null;\n }\n\n /** The merged bind-group declarations, sorted by group then binding. */\n GetBindings()\n {\n return this.m_bindings;\n }\n\n /** Metal's `GetInputs`: the vertex stage's pipeline inputs. */\n GetInputs()\n {\n return this.m_inputs;\n }\n\n /**\n * The colour locations the pixel stage writes, or null without a pixel\n * stage (a depth-only program has no fragment targets at all).\n *\n * @returns {number[]|null} The written locations.\n */\n GetFragmentOutputs()\n {\n const pixel = this.m_shaders.find(shader => shader.GetType() === ShaderType.PIXEL_SHADER);\n\n return pixel ? pixel.GetOutputs() : null;\n }\n\n /**\n * The colour locations whose UNORM override the pixel stage declares\n * (CjsWebgpuShaderAL.GetUnormTargetOverrides), empty without a pixel stage.\n *\n * @returns {number[]} The locations.\n */\n GetUnormTargetOverrides()\n {\n const pixel = this.m_shaders.find(shader => shader.GetType() === ShaderType.PIXEL_SHADER);\n\n return pixel ? pixel.GetUnormTargetOverrides() : [];\n }\n\n /** One `GPUBindGroupLayout` per group, contiguous from zero. */\n GetBindGroupLayouts()\n {\n return this.m_bindGroupLayouts;\n }\n\n /** The `GPUPipelineLayout` a pipeline built from this program takes. */\n GetPipelineLayout()\n {\n return this.m_pipelineLayout;\n }\n\n /** The linked shaders, in the order they were given. */\n GetShaders()\n {\n return this.m_shaders;\n }\n\n /**\n * The module for one stage, or null when the program has no such stage.\n *\n * @param {*} type The stage to find.\n * @returns {GPUShaderModule|null} Its module.\n */\n GetModuleFor(type)\n {\n const shader = this.m_shaders.find(candidate => candidate.GetType() === type);\n\n return shader ? shader.GetModule() : null;\n }\n\n /** Releases the linked shaders and the layout built from them. */\n Destroy()\n {\n // Layout objects have no destroy(); dropping the references releases them.\n this.m_shaders = [];\n this.m_registerMap = new Tr2RegisterMapAL();\n this.m_bindings = [];\n this.m_bindGroupLayouts = [];\n this.m_pipelineLayout = null;\n this.m_inputs = [];\n this.m_id = 0;\n }\n\n /**\n * Builds D3D12 indirect-command signatures.\n *\n * REFUSES, WHICH IS CARBON'S OWN NON-DX12 ANSWER rather than an omission.\n * The shared facade defines it for every other backend as `return E_FAIL`\n * (`src/Tr2ShaderProgramAL.cpp:34-42`), so the method is on the contract\n * everywhere and only its implementation is DX12's.\n *\n * It was recorded as an accepted divergence on the grounds that it is\n * \"DX12-only\". That was a misreading: leaving it out produces a TypeError at\n * the call site, which is the defect class this backend's surface work was\n * written to remove.\n *\n * @param {object} _bufferLayout A `Tr2IndirectBufferLayoutAL`.\n * @param {object} _renderContext The primary render context.\n * @returns {boolean} False.\n */\n CreateCommandSignatures(_bufferLayout, _renderContext)\n {\n return false;\n }\n\n /**\n * Which memory class this program occupies.\n *\n * @returns {number} A `Tr2ALMemoryType` value.\n */\n GetMemoryClass()\n {\n return Tr2ALMemoryType.AL_MEMORY_MANAGED;\n }\n\n /**\n * Fills in a device-resource description.\n *\n * @param {object} description The description to fill.\n * @returns {object} The description, filled.\n */\n Describe(description)\n {\n if (!description) return description;\n\n description.memoryClass = this.GetMemoryClass();\n\n return description;\n }\n\n /**\n * Names the program for a debugger, and every stage under it.\n *\n * WebGPU has no program object to label - there is no link step - so the name\n * reaches the modules, which is where it can actually appear in an error.\n *\n * @param {string} name The name to attach.\n * @returns {number} An `ALResult` value.\n */\n SetName(name)\n {\n for (const shader of this.m_shaders) shader.SetName(name);\n\n return ALResult.S_OK;\n }\n}\n\n// DECLARED AS A CALL, NOT A DECORATOR, for the reason recorded in\n// Tr2BitmapDimensions.js: the layer is imported straight from source by its\n// tests and raw Node cannot parse decorator syntax.\n//\n// The donor is NAMED rather than left to be derived from this class's name.\n// Carbon calls every backend's class the same thing and carries the backend in\n// the FILE name, because only one backend compiles at a time; we ship them\n// together, so the backend moves onto the class name. That divergence is the\n// author's to declare, never a checker's to guess.\nCjsSchema.define(CjsWebgpuShaderProgramAL, { className: \"CjsWebgpuShaderProgramAL\", carbon: \"Tr2ShaderProgramAL\" });\n"],"names":["STAGE_VISIBILITY","Object","freeze","vertex","fragment","compute","PER_STAGE_LIMITS","binding","Boolean","texture","sampler","storageTexture","buffer","type","nextProgramId","LayoutKey","JSON","stringify","resourceKind","registerSpace","registerIndex","CjsWebgpuShaderProgramAL","m_shaders","m_registerMap","Tr2RegisterMapAL","GetRegisterMap","m_id","m_bindings","m_bindGroupLayouts","m_pipelineLayout","m_inputs","Create","shaders","renderContext","Destroy","IsValid","ALResult","E_INVALIDCALL","length","E_INVALIDARG","stages","shader","bit","GetType","merged","Map","visibility","WEBGPU_STAGE_NAME","GetBindings","slot","group","existing","get","layoutKey","set","bindings","Array","from","values","sort","left","right","groupCount","webgpu","GetWebgpu","device","GetDevice","stage","limit","counts","used","filter","limits","bindGroupLayouts","push","createBindGroupLayout","label","entries","map","hasDynamicOffset","createPipelineLayout","slice","find","ShaderType","VERTEX_SHADER","GetInputs","S_OK","GetIdentity","GetFragmentOutputs","pixel","PIXEL_SHADER","GetOutputs","GetUnormTargetOverrides","GetBindGroupLayouts","GetPipelineLayout","GetShaders","GetModuleFor","candidate","GetModule","CreateCommandSignatures","_bufferLayout","_renderContext","GetMemoryClass","Tr2ALMemoryType","AL_MEMORY_MANAGED","Describe","description","memoryClass","SetName","name","CjsSchema","define","className","carbon"],"mappings":"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"}
|
|
@@ -67,6 +67,18 @@ class CjsWebgpuTextureAL {
|
|
|
67
67
|
/** The `GPUTexture`, or null before Create. */
|
|
68
68
|
m_texture = null;
|
|
69
69
|
|
|
70
|
+
/** Whether the texture is a float stand-in for a UNORM format (CjsWebgpuUtils.IsUnormSubstitute). */
|
|
71
|
+
m_unormSubstitute = false;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Whether a pipeline rendering to this texture must store as UNORM does.
|
|
75
|
+
*
|
|
76
|
+
* @returns {boolean} True for a float stand-in for a 16-bit UNORM format.
|
|
77
|
+
*/
|
|
78
|
+
IsUnormSubstitute() {
|
|
79
|
+
return this.m_unormSubstitute;
|
|
80
|
+
}
|
|
81
|
+
|
|
70
82
|
/** The `GPUTextureFormat` it was created with. */
|
|
71
83
|
m_format = null;
|
|
72
84
|
|
|
@@ -122,6 +134,13 @@ class CjsWebgpuTextureAL {
|
|
|
122
134
|
const webgpu = al.GetWebgpu();
|
|
123
135
|
if (!webgpu) return ALResult.E_INVALIDCALL;
|
|
124
136
|
const device = webgpu.GetDevice();
|
|
137
|
+
|
|
138
|
+
// A size past the device's limit is refused here: createTexture would make
|
|
139
|
+
// an invalid texture, and every command buffer using it would fail to
|
|
140
|
+
// submit. Carbon's cascaded shadow atlas is 16384 wide at its default
|
|
141
|
+
// 2048 cell (Tr2ShadowMap.h:14, eight cells a row).
|
|
142
|
+
const maxDimension = type === TextureType.TEX_TYPE_3D ? device.limits.maxTextureDimension3D : device.limits.maxTextureDimension2D;
|
|
143
|
+
if (desc.GetWidth() > maxDimension || desc.GetHeight() > maxDimension) return ALResult.E_INVALIDARG;
|
|
125
144
|
const usageFlags = webgpu.GetTextureUsage();
|
|
126
145
|
const srgbFormat = requestedFormat !== format && requestedFormat.endsWith("-srgb") ? requestedFormat : al.m_utils.GetSRGBViewFormat(format);
|
|
127
146
|
const mipCount = Math.max(1, desc.GetTrueMipCount());
|
|
@@ -162,13 +181,16 @@ class CjsWebgpuTextureAL {
|
|
|
162
181
|
});
|
|
163
182
|
this.m_format = format;
|
|
164
183
|
this.m_srgbFormat = srgbFormat;
|
|
184
|
+
this.m_unormSubstitute = al.m_utils.IsUnormSubstitute(desc.GetFormat());
|
|
165
185
|
this.m_desc = desc;
|
|
166
186
|
this.m_msaa = msaa;
|
|
167
187
|
this.m_gpuUsage = gpuUsage;
|
|
168
188
|
this.m_cpuUsage = cpuUsage;
|
|
169
189
|
this.m_webgpu = webgpu;
|
|
170
190
|
if (depthShadow) this._CreateDepthShadow(device, usageFlags);
|
|
171
|
-
|
|
191
|
+
// A substitute format's data is converted as it uploads (16-bit unorm to
|
|
192
|
+
// half floats; CjsWebgpuUtils.UPLOAD_CONVERSIONS).
|
|
193
|
+
if (initialData) this._Upload(initialData, mipCount, type, al.m_utils.GetUploadConversion(desc.GetFormat()));
|
|
172
194
|
return ALResult.S_OK;
|
|
173
195
|
}
|
|
174
196
|
|
|
@@ -251,8 +273,11 @@ class CjsWebgpuTextureAL {
|
|
|
251
273
|
return true;
|
|
252
274
|
}
|
|
253
275
|
|
|
254
|
-
/**
|
|
255
|
-
|
|
276
|
+
/**
|
|
277
|
+
* One `writeTexture` per subresource, Carbon's `mip + layer * mipCount`
|
|
278
|
+
* order, each through `convert` when the format needs one.
|
|
279
|
+
*/
|
|
280
|
+
_Upload(initialData, mipCount, type, convert = null) {
|
|
256
281
|
const desc = this.m_desc;
|
|
257
282
|
const queue = this.m_webgpu.GetDevice().queue;
|
|
258
283
|
const layerCount = type === TextureType.TEX_TYPE_3D ? 1 : Math.max(1, desc.GetArraySize());
|
|
@@ -260,7 +285,7 @@ class CjsWebgpuTextureAL {
|
|
|
260
285
|
for (let mip = 0; mip < mipCount; mip += 1) {
|
|
261
286
|
const subresource = initialData[mip + layer * mipCount];
|
|
262
287
|
if (!subresource || !subresource.m_sysMem) continue;
|
|
263
|
-
const bytes = subresource.m_sysMem;
|
|
288
|
+
const bytes = convert ? convert(subresource.m_sysMem) : subresource.m_sysMem;
|
|
264
289
|
const pitch = subresource.m_sysMemPitch;
|
|
265
290
|
const slicePitch = subresource.m_sysMemSlicePitch || bytes.byteLength;
|
|
266
291
|
const depth = type === TextureType.TEX_TYPE_3D ? Math.max(1, desc.GetMipDepth(mip)) : 1;
|