Преглед изворни кода

Merge pull request #3435 from PierreLeBlond/fix_mrt

Add MSAA Support for MultiRenderTargets
David Catuhe пре 7 година
родитељ
комит
8cfd46868f

+ 138 - 0
src/Engine/babylon.engine.ts

@@ -1887,6 +1887,64 @@
             this.bindUnboundFramebuffer(null);
         }
 
+        public unBindMultiColorAttachmentFramebuffer(textures: InternalTexture[], disableGenerateMipMaps = false, onBeforeUnbind?: () => void): void {
+            this._currentRenderTarget = null;
+
+            // If MSAA, we need to bitblt back to main texture
+            var gl = this._gl;
+
+
+            if (textures[0]._MSAAFramebuffer) {
+                gl.bindFramebuffer(gl.READ_FRAMEBUFFER, textures[0]._MSAAFramebuffer);
+                gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, textures[0]._framebuffer);
+
+                var attachments = textures[0]._attachments;
+                if(!attachments) {
+                    attachments = new Array(textures.length);
+                    textures[0]._attachments = attachments;
+                }
+
+                for(var i = 0; i < textures.length; i++) {
+                    var texture = textures[i];
+
+                    for(var j = 0; j < attachments.length; j++) {
+                        attachments[j] = gl.NONE;
+                    }
+
+                    attachments[i] = (<any>gl)[this.webGLVersion > 1 ? "COLOR_ATTACHMENT" + i : "COLOR_ATTACHMENT" + i + "_WEBGL"];
+                    gl.readBuffer(attachments[i]);
+                    gl.drawBuffers(attachments);
+                    gl.blitFramebuffer(0, 0, texture.width, texture.height,
+                        0, 0, texture.width, texture.height,
+                        gl.COLOR_BUFFER_BIT, gl.NEAREST);
+
+                }
+                for(var i = 0; i < attachments.length; i++) {
+                    attachments[i] = (<any>gl)[this.webGLVersion > 1 ? "COLOR_ATTACHMENT" + i : "COLOR_ATTACHMENT" + i + "_WEBGL"];
+                }
+                gl.drawBuffers(attachments);
+            }
+
+            for(var i = 0; i < textures.length; i++) {
+                var texture = textures[i];
+                if (texture.generateMipMaps && !disableGenerateMipMaps && !texture.isCube) {
+                    this._bindTextureDirectly(gl.TEXTURE_2D, texture);
+                    gl.generateMipmap(gl.TEXTURE_2D);
+                    this._bindTextureDirectly(gl.TEXTURE_2D, null);
+                }
+            }
+
+            if (onBeforeUnbind) {
+                if (textures[0]._MSAAFramebuffer) {
+                    // Bind the correct framebuffer
+                    this.bindUnboundFramebuffer(textures[0]._framebuffer);
+                }
+                onBeforeUnbind();
+            }
+
+            this.bindUnboundFramebuffer(null);
+        }
+
         public generateMipMapsForCubemap(texture: InternalTexture) {
             if (texture.generateMipMaps) {
                 var gl = this._gl;
@@ -3645,6 +3703,7 @@
                 texture.type = type;
                 texture._generateDepthBuffer = generateDepthBuffer;
                 texture._generateStencilBuffer = generateStencilBuffer;
+                texture._attachments = attachments;
 
                 this._internalTexturesCache.push(texture);
             }
@@ -3753,14 +3812,17 @@
             // Dispose previous render buffers
             if (texture._depthStencilBuffer) {
                 gl.deleteRenderbuffer(texture._depthStencilBuffer);
+                texture._depthStencilBuffer = null;
             }
 
             if (texture._MSAAFramebuffer) {
                 gl.deleteFramebuffer(texture._MSAAFramebuffer);
+                texture._MSAAFramebuffer = null;
             }
 
             if (texture._MSAARenderBuffer) {
                 gl.deleteRenderbuffer(texture._MSAARenderBuffer);
+                texture._MSAARenderBuffer = null;
             }
 
             if (samples > 1) {
@@ -3798,6 +3860,82 @@
             return samples;
         }
 
+        public updateMultipleRenderTargetTextureSampleCount(textures: Nullable<InternalTexture[]>, samples: number): number {
+            if (this.webGLVersion < 2 || !textures || textures.length == 0) {
+                return 1;
+            }
+
+            if (textures[0].samples === samples) {
+                return samples;
+            }
+
+            var gl = this._gl;
+
+            samples = Math.min(samples, gl.getParameter(gl.MAX_SAMPLES));
+
+            // Dispose previous render buffers
+            if (textures[0]._depthStencilBuffer) {
+                gl.deleteRenderbuffer(textures[0]._depthStencilBuffer);
+                textures[0]._depthStencilBuffer = null;
+            }
+
+            if (textures[0]._MSAAFramebuffer) {
+                gl.deleteFramebuffer(textures[0]._MSAAFramebuffer);
+                textures[0]._MSAAFramebuffer = null;
+            }
+
+            for(var i = 0; i < textures.length; i++) {
+                if(textures[i]._MSAARenderBuffer) {
+                    gl.deleteRenderbuffer(textures[i]._MSAARenderBuffer);
+                    textures[i]._MSAARenderBuffer = null;
+                }
+            }
+
+            if (samples > 1) {
+                let framebuffer = gl.createFramebuffer();
+
+                if (!framebuffer) {
+                  throw new Error("Unable to create multi sampled framebuffer");
+                }
+
+                this.bindUnboundFramebuffer(framebuffer);
+
+                let depthStencilBuffer = this._setupFramebufferDepthAttachments(textures[0]._generateStencilBuffer, textures[0]._generateDepthBuffer, textures[0].width, textures[0].height, samples);
+
+                var attachments = [];
+
+                for(var i = 0; i < textures.length; i++) {
+                    var texture = textures[i];
+                    var attachment = (<any>gl)[this.webGLVersion > 1 ? "COLOR_ATTACHMENT" + i : "COLOR_ATTACHMENT" + i + "_WEBGL"];
+
+                    var colorRenderbuffer = gl.createRenderbuffer();
+
+                    if (!colorRenderbuffer) {
+                        throw new Error("Unable to create multi sampled framebuffer");
+                    }
+
+                    gl.bindRenderbuffer(gl.RENDERBUFFER, colorRenderbuffer);
+                    gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples, gl.RGBA8, texture.width, texture.height);
+
+                    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, attachment, gl.RENDERBUFFER, colorRenderbuffer);
+
+                    texture._MSAAFramebuffer = framebuffer;
+                    texture._MSAARenderBuffer = colorRenderbuffer;
+                    texture.samples = samples;
+                    texture._depthStencilBuffer = depthStencilBuffer;
+                    gl.bindRenderbuffer(gl.RENDERBUFFER, null);
+                    attachments.push(attachment);
+                }
+                gl.drawBuffers(attachments);
+            } else {
+                this.bindUnboundFramebuffer(textures[0]._framebuffer);
+            }
+
+            this.bindUnboundFramebuffer(null);
+
+            return samples;
+        }
+
         public _uploadDataToTexture(target: number, lod: number, internalFormat: number, width: number, height: number, format: number, type: number, data: ArrayBufferView) {
             this._gl.texImage2D(target, lod, internalFormat, width, height, 0, format, type, data);
         }

