|
4 | 4 | * area: the best 8x8 transform of each block, merged into larger DCTs where they are estimated to cost less. |
5 | 5 | * Copyright (c) the JPEG XL Project Authors, BSD-3-Clause License (see THIRD_PARTY_NOTICES.md) |
6 | 6 | */ |
| 7 | +import { runChunks, shared, type ChunkTask, type Thread } from '../../util/threads.ts'; |
7 | 8 | import { forwardTransform } from './transforms-enc.ts'; |
8 | 9 | import { inverseTransform } from './dct.ts'; |
9 | 10 | import { defaultDequant, MATRIX_INDEX } from './quant.ts'; |
@@ -117,8 +118,8 @@ function best8x8(x: number, y: number, speed: number, cfg: Config): [number, num |
117 | 118 | class Strategy { |
118 | 119 | readonly types: Int8Array; |
119 | 120 |
|
120 | | - constructor(readonly bw: number, readonly bh: number) { |
121 | | - this.types = new Int8Array(bw * bh); |
| 121 | + constructor(readonly bw: number, readonly bh: number, types?: Int8Array) { |
| 122 | + this.types = types ?? new Int8Array(bw * bh); |
122 | 123 | } |
123 | 124 |
|
124 | 125 | set(bx: number, by: number, type: number): void { |
@@ -285,15 +286,42 @@ function processRect(bx: number, by: number, w: number, h: number, speed: number |
285 | 286 | * The varblock types of an image (XYB planes of whole blocks, rows stride apart): libjxl's search at a speed tier (5: |
286 | 287 | * its effort 5, 4: also the 4x8 and AFV transforms) |
287 | 288 | */ |
288 | | -export function chooseVarblocks(planes: Float32Array[], stride: number, bw: number, bh: number, field: QuantField, distance: number, speed: number): Int8Array { |
| 289 | +export async function chooseVarblocks(planes: Float32Array[], stride: number, bw: number, bh: number, field: QuantField, distance: number, speed: number, threads: Thread[] | null): Promise<Int8Array> { |
| 290 | + const types = new Int8Array(threads ? new SharedArrayBuffer(bw * bh) : new ArrayBuffer(bw * bh)); |
| 291 | + const task: VarblockTask = { |
| 292 | + task: 'jxl-varblocks', stride, bw, bh, distance, speed, types, |
| 293 | + planes: threads ? planes.map(shared) : planes, |
| 294 | + field: threads ? { quant: shared(field.quant), mask: shared(field.mask), mask1x1: shared(field.mask1x1) } : field, |
| 295 | + }; |
| 296 | + // (a row of 64x64 areas each, independent of the others) |
| 297 | + await runChunks(threads, task, Math.ceil(bh / 8), varblockChunks(task)); |
| 298 | + return types; |
| 299 | +} |
| 300 | + |
| 301 | +/** The varblock search of rows of 64x64 areas (see chooseVarblocks) */ |
| 302 | +export interface VarblockTask extends ChunkTask { |
| 303 | + planes: Float32Array[]; |
| 304 | + stride: number; |
| 305 | + bw: number; |
| 306 | + bh: number; |
| 307 | + field: QuantField; |
| 308 | + distance: number; |
| 309 | + speed: number; |
| 310 | + types: Int8Array; |
| 311 | +} |
| 312 | + |
| 313 | +/** The search of a row of 64x64 areas (the chunk), its types set */ |
| 314 | +export function varblockChunks({ planes, stride, bw, bh, field, distance, speed, types }: VarblockTask): (chunk: number) => void { |
289 | 315 | const ratio = (distance + 0.13731742964354549) / (1 + 0.13731742964354549); |
290 | 316 | const cfg: Config = { |
291 | 317 | planes, stride, bw, field, distance, |
292 | 318 | infoLossMul: 1.2 * ratio ** 0.33677806662454718, |
293 | 319 | zerosMul: 9.3089059022677905 * ratio ** 0.50990926717963703, |
294 | 320 | costDelta: 10.833273317067883 * ratio ** 0.36702940662370243 |
295 | 321 | }; |
296 | | - const s = new Strategy(bw, bh); |
297 | | - for (let by = 0; by < bh; by += 8) for (let bx = 0; bx < bw; bx += 8) processRect(bx, by, Math.min(8, bw - bx), Math.min(8, bh - by), speed, cfg, s); |
298 | | - return s.types; |
| 322 | + const s = new Strategy(bw, bh, types); |
| 323 | + return row => { |
| 324 | + const by = row * 8; |
| 325 | + for (let bx = 0; bx < bw; bx += 8) processRect(bx, by, Math.min(8, bw - bx), Math.min(8, bh - by), speed, cfg, s); |
| 326 | + }; |
299 | 327 | } |
0 commit comments