UNPKG

@awayjs/stage

Version:
192 lines (156 loc) 5.75 kB
import { ShaderRegisterElement } from './ShaderRegisterElement'; /** * RegisterPool is used by the shader compilers process to keep track of which registers of a certain type are * currently used and should not be allowed to be written to. Either entire registers can be requested and locked, * or single components (x, y, z, w) of a single register. * It is used by ShaderRegisterCache to track usages of individual register types. * * @see away.materials.ShaderRegisterCache */ export class RegisterPool { private static _regPool: Object = new Object(); private static _regCompsPool: Object = new Object(); private _vectorRegisters: Array<ShaderRegisterElement>; private _registerComponents; private _regName: string; private _usedSingleCount: Array<Array<number>>; private _usedVectorCount: Array<number> /*uint*/; private _regCount: number; private _persistent: boolean; /** * Creates a new RegisterPool object. * @param regName The base name of the register type ("ft" for fragment temporaries, "vc" for vertex constants, etc) * @param regCount The amount of available registers of this type. * @param persistent Whether or not registers, once reserved, can be freed again. For example, temporaries are not persistent, but constants are. */ constructor(regName: string, regCount: number, persistent: boolean = true) { this._regName = regName; this._regCount = regCount; this._persistent = persistent; this.initRegisters(regName, regCount); } /** * Retrieve an entire vector register that's still available. */ public requestFreeVectorReg(): ShaderRegisterElement { for (let i: number = 0; i < this._regCount; ++i) { if (!this.isRegisterUsed(i)) { if (this._persistent) this._usedVectorCount[i]++; return this._vectorRegisters[i]; } } throw new Error('Register overflow!'); } /** * Retrieve a single vector component that's still available. */ public requestFreeRegComponent(): ShaderRegisterElement { for (let i: number = 0; i < this._regCount; ++i) { if (this._usedVectorCount[i] > 0) continue; for (let j: number = 0; j < 4; ++j) { if (this._usedSingleCount[j][i] == 0) { if (this._persistent) this._usedSingleCount[j][i]++; return this._registerComponents[j][i]; } } } throw new Error('Register overflow!'); } /** * Marks a register as used, so it cannot be retrieved. The register won't be able to be used until removeUsage * has been called usageCount times again. * @param register The register to mark as used. * @param usageCount The amount of usages to add. */ public addUsage(register: ShaderRegisterElement, usageCount: number): void { if (register._component > -1) this._usedSingleCount[register._component][register.index] += usageCount; else this._usedVectorCount[register.index] += usageCount; } /** * Removes a usage from a register. When usages reach 0, the register is freed again. * @param register The register for which to remove a usage. */ public removeUsage(register: ShaderRegisterElement): void { if (register._component > -1) { if (--this._usedSingleCount[register._component][register.index] < 0) throw new Error('More usages removed than exist!'); } else { if (--this._usedVectorCount[register.index] < 0) throw new Error('More usages removed than exist!'); } } /** * Disposes any resources used by the current RegisterPool object. */ public dispose(): void { this._vectorRegisters = null; this._registerComponents = null; this._usedSingleCount = null; this._usedVectorCount = null; } /** * Indicates whether or not any registers are in use. */ public hasRegisteredRegs(): boolean { for (let i: number = 0; i < this._regCount; ++i) if (this.isRegisterUsed(i)) return true; return false; } /** * Initializes all registers. */ private initRegisters(regName: string, regCount: number): void { const hash: string = RegisterPool._initPool(regName, regCount); this._vectorRegisters = RegisterPool._regPool[hash]; this._registerComponents = RegisterPool._regCompsPool[hash]; this._usedVectorCount = this._initArray(Array<number>(regCount), 0); this._usedSingleCount = new Array<Array<number>>(4); this._usedSingleCount[0] = this._initArray(new Array<number>(regCount), 0); this._usedSingleCount[1] = this._initArray(new Array<number>(regCount), 0); this._usedSingleCount[2] = this._initArray(new Array<number>(regCount), 0); this._usedSingleCount[3] = this._initArray(new Array<number>(regCount), 0); } private static _initPool(regName: string, regCount: number): string { const hash: string = regName + regCount; if (RegisterPool._regPool[hash] != undefined) return hash; const vectorRegisters: Array<ShaderRegisterElement> = new Array<ShaderRegisterElement>(regCount); RegisterPool._regPool[hash] = vectorRegisters; const registerComponents = [ [], [], [], [] ]; RegisterPool._regCompsPool[hash] = registerComponents; for (let i: number = 0; i < regCount; ++i) { vectorRegisters[i] = new ShaderRegisterElement(regName, i); for (let j: number = 0; j < 4; ++j) registerComponents[j][i] = new ShaderRegisterElement(regName, i, j); } return hash; } /** * Check if the temp register is either used for single or vector use */ private isRegisterUsed(index: number): boolean { if (this._usedVectorCount[index] > 0) return true; for (let i: number = 0; i < 4; ++i) if (this._usedSingleCount[i][index] > 0) return true; return false; } private _initArray(a: Array<any>, val: any): Array<any> { const l: number = a.length; for (let c: number = 0; c < l; c++) a[c] = val; return a; } }