/*
Phaneron - Clustered, accelerated and cloud-fit video server, pre-assembled and in kit form.
Copyright (C) 2020 Streampunk Media Ltd.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
https://www.streampunk.media/ mailto:furnace@streampunk.media
14 Ormiscaig, Aultbea, Achnasheen, IV22 2JJ U.K.
*/
import Packer, { PackImpl } from './packer'
import { clContext as nodenCLContext, OpenCLBuffer, KernelParams } from 'nodencl'
import {
gamma2linearLUT,
ycbcr2rgbMatrix,
matrixFlatten,
rgb2rgbMatrix,
linear2gammaLUT,
rgb2ycbcrMatrix
} from './colourMaths'
import { ClJobs, JobCB, JobID } from '../clJobQueue'
export class Loader extends Packer {
private readonly gammaArray: Float32Array
private readonly colMatrixArray: Float32Array | null = null
private readonly gamutMatrixArray: Float32Array
private gammaLut: OpenCLBuffer | null = null
private colMatrix: OpenCLBuffer | null = null
private gamutMatrix: OpenCLBuffer | null = null
constructor(
clContext: nodenCLContext,
colSpec: string,
outColSpec: string,
packImpl: PackImpl,
clJobs: ClJobs
) {
super(clContext, packImpl, clJobs)
this.gammaArray = gamma2linearLUT(colSpec)
if (!this.packImpl.getIsRGB()) {
const colMatrix2d = ycbcr2rgbMatrix(
colSpec,
this.packImpl.numBits,
this.packImpl.lumaBlack,
this.packImpl.lumaWhite,
this.packImpl.chromaRange
)
this.colMatrixArray = matrixFlatten(colMatrix2d)
}
const gamutMatrix2d = rgb2rgbMatrix(colSpec, outColSpec)
this.gamutMatrixArray = matrixFlatten(gamutMatrix2d)
}
async init(): Promise {
await super.init()
this.gammaLut = await this.clContext.createBuffer(
this.gammaArray.byteLength,
'readonly',
'coarse',
undefined,
'loader gammaLut'
)
await this.gammaLut.hostAccess('writeonly')
Buffer.from(this.gammaArray.buffer).copy(this.gammaLut)
if (this.colMatrixArray) {
this.colMatrix = await this.clContext.createBuffer(
this.colMatrixArray.byteLength,
'readonly',
'none',
undefined,
'loader colMatrix'
)
await this.colMatrix.hostAccess('writeonly')
Buffer.from(this.colMatrixArray.buffer).copy(this.colMatrix)
}
this.gamutMatrix = await this.clContext.createBuffer(
this.gamutMatrixArray.byteLength,
'readonly',
'none',
undefined,
'loader gamutMatrix'
)
await this.gamutMatrix.hostAccess('writeonly')
Buffer.from(this.gamutMatrixArray.buffer).copy(this.gamutMatrix)
}
addRefs(): void {
this.gammaLut?.addRef()
this.colMatrix?.addRef()
this.gamutMatrix?.addRef()
}
releaseRefs(): void {
this.gammaLut?.release()
this.colMatrix?.release()
this.gamutMatrix?.release()
}
run(params: KernelParams, id: JobID, cb: JobCB): void {
if (this.program === null) throw new Error('Loader.run failed with no program available')
this.addRefs()
const kernelParams = this.packImpl.getKernelParams(params)
kernelParams.gammaLut = this.gammaLut
kernelParams.gamutMatrix = this.gamutMatrix
if (this.colMatrix) kernelParams.colMatrix = this.colMatrix
this.clJobs.add(id, this.packImpl.getName(), this.program, kernelParams, () => {
this.releaseRefs()
cb()
})
}
}
export class Saver extends Packer {
private readonly gammaArray: Float32Array
private readonly colMatrixArray: Float32Array | null = null
private gammaLut: OpenCLBuffer | null = null
private colMatrix: OpenCLBuffer | null = null
constructor(clContext: nodenCLContext, colSpec: string, packImpl: PackImpl, clJobs: ClJobs) {
super(clContext, packImpl, clJobs)
this.gammaArray = linear2gammaLUT(colSpec)
if (!this.packImpl.getIsRGB()) {
const colMatrix2d = rgb2ycbcrMatrix(
colSpec,
this.packImpl.numBits,
this.packImpl.lumaBlack,
this.packImpl.lumaWhite,
this.packImpl.chromaRange
)
this.colMatrixArray = matrixFlatten(colMatrix2d)
}
}
async init(): Promise {
await super.init()
this.gammaLut = await this.clContext.createBuffer(
this.gammaArray.byteLength,
'readonly',
'coarse',
undefined,
'saver gammaLut'
)
await this.gammaLut.hostAccess('writeonly')
Buffer.from(this.gammaArray.buffer).copy(this.gammaLut)
if (this.colMatrixArray) {
this.colMatrix = await this.clContext.createBuffer(
this.colMatrixArray.byteLength,
'readonly',
'none',
undefined,
'saver colMatrix'
)
await this.colMatrix.hostAccess('writeonly')
Buffer.from(this.colMatrixArray.buffer).copy(this.colMatrix)
}
}
addRefs(): void {
this.gammaLut?.addRef()
this.colMatrix?.addRef()
}
releaseRefs(): void {
this.gammaLut?.release()
this.colMatrix?.release()
}
run(params: KernelParams, id: JobID, cb: JobCB): void {
if (this.program === null) throw new Error('Saver.run failed with no program available')
this.addRefs()
const kernelParams = this.packImpl.getKernelParams(params)
kernelParams.gammaLut = this.gammaLut
if (this.colMatrix) kernelParams.colMatrix = this.colMatrix
this.clJobs.add(id, this.packImpl.getName(), this.program, kernelParams, () => {
this.releaseRefs()
cb()
})
}
}