+ 2 - 1
src/Materials/Textures/babylon.internalTexture.ts

@@ -47,6 +47,7 @@ module BABYLON {
         public _depthStencilBuffer: Nullable<WebGLRenderbuffer>;
         public _MSAAFramebuffer: Nullable<WebGLFramebuffer>;
         public _MSAARenderBuffer: Nullable<WebGLRenderbuffer>;
+        public _attachments: Nullable<number[]>;
         public _cachedCoordinatesMode: Nullable<number>;
         public _cachedWrapU: Nullable<number>;
         public _cachedWrapV: Nullable<number>;
@@ -239,4 +240,4 @@ module BABYLON {
             }
         }
     }
-}
+}

+ 11 - 7
src/Materials/Textures/babylon.multiRenderTarget.ts

@@ -63,13 +63,13 @@ module BABYLON {
             var samplingModes = [];
 
             for (var i = 0; i < count; i++) {
-                if (options.types && options.types[i]) {
+                if (options.types && options.types[i] !== undefined) {
                     types.push(options.types[i]);
                 } else {
-                    types.push(Engine.TEXTURETYPE_FLOAT);
+                    types.push(Engine.TEXTURETYPE_UNSIGNED_INT);
                 }
 
-                if (options.samplingModes && options.samplingModes[i]) {
+                if (options.samplingModes && options.samplingModes[i] !== undefined) {
                     samplingModes.push(options.samplingModes[i]);
                 } else {
                     samplingModes.push(Texture.BILINEAR_SAMPLINGMODE);
@@ -132,9 +132,7 @@ module BABYLON {
                 return;
             }
 
-            for (var i = 0; i < this._internalTextures.length; i++) {
-                this._samples = this._engine.updateRenderTargetTextureSampleCount(this._internalTextures[i], value);
-            }
+            this._samples = this._engine.updateMultipleRenderTargetTextureSampleCount(this._internalTextures, value);
         }
 
         public resize(size: any) {
@@ -143,6 +141,12 @@ module BABYLON {
             this._createInternalTextures();
         }
 
+        protected unbindFrameBuffer(engine: Engine, faceIndex: number): void {
+            engine.unBindMultiColorAttachmentFramebuffer(this._internalTextures, this.isCube, () => {
+                this.onAfterRenderObservable.notifyObservers(faceIndex);
+            });
+        }
+
         public dispose(): void {
             this.releaseInternalTextures();
 
@@ -162,4 +166,4 @@ module BABYLON {
             }
         }
     }
-}
+}

+ 12 - 4
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -495,6 +495,15 @@
             return Math.min(Tools.FloorPOT(renderDimension), curved);
         }
 
+        protected unbindFrameBuffer(engine: Engine, faceIndex: number): void {
+            if (!this._texture) {
+                return;
+            }
+            engine.unBindFramebuffer(this._texture, this.isCube, () => {
+                this.onAfterRenderObservable.notifyObservers(faceIndex);
+            });
+        }
+
         private renderToTarget(faceIndex: number, currentRenderList: AbstractMesh[], currentRenderListLength: number, useCameraPostProcess: boolean, dumpForDebug: boolean): void {
             var scene = this.getScene();
             
@@ -559,9 +568,8 @@
                     }
                 }
 
-                engine.unBindFramebuffer(this._texture, this.isCube, () => {
-                    this.onAfterRenderObservable.notifyObservers(faceIndex);
-                });
+            this.unbindFrameBuffer(engine, faceIndex);
+
             } else {
                 this.onAfterRenderObservable.notifyObservers(faceIndex);
             }
@@ -702,4 +710,4 @@
             }
         }
     }
-}
+}