oidn-web 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +208 -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 +230 -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?: boolean;
|
|
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,65 @@ 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 (
|
|
257
|
+
this._isInputTexture != undefined &&
|
|
258
|
+
this._isInputTexture === isInputTexture
|
|
259
|
+
) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
this._isInputTexture = isInputTexture;
|
|
264
|
+
const isHDR = this._isHDR;
|
|
265
|
+
const commonCSDefine = /* wgsl */ `
|
|
172
266
|
${constsCode}
|
|
173
267
|
fn PUForward(y: f32) -> f32 {
|
|
174
268
|
if (y <= y0) {
|
|
@@ -178,59 +272,49 @@ fn PUForward(y: f32) -> f32 {
|
|
|
178
272
|
} else {
|
|
179
273
|
return e * log(y + f) + g;
|
|
180
274
|
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
275
|
+
}`;
|
|
276
|
+
function readInputCode(inputName: string) {
|
|
277
|
+
return isInputTexture
|
|
278
|
+
? `textureLoad(in_${inputName}, globalId.xy + vec2u(inputOffset), 0)`
|
|
279
|
+
: `in_${inputName}[inIdx]`;
|
|
280
|
+
}
|
|
281
|
+
const commonCSMain = /* wgsl */ `
|
|
184
282
|
let x = f32(globalId.x);
|
|
185
283
|
let y = f32(globalId.y);
|
|
186
284
|
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];
|
|
285
|
+
let col = ${readInputCode('color')};
|
|
190
286
|
|
|
191
287
|
let outIdx = i32(y * outputSize.x + x);
|
|
192
|
-
|
|
288
|
+
|
|
289
|
+
if (${denoiseAlpha}) {
|
|
290
|
+
// Denoise the inversed alpha. Or the anti aliased edge will be too dark after denoised
|
|
291
|
+
out_color[outIdx] = vec3f(1.0 - col.a);
|
|
292
|
+
}
|
|
293
|
+
else if (${isHDR}) {
|
|
294
|
+
out_color[outIdx] = vec3f(PUForward(col.r * inputScale), PUForward(col.g * inputScale), PUForward(col.b * inputScale)) * normScale;
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
out_color[outIdx] = col.rgb;
|
|
298
|
+
}
|
|
299
|
+
`;
|
|
300
|
+
this._inputPassAux.setCSCode({
|
|
301
|
+
csDefine: commonCSDefine,
|
|
302
|
+
csMain: /* wgsl */ `
|
|
303
|
+
${commonCSMain}
|
|
304
|
+
let alb = ${readInputCode('albedo')};
|
|
305
|
+
let nor = ${readInputCode('normal')};
|
|
193
306
|
out_normal[outIdx] = nor.rgb;
|
|
194
307
|
out_albedo[outIdx] = alb.rgb;
|
|
195
|
-
`
|
|
308
|
+
`
|
|
196
309
|
});
|
|
197
310
|
|
|
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
|
-
],
|
|
311
|
+
this._inputPassColor.setCSCode({
|
|
312
|
+
csDefine: commonCSDefine,
|
|
313
|
+
csMain: /* wgsl */ `
|
|
314
|
+
${commonCSMain}
|
|
315
|
+
`
|
|
316
|
+
});
|
|
317
|
+
this._outputPass.setCSCode({
|
|
234
318
|
csDefine: /* wgsl */ `
|
|
235
319
|
${constsCode}
|
|
236
320
|
fn PUInverse(y: f32) -> f32 {
|
|
@@ -251,40 +335,46 @@ if (x >= outputSize.x || y >= outputSize.y) {
|
|
|
251
335
|
}
|
|
252
336
|
let inIdx = i32((y + inputOffset.y) * inputSize.x + x + inputOffset.x);
|
|
253
337
|
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
|
-
|
|
338
|
+
let col = in_color[inIdx];
|
|
339
|
+
let raw = ${
|
|
340
|
+
isInputTexture
|
|
341
|
+
? 'textureLoad(in_raw, globalId.xy + vec2u(outputOffset), 0)'
|
|
342
|
+
: 'in_raw[outIdx]'
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
if (${denoiseAlpha}) {
|
|
346
|
+
out_color[outIdx] = vec4f(raw.rgb, 1.0 - col.r);
|
|
347
|
+
}
|
|
348
|
+
else if (${isHDR}) {
|
|
349
|
+
out_color[outIdx] = vec4f(
|
|
350
|
+
vec3f(PUInverse(col.r * rcpNormScale), PUInverse(col.g * rcpNormScale), PUInverse(col.b * rcpNormScale)) / inputScale,
|
|
351
|
+
// Pick the alpha
|
|
352
|
+
raw.a
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
out_color[outIdx] = vec4f(col.rgb, raw.a);
|
|
357
|
+
}
|
|
261
358
|
`
|
|
262
359
|
});
|
|
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
360
|
}
|
|
275
361
|
|
|
276
362
|
setImageSize(w: number, h: number) {
|
|
277
|
-
this.
|
|
363
|
+
this._inputPassAux.setUniform('inputSize', new Float32Array([w, h]));
|
|
364
|
+
this._inputPassColor.setUniform('inputSize', new Float32Array([w, h]));
|
|
278
365
|
this._outputPass.setUniform('imageSize', new Float32Array([w, h]));
|
|
279
366
|
this._outputPass.setSize(w, h);
|
|
367
|
+
this._copyPass.setSize(w, h);
|
|
368
|
+
this._copyPass.setUniform('size', new Float32Array([w, h]));
|
|
280
369
|
}
|
|
281
370
|
|
|
282
371
|
setInputTile(tile: Tile) {
|
|
283
|
-
const inputPass = this._inputPass;
|
|
284
372
|
const size = new Float32Array([tile.width, tile.height]);
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
373
|
+
[this._inputPassAux, this._inputPassColor].forEach((inputPass) => {
|
|
374
|
+
inputPass.setUniform('inputOffset', new Float32Array([tile.x, tile.y]));
|
|
375
|
+
inputPass.setUniform('outputSize', size);
|
|
376
|
+
inputPass.setSize(size[0], size[1]);
|
|
377
|
+
});
|
|
288
378
|
|
|
289
379
|
this._outputPass.setUniform('inputSize', size);
|
|
290
380
|
}
|
|
@@ -304,28 +394,56 @@ out_color[outIdx] = vec4f(
|
|
|
304
394
|
}
|
|
305
395
|
|
|
306
396
|
forward(
|
|
307
|
-
colorBuffer: GPUBuffer,
|
|
397
|
+
colorBuffer: GPUBuffer | GPUTexture,
|
|
308
398
|
// TODO optional albedo and normal.
|
|
309
|
-
albedoBuffer: GPUBuffer,
|
|
310
|
-
normalBuffer: GPUBuffer
|
|
399
|
+
albedoBuffer: GPUBuffer | GPUTexture | undefined,
|
|
400
|
+
normalBuffer: GPUBuffer | GPUTexture | undefined,
|
|
401
|
+
|
|
402
|
+
denoiseAlpha: boolean | undefined
|
|
311
403
|
) {
|
|
312
|
-
const
|
|
404
|
+
const isInputTexture = colorBuffer instanceof GPUTexture;
|
|
405
|
+
this._updatePasses(isInputTexture, denoiseAlpha);
|
|
406
|
+
|
|
407
|
+
const inputPassAux = this._inputPassAux;
|
|
408
|
+
const inputPassColor = this._inputPassColor;
|
|
313
409
|
const commandEncoder = this._device.createCommandEncoder();
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
410
|
+
|
|
411
|
+
function createInput(bufferOrTex: GPUBuffer | GPUTexture) {
|
|
412
|
+
return bufferOrTex instanceof GPUTexture
|
|
413
|
+
? {
|
|
414
|
+
texture: bufferOrTex,
|
|
415
|
+
channels: 4
|
|
416
|
+
}
|
|
417
|
+
: {
|
|
418
|
+
buffer: bufferOrTex,
|
|
419
|
+
channels: 4
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
if (albedoBuffer && normalBuffer) {
|
|
423
|
+
inputPassAux.createPass(commandEncoder, {
|
|
424
|
+
color: createInput(colorBuffer),
|
|
425
|
+
albedo: createInput(albedoBuffer),
|
|
426
|
+
normal: createInput(normalBuffer)
|
|
427
|
+
});
|
|
428
|
+
} else {
|
|
429
|
+
inputPassColor.createPass(commandEncoder, {
|
|
430
|
+
color: createInput(colorBuffer)
|
|
431
|
+
});
|
|
432
|
+
}
|
|
319
433
|
this._device.queue.submit([commandEncoder.finish()]);
|
|
320
434
|
|
|
321
|
-
return
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
435
|
+
return albedoBuffer && normalBuffer
|
|
436
|
+
? {
|
|
437
|
+
color: inputPassAux.getOutput('color'),
|
|
438
|
+
albedo: inputPassAux.getOutput('albedo'),
|
|
439
|
+
normal: inputPassAux.getOutput('normal')
|
|
440
|
+
}
|
|
441
|
+
: {
|
|
442
|
+
color: inputPassColor.getOutput('color')
|
|
443
|
+
};
|
|
326
444
|
}
|
|
327
445
|
|
|
328
|
-
inverse(buffer: GPUBuffer, raw: GPUBuffer) {
|
|
446
|
+
inverse(buffer: GPUBuffer, raw: GPUBuffer | GPUTexture) {
|
|
329
447
|
const device = this._device;
|
|
330
448
|
|
|
331
449
|
const commandEncoder = device.createCommandEncoder();
|
|
@@ -333,30 +451,44 @@ out_color[outIdx] = vec4f(
|
|
|
333
451
|
|
|
334
452
|
outputGPUPass.createPass(commandEncoder, {
|
|
335
453
|
color: { buffer: buffer, channels: 4 },
|
|
336
|
-
raw:
|
|
454
|
+
raw:
|
|
455
|
+
raw instanceof GPUBuffer
|
|
456
|
+
? { buffer: raw, channels: 4 }
|
|
457
|
+
: { texture: raw, channels: 4 }
|
|
337
458
|
});
|
|
338
459
|
this._device.queue.submit([commandEncoder.finish()]);
|
|
339
460
|
|
|
340
|
-
return outputGPUPass.
|
|
461
|
+
return outputGPUPass.getOutput('color');
|
|
341
462
|
}
|
|
342
463
|
|
|
343
|
-
copyInputDataToOutput(inputColorBuffer: GPUBuffer) {
|
|
464
|
+
copyInputDataToOutput(inputColorBuffer: GPUBuffer | GPUTexture) {
|
|
344
465
|
const encoder = this._device.createCommandEncoder();
|
|
345
466
|
const outputGPUPass = this._outputPass;
|
|
346
|
-
const colorBuffer = outputGPUPass.
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
467
|
+
const colorBuffer = outputGPUPass.getOutput('color');
|
|
468
|
+
const copyPass = this._copyPass;
|
|
469
|
+
|
|
470
|
+
if (inputColorBuffer instanceof GPUTexture) {
|
|
471
|
+
copyPass.setOutputBuffers({
|
|
472
|
+
color: colorBuffer
|
|
473
|
+
});
|
|
474
|
+
copyPass.createPass(encoder, {
|
|
475
|
+
color: { texture: inputColorBuffer, channels: 4 }
|
|
476
|
+
});
|
|
477
|
+
} else {
|
|
478
|
+
encoder.copyBufferToBuffer(
|
|
479
|
+
inputColorBuffer,
|
|
480
|
+
0,
|
|
481
|
+
colorBuffer,
|
|
482
|
+
0,
|
|
483
|
+
colorBuffer.size
|
|
484
|
+
);
|
|
485
|
+
}
|
|
354
486
|
|
|
355
487
|
this._device.queue.submit([encoder.finish()]);
|
|
356
488
|
}
|
|
357
489
|
|
|
358
490
|
dispose() {
|
|
359
491
|
this._outputPass.dispose();
|
|
360
|
-
this.
|
|
492
|
+
this._inputPassAux.dispose();
|
|
361
493
|
}
|
|
362
494
|
}
|