rayzee 8.3.0 → 8.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -2
- package/dist/DLSSNeural-BNSJ8V3z.js +202 -0
- package/dist/DLSSSuperRes-BoEW89Cl.js +266 -0
- package/dist/ToneMapGPU-DzqSyzTx.js +341 -0
- package/dist/rayzee.es.js +4523 -4577
- package/dist/rayzee.umd.js +260 -66
- package/dist/rolldown-runtime-CAFD8bLK.js +11 -0
- package/package.json +1 -1
- package/src/AssetConfig.js +7 -0
- package/src/EngineDefaults.js +5 -1
- package/src/PathTracerApp.js +6 -4
- package/src/Processor/ToneMapGPU.js +317 -0
- package/src/dlss/DLSSNeural.js +530 -0
- package/src/dlss/DLSSSuperRes.js +584 -0
- package/src/index.js +6 -0
- package/src/managers/DenoisingManager.js +272 -7
package/README.md
CHANGED
|
@@ -287,6 +287,11 @@ configureAssets({
|
|
|
287
287
|
oidnWeightsBaseUrl: '/oidn-tzas/',
|
|
288
288
|
upscalerModelBaseUrl: '/upscaler-onnx/',
|
|
289
289
|
|
|
290
|
+
// DLSS. The runtime is a plain script the host must serve — it installs
|
|
291
|
+
// `globalThis.DLSSRuntime` as a side effect and cannot be imported.
|
|
292
|
+
dlssRuntimeUrl: '/dlss/dlss-runtime.js',
|
|
293
|
+
dlssAssetBaseUrl: '/dlss/',
|
|
294
|
+
|
|
290
295
|
// Prefix for engine-managed IndexedDB stores. Set to a unique value if multiple
|
|
291
296
|
// apps embed the engine on the same origin to avoid cache collisions.
|
|
292
297
|
cacheNamespace: 'my-app',
|
|
@@ -588,8 +593,10 @@ engine.denoisingManager.setOIDNQuality('high')
|
|
|
588
593
|
engine.denoisingManager.setStrategy('oidn') // OIDN owns the live view; see below
|
|
589
594
|
engine.denoisingManager.continuousDenoiseInterval = 250 // cap refreshes at 4/sec (default 8 = uncapped)
|
|
590
595
|
engine.denoisingManager.setUpscalerEnabled(true)
|
|
591
|
-
engine.denoisingManager.
|
|
592
|
-
engine.denoisingManager.
|
|
596
|
+
engine.denoisingManager.setUpscalerBackend('dlss') // 'esrgan' (default) | 'dlss'
|
|
597
|
+
engine.denoisingManager.setUpscalerScaleFactor(2) // ESRGAN only; DLSS is fixed at 2x
|
|
598
|
+
engine.denoisingManager.setUpscalerQuality('high') // ESRGAN only
|
|
599
|
+
engine.denoisingManager.setNeuralRendering(true, { intensity: 1, colorStrength: 0 })
|
|
593
600
|
```
|
|
594
601
|
|
|
595
602
|
### engine.interactionManager
|
|
@@ -1197,6 +1204,51 @@ engine.addEventListener(EngineEvents.UPSCALING_END, () => console.log('Upsc
|
|
|
1197
1204
|
|
|
1198
1205
|
**Chaining with OIDN:** Upscaling and OIDN **can** run together — on render completion, OIDN runs first, then its denoised output is fed into the upscaler. Enable both; no manual coordination required.
|
|
1199
1206
|
|
|
1207
|
+
### The DLSS passes
|
|
1208
|
+
|
|
1209
|
+
Two further neural passes, ported from NVIDIA's DLSS weights. Both run once when a render finishes
|
|
1210
|
+
and both need a denoised frame — on raw Monte-Carlo noise they measurably lose to a plain resize, so
|
|
1211
|
+
enable OIDN alongside them.
|
|
1212
|
+
|
|
1213
|
+
Unlike the ONNX upscaler these are **not fetched from a CDN**: `dlss-runtime.js` installs
|
|
1214
|
+
`globalThis.DLSSRuntime` as a side effect and cannot be imported, so the host serves it and points
|
|
1215
|
+
`configureAssets` at it (see above). It lives at `app/public/dlss/` in this repo, and the local edits
|
|
1216
|
+
it carries are written up in `app/public/dlss/PATCHES.md` — re-vendoring it without re-applying them
|
|
1217
|
+
breaks the retouch pass with an explanatory throw.
|
|
1218
|
+
|
|
1219
|
+
```js
|
|
1220
|
+
// Super resolution, as a second AI Upscaler backend
|
|
1221
|
+
engine.denoisingManager.setUpscalerEnabled(true);
|
|
1222
|
+
engine.denoisingManager.setUpscalerBackend('dlss');
|
|
1223
|
+
|
|
1224
|
+
// The retouch pass — appearance, not resolution. Independent of the upscaler.
|
|
1225
|
+
engine.denoisingManager.setNeuralRendering(true, {
|
|
1226
|
+
intensity: 1, // 0..1 how much of the pass reaches the image
|
|
1227
|
+
localTone: 1, // 0..2 local light shaping; 1 is neutral
|
|
1228
|
+
localStructure: 1, // 0..2 fine surface detail; 1 is neutral
|
|
1229
|
+
colorStrength: 0, // 0..1 0 keeps the render's chroma, 1 takes the model's
|
|
1230
|
+
});
|
|
1231
|
+
```
|
|
1232
|
+
|
|
1233
|
+
The chain is **denoise → retouch (at render size) → super resolution (2x) → tone map**, scene-referred
|
|
1234
|
+
throughout. The retouch pass runs *before* the upscale deliberately: it sees a quarter of the pixels
|
|
1235
|
+
there, and above `DLSS_NR_MAX_PIXELS` (4.19 MP) it takes minutes and then loses every GPU device in
|
|
1236
|
+
the page. `DenoisingManager` skips it above that size rather than letting it run.
|
|
1237
|
+
|
|
1238
|
+
| | Super resolution | Retouch |
|
|
1239
|
+
|---|---|---|
|
|
1240
|
+
| What it changes | Resolution, fixed 2x | Appearance only |
|
|
1241
|
+
| Weights | 3.2 MB | 141 MB, fetched on first use |
|
|
1242
|
+
| Cost (1.9M-tri interior, warm) | 260 ms at 1024²→2048², 947 ms at 2048²→4096² | ~6 s at 2048² |
|
|
1243
|
+
| Against a native render | Ties Real-ESRGAN on accuracy, 3x faster, sharper than native | Close to a no-op on path-traced images |
|
|
1244
|
+
|
|
1245
|
+
Exported for building UI against: `SR_SCALE`, `SR_MAX_INPUT`, `DLSS_NR_DEFAULTS`, `DLSS_NR_RANGES`,
|
|
1246
|
+
`DLSS_NR_MAX_PIXELS`, and `renderUpscaled( app, { outputWidth, outputHeight, samples } )` — the
|
|
1247
|
+
offline entry point that drives a half-size render, denoise and upscale in one call.
|
|
1248
|
+
|
|
1249
|
+
⚠️ Each model brings **its own `GPUDevice`**, built by the runtime and not shareable. With both on,
|
|
1250
|
+
the page holds three: the renderer's and one each.
|
|
1251
|
+
|
|
1200
1252
|
## Troubleshooting
|
|
1201
1253
|
|
|
1202
1254
|
**OIDN: `Cannot find module './tza'` (webpack)**
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { t as e } from "./rolldown-runtime-CAFD8bLK.js";
|
|
2
|
+
import { o as t, r as n, t as r } from "./ToneMapGPU-DzqSyzTx.js";
|
|
3
|
+
//#region src/dlss/DLSSNeural.js
|
|
4
|
+
var i = /* @__PURE__ */ e({
|
|
5
|
+
DLSSNeural: () => m,
|
|
6
|
+
DLSS_NR_COLOR_STRENGTH: () => 0,
|
|
7
|
+
DLSS_NR_DEFAULTS: () => a,
|
|
8
|
+
DLSS_NR_MAX_PIXELS: () => c,
|
|
9
|
+
DLSS_NR_RANGES: () => l,
|
|
10
|
+
enhanceFrame: () => g
|
|
11
|
+
}), a = Object.freeze({
|
|
12
|
+
enabled: !0,
|
|
13
|
+
intensity: 1,
|
|
14
|
+
localTone: 1,
|
|
15
|
+
localStructure: 1,
|
|
16
|
+
skinStructure: -1,
|
|
17
|
+
autoMask: !0,
|
|
18
|
+
style: 0,
|
|
19
|
+
preset: 0,
|
|
20
|
+
uiCorrection: !1
|
|
21
|
+
});
|
|
22
|
+
function o(e = {}) {
|
|
23
|
+
let { colorStrength: t = 0, ...n } = e;
|
|
24
|
+
return {
|
|
25
|
+
runtime: {
|
|
26
|
+
...a,
|
|
27
|
+
...n
|
|
28
|
+
},
|
|
29
|
+
colorStrength: t
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
var s = t("dlss"), c = 2048 * 2048, l = Object.freeze({
|
|
33
|
+
intensity: [0, 1],
|
|
34
|
+
localTone: [0, 2],
|
|
35
|
+
localStructure: [0, 2],
|
|
36
|
+
skinStructure: [-1, 2],
|
|
37
|
+
style: [0, 2],
|
|
38
|
+
preset: [0, 3]
|
|
39
|
+
}), u = null;
|
|
40
|
+
function d() {
|
|
41
|
+
if (u) return u;
|
|
42
|
+
let { dlssRuntimeUrl: e, dlssAssetBaseUrl: t } = n();
|
|
43
|
+
return globalThis.__DLSS5_ASSET_BASE__ = t, u = new Promise((t, n) => {
|
|
44
|
+
if (globalThis.DLSSRuntime?.getSrNrChain) return t(globalThis.DLSSRuntime.getSrNrChain());
|
|
45
|
+
let r = document.createElement("script");
|
|
46
|
+
r.src = e, r.onload = () => {
|
|
47
|
+
let e = globalThis.DLSSRuntime?.getSrNrChain;
|
|
48
|
+
if (!e) return n(/* @__PURE__ */ Error("DLSS runtime loaded but exposed no neural-rendering entry"));
|
|
49
|
+
t(e());
|
|
50
|
+
}, r.onerror = () => n(/* @__PURE__ */ Error(`Failed to load the DLSS runtime from ${e}`)), document.head.appendChild(r);
|
|
51
|
+
}), u;
|
|
52
|
+
}
|
|
53
|
+
var f = "\n@group(0) @binding(0) var src: texture_2d<f32>;\n@group(0) @binding(1) var<storage, read_write> dst: array<u32>;\n\n@compute @workgroup_size(8, 8)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let size = textureDimensions(src);\n if ( gid.x >= size.x || gid.y >= size.y ) { return; }\n let c = textureLoad(src, vec2<i32>(gid.xy), 0);\n let r = u32(clamp(c.r, 0.0, 1.0) * 255.0 + 0.5);\n let g = u32(clamp(c.g, 0.0, 1.0) * 255.0 + 0.5);\n let b = u32(clamp(c.b, 0.0, 1.0) * 255.0 + 0.5);\n dst[gid.y * size.x + gid.x] = r | (g << 8u) | (b << 16u) | (255u << 24u);\n}\n", p = "\n@group(0) @binding(0) var src: texture_2d<f32>;\n@group(0) @binding(1) var<storage, read_write> dst: array<u32>;\n\n@compute @workgroup_size(8, 8)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let size = textureDimensions(src);\n if ( gid.x >= size.x || gid.y >= size.y ) { return; }\n let c = textureLoad(src, vec2<i32>(gid.xy), 0);\n let a = (gid.y * size.x + gid.x) * 2u;\n dst[a] = pack2x16float(c.rg);\n dst[a + 1u] = pack2x16float(vec2<f32>(c.b, 1.0));\n}\n", m = class e {
|
|
54
|
+
constructor(e, t) {
|
|
55
|
+
this.chain = e, this.canvas = t, this.slot = 0, this.source = null, this.staging = null, this._readbackPipeline = null, this._readbackStorage = null, this._readbackMap = null, this._hdrPipeline = null, this._hdrStorage = null, this._hdrMap = null, this._toneMapper = null, this.disposed = !1;
|
|
56
|
+
}
|
|
57
|
+
get device() {
|
|
58
|
+
return this.chain.device;
|
|
59
|
+
}
|
|
60
|
+
get width() {
|
|
61
|
+
return this.chain.pipeline.geometry.validWidth;
|
|
62
|
+
}
|
|
63
|
+
get height() {
|
|
64
|
+
return this.chain.pipeline.geometry.validHeight;
|
|
65
|
+
}
|
|
66
|
+
static async create({ width: t, height: n, canvas: r = null, settings: i = {}, onProgress: a = () => {} }) {
|
|
67
|
+
if (!Number.isInteger(t) || !Number.isInteger(n) || t < 1 || n < 1) throw Error("DLSSNeural.create: width and height must be positive integers");
|
|
68
|
+
if (t * n > 4194304) throw Error(`DLSSNeural.create: ${t}x${n} is ${(t * n / 1e6).toFixed(1)} MP, above the ${(c / 1e6).toFixed(1)} MP this pass survives. Past it the run takes minutes and then loses every GPU device in the page.`);
|
|
69
|
+
let s = r ?? document.createElement("canvas");
|
|
70
|
+
r || (s.style.cssText = "position:fixed;left:-10000px;top:0;pointer-events:none");
|
|
71
|
+
let l = new e(await (await d()).create(s, t, n, a, o(i).runtime), s);
|
|
72
|
+
return l._allocate(), l;
|
|
73
|
+
}
|
|
74
|
+
_allocate() {
|
|
75
|
+
let { validWidth: e, validHeight: t } = this.chain.pipeline.geometry;
|
|
76
|
+
this.source = this.device.createBuffer({
|
|
77
|
+
label: "rayzee:dlss-nr-source",
|
|
78
|
+
size: e * t * 8,
|
|
79
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
80
|
+
}), this.staging = new Uint16Array(e * t * 4);
|
|
81
|
+
let n = e * t * 4;
|
|
82
|
+
this._readbackStorage = this.device.createBuffer({
|
|
83
|
+
label: "rayzee:dlss-nr-readback",
|
|
84
|
+
size: n,
|
|
85
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
|
|
86
|
+
}), this._readbackMap = this.device.createBuffer({
|
|
87
|
+
label: "rayzee:dlss-nr-readback-map",
|
|
88
|
+
size: n,
|
|
89
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
90
|
+
}), this._readbackPipeline = this.device.createComputePipeline({
|
|
91
|
+
label: "rayzee:dlss-nr-readback",
|
|
92
|
+
layout: "auto",
|
|
93
|
+
compute: {
|
|
94
|
+
module: this.device.createShaderModule({ code: f }),
|
|
95
|
+
entryPoint: "main"
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
let r = e * t * 8;
|
|
99
|
+
this._hdrStorage = this.device.createBuffer({
|
|
100
|
+
label: "rayzee:dlss-nr-hdr",
|
|
101
|
+
size: r,
|
|
102
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
|
|
103
|
+
}), this._hdrMap = this.device.createBuffer({
|
|
104
|
+
label: "rayzee:dlss-nr-hdr-map",
|
|
105
|
+
size: r,
|
|
106
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
107
|
+
}), this._hdrPipeline = this.device.createComputePipeline({
|
|
108
|
+
label: "rayzee:dlss-nr-hdr",
|
|
109
|
+
layout: "auto",
|
|
110
|
+
compute: {
|
|
111
|
+
module: this.device.createShaderModule({ code: p }),
|
|
112
|
+
entryPoint: "main"
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
async _packHDR(e, t, n = !1) {
|
|
117
|
+
let r = this.chain.pipeline.slots[this.slot]?.hdrOutput;
|
|
118
|
+
if (!r) throw Error("DLSSNeural: the runtime has no scene-referred output. Either no frame has been produced yet, or dlss-runtime.js was re-vendored without the patch described in its PATCHES.md.");
|
|
119
|
+
let i = this.device.createBindGroup({
|
|
120
|
+
layout: this._hdrPipeline.getBindGroupLayout(0),
|
|
121
|
+
entries: [{
|
|
122
|
+
binding: 0,
|
|
123
|
+
resource: r.createView()
|
|
124
|
+
}, {
|
|
125
|
+
binding: 1,
|
|
126
|
+
resource: { buffer: this._hdrStorage }
|
|
127
|
+
}]
|
|
128
|
+
}), a = this.device.createCommandEncoder({ label: "rayzee:dlss-nr-hdr" }), o = a.beginComputePass();
|
|
129
|
+
o.setPipeline(this._hdrPipeline), o.setBindGroup(0, i), o.dispatchWorkgroups(Math.ceil(e / 8), Math.ceil(t / 8)), o.end(), n && a.copyBufferToBuffer(this._hdrStorage, 0, this._hdrMap, 0, e * t * 8), this.device.queue.submit([a.finish()]);
|
|
130
|
+
}
|
|
131
|
+
async readOutputHDR() {
|
|
132
|
+
let { validWidth: e, validHeight: t } = this.chain.pipeline.geometry;
|
|
133
|
+
await this._packHDR(e, t, !0), await this._hdrMap.mapAsync(GPUMapMode.READ);
|
|
134
|
+
let n = new Uint16Array(this._hdrMap.getMappedRange().slice(0));
|
|
135
|
+
return this._hdrMap.unmap(), {
|
|
136
|
+
half: n,
|
|
137
|
+
width: e,
|
|
138
|
+
height: t
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
async readOutputToned(e) {
|
|
142
|
+
let { validWidth: t, validHeight: n } = this.chain.pipeline.geometry;
|
|
143
|
+
return await this._packHDR(t, n), this._toneMapper ??= new r(this.device, "rayzee:dlss-nr-tonemap"), this._toneMapper.ensureSize(t, n), {
|
|
144
|
+
rgba8: await this._toneMapper.toRGBA8(this._hdrStorage, {
|
|
145
|
+
exposure: e.exposure ?? 1,
|
|
146
|
+
toneMapping: e.toneMapping ?? 0,
|
|
147
|
+
saturation: e.saturation ?? 1
|
|
148
|
+
}),
|
|
149
|
+
width: t,
|
|
150
|
+
height: n
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
async readOutput() {
|
|
154
|
+
let { validWidth: e, validHeight: t } = this.chain.pipeline.geometry, n = this.chain.pipeline.slots[this.slot]?.output;
|
|
155
|
+
if (!n) throw Error("DLSSNeural.readOutput: the pass has not produced a frame yet");
|
|
156
|
+
let r = this.device.createBindGroup({
|
|
157
|
+
layout: this._readbackPipeline.getBindGroupLayout(0),
|
|
158
|
+
entries: [{
|
|
159
|
+
binding: 0,
|
|
160
|
+
resource: n.createView()
|
|
161
|
+
}, {
|
|
162
|
+
binding: 1,
|
|
163
|
+
resource: { buffer: this._readbackStorage }
|
|
164
|
+
}]
|
|
165
|
+
}), i = this.device.createCommandEncoder({ label: "rayzee:dlss-nr-readback" }), a = i.beginComputePass();
|
|
166
|
+
a.setPipeline(this._readbackPipeline), a.setBindGroup(0, r), a.dispatchWorkgroups(Math.ceil(e / 8), Math.ceil(t / 8)), a.end(), i.copyBufferToBuffer(this._readbackStorage, 0, this._readbackMap, 0, e * t * 4), this.device.queue.submit([i.finish()]), await this._readbackMap.mapAsync(GPUMapMode.READ);
|
|
167
|
+
let o = new Uint8ClampedArray(this._readbackMap.getMappedRange().slice(0));
|
|
168
|
+
return this._readbackMap.unmap(), o;
|
|
169
|
+
}
|
|
170
|
+
dispose() {
|
|
171
|
+
if (!this.disposed) {
|
|
172
|
+
this.disposed = !0, this.source?.destroy(), this._readbackStorage?.destroy(), this._readbackMap?.destroy(), this._hdrStorage?.destroy(), this._hdrMap?.destroy(), this._toneMapper?.dispose();
|
|
173
|
+
try {
|
|
174
|
+
this.chain.destroy();
|
|
175
|
+
} catch (e) {
|
|
176
|
+
s.warn("retouch teardown:", e);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}, h = 20;
|
|
181
|
+
async function g({ source: e, settings: t = {}, instance: n = null, exposure: r = 1, tone: i = null, onProgress: a = () => {} }) {
|
|
182
|
+
let s = n;
|
|
183
|
+
s && (s.width !== e.width || s.height !== e.height) && (s.dispose(), s = null), s ||= await m.create({
|
|
184
|
+
width: e.width,
|
|
185
|
+
height: e.height,
|
|
186
|
+
settings: t,
|
|
187
|
+
onProgress: a
|
|
188
|
+
});
|
|
189
|
+
let { runtime: c, colorStrength: l } = o(t), u = s.staging;
|
|
190
|
+
if (!e.half || e.half.length !== u.length) throw Error(`DLSSNeural: expected ${u.length} packed halfs, got ${e.half?.length}`);
|
|
191
|
+
u.set(e.half), s.device.queue.writeBuffer(s.source, 0, u), s.chain.pipeline.paperWhite = 1 / Math.min(Math.max(r, 1 / h), h), s.chain.pipeline.colorStrength = l;
|
|
192
|
+
let d = performance.now(), f = s.device.createCommandEncoder({ label: "rayzee:dlss-nr" });
|
|
193
|
+
await s.chain.encode(f, s.slot, { buffer: s.source }, c, () => {}, { reset: !0 }), s.device.queue.submit([f.finish()]), await s.device.queue.onSubmittedWorkDone();
|
|
194
|
+
let p = i ? await s.readOutputToned(i) : await s.readOutputHDR();
|
|
195
|
+
return {
|
|
196
|
+
instance: s,
|
|
197
|
+
...p,
|
|
198
|
+
ms: performance.now() - d
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
//#endregion
|
|
202
|
+
export { l as i, a as n, c as r, i as t };
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { t as e } from "./rolldown-runtime-CAFD8bLK.js";
|
|
2
|
+
import { o as t, r as n, t as r } from "./ToneMapGPU-DzqSyzTx.js";
|
|
3
|
+
//#region src/EngineEvents.js
|
|
4
|
+
var i = {
|
|
5
|
+
RENDER_COMPLETE: "engine:renderComplete",
|
|
6
|
+
RENDER_RESET: "engine:renderReset",
|
|
7
|
+
FRAME: "engine:frame",
|
|
8
|
+
DENOISING_START: "engine:denoisingStart",
|
|
9
|
+
DENOISING_END: "engine:denoisingEnd",
|
|
10
|
+
UPSCALING_START: "engine:upscalingStart",
|
|
11
|
+
UPSCALING_PROGRESS: "engine:upscalingProgress",
|
|
12
|
+
UPSCALING_END: "engine:upscalingEnd",
|
|
13
|
+
LOADING_UPDATE: "engine:loadingUpdate",
|
|
14
|
+
LOADING_RESET: "engine:loadingReset",
|
|
15
|
+
STATS_UPDATE: "engine:statsUpdate",
|
|
16
|
+
OBJECT_SELECTED: "engine:objectSelected",
|
|
17
|
+
OBJECT_DESELECTED: "engine:objectDeselected",
|
|
18
|
+
OBJECT_DOUBLE_CLICKED: "engine:objectDoubleClicked",
|
|
19
|
+
SELECT_MODE_CHANGED: "engine:selectModeChanged",
|
|
20
|
+
OBJECT_TRANSFORM_START: "engine:objectTransformStart",
|
|
21
|
+
OBJECT_TRANSFORM_END: "engine:objectTransformEnd",
|
|
22
|
+
TRANSFORM_MODE_CHANGED: "engine:transformModeChanged",
|
|
23
|
+
AUTO_FOCUS_UPDATED: "engine:autoFocusUpdated",
|
|
24
|
+
AUTO_EXPOSURE_UPDATED: "engine:autoExposureUpdated",
|
|
25
|
+
AF_POINT_PLACED: "engine:afPointPlaced",
|
|
26
|
+
SETTING_CHANGED: "engine:settingChanged",
|
|
27
|
+
ANIMATION_STARTED: "engine:animationStarted",
|
|
28
|
+
ANIMATION_PAUSED: "engine:animationPaused",
|
|
29
|
+
ANIMATION_STOPPED: "engine:animationStopped",
|
|
30
|
+
ANIMATION_FINISHED: "engine:animationFinished",
|
|
31
|
+
VIDEO_RENDER_PROGRESS: "engine:videoRenderProgress",
|
|
32
|
+
VIDEO_RENDER_COMPLETE: "engine:videoRenderComplete",
|
|
33
|
+
DISPOSE: "engine:dispose",
|
|
34
|
+
DEVICE_LOST: "engine:deviceLost",
|
|
35
|
+
ISSUE: "engine:issue",
|
|
36
|
+
SCENE_METADATA_APPLIED: "engine:sceneMetadataApplied"
|
|
37
|
+
}, a = /* @__PURE__ */ e({
|
|
38
|
+
DLSSSuperRes: () => g,
|
|
39
|
+
SR_MAX_INPUT: () => c,
|
|
40
|
+
SR_SCALE: () => 2,
|
|
41
|
+
presentRGBA8: () => b,
|
|
42
|
+
readDenoisedHalf: () => h,
|
|
43
|
+
releaseDenoisedReader: () => m,
|
|
44
|
+
renderUpscaled: () => v
|
|
45
|
+
}), o = 2, s = t("dlss"), c = 2048, l = null;
|
|
46
|
+
function u() {
|
|
47
|
+
if (l) return l;
|
|
48
|
+
let { dlssRuntimeUrl: e, dlssAssetBaseUrl: t } = n();
|
|
49
|
+
return globalThis.__DLSS5_ASSET_BASE__ = t, l = new Promise((t, n) => {
|
|
50
|
+
if (globalThis.DLSSRuntime?.getNativeSR) return t(globalThis.DLSSRuntime.getNativeSR());
|
|
51
|
+
let r = document.createElement("script");
|
|
52
|
+
r.src = e, r.onload = () => {
|
|
53
|
+
let e = globalThis.DLSSRuntime?.getNativeSR;
|
|
54
|
+
if (!e) return n(/* @__PURE__ */ Error("DLSS runtime loaded but exposed no super-resolution entry"));
|
|
55
|
+
t(e());
|
|
56
|
+
}, r.onerror = () => n(/* @__PURE__ */ Error(`Failed to load the DLSS runtime from ${e}`)), document.head.appendChild(r);
|
|
57
|
+
}), l;
|
|
58
|
+
}
|
|
59
|
+
var d = "\n@group(0) @binding(0) var src: texture_2d<f32>;\n@group(0) @binding(1) var<storage, read_write> dst: array<u32>;\n\n@compute @workgroup_size(8, 8)\nfn main( @builtin(global_invocation_id) gid: vec3<u32> ) {\n let size = textureDimensions( src );\n if ( gid.x >= size.x || gid.y >= size.y ) { return; }\n let c = textureLoad( src, vec2<i32>( gid.xy ), 0 ).rgb;\n let a = ( gid.y * size.x + gid.x ) * 2u;\n dst[ a ] = pack2x16float( c.rg );\n dst[ a + 1u ] = pack2x16float( vec2<f32>( c.b, 1.0 ) );\n}\n", f = null;
|
|
60
|
+
function p(e, t, n) {
|
|
61
|
+
if (f && (f.device !== e || f.width !== t || f.height !== n) && m(), f) return f;
|
|
62
|
+
let r = t * n * 8;
|
|
63
|
+
return f = {
|
|
64
|
+
device: e,
|
|
65
|
+
width: t,
|
|
66
|
+
height: n,
|
|
67
|
+
storage: e.createBuffer({
|
|
68
|
+
label: "rayzee:dlss-sr-pack",
|
|
69
|
+
size: r,
|
|
70
|
+
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC
|
|
71
|
+
}),
|
|
72
|
+
map: e.createBuffer({
|
|
73
|
+
label: "rayzee:dlss-sr-pack-map",
|
|
74
|
+
size: r,
|
|
75
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
|
|
76
|
+
}),
|
|
77
|
+
pipeline: e.createComputePipeline({
|
|
78
|
+
label: "rayzee:dlss-sr-pack",
|
|
79
|
+
layout: "auto",
|
|
80
|
+
compute: {
|
|
81
|
+
module: e.createShaderModule({
|
|
82
|
+
label: "rayzee:dlss-sr-pack",
|
|
83
|
+
code: d
|
|
84
|
+
}),
|
|
85
|
+
entryPoint: "main"
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
}, f;
|
|
89
|
+
}
|
|
90
|
+
function m() {
|
|
91
|
+
f?.storage.destroy(), f?.map.destroy(), f = null;
|
|
92
|
+
}
|
|
93
|
+
async function h(e) {
|
|
94
|
+
let t = e?._outGPUTexture;
|
|
95
|
+
if (!t) throw Error("DLSSSuperRes: no denoised frame — enable OIDN and finish a render first");
|
|
96
|
+
let n = e.gpuDevice, { width: r, height: i } = e._outTexSize, a = p(n, r, i), o = n.createBindGroup({
|
|
97
|
+
layout: a.pipeline.getBindGroupLayout(0),
|
|
98
|
+
entries: [{
|
|
99
|
+
binding: 0,
|
|
100
|
+
resource: t.createView()
|
|
101
|
+
}, {
|
|
102
|
+
binding: 1,
|
|
103
|
+
resource: { buffer: a.storage }
|
|
104
|
+
}]
|
|
105
|
+
}), s = n.createCommandEncoder({ label: "rayzee:dlss-sr-pack" }), c = s.beginComputePass();
|
|
106
|
+
c.setPipeline(a.pipeline), c.setBindGroup(0, o), c.dispatchWorkgroups(Math.ceil(r / 8), Math.ceil(i / 8)), c.end(), s.copyBufferToBuffer(a.storage, 0, a.map, 0, r * i * 8), n.queue.submit([s.finish()]), await a.map.mapAsync(GPUMapMode.READ);
|
|
107
|
+
let l = new Uint16Array(a.map.getMappedRange().slice(0));
|
|
108
|
+
return a.map.unmap(), {
|
|
109
|
+
half: l,
|
|
110
|
+
width: r,
|
|
111
|
+
height: i
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
var g = class e {
|
|
115
|
+
constructor(e, t) {
|
|
116
|
+
this.sr = e, this.canvas = t, this.slot = 0, this._color = null, this._depth = null, this._motion = null, this._toneMapper = null, this.disposed = !1;
|
|
117
|
+
}
|
|
118
|
+
get geometry() {
|
|
119
|
+
return this.sr.geometry;
|
|
120
|
+
}
|
|
121
|
+
get inputWidth() {
|
|
122
|
+
return this.sr.geometry.width;
|
|
123
|
+
}
|
|
124
|
+
get inputHeight() {
|
|
125
|
+
return this.sr.geometry.height;
|
|
126
|
+
}
|
|
127
|
+
get outputWidth() {
|
|
128
|
+
return this.sr.geometry.outputWidth;
|
|
129
|
+
}
|
|
130
|
+
get outputHeight() {
|
|
131
|
+
return this.sr.geometry.outputHeight;
|
|
132
|
+
}
|
|
133
|
+
static async create({ width: t, height: n, onProgress: r = () => {} } = {}) {
|
|
134
|
+
if (!Number.isInteger(t) || !Number.isInteger(n) || t < 1 || n < 1) throw Error("DLSSSuperRes.create: width and height must be positive integers");
|
|
135
|
+
if (t > 2048 || n > 2048) throw Error(`DLSSSuperRes.create: input capped at ${c}px per side (${c * 2}px output), got ${t}x${n}. Above that the runtime's history plane exceeds maxTextureDimension2D and it fails later with an unrelated bind-group error.`);
|
|
136
|
+
let i = await u(), a = document.createElement("canvas");
|
|
137
|
+
a.style.cssText = "position:fixed;left:-10000px;top:0;pointer-events:none", document.body.appendChild(a);
|
|
138
|
+
let o;
|
|
139
|
+
try {
|
|
140
|
+
o = await i.create(a, {
|
|
141
|
+
width: t,
|
|
142
|
+
height: n,
|
|
143
|
+
onProgress: r,
|
|
144
|
+
timestamps: !0,
|
|
145
|
+
nrSettings: null
|
|
146
|
+
});
|
|
147
|
+
} catch (e) {
|
|
148
|
+
throw a.remove(), e;
|
|
149
|
+
}
|
|
150
|
+
let s = new e(o, a);
|
|
151
|
+
return s._allocate(), s;
|
|
152
|
+
}
|
|
153
|
+
_allocate() {
|
|
154
|
+
let e = this.inputWidth, t = this.inputHeight;
|
|
155
|
+
this._color = new Uint16Array(e * t * 4), this._depth = new Float32Array(e * t), this._motion = new Uint16Array(e * t * 2);
|
|
156
|
+
}
|
|
157
|
+
async _run(e) {
|
|
158
|
+
if (this.disposed) throw Error("DLSSSuperRes: disposed");
|
|
159
|
+
let t = this.inputWidth, n = this.inputHeight;
|
|
160
|
+
if (e.width !== t || e.height !== n) throw Error(`DLSSSuperRes: expected a ${t}x${n} source, got ${e.width}x${e.height}`);
|
|
161
|
+
let r = this._color;
|
|
162
|
+
if (!e.half || e.half.length !== r.length) throw Error(`DLSSSuperRes: expected ${r.length} packed halfs from readDenoisedHalf, got ${e.half?.length}`);
|
|
163
|
+
r.set(e.half), this._depth.fill(.5), this._motion.fill(0);
|
|
164
|
+
let i = performance.now(), a = await this.sr.render(this.slot, {
|
|
165
|
+
color: r,
|
|
166
|
+
depth: this._depth,
|
|
167
|
+
motion: this._motion,
|
|
168
|
+
reset: !0,
|
|
169
|
+
jitter: [0, 0]
|
|
170
|
+
});
|
|
171
|
+
return await this.sr.device.queue.onSubmittedWorkDone(), {
|
|
172
|
+
result: a,
|
|
173
|
+
ms: performance.now() - i
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
async upscaleToRGBA8(e, t = {}) {
|
|
177
|
+
let { result: n, ms: i } = await this._run(e), { outputWidth: a, outputHeight: o } = this.geometry;
|
|
178
|
+
this._toneMapper ??= new r(this.sr.device, "rayzee:dlss-sr-tonemap"), this._toneMapper.ensureSize(a, o);
|
|
179
|
+
let s = performance.now();
|
|
180
|
+
return {
|
|
181
|
+
rgba8: await this._toneMapper.toRGBA8(n.hdr.buffer ?? n.hdr, {
|
|
182
|
+
exposure: t.exposure ?? 1,
|
|
183
|
+
toneMapping: t.toneMapping ?? 0,
|
|
184
|
+
saturation: t.saturation ?? 1,
|
|
185
|
+
flipY: !0
|
|
186
|
+
}),
|
|
187
|
+
width: a,
|
|
188
|
+
height: o,
|
|
189
|
+
ms: i,
|
|
190
|
+
toneMs: performance.now() - s
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
dispose() {
|
|
194
|
+
if (!this.disposed) {
|
|
195
|
+
this.disposed = !0, this._toneMapper?.dispose(), this._toneMapper = null, this.canvas.remove();
|
|
196
|
+
try {
|
|
197
|
+
this.sr.destroy();
|
|
198
|
+
} catch (e) {
|
|
199
|
+
s.warn("super resolution teardown:", e);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
function _(e, t, n) {
|
|
205
|
+
return new Promise((r, a) => {
|
|
206
|
+
let o = !1, s = (t, n) => {
|
|
207
|
+
o || (o = !0, e.removeEventListener(i.DENOISING_END, l), clearInterval(u), clearTimeout(d), t ? r() : a(n));
|
|
208
|
+
}, c = !1, l = () => {
|
|
209
|
+
(e.stages?.pathTracer?.frameCount ?? 0) >= t && (c = !0);
|
|
210
|
+
};
|
|
211
|
+
e.addEventListener(i.DENOISING_END, l);
|
|
212
|
+
let u = setInterval(() => {
|
|
213
|
+
c && s(!0);
|
|
214
|
+
}, 200), d = setTimeout(() => s(!1, /* @__PURE__ */ Error("DLSSSuperRes: timed out waiting for the render to finish")), n);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
async function v(e, { outputWidth: t, outputHeight: n, samples: r = 64, upscaler: i = null, timeoutMs: a = 6e5, present: o = !0, onProgress: s = () => {} } = {}) {
|
|
218
|
+
if (t % 2 || n % 2) throw Error(`renderUpscaled: output must be divisible by 2, got ${t}x${n}`);
|
|
219
|
+
let c = t / 2, l = n / 2, u = e.stages?.pathTracer, d = {
|
|
220
|
+
width: u?.width,
|
|
221
|
+
height: u?.height,
|
|
222
|
+
maxSamples: e.settings?.get?.("maxSamples"),
|
|
223
|
+
finalDenoise: e.denoisingManager?.finalDenoise,
|
|
224
|
+
paused: e.pauseRendering
|
|
225
|
+
}, f = !i, p = i, m = {};
|
|
226
|
+
try {
|
|
227
|
+
if (!p) {
|
|
228
|
+
let e = performance.now();
|
|
229
|
+
s("Loading the super-resolution model"), p = await g.create({
|
|
230
|
+
width: c,
|
|
231
|
+
height: l,
|
|
232
|
+
onProgress: s
|
|
233
|
+
}), m.load = performance.now() - e;
|
|
234
|
+
} else if (p.inputWidth !== c || p.inputHeight !== l) throw Error(`renderUpscaled: upscaler is ${p.inputWidth}x${p.inputHeight}, need ${c}x${l}`);
|
|
235
|
+
let i = performance.now();
|
|
236
|
+
s(`Tracing ${c}x${l} at ${r} spp`), e.pauseRendering = !1, e.setCanvasSize(c, l), await new Promise((e) => setTimeout(e, 300)), e.denoisingManager.applyOIDNEnabled(!0), e.settings.set("maxSamples", r);
|
|
237
|
+
let u = _(e, r, a);
|
|
238
|
+
e.reset(), await u, e.pauseRendering = !0, m.render = performance.now() - i, s("Reading the denoised frame");
|
|
239
|
+
let d = performance.now(), f = await h(e.denoisingManager?.denoiser);
|
|
240
|
+
m.read = performance.now() - d, s(`Upscaling to ${t}x${n}`);
|
|
241
|
+
let v = {
|
|
242
|
+
exposure: e.renderer.toneMappingExposure,
|
|
243
|
+
toneMapping: e.renderer.toneMapping,
|
|
244
|
+
saturation: e.settings.get("saturation") ?? 1
|
|
245
|
+
}, { rgba8: b, width: x, height: S, ms: C, toneMs: w } = await p.upscaleToRGBA8(f, v);
|
|
246
|
+
return m.upscale = C, m.tonemap = w, o && y(e.denoisingManager?.upscalerCanvas, b, x, S), {
|
|
247
|
+
rgba8: b,
|
|
248
|
+
width: x,
|
|
249
|
+
height: S,
|
|
250
|
+
timings: m,
|
|
251
|
+
upscaler: p
|
|
252
|
+
};
|
|
253
|
+
} catch (e) {
|
|
254
|
+
throw f && p?.dispose(), e;
|
|
255
|
+
} finally {
|
|
256
|
+
d.width && d.height && e.setCanvasSize(d.width, d.height), d.maxSamples !== void 0 && e.settings?.set?.("maxSamples", d.maxSamples), d.finalDenoise !== void 0 && e.denoisingManager?.applyOIDNEnabled(d.finalDenoise), e.pauseRendering = d.paused;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function y(e, t, n, r) {
|
|
260
|
+
return e ? (e.width = n, e.height = r, e.getContext("2d").putImageData(new ImageData(new Uint8ClampedArray(t.buffer ?? t), n, r), 0, 0), e.style.display = "block", !0) : !1;
|
|
261
|
+
}
|
|
262
|
+
function b(e, t, n, r) {
|
|
263
|
+
return y(e, t, n, r);
|
|
264
|
+
}
|
|
265
|
+
//#endregion
|
|
266
|
+
export { i as a, v as i, c as n, o as r, a as t };
|