@pexip/media-processor 20.3.5 → 22.0.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/CHANGELOG.md +109 -0
- package/README.md +17 -10
- package/api-docs/README.mdx +69 -23
- package/api-docs/functions/assertMediaStreamVideoTrack.mdx +13 -0
- package/api-docs/functions/createBenchmark.mdx +17 -5
- package/api-docs/functions/createFrameCallbackRequest.mdx +8 -2
- package/api-docs/functions/createMediaStreamTrackInputProcessAdaptor.mdx +10 -0
- package/api-docs/functions/createReadWritableStreamFallbackInputProcessAdaptor.mdx +17 -0
- package/api-docs/functions/createReadWritableStreamInputProcessAdaptor.mdx +10 -0
- package/api-docs/functions/createVideoProcessor.mdx +3 -3
- package/api-docs/functions/createWindowedStats.mdx +23 -0
- package/api-docs/functions/getDefaultInputProcessAdaptor.mdx +17 -0
- package/api-docs/functions/iou.mdx +19 -0
- package/api-docs/functions/isMediaStreamVideoTrack.mdx +13 -0
- package/api-docs/functions/labelComponents.mdx +20 -0
- package/api-docs/functions/nearestPowerOfTwo.mdx +21 -0
- package/api-docs/functions/playVideo.mdx +16 -0
- package/api-docs/functions/scoreComponent.mdx +22 -0
- package/api-docs/functions/setVideoElementSrc.mdx +14 -0
- package/api-docs/interfaces/Analyzer.mdx +4 -0
- package/api-docs/interfaces/Benchmark.mdx +26 -2
- package/api-docs/interfaces/FrameTransformStats.mdx +9 -0
- package/api-docs/interfaces/Gain.mdx +4 -0
- package/api-docs/interfaces/ImageSegmenterOptions.mdx +0 -2
- package/api-docs/interfaces/InputProcessAdaptor.mdx +28 -0
- package/api-docs/interfaces/Process.mdx +8 -3
- package/api-docs/interfaces/ProcessEventMute.mdx +6 -0
- package/api-docs/interfaces/ProcessWorkerEventOpened.mdx +7 -0
- package/api-docs/interfaces/ProcessWorkerEventStats.mdx +6 -0
- package/api-docs/interfaces/ProcessWorkerEventUpdated.mdx +7 -0
- package/api-docs/interfaces/ProcessorEvent.mdx +1 -1
- package/api-docs/interfaces/ProcessorOptions.mdx +0 -1
- package/api-docs/interfaces/ProcessorProcessOptions.mdx +3 -1
- package/api-docs/interfaces/ProcessorUpdateOptions.mdx +15 -0
- package/api-docs/interfaces/ReadWritableStream.mdx +12 -0
- package/api-docs/interfaces/Renderer.mdx +2 -2
- package/api-docs/interfaces/RendererOptions.mdx +25 -12
- package/api-docs/interfaces/Segmenter.mdx +89 -10
- package/api-docs/interfaces/SegmenterOptions.mdx +0 -1
- package/api-docs/interfaces/SelectionOptions.mdx +15 -0
- package/api-docs/interfaces/Stats.mdx +11 -0
- package/api-docs/interfaces/VideoProcessor.mdx +49 -5
- package/api-docs/interfaces/Weights.mdx +12 -0
- package/api-docs/type-aliases/OptionalKeys.mdx +10 -0
- package/api-docs/type-aliases/ProcessEvents.mdx +1 -0
- package/api-docs/type-aliases/ProcessInputType.mdx +3 -1
- package/api-docs/type-aliases/ProcessWorkerEvents.mdx +6 -4
- package/api-docs/type-aliases/ProcessorWorkerEvents.mdx +1 -1
- package/api-docs/type-aliases/Struct.mdx +9 -0
- package/api-docs/variables/BACKGROUND_THRESHOLD.mdx +3 -0
- package/api-docs/variables/DOWN_SAMPLE_FACTOR.mdx +3 -0
- package/api-docs/variables/EDGE_BLUR_AMOUNT.mdx +1 -1
- package/api-docs/variables/EXCLUDE_BYSTANDERS.mdx +3 -0
- package/api-docs/variables/FOREGROUND_THRESHOLD.mdx +1 -1
- package/api-docs/variables/FRAME_RATE.mdx +1 -1
- package/api-docs/variables/ImageFetchError.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_BLUR_AMOUNT.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_EDGE_BAND.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_INTENSITY.mdx +3 -0
- package/api-docs/variables/LIGHT_WRAP_TIGHTNESS.mdx +3 -0
- package/api-docs/variables/MASK_COMBINE_RATIO.mdx +1 -1
- package/api-docs/variables/MORPH_DILATE_RADIUS_PX.mdx +3 -0
- package/api-docs/variables/MORPH_ERODE_RADIUS_PX.mdx +3 -0
- package/api-docs/variables/MORPH_PASS.mdx +3 -0
- package/api-docs/variables/MediaStreamTrackTransferable.mdx +5 -0
- package/api-docs/variables/PERSON_CENTER.mdx +3 -0
- package/api-docs/variables/RENDERER_OPTIONS_STRUCT.mdx +3 -0
- package/api-docs/variables/SIGMA_RANGE.mdx +3 -0
- package/api-docs/variables/SIGMA_SPACE.mdx +3 -0
- package/api-docs/variables/STRONG_EDGE_BLUR_AMOUNT.mdx +3 -0
- package/api-docs/variables/cloneImageRecord.mdx +19 -0
- package/api-docs/variables/compareImageRecords.mdx +18 -0
- package/api-docs/variables/createRemoteImageBitmap.mdx +1 -1
- package/api-docs/variables/getCanvasRenderingContext2D.mdx +14 -0
- package/api-docs/variables/getImageSize.mdx +13 -0
- package/api-docs/variables/isRenderOptionsKey.mdx +13 -0
- package/api-docs/variables/isValidGpuAPI.mdx +13 -0
- package/dist/common/backends/webgl/binaryMask.d.ts +8 -0
- package/dist/common/backends/webgl/binaryMask.js +95 -0
- package/dist/common/backends/webgl/blender.d.ts +2 -1
- package/dist/common/backends/webgl/blender.js +18 -15
- package/dist/common/backends/webgl/blur.d.ts +1 -1
- package/dist/common/backends/webgl/blur.js +23 -16
- package/dist/common/backends/webgl/canvas.js +9 -4
- package/dist/common/backends/webgl/diffAbsMask.d.ts +10 -0
- package/dist/common/backends/webgl/diffAbsMask.js +103 -0
- package/dist/common/backends/webgl/geodesicReconstruction.d.ts +13 -0
- package/dist/common/backends/webgl/geodesicReconstruction.js +176 -0
- package/dist/common/backends/webgl/jointBilateralFilter.d.ts +12 -0
- package/dist/common/backends/webgl/jointBilateralFilter.js +108 -0
- package/dist/common/backends/webgl/morphErode.d.ts +13 -0
- package/dist/common/backends/webgl/morphErode.js +121 -0
- package/dist/common/backends/webgl/renderer.js +194 -44
- package/dist/common/backends/webgl/replace.d.ts +17 -0
- package/dist/common/backends/webgl/replace.js +126 -0
- package/dist/common/backends/webgl/selectComponent.d.ts +15 -0
- package/dist/common/backends/webgl/selectComponent.js +102 -0
- package/dist/common/backends/webgl/smoothingMask.d.ts +3 -3
- package/dist/common/backends/webgl/smoothingMask.js +22 -21
- package/dist/common/backends/webgl/tentBlur.d.ts +9 -0
- package/dist/common/backends/webgl/tentBlur.js +118 -0
- package/dist/common/backends/webgl/texture.d.ts +2 -3
- package/dist/common/backends/webgl/texture.js +21 -19
- package/dist/common/backends/webgl/textureToTexture.d.ts +1 -1
- package/dist/common/backends/webgl/textureToTexture.js +19 -16
- package/dist/common/backends/webgl/webglUtils.d.ts +7 -1
- package/dist/common/backends/webgl/webglUtils.js +72 -10
- package/dist/common/backends/webgpu/blender.d.ts +6 -1
- package/dist/common/backends/webgpu/blender.js +96 -51
- package/dist/common/backends/webgpu/constants.js +1 -1
- package/dist/common/backends/webgpu/dualFilterBlur.d.ts +2 -3
- package/dist/common/backends/webgpu/dualFilterBlur.js +146 -140
- package/dist/common/backends/webgpu/jointBilateralFilter.d.ts +7 -0
- package/dist/common/backends/webgpu/jointBilateralFilter.js +162 -0
- package/dist/common/backends/webgpu/renderer.js +205 -43
- package/dist/common/backends/webgpu/replace.d.ts +11 -0
- package/dist/common/backends/webgpu/replace.js +175 -0
- package/dist/common/backends/webgpu/resize.d.ts +4 -0
- package/dist/common/backends/webgpu/resize.js +76 -0
- package/dist/common/backends/webgpu/smoothingMask.d.ts +2 -2
- package/dist/common/backends/webgpu/smoothingMask.js +74 -40
- package/dist/common/backends/webgpu/tentBlur.d.ts +5 -0
- package/dist/common/backends/webgpu/tentBlur.js +131 -0
- package/dist/common/backends/webgpu/texture.d.ts +2 -3
- package/dist/common/backends/webgpu/texture.js +29 -20
- package/dist/common/backends/webgpu/textureToTexture.d.ts +1 -1
- package/dist/common/backends/webgpu/textureToTexture.js +28 -15
- package/dist/common/backends/webgpu/types.d.ts +2 -0
- package/dist/common/backends/webgpu/webgpuUtils.d.ts +24 -4
- package/dist/common/backends/webgpu/webgpuUtils.js +60 -11
- package/dist/common/constants.d.ts +22 -5
- package/dist/common/constants.js +23 -5
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.js +2 -0
- package/dist/common/tsconfig.tsbuildinfo +1 -1
- package/dist/common/typeGuards.d.ts +2 -0
- package/dist/common/typeGuards.js +7 -0
- package/dist/common/types/media.d.ts +5 -1
- package/dist/common/types/messageEvents.d.ts +31 -4
- package/dist/common/types/processor.d.ts +6 -4
- package/dist/common/types/render.d.ts +147 -15
- package/dist/common/types/render.js +23 -1
- package/dist/common/types/segmentation.d.ts +0 -12
- package/dist/common/types/utils.d.ts +21 -0
- package/dist/common/utils.d.ts +29 -2
- package/dist/common/utils.js +206 -10
- package/dist/main/audio.js +3 -3
- package/dist/main/benchUtils.d.ts +35 -3
- package/dist/main/benchUtils.js +149 -15
- package/dist/main/index.d.ts +1 -1
- package/dist/main/index.js +1 -1
- package/dist/main/tsconfig.tsbuildinfo +1 -1
- package/dist/main/types.d.ts +0 -6
- package/dist/main/utils.d.ts +4 -0
- package/dist/main/utils.js +31 -0
- package/dist/main/video/constants.d.ts +1 -4
- package/dist/main/video/constants.js +1 -5
- package/dist/main/video/index.d.ts +3 -4
- package/dist/main/video/index.js +3 -4
- package/dist/main/video/inputProcessAdaptor.d.ts +30 -0
- package/dist/main/video/inputProcessAdaptor.js +198 -0
- package/dist/main/video/segmenter.d.ts +35 -0
- package/dist/main/video/{segmenters/mediapipe.js → segmenter.js} +93 -53
- package/dist/main/video/typeGuards.d.ts +2 -0
- package/dist/main/video/typeGuards.js +8 -1
- package/dist/main/video/types.d.ts +36 -16
- package/dist/main/video/utils.d.ts +5 -4
- package/dist/main/video/utils.js +49 -44
- package/dist/main/video/video.d.ts +29 -7
- package/dist/main/video/video.js +323 -28
- package/dist/workers/mediaWorker.js +35 -162
- package/dist/workers/tsconfig.tsbuildinfo +1 -1
- package/dist/worklets/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -12
- package/api-docs/functions/createCanvasTransform.mdx +0 -14
- package/api-docs/functions/createVideoTrackProcessor.mdx +0 -9
- package/api-docs/functions/createVideoTrackProcessorWithFallback.mdx +0 -15
- package/api-docs/interfaces/Detector.mdx +0 -81
- package/api-docs/interfaces/SegmentationParams.mdx +0 -18
- package/api-docs/interfaces/Transform.mdx +0 -62
- package/api-docs/type-aliases/ProcessVideoTrack.mdx +0 -15
- package/api-docs/type-aliases/SegmentationTransform.mdx +0 -3
- package/dist/common/backends/webgl/shaders/blendFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/blendFragmentShader.js +0 -21
- package/dist/common/backends/webgl/shaders/dualFilterBlurFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/dualFilterBlurFragmentShader.js +0 -45
- package/dist/common/backends/webgl/shaders/smoothingMaskFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/smoothingMaskFragmentShader.js +0 -57
- package/dist/common/backends/webgl/shaders/textureFragmentShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/textureFragmentShader.js +0 -16
- package/dist/common/backends/webgl/shaders/vertexShader.d.ts +0 -1
- package/dist/common/backends/webgl/shaders/vertexShader.js +0 -19
- package/dist/main/transformer.d.ts +0 -1
- package/dist/main/transformer.js +0 -4
- package/dist/main/video/canvasTransform.d.ts +0 -17
- package/dist/main/video/canvasTransform.js +0 -253
- package/dist/main/video/segmenters/mediapipe.d.ts +0 -22
- package/dist/main/video/transformer.d.ts +0 -9
- package/dist/main/video/transformer.js +0 -68
- package/dist/main/video/videoStreamTrackProcessor.d.ts +0 -20
- package/dist/main/video/videoStreamTrackProcessor.js +0 -86
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { assert } from '@pexip/utils';
|
|
2
|
+
import { m3 } from '../../m3';
|
|
3
|
+
import { RENDERING_EVENTS } from '../../constants';
|
|
4
|
+
import { clamping } from '../../utils';
|
|
5
|
+
import { createGLProgram, createMaskTexture, createFrameBuffer, } from './webglUtils';
|
|
6
|
+
import vertexSrc from './shaders/matrix.vert';
|
|
7
|
+
import fragmentSrc from './shaders/tentBlur.frag';
|
|
8
|
+
const MAX_RADIUS_PX = 16;
|
|
9
|
+
const clampRadiusPx = clamping(0, MAX_RADIUS_PX);
|
|
10
|
+
/**
|
|
11
|
+
* Create a tent blur renderer for small radius blurring of a mask.
|
|
12
|
+
* The blur is implemented as a separable filter.
|
|
13
|
+
*/
|
|
14
|
+
export const createTentBlurRenderer = (processor, width, height) => {
|
|
15
|
+
const { gl, program, attribLocations, uniformLocations, floatSingleChannelSupported, floatFullChannelSupported, release, } = createGLProgram(processor, {
|
|
16
|
+
attribs: {
|
|
17
|
+
position: 'a_position',
|
|
18
|
+
texCoord: 'a_texCoord',
|
|
19
|
+
},
|
|
20
|
+
uniforms: {
|
|
21
|
+
matrix: 'u_matrix',
|
|
22
|
+
mask: 'u_mask',
|
|
23
|
+
texelSize: 'u_texel_size',
|
|
24
|
+
direction: 'u_direction',
|
|
25
|
+
radiusPx: 'u_radius_px',
|
|
26
|
+
},
|
|
27
|
+
vertexSrc,
|
|
28
|
+
fragmentSrc,
|
|
29
|
+
});
|
|
30
|
+
const vao = gl.createVertexArray();
|
|
31
|
+
gl.bindVertexArray(vao);
|
|
32
|
+
// Position
|
|
33
|
+
const positionBuffer = gl.createBuffer();
|
|
34
|
+
gl.enableVertexAttribArray(attribLocations.position);
|
|
35
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
|
36
|
+
gl.vertexAttribPointer(attribLocations.position, 2, gl.FLOAT, false, 0, 0);
|
|
37
|
+
gl.bufferData(gl.ARRAY_BUFFER,
|
|
38
|
+
// prettier-ignore
|
|
39
|
+
new Float32Array([
|
|
40
|
+
0, 0,
|
|
41
|
+
0, 1,
|
|
42
|
+
1, 0,
|
|
43
|
+
1, 0,
|
|
44
|
+
0, 1,
|
|
45
|
+
1, 1,
|
|
46
|
+
]), gl.STATIC_DRAW);
|
|
47
|
+
// Texture coordinates for the rectangle
|
|
48
|
+
const texCoordBuffer = gl.createBuffer();
|
|
49
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
|
|
50
|
+
gl.bufferData(gl.ARRAY_BUFFER,
|
|
51
|
+
// prettier-ignore
|
|
52
|
+
new Float32Array([
|
|
53
|
+
0, 0,
|
|
54
|
+
0, 1,
|
|
55
|
+
1, 0,
|
|
56
|
+
1, 0,
|
|
57
|
+
0, 1,
|
|
58
|
+
1, 1,
|
|
59
|
+
]), gl.STATIC_DRAW);
|
|
60
|
+
gl.enableVertexAttribArray(attribLocations.texCoord);
|
|
61
|
+
gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
|
|
62
|
+
const outputTexturePing = createMaskTexture(gl, width, height, false, floatSingleChannelSupported, floatFullChannelSupported);
|
|
63
|
+
const frameBufferPing = createFrameBuffer(gl, outputTexturePing);
|
|
64
|
+
const outputTexturePong = createMaskTexture(gl, width, height, false, floatSingleChannelSupported, floatFullChannelSupported);
|
|
65
|
+
const frameBufferPong = createFrameBuffer(gl, outputTexturePong);
|
|
66
|
+
const scaleFactor = processor.width / width;
|
|
67
|
+
return {
|
|
68
|
+
render: (mask, radiusPx) => {
|
|
69
|
+
assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
|
|
70
|
+
gl.clearColor(0, 0, 0, 0);
|
|
71
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
72
|
+
gl.useProgram(program);
|
|
73
|
+
gl.bindVertexArray(vao);
|
|
74
|
+
gl.uniform2f(uniformLocations.texelSize, 1 / mask.width, 1 / mask.height);
|
|
75
|
+
gl.uniform1i(uniformLocations.radiusPx, clampRadiusPx(Math.floor(radiusPx / scaleFactor)));
|
|
76
|
+
const matrix = m3.projection(1, 1, 1);
|
|
77
|
+
// No Flip Y Coordinate for drawing on the frame buffer
|
|
78
|
+
// Project, position and scale to full-size of the canvas
|
|
79
|
+
gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
|
|
80
|
+
let write = frameBufferPing;
|
|
81
|
+
let read = mask.texture;
|
|
82
|
+
// Ping-pong framebuffers for multiple passes
|
|
83
|
+
// Separable
|
|
84
|
+
for (let j = 0; j < 2; j++) {
|
|
85
|
+
// Textures
|
|
86
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
87
|
+
gl.uniform1i(uniformLocations.mask, 0);
|
|
88
|
+
gl.bindTexture(gl.TEXTURE_2D, read);
|
|
89
|
+
// Horizontal then Vertical
|
|
90
|
+
gl.uniform2f(uniformLocations.direction, 1.0 - j, 0.0 + j);
|
|
91
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, write);
|
|
92
|
+
gl.viewport(0, 0, mask.width, mask.height);
|
|
93
|
+
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
94
|
+
// Swap
|
|
95
|
+
[read, write] =
|
|
96
|
+
write === frameBufferPing
|
|
97
|
+
? [outputTexturePing, frameBufferPong]
|
|
98
|
+
: [outputTexturePong, frameBufferPing];
|
|
99
|
+
}
|
|
100
|
+
// Cleanup
|
|
101
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
102
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
103
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
104
|
+
gl.bindVertexArray(null);
|
|
105
|
+
return { texture: read, width, height };
|
|
106
|
+
},
|
|
107
|
+
release: () => {
|
|
108
|
+
gl.deleteBuffer(positionBuffer);
|
|
109
|
+
gl.deleteBuffer(texCoordBuffer);
|
|
110
|
+
gl.deleteTexture(outputTexturePing);
|
|
111
|
+
gl.deleteTexture(outputTexturePong);
|
|
112
|
+
gl.deleteFramebuffer(frameBufferPing);
|
|
113
|
+
gl.deleteFramebuffer(frameBufferPong);
|
|
114
|
+
gl.deleteVertexArray(vao);
|
|
115
|
+
release();
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
};
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import type { VideoFrameLike } from '../../types/media';
|
|
2
1
|
import type { TextureInfo } from './types';
|
|
3
2
|
/**
|
|
4
3
|
* Render Video frame into texture
|
|
5
4
|
*/
|
|
6
|
-
export declare const createTextureRenderer: (processor: OffscreenCanvas) => {
|
|
7
|
-
render: (
|
|
5
|
+
export declare const createTextureRenderer: (processor: OffscreenCanvas, redOnly: boolean) => {
|
|
6
|
+
render: (frame: VideoFrame | ImageBitmap | OffscreenCanvas) => TextureInfo;
|
|
8
7
|
release: () => void;
|
|
9
8
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { assert } from '@pexip/utils';
|
|
2
2
|
import { RENDERING_EVENTS } from '../../constants';
|
|
3
3
|
import { m3 } from '../../m3';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
4
|
+
import { createFrameBuffer, createGLProgram, createMaskTexture, createRGBAFrameTexture, } from './webglUtils';
|
|
5
|
+
import vertexSrc from './shaders/matrix.vert';
|
|
6
|
+
import fragmentSrc from './shaders/texture.frag';
|
|
7
7
|
/**
|
|
8
8
|
* Render Video frame into texture
|
|
9
9
|
*/
|
|
10
|
-
export const createTextureRenderer = (processor) => {
|
|
11
|
-
const { gl, program, attribLocations, uniformLocations, release } = createGLProgram(processor, {
|
|
10
|
+
export const createTextureRenderer = (processor, redOnly) => {
|
|
11
|
+
const { gl, program, attribLocations, uniformLocations, floatFullChannelSupported, floatSingleChannelSupported, release, } = createGLProgram(processor, {
|
|
12
12
|
attribs: {
|
|
13
13
|
position: 'a_position',
|
|
14
14
|
texCoord: 'a_texCoord',
|
|
@@ -17,8 +17,8 @@ export const createTextureRenderer = (processor) => {
|
|
|
17
17
|
matrix: 'u_matrix',
|
|
18
18
|
texture: 'u_texture',
|
|
19
19
|
},
|
|
20
|
-
vertexSrc
|
|
21
|
-
fragmentSrc
|
|
20
|
+
vertexSrc,
|
|
21
|
+
fragmentSrc,
|
|
22
22
|
});
|
|
23
23
|
const vao = gl.createVertexArray();
|
|
24
24
|
gl.bindVertexArray(vao);
|
|
@@ -53,14 +53,13 @@ export const createTextureRenderer = (processor) => {
|
|
|
53
53
|
]), gl.STATIC_DRAW);
|
|
54
54
|
gl.enableVertexAttribArray(attribLocations.texCoord);
|
|
55
55
|
gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
|
|
56
|
-
const frameTexture =
|
|
57
|
-
const outputTexture =
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, outputTexture, 0);
|
|
56
|
+
const frameTexture = createRGBAFrameTexture(gl, processor.width, processor.height, true, floatFullChannelSupported);
|
|
57
|
+
const outputTexture = redOnly
|
|
58
|
+
? createMaskTexture(gl, processor.width, processor.height, false, floatSingleChannelSupported, floatFullChannelSupported)
|
|
59
|
+
: createRGBAFrameTexture(gl, processor.width, processor.height, true, floatFullChannelSupported);
|
|
60
|
+
const frameBuffer = createFrameBuffer(gl, outputTexture);
|
|
62
61
|
return {
|
|
63
|
-
render: (
|
|
62
|
+
render: (frame) => {
|
|
64
63
|
assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
|
|
65
64
|
// Draw on the frame buffer
|
|
66
65
|
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
@@ -71,16 +70,19 @@ export const createTextureRenderer = (processor) => {
|
|
|
71
70
|
gl.bindVertexArray(vao);
|
|
72
71
|
// Texture Unit setup
|
|
73
72
|
gl.uniform1i(uniformLocations.texture, 0);
|
|
74
|
-
// Project, position and scale to full-size of the canvas
|
|
73
|
+
// Project, position, and scale to full-size of the canvas
|
|
75
74
|
const matrix = m3.projection(1, 1, 1);
|
|
76
75
|
gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
|
|
77
|
-
//
|
|
76
|
+
// Upload the frame to texture
|
|
78
77
|
gl.activeTexture(gl.TEXTURE0);
|
|
79
78
|
gl.bindTexture(gl.TEXTURE_2D, frameTexture);
|
|
80
|
-
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE,
|
|
81
|
-
gl.generateMipmap(gl.TEXTURE_2D);
|
|
79
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, frame);
|
|
82
80
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
83
|
-
|
|
81
|
+
// Cleanup
|
|
82
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
83
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
84
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
85
|
+
gl.bindVertexArray(null);
|
|
84
86
|
return {
|
|
85
87
|
texture: outputTexture,
|
|
86
88
|
width: processor.width,
|
|
@@ -2,7 +2,7 @@ import type { TextureInfo } from './types';
|
|
|
2
2
|
/**
|
|
3
3
|
* Render texture into another texture, i.e. clone
|
|
4
4
|
*/
|
|
5
|
-
export declare const createTextureToTextureRenderer: (processor: OffscreenCanvas) => {
|
|
5
|
+
export declare const createTextureToTextureRenderer: (processor: OffscreenCanvas, redOnly: boolean, linearSampling?: boolean, targetWidth?: number, targetHeight?: number, float?: boolean) => {
|
|
6
6
|
render: (inputTexture: TextureInfo) => TextureInfo;
|
|
7
7
|
release: () => void;
|
|
8
8
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { assert } from '@pexip/utils';
|
|
2
2
|
import { RENDERING_EVENTS } from '../../constants';
|
|
3
3
|
import { m3 } from '../../m3';
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import
|
|
4
|
+
import { createFrameBuffer, createGLProgram, createMaskTexture, createRGBAFrameTexture, } from './webglUtils';
|
|
5
|
+
import vertexSrc from './shaders/matrix.vert';
|
|
6
|
+
import fragmentSrc from './shaders/texture.frag';
|
|
7
7
|
/**
|
|
8
8
|
* Render texture into another texture, i.e. clone
|
|
9
9
|
*/
|
|
10
|
-
export const createTextureToTextureRenderer = (processor) => {
|
|
11
|
-
const { gl, program, attribLocations, uniformLocations, release } = createGLProgram(processor, {
|
|
10
|
+
export const createTextureToTextureRenderer = (processor, redOnly, linearSampling = false, targetWidth = processor.width, targetHeight = processor.height, float = true) => {
|
|
11
|
+
const { gl, program, attribLocations, uniformLocations, floatFullChannelSupported, floatSingleChannelSupported, release, } = createGLProgram(processor, {
|
|
12
12
|
attribs: {
|
|
13
13
|
position: 'a_position',
|
|
14
14
|
texCoord: 'a_texCoord',
|
|
@@ -17,8 +17,8 @@ export const createTextureToTextureRenderer = (processor) => {
|
|
|
17
17
|
matrix: 'u_matrix',
|
|
18
18
|
texture: 'u_texture',
|
|
19
19
|
},
|
|
20
|
-
vertexSrc
|
|
21
|
-
fragmentSrc
|
|
20
|
+
vertexSrc,
|
|
21
|
+
fragmentSrc,
|
|
22
22
|
});
|
|
23
23
|
const vao = gl.createVertexArray();
|
|
24
24
|
gl.bindVertexArray(vao);
|
|
@@ -53,17 +53,16 @@ export const createTextureToTextureRenderer = (processor) => {
|
|
|
53
53
|
]), gl.STATIC_DRAW);
|
|
54
54
|
gl.enableVertexAttribArray(attribLocations.texCoord);
|
|
55
55
|
gl.vertexAttribPointer(attribLocations.texCoord, 2, gl.FLOAT, false, 0, 0);
|
|
56
|
-
const outputTexture =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, outputTexture, 0);
|
|
56
|
+
const outputTexture = redOnly
|
|
57
|
+
? createMaskTexture(gl, targetWidth, targetHeight, linearSampling, float && floatSingleChannelSupported, float && floatFullChannelSupported)
|
|
58
|
+
: createRGBAFrameTexture(gl, targetWidth, targetHeight, linearSampling, float && floatFullChannelSupported);
|
|
59
|
+
const frameBuffer = createFrameBuffer(gl, outputTexture);
|
|
61
60
|
return {
|
|
62
61
|
render: (inputTexture) => {
|
|
63
62
|
assert(!gl.isContextLost(), RENDERING_EVENTS.ContextLost);
|
|
64
63
|
// Draw on the frame buffer
|
|
65
64
|
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
66
|
-
gl.viewport(0, 0,
|
|
65
|
+
gl.viewport(0, 0, targetWidth, targetHeight);
|
|
67
66
|
gl.clearColor(0, 0, 0, 1);
|
|
68
67
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
69
68
|
gl.useProgram(program);
|
|
@@ -76,11 +75,15 @@ export const createTextureToTextureRenderer = (processor) => {
|
|
|
76
75
|
const matrix = m3.projection(1, 1, 1);
|
|
77
76
|
gl.uniformMatrix3fv(uniformLocations.matrix, false, matrix);
|
|
78
77
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
79
|
-
|
|
78
|
+
// Cleanup
|
|
79
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
|
80
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
81
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
82
|
+
gl.bindVertexArray(null);
|
|
80
83
|
return {
|
|
81
84
|
texture: outputTexture,
|
|
82
|
-
width:
|
|
83
|
-
height:
|
|
85
|
+
width: targetWidth,
|
|
86
|
+
height: targetHeight,
|
|
84
87
|
};
|
|
85
88
|
},
|
|
86
89
|
release: () => {
|
|
@@ -61,7 +61,11 @@ export declare const createProgram: (gl: WebGLRenderingContext, shaders: [WebGLS
|
|
|
61
61
|
* A parallel array to opt_attribs letting you assign locations.
|
|
62
62
|
*/
|
|
63
63
|
export declare const createProgramFromSources: (gl: WebGLRenderingContext, [vs, fs]: [GLShaderSource, GLShaderSource], attribs?: string[], locations?: number[]) => [WebGLProgram, Release];
|
|
64
|
-
export declare const createAndSetupTexture: (gl: WebGL2RenderingContext) => WebGLTexture;
|
|
64
|
+
export declare const createAndSetupTexture: (gl: WebGL2RenderingContext, linear: boolean) => WebGLTexture;
|
|
65
|
+
export declare const createRGBAFrameTexture: (gl: WebGL2RenderingContext, width: number, height: number, linear?: boolean, withFloat?: boolean) => WebGLTexture;
|
|
66
|
+
export declare const createMaskTexture: (gl: WebGL2RenderingContext, width: number, height: number, linear?: boolean, withFloatSingle?: boolean, withFloatFull?: boolean) => WebGLTexture;
|
|
67
|
+
export declare const createFrameBuffer: (gl: WebGL2RenderingContext, texture: WebGLTexture) => WebGLFramebuffer;
|
|
68
|
+
export declare const support: (gl: WebGL2RenderingContext, internalFormat: GLint, format: GLenum, width?: number, height?: number) => boolean;
|
|
65
69
|
type Location<S extends string> = S extends `u_${string}` ? ReturnType<WebGL2RenderingContext['getUniformLocation']> : S extends `a_${string}` ? ReturnType<WebGL2RenderingContext['getAttribLocation']> : never;
|
|
66
70
|
export declare const getLocations: <T extends Record<string, string>>(gl: WebGL2RenderingContext, program: WebGLProgram, locations: T) => { [Key in keyof T]: Location<T[Key]>; };
|
|
67
71
|
export declare const createGLProgram: <A extends Record<string, string>, U extends Record<string, string>>(processCanvas: OffscreenCanvas, { attribs, uniforms, vertexSrc, fragmentSrc, }: {
|
|
@@ -75,6 +79,8 @@ export declare const createGLProgram: <A extends Record<string, string>, U exten
|
|
|
75
79
|
attribLocations: { [Key in keyof A]: Location<A[Key]>; };
|
|
76
80
|
uniformLocations: { [Key_1 in keyof U]: Location<U[Key_1]>; };
|
|
77
81
|
release: Release;
|
|
82
|
+
floatSingleChannelSupported: boolean;
|
|
83
|
+
floatFullChannelSupported: boolean;
|
|
78
84
|
};
|
|
79
85
|
export declare const toTextureInfo: (mask: MPMask) => TextureInfo;
|
|
80
86
|
export {};
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { assert } from '@pexip/utils';
|
|
2
|
+
import { RENDERING_EVENTS } from '../../constants';
|
|
1
3
|
/**
|
|
2
4
|
* WebGL Shader type enum
|
|
3
5
|
*/
|
|
@@ -90,6 +92,7 @@ export const loadShader = (gl, shaderType, shaderSource) => {
|
|
|
90
92
|
*/
|
|
91
93
|
export const createProgram = (gl, shaders, attribs, locations) => {
|
|
92
94
|
const program = gl.createProgram();
|
|
95
|
+
let released = false;
|
|
93
96
|
if (!program) {
|
|
94
97
|
throw new Error('Unable to create WebGL program');
|
|
95
98
|
}
|
|
@@ -118,11 +121,14 @@ export const createProgram = (gl, shaders, attribs, locations) => {
|
|
|
118
121
|
return [
|
|
119
122
|
program,
|
|
120
123
|
() => {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
if (!released) {
|
|
125
|
+
released = true;
|
|
126
|
+
for (const shader of shaders) {
|
|
127
|
+
gl.detachShader(program, shader);
|
|
128
|
+
gl.deleteShader(shader);
|
|
129
|
+
}
|
|
130
|
+
gl.deleteProgram(program);
|
|
124
131
|
}
|
|
125
|
-
gl.deleteProgram(program);
|
|
126
132
|
},
|
|
127
133
|
];
|
|
128
134
|
};
|
|
@@ -139,16 +145,69 @@ export const createProgramFromSources = (gl, [vs, fs], attribs, locations) => cr
|
|
|
139
145
|
loadShader(gl, GL_SHADER_TYPE.VertexShader, vs),
|
|
140
146
|
loadShader(gl, GL_SHADER_TYPE.FragmentShader, fs),
|
|
141
147
|
], attribs, locations);
|
|
142
|
-
export const createAndSetupTexture = (gl) => {
|
|
148
|
+
export const createAndSetupTexture = (gl, linear) => {
|
|
143
149
|
const texture = gl.createTexture();
|
|
144
150
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
145
|
-
// Set the parameters so we don't need
|
|
151
|
+
// Set the parameters so we don't need MIPS and so we're not filtering
|
|
146
152
|
// and we don't repeat at the edges.
|
|
147
153
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
148
154
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
155
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, linear ? gl.LINEAR : gl.NEAREST);
|
|
156
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, linear ? gl.LINEAR : gl.NEAREST);
|
|
157
|
+
return texture;
|
|
158
|
+
};
|
|
159
|
+
export const createRGBAFrameTexture = (gl, width, height, linear = false, withFloat = false) => {
|
|
160
|
+
const texture = createAndSetupTexture(gl, linear);
|
|
161
|
+
if (withFloat) {
|
|
162
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, width, height, 0, gl.RGBA, gl.HALF_FLOAT, null);
|
|
163
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
164
|
+
return texture;
|
|
165
|
+
}
|
|
166
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
|
167
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
168
|
+
return texture;
|
|
169
|
+
};
|
|
170
|
+
export const createMaskTexture = (gl, width, height, linear = false, withFloatSingle = false, withFloatFull = false) => {
|
|
171
|
+
const texture = createAndSetupTexture(gl, linear);
|
|
172
|
+
if (withFloatSingle) {
|
|
173
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.R16F, width, height, 0, gl.RED, gl.HALF_FLOAT, null);
|
|
174
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
175
|
+
return texture;
|
|
176
|
+
}
|
|
177
|
+
if (withFloatFull) {
|
|
178
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, width, height, 0, gl.RGBA, gl.HALF_FLOAT, null);
|
|
179
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
180
|
+
return texture;
|
|
181
|
+
}
|
|
182
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.R8, width, height, 0, gl.RED, gl.UNSIGNED_BYTE, null);
|
|
183
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
184
|
+
return texture;
|
|
185
|
+
};
|
|
186
|
+
export const createFrameBuffer = (gl, texture) => {
|
|
187
|
+
const frameBuffer = gl.createFramebuffer();
|
|
188
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
|
|
189
|
+
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
|
190
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
191
|
+
return frameBuffer;
|
|
192
|
+
};
|
|
193
|
+
export const support = (gl, internalFormat, format, width = 2, height = 2) => {
|
|
194
|
+
// Create single-channel float16 texture
|
|
195
|
+
const tex = gl.createTexture();
|
|
196
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
197
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, width, height, 0, format, gl.HALF_FLOAT, null);
|
|
149
198
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
150
199
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
151
|
-
|
|
200
|
+
// Attach texture
|
|
201
|
+
const fb = createFrameBuffer(gl, tex);
|
|
202
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
|
|
203
|
+
// Check completeness
|
|
204
|
+
const complete = gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE;
|
|
205
|
+
// Clean up
|
|
206
|
+
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
|
207
|
+
gl.deleteFramebuffer(fb);
|
|
208
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
209
|
+
gl.deleteTexture(tex);
|
|
210
|
+
return complete;
|
|
152
211
|
};
|
|
153
212
|
export const getLocations = (gl, program, locations) => Object.keys(locations).reduce((acc, key) => {
|
|
154
213
|
const k = key;
|
|
@@ -167,9 +226,7 @@ export const createGLProgram = (processCanvas, { attribs, uniforms, vertexSrc, f
|
|
|
167
226
|
premultipliedAlpha: false,
|
|
168
227
|
powerPreference: 'high-performance',
|
|
169
228
|
});
|
|
170
|
-
|
|
171
|
-
throw new Error('WebGL2 is not supported');
|
|
172
|
-
}
|
|
229
|
+
assert(gl, RENDERING_EVENTS.ContextCreationError);
|
|
173
230
|
gl.enable(gl.BLEND);
|
|
174
231
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
175
232
|
assertShaderSource(vertexSrc);
|
|
@@ -178,12 +235,17 @@ export const createGLProgram = (processCanvas, { attribs, uniforms, vertexSrc, f
|
|
|
178
235
|
vertexSrc,
|
|
179
236
|
fragmentSrc,
|
|
180
237
|
]);
|
|
238
|
+
const hasFloat = !!gl.getExtension('EXT_color_buffer_float');
|
|
239
|
+
const floatSingleChannelSupported = hasFloat && support(gl, gl.R16F, gl.RED);
|
|
240
|
+
const floatFullChannelSupported = hasFloat && support(gl, gl.RGBA16F, gl.RGBA);
|
|
181
241
|
return {
|
|
182
242
|
gl,
|
|
183
243
|
program,
|
|
184
244
|
attribLocations: getLocations(gl, program, attribs),
|
|
185
245
|
uniformLocations: getLocations(gl, program, uniforms),
|
|
186
246
|
release,
|
|
247
|
+
floatSingleChannelSupported,
|
|
248
|
+
floatFullChannelSupported,
|
|
187
249
|
};
|
|
188
250
|
};
|
|
189
251
|
export const toTextureInfo = (mask) => ({
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
+
import type { RendererOptions } from '../../types/render';
|
|
1
2
|
/**
|
|
2
3
|
*
|
|
3
4
|
* Blend foreground and background according to the mask
|
|
4
5
|
*/
|
|
5
6
|
export declare const createBlendRenderer: (processor: OffscreenCanvas, device: GPUDevice, presentationFormat: GPUTextureFormat, isContextLost: () => boolean) => {
|
|
6
|
-
render: (
|
|
7
|
+
render: (encoder: GPUCommandEncoder, { foreground, background, mask, }: {
|
|
8
|
+
foreground: GPUTexture;
|
|
9
|
+
background: GPUTexture;
|
|
10
|
+
mask: GPUTexture;
|
|
11
|
+
}, options: RendererOptions) => void;
|
|
7
12
|
release: () => void;
|
|
8
13
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
+
import { makeShaderDataDefinitions, makeStructuredView } from 'webgpu-utils';
|
|
1
2
|
import { assert } from '@pexip/utils';
|
|
2
3
|
import { RENDERING_EVENTS } from '../../constants';
|
|
3
4
|
import blenderShader from './shaders/blenderShader.wgsl';
|
|
4
|
-
import { RENDER_PASS_COLOR_ATTACHMENT_CLEAR_VALUE } from './constants';
|
|
5
5
|
/**
|
|
6
6
|
*
|
|
7
7
|
* Blend foreground and background according to the mask
|
|
@@ -16,63 +16,108 @@ export const createBlendRenderer = (processor, device, presentationFormat, isCon
|
|
|
16
16
|
format: presentationFormat,
|
|
17
17
|
alphaMode: 'premultiplied',
|
|
18
18
|
});
|
|
19
|
+
const defs = makeShaderDataDefinitions(blenderShader);
|
|
20
|
+
// @ts-expect-error This is what we get from the API
|
|
21
|
+
const uniforms = makeStructuredView(defs.uniforms.thresholds);
|
|
22
|
+
// Cache shader module and pipeline at init time
|
|
23
|
+
const shaderModule = device.createShaderModule({
|
|
24
|
+
label: 'blender shader',
|
|
25
|
+
code: blenderShader,
|
|
26
|
+
});
|
|
27
|
+
const pipeline = device.createRenderPipeline({
|
|
28
|
+
label: 'blender pipeline',
|
|
29
|
+
layout: 'auto',
|
|
30
|
+
vertex: {
|
|
31
|
+
module: shaderModule,
|
|
32
|
+
},
|
|
33
|
+
fragment: {
|
|
34
|
+
module: shaderModule,
|
|
35
|
+
targets: [{ format: presentationFormat }],
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
// Cache sampler at init time
|
|
39
|
+
const linearSampler = device.createSampler({
|
|
40
|
+
addressModeU: 'clamp-to-edge',
|
|
41
|
+
addressModeV: 'clamp-to-edge',
|
|
42
|
+
magFilter: 'linear',
|
|
43
|
+
minFilter: 'linear',
|
|
44
|
+
});
|
|
45
|
+
const nearestSampler = device.createSampler({
|
|
46
|
+
addressModeU: 'clamp-to-edge',
|
|
47
|
+
addressModeV: 'clamp-to-edge',
|
|
48
|
+
magFilter: 'nearest',
|
|
49
|
+
minFilter: 'nearest',
|
|
50
|
+
});
|
|
51
|
+
const uniformsBuffer = device.createBuffer({
|
|
52
|
+
size: uniforms.arrayBuffer.byteLength,
|
|
53
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
54
|
+
});
|
|
55
|
+
const updateUniforms = (options) => {
|
|
56
|
+
uniforms.set({
|
|
57
|
+
background: options.backgroundThreshold,
|
|
58
|
+
foreground: options.foregroundThreshold,
|
|
59
|
+
});
|
|
60
|
+
// Upload to GPU
|
|
61
|
+
device.queue.writeBuffer(uniformsBuffer, 0, uniforms.arrayBuffer);
|
|
62
|
+
};
|
|
63
|
+
const colorAttachment0 = {
|
|
64
|
+
loadOp: 'load',
|
|
65
|
+
storeOp: 'store',
|
|
66
|
+
};
|
|
67
|
+
const renderPassDescriptor = {
|
|
68
|
+
label: 'blender renderPass',
|
|
69
|
+
colorAttachments: [colorAttachment0],
|
|
70
|
+
};
|
|
71
|
+
const bindGroup0 = device.createBindGroup({
|
|
72
|
+
layout: pipeline.getBindGroupLayout(0),
|
|
73
|
+
entries: [
|
|
74
|
+
{ binding: 0, resource: linearSampler },
|
|
75
|
+
{ binding: 1, resource: nearestSampler },
|
|
76
|
+
{ binding: 2, resource: { buffer: uniformsBuffer } },
|
|
77
|
+
],
|
|
78
|
+
});
|
|
79
|
+
let cachedBindGroup1 = null;
|
|
80
|
+
let cachedMask = null;
|
|
81
|
+
let cachedBackground = null;
|
|
82
|
+
let cachedForeground = null;
|
|
83
|
+
let cachedBackgroundThreshold = -1;
|
|
84
|
+
let cachedForegroundThreshold = -1;
|
|
19
85
|
return {
|
|
20
|
-
render: (
|
|
86
|
+
render: (encoder, { foreground, background, mask, }, options) => {
|
|
21
87
|
assert(!isContextLost(), RENDERING_EVENTS.ContextLost);
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
view: context.getCurrentTexture().createView(),
|
|
47
|
-
clearValue: RENDER_PASS_COLOR_ATTACHMENT_CLEAR_VALUE,
|
|
48
|
-
loadOp: 'clear',
|
|
49
|
-
storeOp: 'store',
|
|
50
|
-
},
|
|
51
|
-
],
|
|
52
|
-
});
|
|
88
|
+
colorAttachment0.view = context.getCurrentTexture().createView();
|
|
89
|
+
if (!(cachedBackground === background &&
|
|
90
|
+
cachedForeground === foreground &&
|
|
91
|
+
cachedMask === mask)) {
|
|
92
|
+
cachedBindGroup1 = device.createBindGroup({
|
|
93
|
+
layout: pipeline.getBindGroupLayout(1),
|
|
94
|
+
entries: [
|
|
95
|
+
{ binding: 0, resource: background.createView() },
|
|
96
|
+
{ binding: 1, resource: foreground.createView() },
|
|
97
|
+
{ binding: 2, resource: mask.createView() },
|
|
98
|
+
],
|
|
99
|
+
});
|
|
100
|
+
cachedBackground = background;
|
|
101
|
+
cachedForeground = foreground;
|
|
102
|
+
cachedMask = mask;
|
|
103
|
+
}
|
|
104
|
+
if (!(cachedBackgroundThreshold === options.backgroundThreshold &&
|
|
105
|
+
cachedForegroundThreshold === options.foregroundThreshold)) {
|
|
106
|
+
updateUniforms(options);
|
|
107
|
+
cachedBackgroundThreshold = options.backgroundThreshold;
|
|
108
|
+
cachedForegroundThreshold = options.foregroundThreshold;
|
|
109
|
+
}
|
|
110
|
+
const pass = encoder.beginRenderPass(renderPassDescriptor);
|
|
53
111
|
pass.setPipeline(pipeline);
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
addressModeV: 'repeat',
|
|
57
|
-
magFilter: 'nearest',
|
|
58
|
-
});
|
|
59
|
-
const bindGroup = device.createBindGroup({
|
|
60
|
-
layout: pipeline.getBindGroupLayout(0),
|
|
61
|
-
entries: [
|
|
62
|
-
{ binding: 0, resource: sampler },
|
|
63
|
-
{ binding: 1, resource: bgTexture.createView() },
|
|
64
|
-
{ binding: 2, resource: frameTexture.createView() },
|
|
65
|
-
{ binding: 3, resource: maskTexture.createView() },
|
|
66
|
-
],
|
|
67
|
-
});
|
|
68
|
-
pass.setBindGroup(0, bindGroup);
|
|
112
|
+
pass.setBindGroup(0, bindGroup0);
|
|
113
|
+
pass.setBindGroup(1, cachedBindGroup1);
|
|
69
114
|
pass.draw(6); // call our vertex shader 6 times
|
|
70
115
|
pass.end();
|
|
71
|
-
const commandBuffer = encoder.finish();
|
|
72
|
-
device.queue.submit([commandBuffer]);
|
|
73
116
|
},
|
|
74
117
|
release: () => {
|
|
75
|
-
|
|
118
|
+
uniformsBuffer.destroy();
|
|
119
|
+
cachedBackgroundThreshold = -1;
|
|
120
|
+
cachedForegroundThreshold = -1;
|
|
76
121
|
},
|
|
77
122
|
};
|
|
78
123
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const RENDER_PASS_COLOR_ATTACHMENT_CLEAR_VALUE = [0.0, 0.0, 0.0, 0];
|
|
1
|
+
export const RENDER_PASS_COLOR_ATTACHMENT_CLEAR_VALUE = [0.0, 0.0, 0.0, 1.0];
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
render: (frame: VideoFrameLike, pass: number) => GPUTexture;
|
|
1
|
+
export declare const createBlurRenderer: (device: GPUDevice, width: number, height: number, textureFormat: GPUTextureFormat, isContextLost: () => boolean) => {
|
|
2
|
+
render: (encoder: GPUCommandEncoder, frame: GPUTexture, pass: number) => GPUTexture;
|
|
4
3
|
release: () => void;
|
|
5
4
|
};
|