David Catuhe 6 anni fa
parent
commit
020e9a9591

+ 14 - 0
src/Engines/IPipelineContext.ts

@@ -0,0 +1,14 @@
+
+/**
+ * Class used to store and describe the pipeline context associated with an effect
+ */
+export interface IPipelineContext {
+    /**
+     * Gets a boolean indicating that this pipeline context is supporting asynchronous creating
+     */
+    isAsync: boolean;
+    /**
+     * Gets a boolean indicating that the context is ready to be used (like shaders / pipelines are compiled and ready for instance)
+     */
+    isReady: boolean;
+}

+ 27 - 0
src/Engines/WebGL/webGLPipelineContext.ts

@@ -0,0 +1,27 @@
+import { IPipelineContext } from '../IPipelineContext';
+import { Engine } from '../engine';
+import { Nullable } from '../../types';
+
+/** @hidden */
+export class WebGLPipelineContext implements IPipelineContext {
+    public engine: Engine;
+    public program: Nullable<WebGLProgram>;
+    public context?: WebGLRenderingContext;
+    public vertexShader?: WebGLShader;
+    public fragmentShader?: WebGLShader;
+    public isParallelCompiled: boolean;
+    public onCompiled?: () => void;
+    public transformFeedback?: WebGLTransformFeedback | null;
+
+    public get isAsync() {
+        return this.isParallelCompiled;
+    }
+
+    public get isReady(): boolean {
+        if (this.program && this.isParallelCompiled) {
+            return this.engine._isRenderingStateCompiled(this);
+        }
+
+        return true;
+    }
+}

+ 155 - 107
src/Engines/engine.ts

@@ -28,6 +28,10 @@ import { EngineStore } from "./engineStore";
 import { RenderTargetCreationOptions } from "../Materials/Textures/renderTargetCreationOptions";
 import { _DevTools } from '../Misc/devTools';
 import { WebRequest } from '../Misc/webRequest';
+import { WebGLPipelineContext } from './WebGL/webGLPipelineContext';
+import { IPipelineContext } from './IPipelineContext';
+import { DataBuffer } from '../Meshes/dataBuffer';
+import { WebGLDataBuffer } from '../Meshes/WebGL/webGLDataBuffer';
 
 declare type PostProcess = import("../PostProcesses/postProcess").PostProcess;
 declare type Texture = import("../Materials/Textures/texture").Texture;
