/// <summary> /// Try a certain packed depth/stencil format, and return the status. /// </summary> /// <param name="packedFormat"> </param> /// <returns> true if this combo is supported, false if not </returns> private bool TryPacketFormat(All packedFormat) { int packedRB = 0; /// Generate renderbuffer OpenGLOES.GenRenderbuffers(1, ref packedRB); //bind it to FBO OpenGLOES.BindRenderbuffer(All.RenderbufferOes, packedRB); /// Allocate storage for buffer OpenGLOES.RenderbufferStorage(All.RenderbufferOes, packedFormat, ProbeSize, ProbeSize); /// Attach depth OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, All.DepthAttachmentOes, All.RenderbufferOes, packedRB); /// Attach stencil OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, All.StencilAttachmentOes, All.RenderbufferOes, packedRB); All status = OpenGLOES.CheckFramebufferStatus(All.FramebufferOes); /// Detach and destroy OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, All.DepthAttachmentOes, All.RenderbufferOes, 0); OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, All.StencilAttachmentOes, All.RenderbufferOes, 0); OpenGLOES.DeleteRenderbuffers(1, ref packedRB); return(status == All.FramebufferCompleteOes); }
/// <summary> /// Bind FrameBufferObject /// </summary> public void Bind() { /// Bind it to FBO int fb = this._multiSampleFB != 0 ? this._multiSampleFB : this._fb; OpenGLOES.BindFramebuffer(All.FramebufferOes, fb); GLESConfig.GlCheckError(this); }
/// <summary> /// Try a certain FBO format, and return the status. Also sets mDepthRB and mStencilRB. /// </summary> /// <param name="depthFormat"> </param> /// <param name="stencilFormat"> </param> /// <returns> true if this combo is supported, false if not </returns> private bool TryFormat(All depthFormat, All stencilFormat) { int status = 0, depthRB = 0, stencilRB = 0; if (depthFormat != 0) { /// Generate depth renderbuffer OpenGLOES.GenRenderbuffers(1, ref depthRB); /// Bind it to FBO; OpenGLOES.RenderbufferStorage(All.RenderbufferOes, depthFormat, ProbeSize, ProbeSize); /// Attach depth OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, All.DepthAttachmentOes, All.RenderbufferOes, depthRB); } // Stencil buffers aren't available on iPhone if (stencilFormat != 0) { /// Generate stencil renderbuffer OpenGLOES.GenRenderbuffers(1, ref stencilRB); //bind it to FBO OpenGLOES.BindRenderbuffer(All.RenderbufferOes, stencilRB); /// Allocate storage for stencil buffer OpenGLOES.RenderbufferStorage(All.RenderbufferOes, stencilFormat, ProbeSize, ProbeSize); /// Attach stencil OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, All.StencilAttachmentOes, All.RenderbufferOes, stencilRB); } status = (int)OpenGLOES.CheckFramebufferStatus(All.FramebufferOes); OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, All.DepthAttachmentOes, All.RenderbufferOes, depthRB); OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, All.StencilAttachmentOes, All.RenderbufferOes, stencilRB); if (depthRB != 0) { OpenGLOES.DeleteRenderbuffers(1, ref depthRB); } if (stencilRB != 0) { OpenGLOES.DeleteRenderbuffers(1, ref stencilRB); } //Clear OpenGL Errors create because of the evaluation while (OpenGL.GetError() != All.NoError) { ; } return(status == (int)All.FramebufferCompleteOes); }
/// <summary> /// </summary> public GLESFBORTTManager() : base() { LogManager.Instance.Write("FBO CTOR ENTER"); this._renderBuffer = new Dictionary <RBFormat, RBRef>(); TemporaryFBO = 0; DetectFBOFormats(); OpenGLOES.GenFramebuffers(1, ref this._tempFbo); GLESConfig.GlCheckError(this); LogManager.Instance.Write("FBO CTOR EXIT"); }
/// <summary> /// </summary> /// <param name="manager"> </param> /// <param name="fsaa"> </param> public GLESFrameBufferObject(GLESFBORTTManager manager, int fsaa) { /// Generate framebuffer object OpenGLOES.GenFramebuffers(1, ref this._fb); GLESConfig.GlCheckError(this); this._depth = new GLESSurfaceDescription(); this._stencil = new GLESSurfaceDescription(); for (int x = 0; x < Configuration.Config.MaxMultipleRenderTargets; x++) { this._color[x] = new GLESSurfaceDescription(); } }
/// <summary> /// </summary> public void Dispose() { Manager.ReleaseRenderbuffer(this._depth); Manager.ReleaseRenderbuffer(this._stencil); Manager.ReleaseRenderbuffer(this._multisampleColorBuffer); /// Delete framebuffer object OpenGLOES.DeleteFramebuffers(1, ref this._fb); GLESConfig.GlCheckError(this); if (this._multiSampleFB != 0) { OpenGLOES.DeleteFramebuffers(1, ref this._multiSampleFB); } GLESConfig.GlCheckError(this); }
/// <summary> /// </summary> /// <param name="disposeManagedResources"> </param> protected override void dispose(bool disposeManagedResources) { if (!IsDisposed) { if (disposeManagedResources) { if (data != null) { OpenGLOES.DeleteRenderbuffers(1, ref this._renderbufferID); GLESConfig.GlCheckError(this); } } } // If it is available, make the call to the // base class's Dispose(Boolean) method base.dispose(disposeManagedResources); }
/// <summary> /// </summary> /// <param name="format"> </param> /// <param name="width"> </param> /// <param name="height"> </param> /// <param name="numSamples"> </param> public GLESRenderBuffer(All format, int width, int height, int numSamples) : base(width, height, 1, GLESPixelUtil.GetClosestAxiomFormat(format), BufferUsage.WriteOnly) { _glInternalFormat = format; /// Generate renderbuffer OpenGLOES.GenRenderbuffers(1, ref this._renderbufferID); GLESConfig.GlCheckError(this); /// Bind it to FBO OpenGLOES.BindRenderbuffer(All.RenderbufferOes, this._renderbufferID); GLESConfig.GlCheckError(this); /// Allocate storage for depth buffer if (numSamples <= 0) { OpenGLOES.RenderbufferStorage(All.RenderbufferOes, format, width, height); GLESConfig.GlCheckError(this); } }
/// <summary> /// Bind a certain render target if it is a FBO. If it is not a FBO, bind the main frame buffer. /// </summary> /// <param name="target"> </param> public override void Bind(Graphics.RenderTarget target) { /// Check if the render target is in the rendertarget->FBO map GLESFrameBufferObject fbo = null; fbo = target["FBO"] as GLESFrameBufferObject; if (fbo != null) { fbo.Bind(); } else { // Old style context (window/pbuffer) or copying render texture #if AXIOM_PLATFORM_IPHONE // The screen buffer is 1 on iPhone OpenGLOES.BindFramebuffer(All.FramebufferOes, 1); #else OpenGLOES.BindFramebuffer(All.FramebufferOes, 0); #endif GLESConfig.GlCheckError(this); } }
/// <summary> /// </summary> protected override void UnlockImpl() { if (this._lockedToScratch) { if (this._scratchUploadOnUnlock) { // have to write the data back to vertex buffer this.WriteData(this._scratchOffset, this._scratchSize, this._scratchPtr, this._scratchOffset == 0 && this._scratchSize == sizeInBytes); } // deallocate from scratch buffer ((GLESHardwareBufferManager)HardwareBufferManager.Instance).DeallocateScratch(this._scratchPtr); this._lockedToScratch = false; } else { OpenGL.BindBuffer(All.ElementArrayBuffer, this._bufferId); GLESConfig.GlCheckError(this); if (!OpenGLOES.UnmapBuffer(All.ElementArrayBuffer)) { throw new AxiomException("Buffer data corrupted, please reload"); } } isLocked = false; }
/// <summary> /// </summary> /// <param name="offset"> </param> /// <param name="length"> </param> /// <param name="locking"> </param> /// <returns> </returns> protected override BufferBase LockImpl(int offset, int length, BufferLocking locking) { All access = 0; if (isLocked) { throw new AxiomException("Invalid attempt to lock an index buffer that has already been locked"); } BufferBase retPtr = null; if (length < MapBufferThreshold) { retPtr = ((GLESHardwareBufferManager)HardwareBufferManager.Instance).AllocateScratch(length); if (retPtr != null) { this._lockedToScratch = true; this._scratchOffset = offset; this._scratchSize = length; this._scratchPtr = retPtr; this._scratchUploadOnUnlock = (locking != BufferLocking.ReadOnly); if (locking != BufferLocking.Discard) { this.ReadData(offset, length, retPtr); } } } else { throw new AxiomException("Invalid Buffer lockSize"); } if (retPtr == null) { OpenGL.BindBuffer(All.ElementArrayBuffer, this._bufferId); GLESConfig.GlCheckError(this); // Use glMapBuffer if (locking == BufferLocking.Discard) { OpenGL.BufferData(All.ElementArrayBuffer, new IntPtr(sizeInBytes), IntPtr.Zero, GLESHardwareBufferManager.GetGLUsage(usage)); GLESConfig.GlCheckError(this); } if ((usage & BufferUsage.WriteOnly) != 0) { access = All.WriteOnlyOes; } IntPtr pBuffer = OpenGLOES.MapBuffer(All.ElementArrayBuffer, access); GLESConfig.GlCheckError(this); if (pBuffer == IntPtr.Zero) { throw new AxiomException("Index Buffer: Out of memory"); } unsafe { // return offset retPtr = BufferBase.Wrap(pBuffer, sizeInBytes); } this._lockedToScratch = false; } isLocked = true; return(retPtr); }
/// <summary> /// </summary> /// <param name="attachment"> </param> /// <param name="zOffset"> </param> public override void BindToFramebuffer(All attachment, int zOffset) { Utilities.Contract.Requires(zOffset < Depth); OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, attachment, All.RenderbufferOes, this._renderbufferID); GLESConfig.GlCheckError(this); }
/// <summary> /// Detect which internal formats are allowed as RTT Also detect what combinations of stencil and depth are allowed with this internal format. /// </summary> private void DetectFBOFormats() { // Try all formats, and report which ones work as target int fb = 0, tid = 0; All target = All.Texture2D; for (int x = 0; x < (int)Media.PixelFormat.Count; x++) { LogManager.Instance.Write("[GLES] [DEBUG] testing PixelFormat : {0}", (Media.PixelFormat)x); this._props[x] = new FormatProperties(); this._props[x].Modes = new List <FormatProperties.Mode>(); this._props[x].IsValid = false; // Fetch GL format token All fmt = GLESPixelUtil.GetClosestGLInternalFormat((Media.PixelFormat)x); LogManager.Instance.Write("[GLES] [DEBUG] fmt={0}", fmt); if (fmt == All.Zero && x != 0) { continue; } // No test for compressed formats if (PixelUtil.IsCompressed((Media.PixelFormat)x)) { continue; } // Create and attach framebuffer OpenGLOES.GenRenderbuffers(1, ref fb); GLESConfig.GlCheckError(this); OpenGLOES.BindFramebuffer(All.FramebufferOes, fb); GLESConfig.GlCheckError(this); if (fmt != All.Zero) { // Create and attach texture OpenGL.GenTextures(1, ref tid); GLESConfig.GlCheckError(this); OpenGL.BindTexture(target, tid); GLESConfig.GlCheckError(this); // Set some default parameters OpenGL.TexParameterx(target, All.TextureMinFilter, (int)All.LinearMipmapNearest); GLESConfig.GlCheckError(this); OpenGL.TexParameterx(target, All.TextureMagFilter, (int)All.Nearest); GLESConfig.GlCheckError(this); OpenGL.TexParameterx(target, All.TextureWrapS, (int)All.ClampToEdge); GLESConfig.GlCheckError(this); OpenGL.TexParameterx(target, All.TextureWrapT, (int)All.ClampToEdge); GLESConfig.GlCheckError(this); OpenGL.TexImage2D(target, 0, (int)fmt, ProbeSize, ProbeSize, 0, fmt, All.UnsignedByte, IntPtr.Zero); GLESConfig.GlCheckError(this); OpenGLOES.FramebufferTexture2D(All.FramebufferOes, All.ColorAttachment0Oes, target, tid, 0); GLESConfig.GlCheckError(this); } // Check status All status = OpenGLOES.CheckFramebufferStatus(All.FramebufferOes); GLESConfig.GlCheckError(this); LogManager.Instance.Write("[GLES] [DEBUG] status={0}", status); // Ignore status in case of fmt==GL_NONE, because no implementation will accept // a buffer without *any* attachment. Buffers with only stencil and depth attachment // might still be supported, so we must continue probing. if (fmt == 0 || status == All.FramebufferCompleteOes) { this._props[x].IsValid = true; var str = new StringBuilder(); str.Append("FBO " + PixelUtil.GetFormatName((Media.PixelFormat)x) + " depth/stencil support: "); // For each depth/stencil formats for (int depth = 0; depth < DepthFormats.Length; ++depth) { if (DepthFormats[depth] != All.Depth24Stencil8Oes) { // General depth/stencil combination for (int stencil = 0; stencil < StencilFormats.Length; ++stencil) { if (TryFormat(DepthFormats[depth], StencilFormats[stencil])) { /// Add mode to allowed modes str.Append("D" + DepthBits[depth] + "S" + StencilBits[stencil] + " "); var mode = new FormatProperties.Mode(); mode.Depth = depth; mode.Stencil = stencil; this._props[x].Modes.Add(mode); } } //end for stencil } //end if else { // Packed depth/stencil format if (TryPacketFormat(DepthFormats[depth])) { /// Add mode to allowed modes str.Append("Packed-D" + DepthBits[depth] + "S8" + " "); var mode = new FormatProperties.Mode(); mode.Depth = depth; mode.Stencil = 0; //unused this._props[x].Modes.Add(mode); } } } //end for depth LogManager.Instance.Write(str.ToString()); } //end if // Delete texture and framebuffer #if AXIOM_PLATFORM_IPHONE // The screen buffer is 1 on iPhone OpenGLOES.BindFramebuffer(All.FramebufferOes, 1); #else OpenGLOES.BindFramebuffer(All.FramebufferOes, 0); #endif GLESConfig.GlCheckError(this); OpenGLOES.DeleteFramebuffers(1, ref fb); GLESConfig.GlCheckError(this); if (fmt != 0) { OpenGL.DeleteTextures(1, ref tid); } } //end for pixelformat count string fmtstring = string.Empty; for (int x = 0; x < (int)Media.PixelFormat.Count; x++) { if (this._props[x].IsValid) { fmtstring += PixelUtil.GetFormatName((Media.PixelFormat)x); } } LogManager.Instance.Write("[GLES] : Valid FBO targets " + fmtstring); }
/// <summary> /// </summary> private void Intialize() { // Release depth and stencil, if they were bound Manager.ReleaseRenderbuffer(this._depth); Manager.ReleaseRenderbuffer(this._stencil); Manager.ReleaseRenderbuffer(this._multisampleColorBuffer); /// First buffer must be bound if (this._color[0].Buffer == null) { throw new AxiomException("Attachment 0 must have surface attached"); } // If we're doing multisampling, then we need another FBO which contains a // renderbuffer which is set up to multisample, and we'll blit it to the final // FBO afterwards to perform the multisample resolve. In that case, the // mMultisampleFB is bound during rendering and is the one with a depth/stencil /// Store basic stats int width = this._color[0].Buffer.Width; int height = this._color[0].Buffer.Height; All format = this._color[0].Buffer.GLFormat; Media.PixelFormat axiomFormat = this._color[0].Buffer.Format; // Bind simple buffer to add colour attachments OpenGLOES.BindFramebuffer(All.FramebufferOes, this._fb); GLESConfig.GlCheckError(this); /// Bind all attachment points to frame buffer for (int x = 0; x < Configuration.Config.MaxMultipleRenderTargets; x++) { if (this._color[x].Buffer != null) { if (this._color[x].Buffer.Width != width || this._color[x].Buffer.Height != height) { string ss = string.Empty; ss += "Attachment " + x + " has incompatible size "; ss += this._color[x].Buffer.Width + "x" + this._color[0].Buffer.Height; ss += ". It must be of the same as the size of surface 0, "; ss += width + "x" + height; ss += "."; throw new AxiomException(ss); } if (this._color[x].Buffer.GLFormat != format) { string ss = string.Empty; ss += "Attachment " + x + " has incompatible format."; throw new AxiomException(ss); } this._color[x].Buffer.BindToFramebuffer(All.ColorAttachment0Oes + x, this._color[x].ZOffset); } else { // Detach OpenGLOES.FramebufferRenderbuffer(All.FramebufferOes, All.ColorAttachment0Oes + x, All.RenderbufferOes, 0); GLESConfig.GlCheckError(this); } } //end for x // Now deal with depth / stencil if (this._multiSampleFB != 0) { // Bind multisample buffer OpenGLOES.BindFramebuffer(All.FramebufferOes, this._multiSampleFB); GLESConfig.GlCheckError(this); // Create AA render buffer (color) // note, this can be shared too because we blit it to the final FBO // right after the render is finished this._multisampleColorBuffer = Manager.RequestRenderbuffer(format, width, height, this._numSamples); // Attach it, because we won't be attaching below and non-multisample has // actually been attached to other FBO this._multisampleColorBuffer.Buffer.BindToFramebuffer(All.ColorAttachment0Oes, this._multisampleColorBuffer.ZOffset); // depth & stencil will be dealt with below } /// Depth buffer is not handled here anymore. /// See GLESFrameBufferObject::attachDepthBuffer() & RenderSystem::setDepthBufferFor() /// Do glDrawBuffer calls var bufs = new All[Configuration.Config.MaxMultipleRenderTargets]; int n = 0; for (int x = 0; x < Configuration.Config.MaxMultipleRenderTargets; x++) { // Fill attached colour buffers if (this._color[x].Buffer != null) { bufs[x] = All.ColorAttachment0Oes + x; // Keep highest used buffer + 1 n = x + 1; } else { bufs[x] = All.Never; } } //end for x /// Check status All status = OpenGLOES.CheckFramebufferStatus(All.FramebufferOes); GLESConfig.GlCheckError(this); /// Bind main buffer #if AXIOM_PLATFORM_IPHONE // The screen buffer is 1 on iPhone OpenGLOES.BindFramebuffer(All.FramebufferOes, 1); #else OpenGLOES.BindFramebuffer(All.FramebufferOes, 0); #endif GLESConfig.GlCheckError(this); switch (status) { case All.FramebufferCompleteOes: // everything is fine break; case All.FramebufferUnsupportedOes: throw new AxiomException("All framebuffer formats with this texture internal format unsupported"); default: throw new AxiomException("Framebuffer incomplete or other FBO status error"); } }