|
@@ -22,8 +22,15 @@ import "../Engines/Extensions/engine.uniformBuffer";
|
|
|
* https://www.khronos.org/opengl/wiki/Uniform_Buffer_Object
|
|
|
*/
|
|
|
export class UniformBuffer {
|
|
|
+ /** @hidden */
|
|
|
+ public static _updatedUbosInFrame: { [name: string]: number } = {};
|
|
|
+
|
|
|
private _engine: Engine;
|
|
|
private _buffer: Nullable<DataBuffer>;
|
|
|
+ private _buffers : Array<[Nullable<DataBuffer>, Float32Array, { [name: string]: number }]>;
|
|
|
+ private _bufferIndex: number;
|
|
|
+ private _createBufferOnWrite: boolean;
|
|
|
+ private _advanceToNextBuffer: boolean;
|
|
|
private _data: number[];
|
|
|
private _bufferData: Float32Array;
|
|
|
private _dynamic?: boolean;
|
|
@@ -34,6 +41,7 @@ export class UniformBuffer {
|
|
|
private _needSync: boolean;
|
|
|
private _noUBO: boolean;
|
|
|
private _currentEffect: Effect;
|
|
|
+ private _currentFrameId: number;
|
|
|
|
|
|
/** @hidden */
|
|
|
public _alreadyBound = false;
|
|
@@ -166,6 +174,14 @@ export class UniformBuffer {
|
|
|
this._uniformLocationPointer = 0;
|
|
|
this._needSync = false;
|
|
|
|
|
|
+ if (ThinEngine.Features.trackUbosInFrame) {
|
|
|
+ this._buffers = [];
|
|
|
+ this._bufferIndex = -1;
|
|
|
+ this._createBufferOnWrite = false;
|
|
|
+ this._advanceToNextBuffer = false;
|
|
|
+ this._currentFrameId = 0;
|
|
|
+ }
|
|
|
+
|
|
|
if (this._noUBO) {
|
|
|
this.updateMatrix3x3 = this._updateMatrix3x3ForEffect;
|
|
|
this.updateMatrix2x2 = this._updateMatrix2x2ForEffect;
|
|
@@ -458,6 +474,21 @@ export class UniformBuffer {
|
|
|
} else {
|
|
|
this._buffer = this._engine.createUniformBuffer(this._bufferData);
|
|
|
}
|
|
|
+
|
|
|
+ if (ThinEngine.Features.trackUbosInFrame) {
|
|
|
+ this._buffers.push([this._buffer, this._bufferData, this._valueCache]);
|
|
|
+ this._bufferIndex = this._buffers.length - 1;
|
|
|
+ this._createBufferOnWrite = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /** @hidden */
|
|
|
+ public get _numBuffers(): number {
|
|
|
+ return this._buffers.length;
|
|
|
+ }
|
|
|
+
|
|
|
+ public get name(): string {
|
|
|
+ return this._name;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -472,12 +503,55 @@ export class UniformBuffer {
|
|
|
}
|
|
|
|
|
|
if (!this._dynamic && !this._needSync) {
|
|
|
+ this._advanceToNextBuffer = ThinEngine.Features.trackUbosInFrame;
|
|
|
+ this._createBufferOnWrite = ThinEngine.Features.trackUbosInFrame;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
this._engine.updateUniformBuffer(this._buffer, this._bufferData);
|
|
|
|
|
|
+ if (ThinEngine.Features._collectUbosUpdatedInFrame) {
|
|
|
+ if (!UniformBuffer._updatedUbosInFrame[this._name]) {
|
|
|
+ UniformBuffer._updatedUbosInFrame[this._name] = 0;
|
|
|
+ }
|
|
|
+ UniformBuffer._updatedUbosInFrame[this._name]++;
|
|
|
+ }
|
|
|
+
|
|
|
this._needSync = false;
|
|
|
+ this._createBufferOnWrite = ThinEngine.Features.trackUbosInFrame;
|
|
|
+ this._advanceToNextBuffer = ThinEngine.Features.trackUbosInFrame;
|
|
|
+ }
|
|
|
+
|
|
|
+ private _createNewBuffer(): void {
|
|
|
+ this._bufferData = this._bufferData.slice();
|
|
|
+ this._valueCache = { ...this._valueCache }; // clone
|
|
|
+ this._rebuild();
|
|
|
+ }
|
|
|
+
|
|
|
+ private _checkBuffers(): void {
|
|
|
+ if (this._advanceToNextBuffer) {
|
|
|
+ if (this._bufferIndex + 1 < this._buffers.length) {
|
|
|
+ this._bufferIndex++;
|
|
|
+ this._buffer = this._buffers[this._bufferIndex][0];
|
|
|
+ this._bufferData = this._buffers[this._bufferIndex][1];
|
|
|
+ this._valueCache = this._buffers[this._bufferIndex][2];
|
|
|
+ this._createBufferOnWrite = false;
|
|
|
+ }
|
|
|
+ this._advanceToNextBuffer = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ThinEngine.Features.trackUbosInFrame && this._currentFrameId !== this._engine.frameId) {
|
|
|
+ this._currentFrameId = this._engine.frameId;
|
|
|
+ this._createBufferOnWrite = false;
|
|
|
+ if (this._buffers && this._buffers.length > 0) {
|
|
|
+ this._bufferIndex = 0;
|
|
|
+ this._buffer = this._buffers[this._bufferIndex][0];
|
|
|
+ this._bufferData = this._buffers[this._bufferIndex][1];
|
|
|
+ this._valueCache = this._buffers[this._bufferIndex][2];
|
|
|
+ } else {
|
|
|
+ this._bufferIndex = -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -487,6 +561,7 @@ export class UniformBuffer {
|
|
|
* @param size Define the size of the data.
|
|
|
*/
|
|
|
public updateUniform(uniformName: string, data: FloatArray, size: number) {
|
|
|
+ this._checkBuffers();
|
|
|
|
|
|
var location = this._uniformLocations[uniformName];
|
|
|
if (location === undefined) {
|
|
@@ -510,6 +585,9 @@ export class UniformBuffer {
|
|
|
for (var i = 0; i < size; i++) {
|
|
|
if ((size === 16 && !ThinEngine.Features.uniformBufferHardCheckMatrix) || this._bufferData[location + i] !== data[i]) {
|
|
|
changed = true;
|
|
|
+ if (this._createBufferOnWrite) {
|
|
|
+ this._createNewBuffer();
|
|
|
+ }
|
|
|
this._bufferData[location + i] = data[i];
|
|
|
}
|
|
|
}
|
|
@@ -517,6 +595,9 @@ export class UniformBuffer {
|
|
|
this._needSync = this._needSync || changed;
|
|
|
} else {
|
|
|
// No cache for dynamic
|
|
|
+ if (this._createBufferOnWrite) {
|
|
|
+ this._createNewBuffer();
|
|
|
+ }
|
|
|
for (var i = 0; i < size; i++) {
|
|
|
this._bufferData[location + i] = data[i];
|
|
|
}
|
|
@@ -530,6 +611,7 @@ export class UniformBuffer {
|
|
|
* @param size Define the size of the data.
|
|
|
*/
|
|
|
public updateUniformArray(uniformName: string, data: FloatArray, size: number) {
|
|
|
+ this._checkBuffers();
|
|
|
|
|
|
var location = this._uniformLocations[uniformName];
|
|
|
if (location === undefined) {
|
|
@@ -551,6 +633,9 @@ export class UniformBuffer {
|
|
|
for (var i = 0; i < size; i++) {
|
|
|
if (this._bufferData[location + baseStride * 4 + countToFour] !== data[i]) {
|
|
|
changed = true;
|
|
|
+ if (this._createBufferOnWrite) {
|
|
|
+ this._createNewBuffer();
|
|
|
+ }
|
|
|
this._bufferData[location + baseStride * 4 + countToFour] = data[i];
|
|
|
}
|
|
|
countToFour++;
|
|
@@ -566,6 +651,9 @@ export class UniformBuffer {
|
|
|
this._needSync = this._needSync || changed;
|
|
|
} else {
|
|
|
// No cache for dynamic
|
|
|
+ if (this._createBufferOnWrite) {
|
|
|
+ this._createNewBuffer();
|
|
|
+ }
|
|
|
for (var i = 0; i < size; i++) {
|
|
|
this._bufferData[location + i] = data[i];
|
|
|
}
|
|
@@ -573,8 +661,10 @@ export class UniformBuffer {
|
|
|
}
|
|
|
|
|
|
// Matrix cache
|
|
|
- private _valueCache: { [key: string]: any } = {};
|
|
|
+ private _valueCache: { [key: string]: number } = {};
|
|
|
private _cacheMatrix(name: string, matrix: IMatrixLike): boolean {
|
|
|
+ this._checkBuffers();
|
|
|
+
|
|
|
var cache = this._valueCache[name];
|
|
|
var flag = matrix.updateFlag;
|
|
|
if (cache !== undefined && cache === flag) {
|
|
@@ -786,10 +876,12 @@ export class UniformBuffer {
|
|
|
uniformBuffers.pop();
|
|
|
}
|
|
|
|
|
|
- if (!this._buffer) {
|
|
|
- return;
|
|
|
- }
|
|
|
- if (this._engine._releaseBuffer(this._buffer)) {
|
|
|
+ if (ThinEngine.Features.trackUbosInFrame && this._buffers) {
|
|
|
+ for (let i = 0; i < this._buffers.length; ++i) {
|
|
|
+ const buffer = this._buffers[i][0];
|
|
|
+ this._engine._releaseBuffer(buffer!);
|
|
|
+ }
|
|
|
+ } else if (this._buffer && this._engine._releaseBuffer(this._buffer)) {
|
|
|
this._buffer = null;
|
|
|
}
|
|
|
}
|