jassub 2.0.20 → 2.2.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 +31 -11
- package/dist/debug.js +1 -1
- package/dist/debug.js.map +1 -1
- package/dist/wasm/jassub-worker-modern.wasm +0 -0
- package/dist/wasm/jassub-worker.js +1 -1
- package/dist/wasm/jassub-worker.js.map +1 -1
- package/dist/wasm/jassub-worker.wasm +0 -0
- package/dist/wasm/types.d.ts +1 -5
- package/dist/worker/webgl-renderer.d.ts +45 -0
- package/dist/worker/webgl-renderer.js +328 -0
- package/dist/worker/webgl-renderer.js.map +1 -0
- package/dist/worker/webgpu-renderer.d.ts +4 -5
- package/dist/worker/webgpu-renderer.js +87 -99
- package/dist/worker/webgpu-renderer.js.map +1 -1
- package/dist/worker/worker.d.ts +3 -3
- package/dist/worker/worker.js +16 -8
- package/dist/worker/worker.js.map +1 -1
- package/package.json +3 -2
- package/src/debug.ts +1 -1
- package/src/wasm/types.d.ts +1 -5
- package/src/worker/webgl-renderer.ts +412 -0
- package/src/worker/webgpu-renderer.ts +89 -103
- package/src/worker/worker.ts +19 -8
package/dist/worker/worker.js
CHANGED
|
@@ -3,14 +3,14 @@ import { finalizer } from 'abslink';
|
|
|
3
3
|
import { expose } from 'abslink/w3c';
|
|
4
4
|
import WASM from '../wasm/jassub-worker.js';
|
|
5
5
|
import { libassYCbCrMap, read_, readAsync, _applyKeys } from './util';
|
|
6
|
-
import {
|
|
6
|
+
import { WebGL2Renderer } from './webgl-renderer';
|
|
7
7
|
export class ASSRenderer {
|
|
8
8
|
_offCanvas;
|
|
9
9
|
_wasm;
|
|
10
10
|
_subtitleColorSpace;
|
|
11
11
|
_videoColorSpace;
|
|
12
12
|
_malloc;
|
|
13
|
-
_gpurender = new
|
|
13
|
+
_gpurender = new WebGL2Renderer();
|
|
14
14
|
debug = false;
|
|
15
15
|
useLocalFonts = false;
|
|
16
16
|
_availableFonts = {};
|
|
@@ -27,15 +27,19 @@ export class ASSRenderer {
|
|
|
27
27
|
const _fetch = globalThis.fetch;
|
|
28
28
|
globalThis.fetch = _ => _fetch(data.wasmUrl);
|
|
29
29
|
// TODO: abslink doesnt support transferables yet
|
|
30
|
-
const handleMessage = ({ data }) => {
|
|
30
|
+
const handleMessage = async ({ data }) => {
|
|
31
31
|
if (data.name === 'offscreenCanvas') {
|
|
32
|
+
// await this._ready // needed for webGPU
|
|
32
33
|
this._offCanvas = data.ctrl;
|
|
33
34
|
this._gpurender.setCanvas(this._offCanvas, this._offCanvas.width, this._offCanvas.height);
|
|
34
35
|
removeEventListener('message', handleMessage);
|
|
35
36
|
}
|
|
36
37
|
};
|
|
37
38
|
addEventListener('message', handleMessage);
|
|
38
|
-
|
|
39
|
+
// const devicePromise = navigator.gpu?.requestAdapter({
|
|
40
|
+
// powerPreference: 'high-performance'
|
|
41
|
+
// }).then(adapter => adapter?.requestDevice())
|
|
42
|
+
this._ready = WASM({ __url: data.wasmUrl }).then(async (Module) => {
|
|
39
43
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
40
44
|
this._malloc = Module._malloc;
|
|
41
45
|
const fallbackFont = data.fallbackFont.toLowerCase();
|
|
@@ -52,6 +56,9 @@ export class ASSRenderer {
|
|
|
52
56
|
if (data.libassMemoryLimit > 0 || data.libassGlyphLimit > 0) {
|
|
53
57
|
this._wasm.setMemoryLimits(data.libassGlyphLimit || 0, data.libassMemoryLimit || 0);
|
|
54
58
|
}
|
|
59
|
+
// const device = await devicePromise
|
|
60
|
+
// this._gpurender = device ? new WebGPURenderer(device) : new WebGL2Renderer()
|
|
61
|
+
// if (this._offCanvas) this._gpurender.setCanvas(this._offCanvas, this._offCanvas.width, this._offCanvas.height)
|
|
55
62
|
this._checkColorSpace();
|
|
56
63
|
});
|
|
57
64
|
}
|
|
@@ -121,7 +128,7 @@ export class ASSRenderer {
|
|
|
121
128
|
_checkColorSpace() {
|
|
122
129
|
if (!this._subtitleColorSpace || !this._videoColorSpace)
|
|
123
130
|
return;
|
|
124
|
-
this._gpurender.setColorMatrix(
|
|
131
|
+
this._gpurender.setColorMatrix(this._subtitleColorSpace, this._videoColorSpace);
|
|
125
132
|
}
|
|
126
133
|
_findAvailableFonts(font) {
|
|
127
134
|
font = font.trim().toLowerCase();
|
|
@@ -168,11 +175,12 @@ export class ASSRenderer {
|
|
|
168
175
|
}
|
|
169
176
|
}
|
|
170
177
|
_canvas(width, height, videoWidth, videoHeight) {
|
|
171
|
-
if (this._offCanvas)
|
|
178
|
+
if (this._offCanvas && this._gpurender)
|
|
172
179
|
this._gpurender.setCanvas(this._offCanvas, width, height);
|
|
173
180
|
this._wasm.resizeCanvas(width, height, videoWidth, videoHeight);
|
|
174
181
|
}
|
|
175
|
-
[finalizer]() {
|
|
182
|
+
async [finalizer]() {
|
|
183
|
+
await this._ready;
|
|
176
184
|
this._wasm.quitLibrary();
|
|
177
185
|
this._gpurender.destroy();
|
|
178
186
|
// @ts-expect-error force GC
|
|
@@ -182,7 +190,7 @@ export class ASSRenderer {
|
|
|
182
190
|
this._availableFonts = {};
|
|
183
191
|
}
|
|
184
192
|
_draw(time, force = false) {
|
|
185
|
-
if (!this._offCanvas)
|
|
193
|
+
if (!this._offCanvas || !this._gpurender)
|
|
186
194
|
return;
|
|
187
195
|
const result = this._wasm.rawRender(time, Number(force));
|
|
188
196
|
if (this._wasm.changed === 0 && !force)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/worker/worker.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,OAAO,IAAI,MAAM,0BAA0B,CAAA;AAE3C,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACrE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/worker/worker.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jassub",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "The Fastest JavaScript SSA/ASS Subtitle Renderer For Browsers",
|
|
5
5
|
"main": "dist/jassub.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"files": [
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"WebAssembly",
|
|
29
29
|
"subtitles",
|
|
30
30
|
"webgpu",
|
|
31
|
+
"webgl2",
|
|
31
32
|
"typescript"
|
|
32
33
|
],
|
|
33
34
|
"author": "ThaUnknown",
|
package/src/debug.ts
CHANGED
|
@@ -31,7 +31,7 @@ export class Debug {
|
|
|
31
31
|
this._startTime = performance.now()
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
onsubtitleFrameCallback?: (now: DOMHighResTimeStamp, metadata: SubtitleCallbackMetadata) => void
|
|
34
|
+
onsubtitleFrameCallback?: (now: DOMHighResTimeStamp, metadata: SubtitleCallbackMetadata) => void
|
|
35
35
|
|
|
36
36
|
_endFrame (meta: VideoFrameCallbackMetadata) {
|
|
37
37
|
++this.presentedFrames
|
package/src/wasm/types.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
// TypeScript bindings for emscripten-generated code. Automatically generated at compile time.
|
|
2
|
-
declare namespace RuntimeExports {
|
|
3
|
-
function getTempRet0(val: any): any;
|
|
4
|
-
function setTempRet0(val: any): any;
|
|
5
|
-
}
|
|
6
2
|
interface WasmModule {
|
|
7
3
|
__ZdlPvm(_0: number, _1: number): void;
|
|
8
4
|
_malloc(_0: number): number;
|
|
@@ -134,5 +130,5 @@ interface EmbindModule {
|
|
|
134
130
|
};
|
|
135
131
|
}
|
|
136
132
|
|
|
137
|
-
export type MainModule = WasmModule &
|
|
133
|
+
export type MainModule = WasmModule & EmbindModule;
|
|
138
134
|
export default function MainModuleFactory (options?: unknown): Promise<MainModule>;
|
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
import type { ASSImage } from '../jassub'
|
|
2
|
+
|
|
3
|
+
declare const self: DedicatedWorkerGlobalScope &
|
|
4
|
+
typeof globalThis & {
|
|
5
|
+
HEAPU8RAW: Uint8Array<ArrayBuffer>
|
|
6
|
+
WASMMEMORY: WebAssembly.Memory
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// @ts-expect-error new experimental API
|
|
10
|
+
const SUPPORTS_GROWTH = !!WebAssembly.Memory.prototype.toResizableBuffer
|
|
11
|
+
|
|
12
|
+
const IDENTITY_MATRIX = new Float32Array([
|
|
13
|
+
1, 0, 0,
|
|
14
|
+
0, 1, 0,
|
|
15
|
+
0, 0, 1
|
|
16
|
+
])
|
|
17
|
+
|
|
18
|
+
// Color matrix conversion map - mat3x3 for WebGL2
|
|
19
|
+
// Each matrix converts FROM the key color space TO the nested key color space
|
|
20
|
+
export const colorMatrixConversionMap = {
|
|
21
|
+
BT601: {
|
|
22
|
+
BT709: new Float32Array([
|
|
23
|
+
1.0863, 0.0965, -0.01411,
|
|
24
|
+
-0.0723, 0.8451, -0.0277,
|
|
25
|
+
-0.0141, 0.0584, 1.0418
|
|
26
|
+
]),
|
|
27
|
+
BT601: IDENTITY_MATRIX
|
|
28
|
+
},
|
|
29
|
+
BT709: {
|
|
30
|
+
BT601: new Float32Array([
|
|
31
|
+
0.9137, 0.0784, 0.0079,
|
|
32
|
+
-0.1049, 1.1722, -0.0671,
|
|
33
|
+
0.0096, 0.0322, 0.9582
|
|
34
|
+
]),
|
|
35
|
+
BT709: IDENTITY_MATRIX
|
|
36
|
+
},
|
|
37
|
+
FCC: {
|
|
38
|
+
BT709: new Float32Array([
|
|
39
|
+
1.0873, -0.0736, -0.0137,
|
|
40
|
+
0.0974, 0.8494, 0.0531,
|
|
41
|
+
-0.0127, -0.0251, 1.0378
|
|
42
|
+
]),
|
|
43
|
+
BT601: new Float32Array([
|
|
44
|
+
1.001, -0.0008, -0.0002,
|
|
45
|
+
0.0009, 1.005, -0.006,
|
|
46
|
+
0.0013, 0.0027, 0.996
|
|
47
|
+
])
|
|
48
|
+
},
|
|
49
|
+
SMPTE240M: {
|
|
50
|
+
BT709: new Float32Array([
|
|
51
|
+
0.9993, 0.0006, 0.0001,
|
|
52
|
+
-0.0004, 0.9812, 0.0192,
|
|
53
|
+
-0.0034, -0.0114, 1.0148
|
|
54
|
+
]),
|
|
55
|
+
BT601: new Float32Array([
|
|
56
|
+
0.913, 0.0774, 0.0096,
|
|
57
|
+
-0.1051, 1.1508, -0.0456,
|
|
58
|
+
0.0063, 0.0207, 0.973
|
|
59
|
+
])
|
|
60
|
+
}
|
|
61
|
+
} as const
|
|
62
|
+
|
|
63
|
+
export type ColorSpace = keyof typeof colorMatrixConversionMap
|
|
64
|
+
|
|
65
|
+
// GLSL ES 3.0 Vertex Shader
|
|
66
|
+
const VERTEX_SHADER = /* glsl */`#version 300 es
|
|
67
|
+
precision highp float;
|
|
68
|
+
|
|
69
|
+
const vec2 QUAD_POSITIONS[6] = vec2[6](
|
|
70
|
+
vec2(0.0, 0.0),
|
|
71
|
+
vec2(1.0, 0.0),
|
|
72
|
+
vec2(0.0, 1.0),
|
|
73
|
+
vec2(1.0, 0.0),
|
|
74
|
+
vec2(1.0, 1.0),
|
|
75
|
+
vec2(0.0, 1.0)
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
uniform vec2 u_resolution;
|
|
79
|
+
uniform vec4 u_destRect; // x, y, w, h
|
|
80
|
+
uniform vec4 u_color; // r, g, b, a
|
|
81
|
+
uniform float u_texLayer;
|
|
82
|
+
|
|
83
|
+
flat out vec2 v_destXY;
|
|
84
|
+
flat out vec4 v_color;
|
|
85
|
+
flat out vec2 v_texSize;
|
|
86
|
+
flat out float v_texLayer;
|
|
87
|
+
|
|
88
|
+
void main() {
|
|
89
|
+
vec2 quadPos = QUAD_POSITIONS[gl_VertexID];
|
|
90
|
+
vec2 pixelPos = u_destRect.xy + quadPos * u_destRect.zw;
|
|
91
|
+
vec2 clipPos = (pixelPos / u_resolution) * 2.0 - 1.0;
|
|
92
|
+
clipPos.y = -clipPos.y;
|
|
93
|
+
|
|
94
|
+
gl_Position = vec4(clipPos, 0.0, 1.0);
|
|
95
|
+
v_destXY = u_destRect.xy;
|
|
96
|
+
v_color = u_color;
|
|
97
|
+
v_texSize = u_destRect.zw;
|
|
98
|
+
v_texLayer = u_texLayer;
|
|
99
|
+
}
|
|
100
|
+
`
|
|
101
|
+
|
|
102
|
+
// GLSL ES 3.0 Fragment Shader - use texelFetch for pixel-perfect sampling
|
|
103
|
+
const FRAGMENT_SHADER = /* glsl */`#version 300 es
|
|
104
|
+
precision highp float;
|
|
105
|
+
precision highp sampler2DArray;
|
|
106
|
+
|
|
107
|
+
uniform sampler2DArray u_texArray;
|
|
108
|
+
uniform mat3 u_colorMatrix;
|
|
109
|
+
uniform vec2 u_resolution;
|
|
110
|
+
|
|
111
|
+
flat in vec2 v_destXY;
|
|
112
|
+
flat in vec4 v_color;
|
|
113
|
+
flat in vec2 v_texSize;
|
|
114
|
+
flat in float v_texLayer;
|
|
115
|
+
|
|
116
|
+
out vec4 fragColor;
|
|
117
|
+
|
|
118
|
+
void main() {
|
|
119
|
+
// Flip Y: WebGL's gl_FragCoord.y is 0 at bottom, but destXY.y is from top
|
|
120
|
+
vec2 fragPos = vec2(gl_FragCoord.x, u_resolution.y - gl_FragCoord.y);
|
|
121
|
+
|
|
122
|
+
// Calculate local position within the quad (screen coords)
|
|
123
|
+
vec2 localPos = fragPos - v_destXY;
|
|
124
|
+
|
|
125
|
+
// Convert to integer texel coordinates for texelFetch
|
|
126
|
+
ivec2 texCoord = ivec2(floor(localPos));
|
|
127
|
+
|
|
128
|
+
// Bounds check (prevents out-of-bounds access)
|
|
129
|
+
ivec2 texSizeI = ivec2(v_texSize);
|
|
130
|
+
if (texCoord.x < 0 || texCoord.y < 0 || texCoord.x >= texSizeI.x || texCoord.y >= texSizeI.y) {
|
|
131
|
+
fragColor = vec4(0.0);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// texelFetch: integer coords, no interpolation, no precision issues
|
|
136
|
+
float mask = texelFetch(u_texArray, ivec3(texCoord, int(v_texLayer)), 0).r;
|
|
137
|
+
|
|
138
|
+
// Apply color matrix conversion (identity if no conversion needed)
|
|
139
|
+
vec3 correctedColor = u_colorMatrix * v_color.rgb;
|
|
140
|
+
|
|
141
|
+
// libass color alpha: 0 = opaque, 255 = transparent (inverted)
|
|
142
|
+
float colorAlpha = 1.0 - v_color.a;
|
|
143
|
+
|
|
144
|
+
// Final alpha = colorAlpha * mask
|
|
145
|
+
float a = colorAlpha * mask;
|
|
146
|
+
|
|
147
|
+
// Premultiplied alpha output
|
|
148
|
+
fragColor = vec4(correctedColor * a, a);
|
|
149
|
+
}
|
|
150
|
+
`
|
|
151
|
+
|
|
152
|
+
// Texture array configuration
|
|
153
|
+
const TEX_ARRAY_SIZE = 64 // Fixed layer count
|
|
154
|
+
const TEX_INITIAL_SIZE = 256 // Initial width/height
|
|
155
|
+
|
|
156
|
+
export class WebGL2Renderer {
|
|
157
|
+
gl: WebGL2RenderingContext | null = null
|
|
158
|
+
program: WebGLProgram | null = null
|
|
159
|
+
vao: WebGLVertexArrayObject | null = null
|
|
160
|
+
|
|
161
|
+
// Uniform locations
|
|
162
|
+
u_resolution: WebGLUniformLocation | null = null
|
|
163
|
+
u_destRect: WebGLUniformLocation | null = null
|
|
164
|
+
u_color: WebGLUniformLocation | null = null
|
|
165
|
+
u_texArray: WebGLUniformLocation | null = null
|
|
166
|
+
u_colorMatrix: WebGLUniformLocation | null = null
|
|
167
|
+
u_texLayer: WebGLUniformLocation | null = null
|
|
168
|
+
|
|
169
|
+
// Single texture array instead of individual textures
|
|
170
|
+
texArray: WebGLTexture | null = null
|
|
171
|
+
texArrayWidth = 0
|
|
172
|
+
texArrayHeight = 0
|
|
173
|
+
|
|
174
|
+
colorMatrix: Float32Array = IDENTITY_MATRIX
|
|
175
|
+
|
|
176
|
+
setCanvas (canvas: OffscreenCanvas, width: number, height: number) {
|
|
177
|
+
// WebGL2 doesn't allow 0-sized canvases
|
|
178
|
+
if (width <= 0 || height <= 0) return
|
|
179
|
+
|
|
180
|
+
canvas.width = width
|
|
181
|
+
canvas.height = height
|
|
182
|
+
|
|
183
|
+
if (!this.gl) {
|
|
184
|
+
// Get canvas context
|
|
185
|
+
// Note: preserveDrawingBuffer is false (default) - the browser handles
|
|
186
|
+
// buffer swaps for OffscreenCanvas, avoiding flicker
|
|
187
|
+
this.gl = canvas.getContext('webgl2', {
|
|
188
|
+
alpha: true,
|
|
189
|
+
premultipliedAlpha: true,
|
|
190
|
+
antialias: false,
|
|
191
|
+
depth: false,
|
|
192
|
+
stencil: false,
|
|
193
|
+
desynchronized: true
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
if (!this.gl) {
|
|
197
|
+
throw new Error('Could not get WebGL2 context')
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Create shaders
|
|
201
|
+
const vertexShader = this.createShader(this.gl.VERTEX_SHADER, VERTEX_SHADER)
|
|
202
|
+
const fragmentShader = this.createShader(this.gl.FRAGMENT_SHADER, FRAGMENT_SHADER)
|
|
203
|
+
|
|
204
|
+
if (!vertexShader || !fragmentShader) {
|
|
205
|
+
throw new Error('Failed to create shaders')
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Create program
|
|
209
|
+
this.program = this.gl.createProgram()!
|
|
210
|
+
this.gl.attachShader(this.program, vertexShader)
|
|
211
|
+
this.gl.attachShader(this.program, fragmentShader)
|
|
212
|
+
this.gl.linkProgram(this.program)
|
|
213
|
+
|
|
214
|
+
if (!this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS)) {
|
|
215
|
+
const info = this.gl.getProgramInfoLog(this.program)
|
|
216
|
+
throw new Error('Failed to link program: ' + info)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
this.gl.deleteShader(vertexShader)
|
|
220
|
+
this.gl.deleteShader(fragmentShader)
|
|
221
|
+
|
|
222
|
+
// Get uniform locations
|
|
223
|
+
this.u_resolution = this.gl.getUniformLocation(this.program, 'u_resolution')
|
|
224
|
+
this.u_destRect = this.gl.getUniformLocation(this.program, 'u_destRect')
|
|
225
|
+
this.u_color = this.gl.getUniformLocation(this.program, 'u_color')
|
|
226
|
+
this.u_texArray = this.gl.getUniformLocation(this.program, 'u_texArray')
|
|
227
|
+
this.u_colorMatrix = this.gl.getUniformLocation(this.program, 'u_colorMatrix')
|
|
228
|
+
this.u_texLayer = this.gl.getUniformLocation(this.program, 'u_texLayer')
|
|
229
|
+
|
|
230
|
+
// Create a VAO (required for WebGL2)
|
|
231
|
+
this.vao = this.gl.createVertexArray()
|
|
232
|
+
this.gl.bindVertexArray(this.vao)
|
|
233
|
+
|
|
234
|
+
// Set up blending for premultiplied alpha
|
|
235
|
+
this.gl.enable(this.gl.BLEND)
|
|
236
|
+
this.gl.blendFunc(this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA)
|
|
237
|
+
|
|
238
|
+
// Use the program
|
|
239
|
+
this.gl.useProgram(this.program)
|
|
240
|
+
|
|
241
|
+
// Set texture unit
|
|
242
|
+
this.gl.uniform1i(this.u_texArray, 0)
|
|
243
|
+
|
|
244
|
+
// Set initial color matrix
|
|
245
|
+
this.gl.uniformMatrix3fv(this.u_colorMatrix, false, this.colorMatrix)
|
|
246
|
+
|
|
247
|
+
// Set one-time GL state
|
|
248
|
+
this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1)
|
|
249
|
+
this.gl.clearColor(0, 0, 0, 0)
|
|
250
|
+
this.gl.activeTexture(this.gl.TEXTURE0)
|
|
251
|
+
|
|
252
|
+
// Create initial texture array
|
|
253
|
+
this.createTexArray(TEX_INITIAL_SIZE, TEX_INITIAL_SIZE)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Update viewport and resolution uniform
|
|
257
|
+
this.gl.viewport(0, 0, width, height)
|
|
258
|
+
this.gl.uniform2f(this.u_resolution, width, height)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
createShader (type: number, source: string): WebGLShader | null {
|
|
262
|
+
const shader = this.gl!.createShader(type)!
|
|
263
|
+
this.gl!.shaderSource(shader, source)
|
|
264
|
+
this.gl!.compileShader(shader)
|
|
265
|
+
|
|
266
|
+
if (!this.gl!.getShaderParameter(shader, this.gl!.COMPILE_STATUS)) {
|
|
267
|
+
const info = this.gl!.getShaderInfoLog(shader)
|
|
268
|
+
console.log(info)
|
|
269
|
+
this.gl!.deleteShader(shader)
|
|
270
|
+
return null
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return shader
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Set the color matrix for color space conversion.
|
|
278
|
+
* Pass null or undefined to use identity (no conversion).
|
|
279
|
+
*/
|
|
280
|
+
setColorMatrix (subtitleColorSpace?: 'BT601' | 'BT709' | 'SMPTE240M' | 'FCC', videoColorSpace?: 'BT601' | 'BT709') {
|
|
281
|
+
this.colorMatrix = (subtitleColorSpace && videoColorSpace && colorMatrixConversionMap[subtitleColorSpace]?.[videoColorSpace]) ?? IDENTITY_MATRIX
|
|
282
|
+
if (this.gl && this.u_colorMatrix && this.program) {
|
|
283
|
+
this.gl.useProgram(this.program)
|
|
284
|
+
this.gl.uniformMatrix3fv(this.u_colorMatrix, false, this.colorMatrix)
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
createTexArray (width: number, height: number) {
|
|
289
|
+
if (this.texArray) {
|
|
290
|
+
this.gl!.deleteTexture(this.texArray)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
this.texArray = this.gl!.createTexture()
|
|
294
|
+
this.gl!.bindTexture(this.gl!.TEXTURE_2D_ARRAY, this.texArray)
|
|
295
|
+
|
|
296
|
+
// Allocate storage for texture array
|
|
297
|
+
this.gl!.texImage3D(
|
|
298
|
+
this.gl!.TEXTURE_2D_ARRAY,
|
|
299
|
+
0,
|
|
300
|
+
this.gl!.R8,
|
|
301
|
+
width,
|
|
302
|
+
height,
|
|
303
|
+
TEX_ARRAY_SIZE,
|
|
304
|
+
0,
|
|
305
|
+
this.gl!.RED,
|
|
306
|
+
this.gl!.UNSIGNED_BYTE,
|
|
307
|
+
null
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
// Set texture parameters (no filtering needed for texelFetch, but set anyway)
|
|
311
|
+
this.gl!.texParameteri(this.gl!.TEXTURE_2D_ARRAY, this.gl!.TEXTURE_MIN_FILTER, this.gl!.NEAREST)
|
|
312
|
+
this.gl!.texParameteri(this.gl!.TEXTURE_2D_ARRAY, this.gl!.TEXTURE_MAG_FILTER, this.gl!.NEAREST)
|
|
313
|
+
this.gl!.texParameteri(this.gl!.TEXTURE_2D_ARRAY, this.gl!.TEXTURE_WRAP_S, this.gl!.CLAMP_TO_EDGE)
|
|
314
|
+
this.gl!.texParameteri(this.gl!.TEXTURE_2D_ARRAY, this.gl!.TEXTURE_WRAP_T, this.gl!.CLAMP_TO_EDGE)
|
|
315
|
+
|
|
316
|
+
this.texArrayWidth = width
|
|
317
|
+
this.texArrayHeight = height
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
render (images: ASSImage[], heap: Uint8Array): void {
|
|
321
|
+
if (!this.gl || !this.program || !this.vao || !this.texArray) return
|
|
322
|
+
|
|
323
|
+
// Hack: work around shared memory issues, webGL doesnt support shared memory, so there are race conditions when growing memory
|
|
324
|
+
if ((self.HEAPU8RAW.buffer !== self.WASMMEMORY.buffer) || SUPPORTS_GROWTH) {
|
|
325
|
+
heap = self.HEAPU8RAW = new Uint8Array(self.WASMMEMORY.buffer)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Clear canvas
|
|
329
|
+
this.gl.clear(this.gl.COLOR_BUFFER_BIT)
|
|
330
|
+
|
|
331
|
+
// Find max dimensions needed
|
|
332
|
+
let maxW = this.texArrayWidth
|
|
333
|
+
let maxH = this.texArrayHeight
|
|
334
|
+
for (const img of images) {
|
|
335
|
+
if (img.w > maxW) maxW = img.w
|
|
336
|
+
if (img.h > maxH) maxH = img.h
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Resize texture array if needed
|
|
340
|
+
if (maxW > this.texArrayWidth || maxH > this.texArrayHeight) {
|
|
341
|
+
this.createTexArray(maxW, maxH)
|
|
342
|
+
this.gl.bindTexture(this.gl.TEXTURE_2D_ARRAY, this.texArray)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// Render each image
|
|
346
|
+
for (let i = 0, texLayer = 0; i < images.length; i++) {
|
|
347
|
+
const img = images[i]!
|
|
348
|
+
|
|
349
|
+
// Skip images with invalid dimensions
|
|
350
|
+
if (img.w <= 0 || img.h <= 0) continue
|
|
351
|
+
|
|
352
|
+
// Use modulo to cycle through layers if we have more images than layers
|
|
353
|
+
const layer = texLayer % TEX_ARRAY_SIZE
|
|
354
|
+
texLayer++
|
|
355
|
+
|
|
356
|
+
// Upload bitmap data to texture array layer
|
|
357
|
+
this.gl.pixelStorei(this.gl.UNPACK_ROW_LENGTH, img.stride)
|
|
358
|
+
|
|
359
|
+
this.gl.texSubImage3D(
|
|
360
|
+
this.gl.TEXTURE_2D_ARRAY,
|
|
361
|
+
0,
|
|
362
|
+
0, 0, layer, // x, y, z offset
|
|
363
|
+
img.w,
|
|
364
|
+
img.h,
|
|
365
|
+
1, // depth (1 layer)
|
|
366
|
+
this.gl.RED,
|
|
367
|
+
this.gl.UNSIGNED_BYTE,
|
|
368
|
+
heap,
|
|
369
|
+
img.bitmap
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
this.gl.pixelStorei(this.gl.UNPACK_ROW_LENGTH, 0)
|
|
373
|
+
|
|
374
|
+
// Set uniforms
|
|
375
|
+
this.gl.uniform4f(this.u_destRect, img.dst_x, img.dst_y, img.w, img.h)
|
|
376
|
+
this.gl.uniform1f(this.u_texLayer, layer)
|
|
377
|
+
|
|
378
|
+
// color (RGBA from 0xRRGGBBAA)
|
|
379
|
+
this.gl.uniform4f(
|
|
380
|
+
this.u_color,
|
|
381
|
+
((img.color >>> 24) & 0xFF) / 255,
|
|
382
|
+
((img.color >>> 16) & 0xFF) / 255,
|
|
383
|
+
((img.color >>> 8) & 0xFF) / 255,
|
|
384
|
+
(img.color & 0xFF) / 255
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
// 6 vertices for quad
|
|
388
|
+
this.gl.drawArrays(this.gl.TRIANGLES, 0, 6)
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
destroy () {
|
|
393
|
+
if (this.gl) {
|
|
394
|
+
if (this.texArray) {
|
|
395
|
+
this.gl.deleteTexture(this.texArray)
|
|
396
|
+
this.texArray = null
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (this.vao) {
|
|
400
|
+
this.gl.deleteVertexArray(this.vao)
|
|
401
|
+
this.vao = null
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (this.program) {
|
|
405
|
+
this.gl.deleteProgram(this.program)
|
|
406
|
+
this.program = null
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
this.gl = null
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|