oidn-web 0.2.2 → 0.3.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 +6 -3
- package/dist/oidn.js +3520 -3407
- package/dist/oidn.umd.cjs +474 -464
- package/lib/UNet.d.ts +22 -5
- package/lib/UNet.js +101 -74
- package/lib/UNet.js.map +1 -1
- package/lib/WGPUComputePass.d.ts +13 -3
- package/lib/WGPUComputePass.js +85 -29
- package/lib/WGPUComputePass.js.map +1 -1
- package/lib/backend.js +6 -1
- package/lib/backend.js.map +1 -1
- package/lib/helper.d.ts +3 -0
- package/lib/helper.js +6 -0
- package/lib/helper.js.map +1 -1
- package/lib/process.d.ts +14 -5
- package/lib/process.js +207 -86
- package/lib/process.js.map +1 -1
- package/package.json +1 -1
- package/src/UNet.ts +154 -100
- package/src/WGPUComputePass.ts +100 -38
- package/src/backend.ts +8 -2
- package/src/helper.ts +8 -0
- package/src/process.ts +227 -98
package/src/process.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { buffer, data } from '@tensorflow/tfjs';
|
|
1
2
|
import { WGPUComputePass } from './WGPUComputePass';
|
|
2
3
|
|
|
3
4
|
const a = 1.41283765e3;
|
|
@@ -140,12 +141,53 @@ const rcpNormScale = ${rcpNormScale};
|
|
|
140
141
|
`;
|
|
141
142
|
|
|
142
143
|
export class GPUDataProcess {
|
|
143
|
-
private
|
|
144
|
+
private _inputPassAux;
|
|
145
|
+
private _inputPassColor;
|
|
144
146
|
private _outputPass;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
private _copyPass;
|
|
148
|
+
|
|
149
|
+
private _isInputTexture = false;
|
|
150
|
+
|
|
151
|
+
constructor(private _device: GPUDevice, private _isHDR: boolean) {
|
|
152
|
+
const commonUniforms = [
|
|
153
|
+
{
|
|
154
|
+
label: 'inputScale',
|
|
155
|
+
type: 'f32',
|
|
156
|
+
data: new Float32Array([1])
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
label: 'inputSize',
|
|
160
|
+
type: 'vec2<f32>',
|
|
161
|
+
data: new Float32Array(2)
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
label: 'outputSize',
|
|
165
|
+
type: 'vec2<f32>',
|
|
166
|
+
data: new Float32Array(2)
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
label: 'inputOffset',
|
|
170
|
+
type: 'vec2<f32>',
|
|
171
|
+
data: new Float32Array(2)
|
|
172
|
+
}
|
|
173
|
+
];
|
|
174
|
+
this._inputPassAux = new WGPUComputePass('inputPassAux', this._device, {
|
|
147
175
|
inputs: ['color', 'albedo', 'normal'],
|
|
148
176
|
outputs: ['color', 'albedo', 'normal'],
|
|
177
|
+
uniforms: commonUniforms,
|
|
178
|
+
csDefine: '',
|
|
179
|
+
csMain: ``
|
|
180
|
+
});
|
|
181
|
+
this._inputPassColor = new WGPUComputePass('inputPassColor', this._device, {
|
|
182
|
+
inputs: ['color'],
|
|
183
|
+
outputs: ['color'],
|
|
184
|
+
uniforms: commonUniforms,
|
|
185
|
+
csDefine: '',
|
|
186
|
+
csMain: ``
|
|
187
|
+
});
|
|
188
|
+
this._outputPass = new WGPUComputePass('outputPass', this._device, {
|
|
189
|
+
inputs: ['color', 'raw'],
|
|
190
|
+
outputs: ['color'],
|
|
149
191
|
uniforms: [
|
|
150
192
|
{
|
|
151
193
|
label: 'inputScale',
|
|
@@ -162,13 +204,62 @@ export class GPUDataProcess {
|
|
|
162
204
|
type: 'vec2<f32>',
|
|
163
205
|
data: new Float32Array(2)
|
|
164
206
|
},
|
|
207
|
+
{
|
|
208
|
+
label: 'imageSize',
|
|
209
|
+
type: 'vec2<f32>',
|
|
210
|
+
data: new Float32Array(2)
|
|
211
|
+
},
|
|
165
212
|
{
|
|
166
213
|
label: 'inputOffset',
|
|
167
214
|
type: 'vec2<f32>',
|
|
168
215
|
data: new Float32Array(2)
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
label: 'outputOffset',
|
|
219
|
+
type: 'vec2<f32>',
|
|
220
|
+
data: new Float32Array(2)
|
|
169
221
|
}
|
|
170
222
|
],
|
|
171
|
-
csDefine:
|
|
223
|
+
csDefine: '',
|
|
224
|
+
csMain: ``
|
|
225
|
+
});
|
|
226
|
+
this._copyPass = new WGPUComputePass('copyPass', this._device, {
|
|
227
|
+
inputs: ['color'],
|
|
228
|
+
outputs: ['color'],
|
|
229
|
+
autoUpdateOutputBuffer: false,
|
|
230
|
+
uniforms: [
|
|
231
|
+
{
|
|
232
|
+
label: 'size',
|
|
233
|
+
type: 'vec2<f32>',
|
|
234
|
+
data: new Float32Array(2)
|
|
235
|
+
}
|
|
236
|
+
],
|
|
237
|
+
csMain: /*wgsl*/ `
|
|
238
|
+
let outIdx = i32(globalId.x + globalId.y * u32(size.x));
|
|
239
|
+
out_color[outIdx] = textureLoad(in_color, globalId.xy, 0);
|
|
240
|
+
`
|
|
241
|
+
});
|
|
242
|
+
this._inputPassAux.setOutputParams({
|
|
243
|
+
color: { channels: 3 },
|
|
244
|
+
albedo: { channels: 3 },
|
|
245
|
+
normal: { channels: 3 }
|
|
246
|
+
});
|
|
247
|
+
this._inputPassColor.setOutputParams({
|
|
248
|
+
color: { channels: 3 }
|
|
249
|
+
});
|
|
250
|
+
this._outputPass.setOutputParams({
|
|
251
|
+
color: { channels: 4 }
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private _updatePasses(isInputTexture: boolean, denoiseAlpha = false) {
|
|
256
|
+
if (this._isInputTexture === isInputTexture) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
this._isInputTexture = isInputTexture;
|
|
261
|
+
const isHDR = this._isHDR;
|
|
262
|
+
const commonCSDefine = /* wgsl */ `
|
|
172
263
|
${constsCode}
|
|
173
264
|
fn PUForward(y: f32) -> f32 {
|
|
174
265
|
if (y <= y0) {
|
|
@@ -178,59 +269,49 @@ fn PUForward(y: f32) -> f32 {
|
|
|
178
269
|
} else {
|
|
179
270
|
return e * log(y + f) + g;
|
|
180
271
|
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
272
|
+
}`;
|
|
273
|
+
function readInputCode(inputName: string) {
|
|
274
|
+
return isInputTexture
|
|
275
|
+
? `textureLoad(in_${inputName}, globalId.xy + vec2u(inputOffset), 0)`
|
|
276
|
+
: `in_${inputName}[inIdx]'`;
|
|
277
|
+
}
|
|
278
|
+
const commonCSMain = /* wgsl */ `
|
|
184
279
|
let x = f32(globalId.x);
|
|
185
280
|
let y = f32(globalId.y);
|
|
186
281
|
let inIdx = i32((y + inputOffset.y) * inputSize.x + (x + inputOffset.x));
|
|
187
|
-
let col =
|
|
188
|
-
let alb = in_albedo[inIdx];
|
|
189
|
-
let nor = in_normal[inIdx];
|
|
282
|
+
let col = ${readInputCode('color')};
|
|
190
283
|
|
|
191
284
|
let outIdx = i32(y * outputSize.x + x);
|
|
192
|
-
|
|
285
|
+
|
|
286
|
+
if (${denoiseAlpha}) {
|
|
287
|
+
// Denoise the inversed alpha. Or the anti aliased edge will be too dark after denoised
|
|
288
|
+
out_color[outIdx] = vec3f(1.0 - col.a);
|
|
289
|
+
}
|
|
290
|
+
else if (${isHDR}) {
|
|
291
|
+
out_color[outIdx] = vec3f(PUForward(col.r * inputScale), PUForward(col.g * inputScale), PUForward(col.b * inputScale)) * normScale;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
out_color[outIdx] = col.rgb;
|
|
295
|
+
}
|
|
296
|
+
`;
|
|
297
|
+
this._inputPassAux.setCSCode({
|
|
298
|
+
csDefine: commonCSDefine,
|
|
299
|
+
csMain: /* wgsl */ `
|
|
300
|
+
${commonCSMain}
|
|
301
|
+
let alb = ${readInputCode('albedo')};
|
|
302
|
+
let nor = ${readInputCode('normal')};
|
|
193
303
|
out_normal[outIdx] = nor.rgb;
|
|
194
304
|
out_albedo[outIdx] = alb.rgb;
|
|
195
|
-
`
|
|
305
|
+
`
|
|
196
306
|
});
|
|
197
307
|
|
|
198
|
-
this.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
type: 'f32',
|
|
206
|
-
data: new Float32Array([1])
|
|
207
|
-
},
|
|
208
|
-
{
|
|
209
|
-
label: 'inputSize',
|
|
210
|
-
type: 'vec2<f32>',
|
|
211
|
-
data: new Float32Array(2)
|
|
212
|
-
},
|
|
213
|
-
{
|
|
214
|
-
label: 'outputSize',
|
|
215
|
-
type: 'vec2<f32>',
|
|
216
|
-
data: new Float32Array(2)
|
|
217
|
-
},
|
|
218
|
-
{
|
|
219
|
-
label: 'imageSize',
|
|
220
|
-
type: 'vec2<f32>',
|
|
221
|
-
data: new Float32Array(2)
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
label: 'inputOffset',
|
|
225
|
-
type: 'vec2<f32>',
|
|
226
|
-
data: new Float32Array(2)
|
|
227
|
-
},
|
|
228
|
-
{
|
|
229
|
-
label: 'outputOffset',
|
|
230
|
-
type: 'vec2<f32>',
|
|
231
|
-
data: new Float32Array(2)
|
|
232
|
-
}
|
|
233
|
-
],
|
|
308
|
+
this._inputPassColor.setCSCode({
|
|
309
|
+
csDefine: commonCSDefine,
|
|
310
|
+
csMain: /* wgsl */ `
|
|
311
|
+
${commonCSMain}
|
|
312
|
+
`
|
|
313
|
+
});
|
|
314
|
+
this._outputPass.setCSCode({
|
|
234
315
|
csDefine: /* wgsl */ `
|
|
235
316
|
${constsCode}
|
|
236
317
|
fn PUInverse(y: f32) -> f32 {
|
|
@@ -251,40 +332,46 @@ if (x >= outputSize.x || y >= outputSize.y) {
|
|
|
251
332
|
}
|
|
252
333
|
let inIdx = i32((y + inputOffset.y) * inputSize.x + x + inputOffset.x);
|
|
253
334
|
let outIdx = i32((y + outputOffset.y) * imageSize.x + x + outputOffset.x);
|
|
254
|
-
let col = in_color[inIdx]
|
|
255
|
-
let raw =
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
335
|
+
let col = in_color[inIdx];
|
|
336
|
+
let raw = ${
|
|
337
|
+
isInputTexture
|
|
338
|
+
? 'textureLoad(in_raw, globalId.xy + vec2u(outputOffset), 0)'
|
|
339
|
+
: 'in_raw[outIdx]'
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
if (${denoiseAlpha}) {
|
|
343
|
+
out_color[outIdx] = vec4f(raw.rgb, 1.0 - col.r);
|
|
344
|
+
}
|
|
345
|
+
else if (${isHDR}) {
|
|
346
|
+
out_color[outIdx] = vec4f(
|
|
347
|
+
vec3f(PUInverse(col.r * rcpNormScale), PUInverse(col.g * rcpNormScale), PUInverse(col.b * rcpNormScale)) / inputScale,
|
|
348
|
+
// Pick the alpha
|
|
349
|
+
raw.a
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
out_color[outIdx] = vec4f(col.rgb, raw.a);
|
|
354
|
+
}
|
|
261
355
|
`
|
|
262
356
|
});
|
|
263
|
-
|
|
264
|
-
// TODO input scale
|
|
265
|
-
this._inputPass.setOutputParams({
|
|
266
|
-
color: { channels: 3 },
|
|
267
|
-
albedo: { channels: 3 },
|
|
268
|
-
normal: { channels: 3 }
|
|
269
|
-
});
|
|
270
|
-
// TODO input scale
|
|
271
|
-
this._outputPass.setOutputParams({
|
|
272
|
-
color: { channels: 4 }
|
|
273
|
-
});
|
|
274
357
|
}
|
|
275
358
|
|
|
276
359
|
setImageSize(w: number, h: number) {
|
|
277
|
-
this.
|
|
360
|
+
this._inputPassAux.setUniform('inputSize', new Float32Array([w, h]));
|
|
361
|
+
this._inputPassColor.setUniform('inputSize', new Float32Array([w, h]));
|
|
278
362
|
this._outputPass.setUniform('imageSize', new Float32Array([w, h]));
|
|
279
363
|
this._outputPass.setSize(w, h);
|
|
364
|
+
this._copyPass.setSize(w, h);
|
|
365
|
+
this._copyPass.setUniform('size', new Float32Array([w, h]));
|
|
280
366
|
}
|
|
281
367
|
|
|
282
368
|
setInputTile(tile: Tile) {
|
|
283
|
-
const inputPass = this._inputPass;
|
|
284
369
|
const size = new Float32Array([tile.width, tile.height]);
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
370
|
+
[this._inputPassAux, this._inputPassColor].forEach((inputPass) => {
|
|
371
|
+
inputPass.setUniform('inputOffset', new Float32Array([tile.x, tile.y]));
|
|
372
|
+
inputPass.setUniform('outputSize', size);
|
|
373
|
+
inputPass.setSize(size[0], size[1]);
|
|
374
|
+
});
|
|
288
375
|
|
|
289
376
|
this._outputPass.setUniform('inputSize', size);
|
|
290
377
|
}
|
|
@@ -304,28 +391,56 @@ out_color[outIdx] = vec4f(
|
|
|
304
391
|
}
|
|
305
392
|
|
|
306
393
|
forward(
|
|
307
|
-
colorBuffer: GPUBuffer,
|
|
394
|
+
colorBuffer: GPUBuffer | GPUTexture,
|
|
308
395
|
// TODO optional albedo and normal.
|
|
309
|
-
albedoBuffer: GPUBuffer,
|
|
310
|
-
normalBuffer: GPUBuffer
|
|
396
|
+
albedoBuffer: GPUBuffer | GPUTexture | undefined,
|
|
397
|
+
normalBuffer: GPUBuffer | GPUTexture | undefined,
|
|
398
|
+
|
|
399
|
+
denoiseAlpha: boolean | undefined
|
|
311
400
|
) {
|
|
312
|
-
const
|
|
401
|
+
const isInputTexture = colorBuffer instanceof GPUTexture;
|
|
402
|
+
this._updatePasses(isInputTexture, denoiseAlpha);
|
|
403
|
+
|
|
404
|
+
const inputPassAux = this._inputPassAux;
|
|
405
|
+
const inputPassColor = this._inputPassColor;
|
|
313
406
|
const commandEncoder = this._device.createCommandEncoder();
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
407
|
+
|
|
408
|
+
function createInput(bufferOrTex: GPUBuffer | GPUTexture) {
|
|
409
|
+
return bufferOrTex instanceof GPUTexture
|
|
410
|
+
? {
|
|
411
|
+
texture: bufferOrTex,
|
|
412
|
+
channels: 4
|
|
413
|
+
}
|
|
414
|
+
: {
|
|
415
|
+
buffer: bufferOrTex,
|
|
416
|
+
channels: 4
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
if (albedoBuffer && normalBuffer) {
|
|
420
|
+
inputPassAux.createPass(commandEncoder, {
|
|
421
|
+
color: createInput(colorBuffer),
|
|
422
|
+
albedo: createInput(albedoBuffer),
|
|
423
|
+
normal: createInput(normalBuffer)
|
|
424
|
+
});
|
|
425
|
+
} else {
|
|
426
|
+
inputPassColor.createPass(commandEncoder, {
|
|
427
|
+
color: createInput(colorBuffer)
|
|
428
|
+
});
|
|
429
|
+
}
|
|
319
430
|
this._device.queue.submit([commandEncoder.finish()]);
|
|
320
431
|
|
|
321
|
-
return
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
432
|
+
return albedoBuffer && normalBuffer
|
|
433
|
+
? {
|
|
434
|
+
color: inputPassAux.getOutput('color'),
|
|
435
|
+
albedo: inputPassAux.getOutput('albedo'),
|
|
436
|
+
normal: inputPassAux.getOutput('normal')
|
|
437
|
+
}
|
|
438
|
+
: {
|
|
439
|
+
color: inputPassColor.getOutput('color')
|
|
440
|
+
};
|
|
326
441
|
}
|
|
327
442
|
|
|
328
|
-
inverse(buffer: GPUBuffer, raw: GPUBuffer) {
|
|
443
|
+
inverse(buffer: GPUBuffer, raw: GPUBuffer | GPUTexture) {
|
|
329
444
|
const device = this._device;
|
|
330
445
|
|
|
331
446
|
const commandEncoder = device.createCommandEncoder();
|
|
@@ -333,30 +448,44 @@ out_color[outIdx] = vec4f(
|
|
|
333
448
|
|
|
334
449
|
outputGPUPass.createPass(commandEncoder, {
|
|
335
450
|
color: { buffer: buffer, channels: 4 },
|
|
336
|
-
raw:
|
|
451
|
+
raw:
|
|
452
|
+
raw instanceof GPUBuffer
|
|
453
|
+
? { buffer: raw, channels: 4 }
|
|
454
|
+
: { texture: raw, channels: 4 }
|
|
337
455
|
});
|
|
338
456
|
this._device.queue.submit([commandEncoder.finish()]);
|
|
339
457
|
|
|
340
|
-
return outputGPUPass.
|
|
458
|
+
return outputGPUPass.getOutput('color');
|
|
341
459
|
}
|
|
342
460
|
|
|
343
|
-
copyInputDataToOutput(inputColorBuffer: GPUBuffer) {
|
|
461
|
+
copyInputDataToOutput(inputColorBuffer: GPUBuffer | GPUTexture) {
|
|
344
462
|
const encoder = this._device.createCommandEncoder();
|
|
345
463
|
const outputGPUPass = this._outputPass;
|
|
346
|
-
const colorBuffer = outputGPUPass.
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
464
|
+
const colorBuffer = outputGPUPass.getOutput('color');
|
|
465
|
+
const copyPass = this._copyPass;
|
|
466
|
+
|
|
467
|
+
if (inputColorBuffer instanceof GPUTexture) {
|
|
468
|
+
copyPass.setOutputBuffers({
|
|
469
|
+
color: colorBuffer
|
|
470
|
+
});
|
|
471
|
+
copyPass.createPass(encoder, {
|
|
472
|
+
color: { texture: inputColorBuffer, channels: 4 }
|
|
473
|
+
});
|
|
474
|
+
} else {
|
|
475
|
+
encoder.copyBufferToBuffer(
|
|
476
|
+
inputColorBuffer,
|
|
477
|
+
0,
|
|
478
|
+
colorBuffer,
|
|
479
|
+
0,
|
|
480
|
+
colorBuffer.size
|
|
481
|
+
);
|
|
482
|
+
}
|
|
354
483
|
|
|
355
484
|
this._device.queue.submit([encoder.finish()]);
|
|
356
485
|
}
|
|
357
486
|
|
|
358
487
|
dispose() {
|
|
359
488
|
this._outputPass.dispose();
|
|
360
|
-
this.
|
|
489
|
+
this._inputPassAux.dispose();
|
|
361
490
|
}
|
|
362
491
|
}
|