@@ -884,7 +888,7 @@ export class Engine {
     /** @hidden */
     protected _cachedVertexBuffers: any;
     /** @hidden */
-    protected _cachedIndexBuffer: Nullable<WebGLBuffer>;
+    protected _cachedIndexBuffer: Nullable<DataBuffer>;
     /** @hidden */
     protected _cachedEffectForVertexBuffers: Nullable<Effect>;
     /** @hidden */
@@ -895,7 +899,7 @@ export class Engine {
     protected _currentFramebuffer: Nullable<WebGLFramebuffer> = null;
     private _currentBufferPointers = new Array<BufferPointer>();
     private _currentInstanceLocations = new Array<number>();
-    private _currentInstanceBuffers = new Array<WebGLBuffer>();
+    private _currentInstanceBuffers = new Array<DataBuffer>();
     private _textureUnits: Int32Array;
 
     /** @hidden */
@@ -2536,14 +2540,15 @@ export class Engine {
      * @param elements defines the content of the uniform buffer
      * @returns the webGL uniform buffer
      */
-    public createUniformBuffer(elements: FloatArray): WebGLBuffer {
+    public createUniformBuffer(elements: FloatArray): DataBuffer {
         var ubo = this._gl.createBuffer();
 
         if (!ubo) {
             throw new Error("Unable to create uniform buffer");
         }
+        let result = new WebGLDataBuffer(ubo);
 
-        this.bindUniformBuffer(ubo);
+        this.bindUniformBuffer(result);
 
         if (elements instanceof Float32Array) {
             this._gl.bufferData(this._gl.UNIFORM_BUFFER, <Float32Array>elements, this._gl.STATIC_DRAW);
@@ -2553,8 +2558,8 @@ export class Engine {
 
         this.bindUniformBuffer(null);
 
-        ubo.references = 1;
-        return ubo;
+        result.references = 1;
+        return result;
     }
 
     /**
@@ -2563,14 +2568,15 @@ export class Engine {
      * @param elements defines the content of the uniform buffer
      * @returns the webGL uniform buffer
      */
-    public createDynamicUniformBuffer(elements: FloatArray): WebGLBuffer {
+    public createDynamicUniformBuffer(elements: FloatArray): DataBuffer {
         var ubo = this._gl.createBuffer();
 
         if (!ubo) {
             throw new Error("Unable to create dynamic uniform buffer");
         }
 
-        this.bindUniformBuffer(ubo);
+        let result = new WebGLDataBuffer(ubo);
+        this.bindUniformBuffer(result);
 
         if (elements instanceof Float32Array) {
             this._gl.bufferData(this._gl.UNIFORM_BUFFER, <Float32Array>elements, this._gl.DYNAMIC_DRAW);
@@ -2580,8 +2586,8 @@ export class Engine {
 
         this.bindUniformBuffer(null);
 
-        ubo.references = 1;
-        return ubo;
+        result.references = 1;
+        return result;
     }
 
     /**
@@ -2592,7 +2598,7 @@ export class Engine {
      * @param offset defines the offset in the uniform buffer where update should start
      * @param count defines the size of the data to update
      */
-    public updateUniformBuffer(uniformBuffer: WebGLBuffer, elements: FloatArray, offset?: number, count?: number): void {
+    public updateUniformBuffer(uniformBuffer: DataBuffer, elements: FloatArray, offset?: number, count?: number): void {
         this.bindUniformBuffer(uniformBuffer);
 
         if (offset === undefined) {
@@ -2627,14 +2633,15 @@ export class Engine {
      * @param data the data for the vertex buffer
      * @returns the new WebGL static buffer
      */
-    public createVertexBuffer(data: DataArray): WebGLBuffer {
+    public createVertexBuffer(data: DataArray): DataBuffer {
         var vbo = this._gl.createBuffer();
 
         if (!vbo) {
             throw new Error("Unable to create vertex buffer");
         }
 
-        this.bindArrayBuffer(vbo);
+        let dataBuffer = new WebGLDataBuffer(vbo);
+        this.bindArrayBuffer(dataBuffer);
 
         if (data instanceof Array) {
             this._gl.bufferData(this._gl.ARRAY_BUFFER, new Float32Array(data), this._gl.STATIC_DRAW);
@@ -2643,8 +2650,9 @@ export class Engine {
         }
 
         this._resetVertexBufferBinding();
-        vbo.references = 1;
-        return vbo;
+
+        dataBuffer.references = 1;
+        return dataBuffer;
     }
 
     /**
@@ -2652,14 +2660,15 @@ export class Engine {
      * @param data the data for the dynamic vertex buffer
      * @returns the new WebGL dynamic buffer
      */
-    public createDynamicVertexBuffer(data: DataArray): WebGLBuffer {
+    public createDynamicVertexBuffer(data: DataArray): DataBuffer {
         var vbo = this._gl.createBuffer();
 
         if (!vbo) {
             throw new Error("Unable to create dynamic vertex buffer");
         }
 
-        this.bindArrayBuffer(vbo);
+        let result = new WebGLDataBuffer(vbo);
+        this.bindArrayBuffer(result);
 
         if (data instanceof Array) {
             this._gl.bufferData(this._gl.ARRAY_BUFFER, new Float32Array(data), this._gl.DYNAMIC_DRAW);
@@ -2668,8 +2677,8 @@ export class Engine {
         }
 
         this._resetVertexBufferBinding();
-        vbo.references = 1;
-        return vbo;
+        result.references = 1;
+        return result;
     }
 
     /**
@@ -2678,7 +2687,7 @@ export class Engine {
      * @param indices defines the data to update
      * @param offset defines the offset in the target index buffer where update should start
      */
-    public updateDynamicIndexBuffer(indexBuffer: WebGLBuffer, indices: IndicesArray, offset: number = 0): void {
+    public updateDynamicIndexBuffer(indexBuffer: DataBuffer, indices: IndicesArray, offset: number = 0): void {
         // Force cache update
         this._currentBoundBuffer[this._gl.ELEMENT_ARRAY_BUFFER] = null;
         this.bindIndexBuffer(indexBuffer);
@@ -2702,7 +2711,7 @@ export class Engine {
      * @param byteOffset the byte offset of the data
      * @param byteLength the byte length of the data
      */
-    public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void {
+    public updateDynamicVertexBuffer(vertexBuffer: DataBuffer, data: DataArray, byteOffset?: number, byteLength?: number): void {
         this.bindArrayBuffer(vertexBuffer);
 
         if (byteOffset === undefined) {
@@ -2747,14 +2756,15 @@ export class Engine {
      * @param updatable defines if the index buffer must be updatable
      * @returns a new webGL buffer
      */
-    public createIndexBuffer(indices: IndicesArray, updatable?: boolean): WebGLBuffer {
+    public createIndexBuffer(indices: IndicesArray, updatable?: boolean): DataBuffer {
         var vbo = this._gl.createBuffer();
+        let dataBuffer = new WebGLDataBuffer(vbo!);
 
         if (!vbo) {
             throw new Error("Unable to create index buffer");
         }
 
-        this.bindIndexBuffer(vbo);
+        this.bindIndexBuffer(dataBuffer);
 
         // Check for 32 bits indices
         var arrayBuffer;
@@ -2787,16 +2797,16 @@ export class Engine {
 
         this._gl.bufferData(this._gl.ELEMENT_ARRAY_BUFFER, arrayBuffer, updatable ? this._gl.DYNAMIC_DRAW : this._gl.STATIC_DRAW);
         this._resetIndexBufferBinding();
-        vbo.references = 1;
-        vbo.is32Bits = need32Bits;
-        return vbo;
+        dataBuffer.references = 1;
+        dataBuffer.is32Bits = need32Bits;
+        return dataBuffer;
     }
 
     /**
      * Bind a webGL buffer to the webGL context
      * @param buffer defines the buffer to bind
      */
-    public bindArrayBuffer(buffer: Nullable<WebGLBuffer>): void {
+    public bindArrayBuffer(buffer: Nullable<DataBuffer>): void {
         if (!this._vaoRecordInProgress) {
             this._unbindVertexArrayObject();
         }
@@ -2807,8 +2817,8 @@ export class Engine {
      * Bind an uniform buffer to the current webGL context
      * @param buffer defines the buffer to bind
      */
-    public bindUniformBuffer(buffer: Nullable<WebGLBuffer>): void {
-        this._gl.bindBuffer(this._gl.UNIFORM_BUFFER, buffer);
+    public bindUniformBuffer(buffer: Nullable<DataBuffer>): void {
+        this._gl.bindBuffer(this._gl.UNIFORM_BUFFER, buffer ? buffer.underlyingResource : null);
     }
 
     /**
@@ -2816,32 +2826,34 @@ export class Engine {
      * @param buffer defines the buffer to bind
      * @param location defines the index where to bind the buffer
      */
-    public bindUniformBufferBase(buffer: WebGLBuffer, location: number): void {
-        this._gl.bindBufferBase(this._gl.UNIFORM_BUFFER, location, buffer);
+    public bindUniformBufferBase(buffer: DataBuffer, location: number): void {
+        this._gl.bindBufferBase(this._gl.UNIFORM_BUFFER, location, buffer ? buffer.underlyingResource : null);
     }
 
     /**
      * Bind a specific block at a given index in a specific shader program
-     * @param shaderProgram defines the shader program
+     * @param pipelineContext defines the pipeline context to use
      * @param blockName defines the block name
      * @param index defines the index where to bind the block
      */
-    public bindUniformBlock(shaderProgram: WebGLProgram, blockName: string, index: number): void {
-        var uniformLocation = this._gl.getUniformBlockIndex(shaderProgram, blockName);
+    public bindUniformBlock(pipelineContext: IPipelineContext, blockName: string, index: number): void {
+        let program = (pipelineContext as WebGLPipelineContext).program!;
+
+        var uniformLocation = this._gl.getUniformBlockIndex(program, blockName);
 
-        this._gl.uniformBlockBinding(shaderProgram, uniformLocation, index);
+        this._gl.uniformBlockBinding(program, uniformLocation, index);
     }
 
-    private bindIndexBuffer(buffer: Nullable<WebGLBuffer>): void {
+    private bindIndexBuffer(buffer: Nullable<DataBuffer>): void {
         if (!this._vaoRecordInProgress) {
             this._unbindVertexArrayObject();
         }
         this.bindBuffer(buffer, this._gl.ELEMENT_ARRAY_BUFFER);
     }
 
-    private bindBuffer(buffer: Nullable<WebGLBuffer>, target: number): void {
+    private bindBuffer(buffer: Nullable<DataBuffer>, target: number): void {
         if (this._vaoRecordInProgress || this._currentBoundBuffer[target] !== buffer) {
-            this._gl.bindBuffer(target, buffer);
+            this._gl.bindBuffer(target, buffer ? buffer.underlyingResource : null);
             this._currentBoundBuffer[target] = buffer;
         }
     }
@@ -2854,7 +2866,7 @@ export class Engine {
         this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, data);
     }
 
-    private _vertexAttribPointer(buffer: WebGLBuffer, indx: number, size: number, type: number, normalized: boolean, stride: number, offset: number): void {
+    private _vertexAttribPointer(buffer: DataBuffer, indx: number, size: number, type: number, normalized: boolean, stride: number, offset: number): void {
         var pointer = this._currentBufferPointers[indx];
 
         var changed = false;
@@ -2883,7 +2895,7 @@ export class Engine {
         }
     }
 
-    private _bindIndexBufferWithCache(indexBuffer: Nullable<WebGLBuffer>): void {
+    private _bindIndexBufferWithCache(indexBuffer: Nullable<DataBuffer>): void {
         if (indexBuffer == null) {
             return;
         }
@@ -2942,7 +2954,7 @@ export class Engine {
      * @param effect defines the effect to store
      * @returns the new vertex array object
      */
-    public recordVertexArrayObject(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: Nullable<WebGLBuffer>, effect: Effect): WebGLVertexArrayObject {
+    public recordVertexArrayObject(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: Nullable<DataBuffer>, effect: Effect): WebGLVertexArrayObject {
         var vao = this._gl.createVertexArray();
 
         this._vaoRecordInProgress = true;
@@ -2966,7 +2978,7 @@ export class Engine {
      * @param vertexArrayObject defines the vertex array object to bind
      * @param indexBuffer defines the index buffer to bind
      */
-    public bindVertexArrayObject(vertexArrayObject: WebGLVertexArrayObject, indexBuffer: Nullable<WebGLBuffer>): void {
+    public bindVertexArrayObject(vertexArrayObject: WebGLVertexArrayObject, indexBuffer: Nullable<DataBuffer>): void {
         if (this._cachedVertexArrayObject !== vertexArrayObject) {
             this._cachedVertexArrayObject = vertexArrayObject;
 
@@ -2987,7 +2999,7 @@ export class Engine {
      * @param vertexStrideSize defines the vertex stride of the vertex buffer
      * @param effect defines the effect associated with the vertex buffer
      */
-    public bindBuffersDirectly(vertexBuffer: WebGLBuffer, indexBuffer: WebGLBuffer, vertexDeclaration: number[], vertexStrideSize: number, effect: Effect): void {
+    public bindBuffersDirectly(vertexBuffer: DataBuffer, indexBuffer: DataBuffer, vertexDeclaration: number[], vertexStrideSize: number, effect: Effect): void {
         if (this._cachedVertexBuffers !== vertexBuffer || this._cachedEffectForVertexBuffers !== effect) {
             this._cachedVertexBuffers = vertexBuffer;
             this._cachedEffectForVertexBuffers = effect;
@@ -3033,7 +3045,7 @@ export class Engine {
      * @param indexBuffer defines the index buffer to bind
      * @param effect defines the effect associated with the vertex buffers
      */
-    public bindBuffers(vertexBuffers: { [key: string]: Nullable<VertexBuffer> }, indexBuffer: Nullable<WebGLBuffer>, effect: Effect): void {
+    public bindBuffers(vertexBuffers: { [key: string]: Nullable<VertexBuffer> }, indexBuffer: Nullable<DataBuffer>, effect: Effect): void {
         if (this._cachedVertexBuffers !== vertexBuffers || this._cachedEffectForVertexBuffers !== effect) {
             this._cachedVertexBuffers = vertexBuffers;
             this._cachedEffectForVertexBuffers = effect;
@@ -3071,11 +3083,11 @@ export class Engine {
     }
 
     /** @hidden */
-    public _releaseBuffer(buffer: WebGLBuffer): boolean {
+    public _releaseBuffer(buffer: DataBuffer): boolean {
         buffer.references--;
 
         if (buffer.references === 0) {
-            this._gl.deleteBuffer(buffer);
+            this._gl.deleteBuffer(buffer.underlyingResource);
             return true;
         }
 
@@ -3087,18 +3099,19 @@ export class Engine {
      * @param capacity defines the size of the buffer
      * @returns the webGL buffer
      */
-    public createInstancesBuffer(capacity: number): WebGLBuffer {
+    public createInstancesBuffer(capacity: number): DataBuffer {
         var buffer = this._gl.createBuffer();
 
         if (!buffer) {
             throw new Error("Unable to create instance buffer");
         }
 
-        buffer.capacity = capacity;
+        var result = new WebGLDataBuffer(buffer);
+        result.capacity = capacity;
 
-        this.bindArrayBuffer(buffer);
+        this.bindArrayBuffer(result);
         this._gl.bufferData(this._gl.ARRAY_BUFFER, capacity, this._gl.DYNAMIC_DRAW);
-        return buffer;
+        return result;
     }
 
     /**
@@ -3115,7 +3128,7 @@ export class Engine {
      * @param data defines the data to store in the buffer
      * @param offsetLocations defines the offsets or attributes information used to determine where data must be stored in the buffer
      */
-    public updateAndBindInstancesBuffer(instancesBuffer: WebGLBuffer, data: Float32Array, offsetLocations: number[] | InstancingAttributeInfo[]): void {
+    public updateAndBindInstancesBuffer(instancesBuffer: DataBuffer, data: Float32Array, offsetLocations: number[] | InstancingAttributeInfo[]): void {
         this.bindArrayBuffer(instancesBuffer);
         if (data) {
             this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, data);
@@ -3276,21 +3289,22 @@ export class Engine {
         if (this._compiledEffects[effect._key]) {
             delete this._compiledEffects[effect._key];
 
-            this._deleteProgram(effect.getProgram());
+            this._deletePipelineContext(effect.getPipelineContext() as WebGLPipelineContext);
         }
     }
 
     /** @hidden */
-    public _deleteProgram(program: WebGLProgram): void {
-        if (program) {
-            program.__SPECTOR_rebuildProgram = null;
-
-            if (program.transformFeedback) {
-                this.deleteTransformFeedback(program.transformFeedback);
-                program.transformFeedback = null;
+    public _deletePipelineContext(pipelineContext: IPipelineContext): void {
+        let webGLPipelineContext = pipelineContext as WebGLPipelineContext;
+        if (webGLPipelineContext && webGLPipelineContext.program) {
+            webGLPipelineContext.program.__SPECTOR_rebuildProgram = null;
+
+            if (webGLPipelineContext.transformFeedback) {
+                this.deleteTransformFeedback(webGLPipelineContext.transformFeedback);
+                webGLPipelineContext.transformFeedback = null;
             }
 
-            this._gl.deleteProgram(program);
+            this._gl.deleteProgram(webGLPipelineContext.program);
         }
     }
 
@@ -3348,23 +3362,25 @@ export class Engine {
 
     /**
      * Directly creates a webGL program
+     * @param pipelineContext  defines the pipeline context to attach to
      * @param vertexCode defines the vertex shader code to use
      * @param fragmentCode defines the fragment shader code to use
      * @param context defines the webGL context to use (if not set, the current one will be used)
      * @param transformFeedbackVaryings defines the list of transform feedback varyings to use
      * @returns the new webGL program
      */
-    public createRawShaderProgram(vertexCode: string, fragmentCode: string, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
+    public createRawShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
         context = context || this._gl;
 
         var vertexShader = this._compileRawShader(vertexCode, "vertex");
         var fragmentShader = this._compileRawShader(fragmentCode, "fragment");
 
-        return this._createShaderProgram(vertexShader, fragmentShader, context, transformFeedbackVaryings);
+        return this._createShaderProgram(pipelineContext as WebGLPipelineContext, vertexShader, fragmentShader, context, transformFeedbackVaryings);
     }
 
     /**
      * Creates a webGL program
+     * @param pipelineContext  defines the pipeline context to attach to
      * @param vertexCode  defines the vertex shader code to use
      * @param fragmentCode defines the fragment shader code to use
      * @param defines defines the string containing the defines to use to compile the shaders
@@ -3372,7 +3388,7 @@ export class Engine {
      * @param transformFeedbackVaryings defines the list of transform feedback varyings to use
      * @returns the new webGL program
      */
-    public createShaderProgram(vertexCode: string, fragmentCode: string, defines: Nullable<string>, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
+    public createShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, defines: Nullable<string>, context?: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
         context = context || this._gl;
 
         this.onBeforeShaderCompilationObservable.notifyObservers(this);
@@ -3381,24 +3397,36 @@ export class Engine {
         var vertexShader = this._compileShader(vertexCode, "vertex", defines, shaderVersion);
         var fragmentShader = this._compileShader(fragmentCode, "fragment", defines, shaderVersion);
 
-        let program = this._createShaderProgram(vertexShader, fragmentShader, context, transformFeedbackVaryings);
+        let program = this._createShaderProgram(pipelineContext as WebGLPipelineContext, vertexShader, fragmentShader, context, transformFeedbackVaryings);
 
         this.onAfterShaderCompilationObservable.notifyObservers(this);
 
         return program;
     }
 
-    private _createShaderProgram(vertexShader: WebGLShader, fragmentShader: WebGLShader, context: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
+    /**
+     * Creates a new pipeline context
+     * @returns the new pipeline
+     */
+    public createPipelineContext() {
+        var pipelineContext = new WebGLPipelineContext();
+        pipelineContext.engine = this;
+
+        if (this._caps.parallelShaderCompile) {
+            pipelineContext.isParallelCompiled = true;
+        }
+
+        return pipelineContext;
+    }
+
+    private _createShaderProgram(pipelineContext: WebGLPipelineContext, vertexShader: WebGLShader, fragmentShader: WebGLShader, context: WebGLRenderingContext, transformFeedbackVaryings: Nullable<string[]> = null): WebGLProgram {
         var shaderProgram = context.createProgram();
+        pipelineContext.program = shaderProgram;
 
         if (!shaderProgram) {
             throw new Error("Unable to create program");
         }
 
-        if (this._caps.parallelShaderCompile) {
-            shaderProgram.isParallelCompiled = true;
-        }
-
         context.attachShader(shaderProgram, vertexShader);
         context.attachShader(shaderProgram, fragmentShader);
 
@@ -3407,7 +3435,7 @@ export class Engine {
 
             this.bindTransformFeedback(transformFeedback);
             this.setTranformFeedbackVaryings(shaderProgram, transformFeedbackVaryings);
-            shaderProgram.transformFeedback = transformFeedback;
+            pipelineContext.transformFeedback = transformFeedback;
         }
 
         context.linkProgram(shaderProgram);
@@ -3416,23 +3444,24 @@ export class Engine {
             this.bindTransformFeedback(null);
         }
 
-        shaderProgram.context = context;
-        shaderProgram.vertexShader = vertexShader;
-        shaderProgram.fragmentShader = fragmentShader;
+        pipelineContext.context = context;
+        pipelineContext.vertexShader = vertexShader;
+        pipelineContext.fragmentShader = fragmentShader;
 
-        if (!shaderProgram.isParallelCompiled) {
-            this._finalizeProgram(shaderProgram);
+        if (!pipelineContext.isParallelCompiled) {
+            this._finalizePipelineContext(pipelineContext);
         }
 
         return shaderProgram;
     }
 
-    private _finalizeProgram(shaderProgram: WebGLProgram) {
-        const context = shaderProgram.context!;
-        const vertexShader = shaderProgram.vertexShader!;
-        const fragmentShader = shaderProgram.fragmentShader!;
+    private _finalizePipelineContext(pipelineContext: WebGLPipelineContext) {
+        const context = pipelineContext.context!;
+        const vertexShader = pipelineContext.vertexShader!;
+        const fragmentShader = pipelineContext.fragmentShader!;
+        const program = pipelineContext.program!;
 
-        var linked = context.getProgramParameter(shaderProgram, context.LINK_STATUS);
+        var linked = context.getProgramParameter(program, context.LINK_STATUS);
 
         if (!linked) { // Get more info
 
@@ -3452,18 +3481,18 @@ export class Engine {
                 }
             }
 
-            var error = context.getProgramInfoLog(shaderProgram);
+            var error = context.getProgramInfoLog(program);
             if (error) {
                 throw new Error(error);
             }
         }
 
         if (this.validateShaderPrograms) {
-            context.validateProgram(shaderProgram);
-            var validated = context.getProgramParameter(shaderProgram, context.VALIDATE_STATUS);
+            context.validateProgram(program);
+            var validated = context.getProgramParameter(program, context.VALIDATE_STATUS);
 
             if (!validated) {
-                var error = context.getProgramInfoLog(shaderProgram);
+                var error = context.getProgramInfoLog(program);
                 if (error) {
                     throw new Error(error);
                 }
@@ -3473,24 +3502,37 @@ export class Engine {
         context.deleteShader(vertexShader);
         context.deleteShader(fragmentShader);
 
-        shaderProgram.context = undefined;
-        shaderProgram.vertexShader = undefined;
-        shaderProgram.fragmentShader = undefined;
+        pipelineContext.context = undefined;
+        pipelineContext.vertexShader = undefined;
+        pipelineContext.fragmentShader = undefined;
 
-        if (shaderProgram.onCompiled) {
-            shaderProgram.onCompiled();
-            shaderProgram.onCompiled = undefined;
+        if (pipelineContext.onCompiled) {
+            pipelineContext.onCompiled();
+            pipelineContext.onCompiled = undefined;
         }
     }
 
     /** @hidden */
-    public _isProgramCompiled(shaderProgram: WebGLProgram): boolean {
-        if (!shaderProgram.isParallelCompiled) {
-            return true;
+    public _preparePipelineContext(pipelineContext: IPipelineContext, vertexSourceCode: string, fragmentSourceCode: string, createAsRaw: boolean,
+        rebuildRebind: any,
+        defines: Nullable<string>,
+        transformFeedbackVaryings: Nullable<string[]>) {
+        let webGLRenderingState = pipelineContext as WebGLPipelineContext;
+
+        if (createAsRaw) {
+            webGLRenderingState.program = this.createRawShaderProgram(webGLRenderingState, vertexSourceCode, fragmentSourceCode, undefined, transformFeedbackVaryings);
         }
+        else {
+            webGLRenderingState.program = this.createShaderProgram(webGLRenderingState, vertexSourceCode, fragmentSourceCode, defines, undefined, transformFeedbackVaryings);
+        }
+        webGLRenderingState.program.__SPECTOR_rebuildProgram = rebuildRebind;
+    }
 
-        if (this._gl.getProgramParameter(shaderProgram, this._caps.parallelShaderCompile.COMPLETION_STATUS_KHR)) {
-            this._finalizeProgram(shaderProgram);
+    /** @hidden */
+    public _isRenderingStateCompiled(pipelineContext: IPipelineContext): boolean {
+        let webGLPipelineContext = pipelineContext as WebGLPipelineContext;
+        if (this._gl.getProgramParameter(webGLPipelineContext.program!, this._caps.parallelShaderCompile.COMPLETION_STATUS_KHR)) {
+            this._finalizePipelineContext(webGLPipelineContext);
             return true;
         }
 
@@ -3498,26 +3540,29 @@ export class Engine {
     }
 
     /** @hidden */
-    public _executeWhenProgramIsCompiled(shaderProgram: WebGLProgram, action: () => void) {
-        if (!shaderProgram.isParallelCompiled) {
+    public _executeWhenRenderingStateIsCompiled(pipelineContext: IPipelineContext, action: () => void) {
+        let webGLPipelineContext = pipelineContext as WebGLPipelineContext;
+
+        if (!webGLPipelineContext.isParallelCompiled) {
             action();
             return;
         }
 
-        shaderProgram.onCompiled = action;
+        webGLPipelineContext.onCompiled = action;
     }
 
     /**
      * Gets the list of webGL uniform locations associated with a specific program based on a list of uniform names
-     * @param shaderProgram defines the webGL program to use
+     * @param pipelineContext defines the pipeline context to use
      * @param uniformsNames defines the list of uniform names
      * @returns an array of webGL uniform locations
      */
-    public getUniforms(shaderProgram: WebGLProgram, uniformsNames: string[]): Nullable<WebGLUniformLocation>[] {
+    public getUniforms(pipelineContext: IPipelineContext, uniformsNames: string[]): Nullable<WebGLUniformLocation>[] {
         var results = new Array<Nullable<WebGLUniformLocation>>();
+        let webGLPipelineContext = pipelineContext as WebGLPipelineContext;
 
         for (var index = 0; index < uniformsNames.length; index++) {
-            results.push(this._gl.getUniformLocation(shaderProgram, uniformsNames[index]));
+            results.push(this._gl.getUniformLocation(webGLPipelineContext.program!, uniformsNames[index]));
         }
 
         return results;
@@ -3525,16 +3570,17 @@ export class Engine {
 
     /**
      * Gets the lsit of active attributes for a given webGL program
-     * @param shaderProgram defines the webGL program to use
+     * @param pipelineContext defines the pipeline context to use
      * @param attributesNames defines the list of attribute names to get
      * @returns an array of indices indicating the offset of each attribute
      */
-    public getAttributes(shaderProgram: WebGLProgram, attributesNames: string[]): number[] {
+    public getAttributes(pipelineContext: IPipelineContext, attributesNames: string[]): number[] {
         var results = [];
+        let webGLPipelineContext = pipelineContext as WebGLPipelineContext;
 
         for (var index = 0; index < attributesNames.length; index++) {
             try {
-                results.push(this._gl.getAttribLocation(shaderProgram, attributesNames[index]));
+                results.push(this._gl.getAttribLocation(webGLPipelineContext.program!, attributesNames[index]));
             } catch (e) {
                 results.push(-1);
             }
@@ -5361,7 +5407,8 @@ export class Engine {
      * @param effect defines the effect to bind
      */
     public bindSamplers(effect: Effect): void {
-        this.setProgram(effect.getProgram());
+        let webGLPipelineContext = effect.getPipelineContext() as WebGLPipelineContext;
+        this.setProgram(webGLPipelineContext.program!);
         var samplers = effect.getSamplers();
         for (var index = 0; index < samplers.length; index++) {
             var uniform = effect.getUniform(samplers[index]);
@@ -5803,7 +5850,8 @@ export class Engine {
      */
     public releaseEffects() {
         for (var name in this._compiledEffects) {
-            this._deleteProgram(this._compiledEffects[name]._program);
+            let webGLPipelineContext = this._compiledEffects[name].getPipelineContext() as WebGLPipelineContext;
+            this._deletePipelineContext(webGLPipelineContext);
         }
 
         this._compiledEffects = {};
@@ -6502,4 +6550,4 @@ export class Engine {
             return false;
         }
     }
-}
+}

+ 3 - 1
src/Engines/index.ts

@@ -2,4 +2,6 @@ export * from "./constants";
 export * from "./engine";
 export * from "./engineStore";
 export * from "./nullEngine";
-export * from "./Extensions/index";
+export * from "./Extensions/index";
+export * from "./IPipelineContext";
+export * from "./WebGL/webGLPipelineContext";

+ 20 - 27
src/Engines/nullEngine.ts

@@ -10,6 +10,8 @@ import { Effect } from "../Materials/effect";
 import { _TimeToken } from "../Instrumentation/timeToken";
 import { _DepthCullingState, _StencilState, _AlphaState } from "../States/index";
 import { Constants } from "./constants";
+import { IPipelineContext } from './IPipelineContext';
+import { DataBuffer } from '../Meshes/dataBuffer';
 
 declare const global: any;
 
@@ -144,20 +146,16 @@ export class NullEngine extends Engine {
         }
     }
 
-    public createVertexBuffer(vertices: FloatArray): WebGLBuffer {
-        return {
-            capacity: 0,
-            references: 1,
-            is32Bits: false
-        };
+    public createVertexBuffer(vertices: FloatArray): DataBuffer {
+        let buffer = new DataBuffer();
+        buffer.references = 1;
+        return buffer;
     }
 
-    public createIndexBuffer(indices: IndicesArray): WebGLBuffer {
-        return {
-            capacity: 0,
-            references: 1,
-            is32Bits: false
-        };
+    public createIndexBuffer(indices: IndicesArray): DataBuffer {
+        let buffer = new DataBuffer();
+        buffer.references = 1;
+        return buffer;
     }
 
     public clear(color: Color4, backBuffer: boolean, depth: boolean, stencil: boolean = false): void {
@@ -183,19 +181,17 @@ export class NullEngine extends Engine {
         this._cachedViewport = viewport;
     }
 
-    public createShaderProgram(vertexCode: string, fragmentCode: string, defines: string, context?: WebGLRenderingContext): WebGLProgram {
+    public createShaderProgram(pipelineContext: IPipelineContext, vertexCode: string, fragmentCode: string, defines: string, context?: WebGLRenderingContext): WebGLProgram {
         return {
-            transformFeedback: null,
             __SPECTOR_rebuildProgram: null,
-            isParallelCompiled: false
         };
     }
 
-    public getUniforms(shaderProgram: WebGLProgram, uniformsNames: string[]): WebGLUniformLocation[] {
+    public getUniforms(pipelineContext: IPipelineContext, uniformsNames: string[]): Nullable<WebGLUniformLocation>[] {
         return [];
     }
 
-    public getAttributes(shaderProgram: WebGLProgram, attributesNames: string[]): number[] {
+    public getAttributes(pipelineContext: IPipelineContext, attributesNames: string[]): number[] {
         return [];
     }
 
@@ -299,7 +295,7 @@ export class NullEngine extends Engine {
         this._alphaMode = mode;
     }
 
-    public bindBuffers(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: WebGLBuffer, effect: Effect): void {
+    public bindBuffers(vertexBuffers: { [key: string]: VertexBuffer; }, indexBuffer: DataBuffer, effect: Effect): void {
     }
 
     public wipeCaches(bruteForce?: boolean): void {
@@ -434,14 +430,11 @@ export class NullEngine extends Engine {
         this._currentFramebuffer = null;
     }
 
-    public createDynamicVertexBuffer(vertices: FloatArray): WebGLBuffer {
-        var vbo = {
-            capacity: 1,
-            references: 1,
-            is32Bits: false
-        };
-
-        return vbo;
+    public createDynamicVertexBuffer(vertices: FloatArray): DataBuffer {
+        let buffer = new DataBuffer();
+        buffer.references = 1;
+        buffer.capacity = 1;
+        return buffer;
     }
 
     public updateDynamicTexture(texture: Nullable<InternalTexture>, canvas: HTMLCanvasElement, invertY: boolean, premulAlpha: boolean = false, format?: number): void {
@@ -502,7 +495,7 @@ export class NullEngine extends Engine {
     }
 
     /** @hidden */
-    public _releaseBuffer(buffer: WebGLBuffer): boolean {
+    public _releaseBuffer(buffer: DataBuffer): boolean {
         buffer.references--;
 
         if (buffer.references === 0) {

+ 2 - 1
src/Layers/effectLayer.ts

@@ -26,6 +26,7 @@ import { Constants } from "../Engines/constants";
 import "../Shaders/glowMapGeneration.fragment";
 import "../Shaders/glowMapGeneration.vertex";
 import { _DevTools } from '../Misc/devTools';
+import { DataBuffer } from '../Meshes/dataBuffer';
 
 /**
  * Effect layer options. This helps customizing the behaviour
@@ -70,7 +71,7 @@ export interface IEffectLayerOptions {
 export abstract class EffectLayer {
 
     private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
-    private _indexBuffer: Nullable<WebGLBuffer>;
+    private _indexBuffer: Nullable<DataBuffer>;
     private _cachedDefines: string;
     private _effectLayerMapGenerationEffect: Effect;
     private _effectLayerOptions: IEffectLayerOptions;

+ 2 - 1
src/Layers/layer.ts

@@ -16,6 +16,7 @@ import { RenderTargetTexture } from "../Materials/Textures/renderTargetTexture";
 
 import "../Shaders/layer.fragment";
 import "../Shaders/layer.vertex";
+import { DataBuffer } from '../Meshes/dataBuffer';
 
 /**
  * This represents a full screen 2d layer.
@@ -78,7 +79,7 @@ export class Layer {
 
     private _scene: Scene;
     private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
-    private _indexBuffer: Nullable<WebGLBuffer>;
+    private _indexBuffer: Nullable<DataBuffer>;
     private _effect: Effect;
     private _alphaTestEffect: Effect;
 

+ 2 - 1
src/LensFlares/lensFlareSystem.ts

@@ -17,6 +17,7 @@ import { Constants } from "../Engines/constants";
 import "../Shaders/lensFlare.fragment";
 import "../Shaders/lensFlare.vertex";
 import { _DevTools } from '../Misc/devTools';
+import { DataBuffer } from '../Meshes/dataBuffer';
 
 /**
  * This represents a Lens Flare System or the shiny effect created by the light reflection on the  camera lenses.
@@ -58,7 +59,7 @@ export class LensFlareSystem {
     private _scene: Scene;
     private _emitter: any;
     private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
-    private _indexBuffer: Nullable<WebGLBuffer>;
+    private _indexBuffer: Nullable<DataBuffer>;
     private _effect: Effect;
     private _positionX: number;
     private _positionY: number;

+ 0 - 16
src/LibDeclarations/webgl.d.ts

@@ -1,12 +1,3 @@
-
-interface WebGLProgram {
-    context?: WebGLRenderingContext;
-    vertexShader?: WebGLShader;
-    fragmentShader?: WebGLShader;
-    isParallelCompiled: boolean;
-    onCompiled?: () => void;
-}
-
 interface WebGLRenderingContext {
     drawArraysInstanced(mode: number, first: number, count: number, primcount: number): void;
     drawElementsInstanced(mode: number, count: number, type: number, offset: number, primcount: number): void;
@@ -70,14 +61,7 @@ interface WebGLRenderingContext {
     QUERY_RESULT: number;
 }
 
-interface WebGLBuffer {
-    references: number;
-    capacity: number;
-    is32Bits: boolean;
-}
-
 interface WebGLProgram {
-    transformFeedback?: WebGLTransformFeedback | null;
     __SPECTOR_rebuildProgram?: ((vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (program: WebGLProgram) => void, onError: (message: string) => void) => void) | null;
 }
 

+ 2 - 1
src/Materials/Textures/Procedurals/proceduralTexture.ts

@@ -17,6 +17,7 @@ import { ProceduralTextureSceneComponent } from "./proceduralTextureSceneCompone
 
 import "../../../Engines/Extensions/engine.renderTarget";
 import "../../../Shaders/procedural.vertex";
+import { DataBuffer } from '../../../Meshes/dataBuffer';
 
 /**
  * Procedural texturing is a way to programmatically create a texture. There are 2 types of procedural textures: code-only, and code that references some classic 2D images, sometimes calmpler' images.
@@ -61,7 +62,7 @@ export class ProceduralTexture extends Texture {
     private _currentRefreshId = -1;
     private _refreshRate = 1;
     private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
-    private _indexBuffer: Nullable<WebGLBuffer>;
+    private _indexBuffer: Nullable<DataBuffer>;
     private _uniforms = new Array<string>();
     private _samplers = new Array<string>();
     private _fragment: any;

+ 32 - 39
src/Materials/effect.ts

@@ -5,6 +5,8 @@ import { Constants } from "../Engines/constants";
 import { DomManagement } from "../Misc/domManagement";
 import { Logger } from "../Misc/logger";
 import { IDisposable } from '../scene';
+import { IPipelineContext } from '../Engines/IPipelineContext';
+import { DataBuffer } from '../Meshes/dataBuffer';
 
 declare type Engine = import("../Engines/engine").Engine;
 declare type InternalTexture = import("../Materials/Textures/internalTexture").InternalTexture;
@@ -243,12 +245,12 @@ export class Effect implements IDisposable {
     private _uniformBuffersNames: { [key: string]: number } = {};
     private _uniformsNames: string[];
     private _samplerList: string[];
-    private _samplers: {[key: string]: number} = {};
+    private _samplers: { [key: string]: number } = {};
     private _isReady = false;
     private _compilationError = "";
     private _attributesNames: string[];
     private _attributes: number[];
-    private _uniforms: {[key: string] : Nullable<WebGLUniformLocation>} = {};
+    private _uniforms: { [key: string]: Nullable<WebGLUniformLocation> } = {};
     /**
      * Key for the effect.
      * @hidden
@@ -265,9 +267,9 @@ export class Effect implements IDisposable {
      * Compiled shader to webGL program.
      * @hidden
      */
-    public _program: WebGLProgram;
+    public _pipelineContext: IPipelineContext;
     private _valueCache: { [key: string]: any };
-    private static _baseCache: { [key: number]: WebGLBuffer } = {};
+    private static _baseCache: { [key: number]: DataBuffer } = {};
 
     /**
      * Instantiates an effect.
@@ -382,10 +384,7 @@ export class Effect implements IDisposable {
      * @returns if the effect is compiled and prepared.
      */
     public isReady(): boolean {
-        if (!this._isReady && this._program && this._program.isParallelCompiled) {
-            return this._engine._isProgramCompiled(this._program);
-        }
-        return this._isReady;
+        return this._isReady && this._pipelineContext.isReady;
     }
 
     /**
@@ -397,11 +396,11 @@ export class Effect implements IDisposable {
     }
 
     /**
-     * The compiled webGL program for the effect
-     * @returns the webGL program.
+     * The pipeline context for this effect
+     * @returns the associated pipeline context
      */
-    public getProgram(): WebGLProgram {
-        return this._program;
+    public getPipelineContext(): IPipelineContext {
+        return this._pipelineContext;
     }
 
     /**
@@ -488,7 +487,7 @@ export class Effect implements IDisposable {
             func(effect);
         });
 
-        if (!this._program || this._program.isParallelCompiled) {
+        if (!this._pipelineContext || this._pipelineContext.isAsync) {
             setTimeout(() => {
                 this._checkIsReady();
             }, 16);
@@ -772,7 +771,7 @@ export class Effect implements IDisposable {
      * @param onError Callback called on error.
      * @hidden
      */
-    public _rebuildProgram(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (program: WebGLProgram) => void, onError: (message: string) => void) {
+    public _rebuildProgram(vertexSourceCode: string, fragmentSourceCode: string, onCompiled: (pipelineContext: IPipelineContext) => void, onError: (message: string) => void) {
         this._isReady = false;
 
         this._vertexSourceCodeOverride = vertexSourceCode;
@@ -789,7 +788,7 @@ export class Effect implements IDisposable {
             }
 
             if (onCompiled) {
-                onCompiled(this._program);
+                onCompiled(this._pipelineContext);
             }
         };
         this._fallbacks = null;
@@ -797,16 +796,6 @@ export class Effect implements IDisposable {
     }
 
     /**
-     * Gets the uniform locations of the the specified variable names
-     * @param names THe names of the variables to lookup.
-     * @returns Array of locations in the same order as variable names.
-     */
-    public getSpecificUniformLocations(names: string[]): Nullable<WebGLUniformLocation>[] {
-        let engine = this._engine;
-        return engine.getUniforms(this._program, names);
-    }
-
-    /**
      * Prepares the effect
      * @hidden
      */
@@ -816,32 +805,36 @@ export class Effect implements IDisposable {
         let fallbacks = this._fallbacks;
         this._valueCache = {};
 
-        var previousProgram = this._program;
+        var previousPipelineContext = this._pipelineContext;
 
         try {
             let engine = this._engine;
 
+            if (!this._pipelineContext) {
+                this._pipelineContext = engine.createPipelineContext();
+            }
+
+            let rebuildRebind = this._rebuildProgram.bind(this);
             if (this._vertexSourceCodeOverride && this._fragmentSourceCodeOverride) {
-                this._program = engine.createRawShaderProgram(this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, undefined, this._transformFeedbackVaryings);
+                engine._preparePipelineContext(this._pipelineContext, this._vertexSourceCodeOverride, this._fragmentSourceCodeOverride, true, rebuildRebind, null, this._transformFeedbackVaryings);
             }
             else {
-                this._program = engine.createShaderProgram(this._vertexSourceCode, this._fragmentSourceCode, defines, undefined, this._transformFeedbackVaryings);
+                engine._preparePipelineContext(this._pipelineContext, this._vertexSourceCode, this._fragmentSourceCode, false, rebuildRebind, defines, this._transformFeedbackVaryings);
             }
-            this._program.__SPECTOR_rebuildProgram = this._rebuildProgram.bind(this);
 
-            engine._executeWhenProgramIsCompiled(this._program, () => {
+            engine._executeWhenRenderingStateIsCompiled(this._pipelineContext, () => {
                 if (engine.supportsUniformBuffers) {
                     for (var name in this._uniformBuffersNames) {
                         this.bindUniformBlock(name, this._uniformBuffersNames[name]);
                     }
                 }
 
-                let uniforms = engine.getUniforms(this._program, this._uniformsNames);
+                let uniforms = engine.getUniforms(this._pipelineContext, this._uniformsNames);
                 uniforms.forEach((uniform, index) => {
                     this._uniforms[this._uniformsNames[index]] = uniform;
                 });
 
-                this._attributes = engine.getAttributes(this._program, attributesNames);
+                this._attributes = engine.getAttributes(this._pipelineContext, attributesNames);
 
                 var index: number;
                 for (index = 0; index < this._samplerList.length; index++) {
@@ -872,12 +865,12 @@ export class Effect implements IDisposable {
                     this._fallbacks.unBindMesh();
                 }
 
-                if (previousProgram) {
-                    this.getEngine()._deleteProgram(previousProgram);
+                if (previousPipelineContext) {
+                    this.getEngine()._deletePipelineContext(previousPipelineContext);
                 }
             });
 
-            if (this._program.isParallelCompiled) {
+            if (this._pipelineContext.isAsync) {
                 this._checkIsReady();
             }
 
@@ -893,8 +886,8 @@ export class Effect implements IDisposable {
                 return " " + attribute;
             }));
             Logger.Error("Error: " + this._compilationError);
-            if (previousProgram) {
-                this._program = previousProgram;
+            if (previousPipelineContext) {
+                this._pipelineContext = previousPipelineContext;
                 this._isReady = true;
                 if (this.onError) {
                     this.onError(this, this._compilationError);
@@ -1090,7 +1083,7 @@ export class Effect implements IDisposable {
      * @param buffer Buffer to bind.
      * @param name Name of the uniform variable to bind to.
      */
-    public bindUniformBuffer(buffer: WebGLBuffer, name: string): void {
+    public bindUniformBuffer(buffer: DataBuffer, name: string): void {
         let bufferName = this._uniformBuffersNames[name];
         if (bufferName === undefined || Effect._baseCache[bufferName] === buffer) {
             return;
@@ -1105,7 +1098,7 @@ export class Effect implements IDisposable {
      * @param index Index to bind.
      */
     public bindUniformBlock(blockName: string, index: number): void {
-        this._engine.bindUniformBlock(this._program, blockName, index);
+        this._engine.bindUniformBlock(this._pipelineContext, blockName, index);
     }
 
     /**

+ 3 - 2
src/Materials/uniformBuffer.ts

@@ -4,6 +4,7 @@ import { Matrix, Vector3, Color3, Vector4 } from "../Maths/math";
 import { Engine } from "../Engines/engine";
 import { Effect } from "./effect";
 import { BaseTexture } from "../Materials/Textures/baseTexture";
+import { DataBuffer } from '../Meshes/dataBuffer';
 /**
  * Uniform buffer objects.
  *
@@ -16,7 +17,7 @@ import { BaseTexture } from "../Materials/Textures/baseTexture";
  */
 export class UniformBuffer {
     private _engine: Engine;
-    private _buffer: Nullable<WebGLBuffer>;
+    private _buffer: Nullable<DataBuffer>;
     private _data: number[];
     private _bufferData: Float32Array;
     private _dynamic?: boolean;
@@ -201,7 +202,7 @@ export class UniformBuffer {
      * The underlying WebGL Uniform buffer.
      * @returns the webgl buffer
      */
-    public getBuffer(): Nullable<WebGLBuffer> {
+    public getBuffer(): Nullable<DataBuffer> {
         return this._buffer;
     }
 

+ 16 - 0
src/Meshes/WebGL/webGLDataBuffer.ts

@@ -0,0 +1,16 @@
+import { DataBuffer } from '../dataBuffer';
+import { Nullable } from '../../types';
+
+/** @hidden */
+export class WebGLDataBuffer extends DataBuffer {
+    private _buffer: Nullable<WebGLBuffer>;
+
+    public constructor(resource: WebGLBuffer) {
+        super();
+        this._buffer = resource;
+    }
+
+    public get underlyingResource(): any {
+        return this._buffer;
+    }
+}

+ 4 - 3
src/Meshes/buffer.ts

@@ -1,12 +1,13 @@
 import { Nullable, DataArray } from "../types";
 import { Engine } from "../Engines/engine";
+import { DataBuffer } from './dataBuffer';
 
 /**
  * Class used to store data that will be store in GPU memory
  */
 export class Buffer {
     private _engine: Engine;
-    private _buffer: Nullable<WebGLBuffer>;
+    private _buffer: Nullable<DataBuffer>;
     /** @hidden */
     public _data: Nullable<DataArray>;
     private _updatable: boolean;
@@ -87,7 +88,7 @@ export class Buffer {
      * Gets underlying native buffer
      * @returns underlying native buffer
      */
-    public getBuffer(): Nullable<WebGLBuffer> {
+    public getBuffer(): Nullable<DataBuffer> {
         return this._buffer;
     }
 
@@ -357,7 +358,7 @@ export class VertexBuffer {
      * Gets underlying native buffer
      * @returns underlying native buffer
      */
-    public getBuffer(): Nullable<WebGLBuffer> {
+    public getBuffer(): Nullable<DataBuffer> {
         return this._buffer.getBuffer();
     }
 

+ 22 - 0
src/Meshes/dataBuffer.ts

@@ -0,0 +1,22 @@
+/**
+ * Class used to store gfx data (like WebGLBuffer)
+ */
+export class DataBuffer {
+    /**
+     * Gets or sets the number of objects referencing this buffer
+     */
+    public references: number = 0;
+    /** Gets or sets the size of the underlying buffer */
+    public capacity: number = 0;
+    /**
+     * Gets or sets a boolean indicating if the buffer contains 32bits indices
+     */
+    public is32Bits: boolean = false;
+
+    /**
+     * Gets the underlying buffer
+     */
+    public get underlyingResource(): any {
+        return null;
+    }
+}

+ 5 - 4
src/Meshes/geometry.ts

@@ -12,6 +12,7 @@ import { BoundingInfo } from "../Culling/boundingInfo";
 import { Constants } from "../Engines/constants";
 import { Tools } from "../Misc/tools";
 import { Tags } from "../Misc/tags";
+import { DataBuffer } from './dataBuffer';
 
 declare type Mesh = import("../Meshes/mesh").Mesh;
 
@@ -55,7 +56,7 @@ export class Geometry implements IGetSetVerticesData {
     private _boundingBias: Vector2;
     /** @hidden */
     public _delayInfo: Array<string>;
-    private _indexBuffer: Nullable<WebGLBuffer>;
+    private _indexBuffer: Nullable<DataBuffer>;
     private _indexBufferIsUpdatable = false;
     /** @hidden */
     public _boundingInfo: Nullable<BoundingInfo>;
@@ -285,7 +286,7 @@ export class Geometry implements IGetSetVerticesData {
 
     /**
      * Update a specific vertex buffer
-     * This function will directly update the underlying WebGLBuffer according to the passed numeric array or Float32Array
+     * This function will directly update the underlying DataBuffer according to the passed numeric array or Float32Array
      * It will do nothing if the buffer is not updatable
      * @param kind defines the data kind (Position, normal, etc...)
      * @param data defines the data to use
@@ -351,7 +352,7 @@ export class Geometry implements IGetSetVerticesData {
     }
 
     /** @hidden */
-    public _bind(effect: Nullable<Effect>, indexToBind?: Nullable<WebGLBuffer>): void {
+    public _bind(effect: Nullable<Effect>, indexToBind?: Nullable<DataBuffer>): void {
         if (!effect) {
             return;
         }
@@ -615,7 +616,7 @@ export class Geometry implements IGetSetVerticesData {
      * Gets the index buffer
      * @return the index buffer
      */
-    public getIndexBuffer(): Nullable<WebGLBuffer> {
+    public getIndexBuffer(): Nullable<DataBuffer> {
         if (!this.isReady()) {
             return null;
         }

+ 3 - 1
src/Meshes/index.ts

@@ -15,4 +15,6 @@ export * from "./meshSimplificationSceneComponent";
 export * from "./polygonMesh";
 export * from "./subMesh";
 export * from "./transformNode";
-export * from "./Builders/index";
+export * from "./Builders/index";
+export * from "./dataBuffer";
+export * from "./WebGL/webGLDataBuffer";

+ 3 - 2
src/Meshes/subMesh.ts

@@ -7,6 +7,7 @@ import { IntersectionInfo } from "../Collisions/intersectionInfo";
 import { ICullable, BoundingInfo } from "../Culling/boundingInfo";
 import { Effect } from "../Materials/effect";
 import { Constants } from "../Engines/constants";
+import { DataBuffer } from './dataBuffer';
 
 declare type Collider = import("../Collisions/collider").Collider;
 declare type Material = import("../Materials/material").Material;
@@ -59,7 +60,7 @@ export class SubMesh extends BaseSubMesh implements ICullable {
     private _mesh: AbstractMesh;
     private _renderingMesh: Mesh;
     private _boundingInfo: BoundingInfo;
-    private _linesIndexBuffer: Nullable<WebGLBuffer> = null;
+    private _linesIndexBuffer: Nullable<DataBuffer> = null;
     /** @hidden */
     public _lastColliderWorldVertices: Nullable<Vector3[]> = null;
     /** @hidden */
@@ -310,7 +311,7 @@ export class SubMesh extends BaseSubMesh implements ICullable {
     /**
      * @hidden
      */
-    public _getLinesIndexBuffer(indices: IndicesArray, engine: Engine): WebGLBuffer {
+    public _getLinesIndexBuffer(indices: IndicesArray, engine: Engine): DataBuffer {
         if (!this._linesIndexBuffer) {
             var linesIndices = [];
 

+ 2 - 1
src/Particles/particleSystem.ts

@@ -27,6 +27,7 @@ import { _TypeStore } from '../Misc/typeStore';
 
 import "../Shaders/particles.fragment";
 import "../Shaders/particles.vertex";
+import { DataBuffer } from '../Meshes/dataBuffer';
 
 /**
  * This represents a particle system in Babylon.
@@ -98,7 +99,7 @@ export class ParticleSystem extends BaseParticleSystem implements IDisposable, I
     private _vertexBuffer: Nullable<Buffer>;
     private _vertexBuffers: { [key: string]: VertexBuffer } = {};
     private _spriteBuffer: Nullable<Buffer>;
-    private _indexBuffer: Nullable<WebGLBuffer>;
+    private _indexBuffer: Nullable<DataBuffer>;
     private _effect: Effect;
     private _customEffect: Nullable<Effect>;
     private _cachedDefines: string;

+ 3 - 2
src/PostProcesses/postProcessManager.ts

@@ -4,8 +4,9 @@ import { InternalTexture } from "../Materials/Textures/internalTexture";
 import { PostProcess } from "./postProcess";
 import { VertexBuffer } from "../Meshes/buffer";
 import { Constants } from "../Engines/constants";
+import { DataBuffer } from '../Meshes/dataBuffer';
 
-declare type Scene  = import("../scene").Scene;
+declare type Scene = import("../scene").Scene;
 
 /**
  * PostProcessManager is used to manage one or more post processes or post process pipelines
@@ -13,7 +14,7 @@ declare type Scene  = import("../scene").Scene;
  */
 export class PostProcessManager {
     private _scene: Scene;
-    private _indexBuffer: Nullable<WebGLBuffer>;
+    private _indexBuffer: Nullable<DataBuffer>;
     private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
 
     /**

+ 2 - 1
src/Rendering/boundingBoxRenderer.ts

@@ -16,6 +16,7 @@ import "../Meshes/Builders/boxBuilder";
 
 import "../Shaders/color.fragment";
 import "../Shaders/color.vertex";
+import { DataBuffer } from '../Meshes/dataBuffer';
 
 declare module "../scene" {
     export interface Scene {
@@ -123,7 +124,7 @@ export class BoundingBoxRenderer implements ISceneComponent {
 
     private _colorShader: ShaderMaterial;
     private _vertexBuffers: { [key: string]: Nullable<VertexBuffer> } = {};
-    private _indexBuffer: WebGLBuffer;
+    private _indexBuffer: DataBuffer;
 
     /**
      * Instantiates a new bounding box renderer in a scene.

+ 2 - 1
src/Rendering/edgesRenderer.ts

@@ -14,6 +14,7 @@ import { Node } from "../node";
 
 import "../Shaders/line.fragment";
 import "../Shaders/line.vertex";
+import { DataBuffer } from '../Meshes/dataBuffer';
 
 declare module "../Meshes/abstractMesh" {
     export interface AbstractMesh {
@@ -154,7 +155,7 @@ export class EdgesRenderer implements IEdgesRenderer {
     protected _indicesCount: number;
 
     protected _lineShader: ShaderMaterial;
-    protected _ib: WebGLBuffer;
+    protected _ib: DataBuffer;
     protected _buffers: { [key: string]: Nullable<VertexBuffer> } = {};
     protected _checkVerticesInsteadOfIndices = false;
 

+ 2 - 1
src/Sprites/spriteManager.ts

@@ -16,6 +16,7 @@ import { Constants } from "../Engines/constants";
 
 import "../Shaders/sprites.fragment";
 import "../Shaders/sprites.vertex";
+import { DataBuffer } from '../Meshes/dataBuffer';
 declare type Ray = import("../Culling/ray").Ray;
 
 /**
@@ -106,7 +107,7 @@ export class SpriteManager implements ISpriteManager {
     private _vertexData: Float32Array;
     private _buffer: Buffer;
     private _vertexBuffers: { [key: string]: VertexBuffer } = {};
-    private _indexBuffer: WebGLBuffer;
+    private _indexBuffer: DataBuffer;
     private _effectBase: Effect;
     private _effectFog: Effect;