@awayjs/stage
Version:
Stage for AwayJS
192 lines (156 loc) • 5.75 kB
text/typescript
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;
}
}