/// <summary> /// Detect allowed FBO formats /// </summary> private void _detectFBOFormats() { // Try all formats, and report which ones work as target int fb, tid; int old_drawbuffer, old_readbuffer; int target = Gl.GL_TEXTURE_2D; Gl.glGetIntegerv(Gl.GL_DRAW_BUFFER, out old_drawbuffer); Gl.glGetIntegerv(Gl.GL_READ_BUFFER, out old_readbuffer); for (int x = 0; x < (int)PixelFormat.Count; ++x) { this._props[x].Valid = false; // Fetch GL format token int fmt = GLPixelUtil.GetGLInternalFormat((PixelFormat)x); if (fmt == Gl.GL_NONE && x != 0) { continue; } // No test for compressed formats if (PixelUtil.IsCompressed((PixelFormat)x)) { continue; } // Buggy ATI cards *crash* on non-RGB(A) formats int[] depths = PixelUtil.GetBitDepths((PixelFormat)x); if (fmt != Gl.GL_NONE && this._atiMode && (depths[0] == 0 || depths[1] == 0 || depths[2] == 0)) { continue; } // Buggy NVidia Drivers fail on 32Bit FP formats on Windows. if (PixelUtil.IsFloatingPoint((PixelFormat)x) && PlatformManager.IsWindowsOS && !this._atiMode) { continue; } // Create and attach framebuffer Gl.glGenFramebuffersEXT(1, out fb); Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, fb); if (fmt != Gl.GL_NONE) { // Create and attach texture Gl.glGenTextures(1, out tid); Gl.glBindTexture(target, tid); // Set some default parameters so it won't fail on NVidia cards Gl.glTexParameteri(target, Gl.GL_TEXTURE_MAX_LEVEL, 0); Gl.glTexParameteri(target, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST); Gl.glTexParameteri(target, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST); Gl.glTexParameteri(target, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP_TO_EDGE); Gl.glTexParameteri(target, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP_TO_EDGE); Gl.glTexImage2D(target, 0, fmt, PROBE_SIZE, PROBE_SIZE, 0, Gl.GL_RGBA, Gl.GL_UNSIGNED_BYTE, IntPtr.Zero); Gl.glFramebufferTexture2DEXT(Gl.GL_FRAMEBUFFER_EXT, Gl.GL_COLOR_ATTACHMENT0_EXT, target, tid, 0); } else { // Draw to nowhere -- stencil/depth only tid = 0; Gl.glDrawBuffer(Gl.GL_NONE); Gl.glReadBuffer(Gl.GL_NONE); } // Check status int status = Gl.glCheckFramebufferStatusEXT(Gl.GL_FRAMEBUFFER_EXT); // 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 == Gl.GL_NONE || status == Gl.GL_FRAMEBUFFER_COMPLETE_EXT) { this._props[x].Valid = true; var str = new StringBuilder(); str.AppendFormat("\tFBO {0} depth/stencil support: ", PixelUtil.GetFormatName((PixelFormat)x)); // For each depth/stencil formats for (int depth = 0; depth < this._depthFormats.GetLength(0); ++depth) { if (this._depthFormats[depth] != GL_DEPTH24_STENCIL8_EXT) { // General depth/stencil combination for (int stencil = 0; stencil < this._stencilFormats.GetLength(0); ++stencil) { //LogManager.Instance.Write( "Trying {0} D{1}S{2} ", PixelUtil.GetFormatName( (PixelFormat)x ), _depthBits[ depth ], _stencilBits[ stencil ] ); if (_tryFormat(this._depthFormats[depth], this._stencilFormats[stencil])) { /// Add mode to allowed modes str.AppendFormat("D{0}S{1} ", this._depthBits[depth], this._stencilBits[stencil]); FormatProperties.Mode mode; mode.Depth = depth; mode.Stencil = stencil; this._props[x].Modes.Add(mode); } } } else { // Packed depth/stencil format #if false // Only query packed depth/stencil formats for 32-bit // non-floating point formats (ie not R32!) // Linux nVidia driver segfaults if you query others if (!PlatformManager.IsWindowsOS && (PixelUtil.GetNumElemBits((PixelFormat)x) != 32 || PixelUtil.IsFloatingPoint((PixelFormat)x))) { continue; } #endif if (_tryPackedFormat(this._depthFormats[depth])) { /// Add mode to allowed modes str.AppendFormat("Packed-D{0}S8 ", this._depthBits[depth]); FormatProperties.Mode mode; mode.Depth = depth; mode.Stencil = 0; // unuse this._props[x].Modes.Add(mode); } } } LogManager.Instance.Write(str.ToString()); } // Delete texture and framebuffer Gl.glBindFramebufferEXT(Gl.GL_FRAMEBUFFER_EXT, 0); Gl.glDeleteFramebuffersEXT(1, ref fb); // Workaround for NVIDIA / Linux 169.21 driver problem // see http://www.ogre3d.org/phpBB2/viewtopic.php?t=38037&start=25 Gl.glFinish(); Gl.glDeleteTextures(1, ref tid); } // It seems a bug in nVidia driver: glBindFramebufferEXT should restore // draw and read buffers, but in some unclear circumstances it won't. Gl.glDrawBuffer(old_drawbuffer); Gl.glReadBuffer(old_readbuffer); string fmtstring = ""; for (int x = 0; x < (int)PixelFormat.Count; ++x) { if (this._props[x].Valid) { fmtstring += PixelUtil.GetFormatName((PixelFormat)x) + " "; } } LogManager.Instance.Write("[GL] : Valid FBO targets " + fmtstring); }
public static void ConvertToIL(PixelBox src) { // ilTexImage http://openil.sourceforge.net/docs/il/f00059.htm var ifmt = Convert(src.Format); if (src.IsConsecutive && ifmt.IsValid) { // The easy case, the buffer is laid out in memory just like // we want it to be and is in a format DevIL can understand directly // We could even save the copy if DevIL would let us Il.ilTexImage(src.Width, src.Height, src.Depth, (byte)ifmt.Channels, ifmt.Format, ifmt.Type, src.Data.Pin()); src.Data.UnPin(); } else if (ifmt.IsValid) { // The format can be understood directly by DevIL. The only // problem is that ilTexImage expects our image data consecutively // so we cannot use that directly. // Let DevIL allocate the memory for us, and copy the data consecutively // to its memory Il.ilTexImage(src.Width, src.Height, src.Depth, (byte)ifmt.Channels, ifmt.Format, ifmt.Type, IntPtr.Zero); using (var dstbuf = BufferBase.Wrap(Il.ilGetData(), Il.ilGetInteger(Il.IL_IMAGE_SIZE_OF_DATA))) { var dst = new PixelBox(src.Width, src.Height, src.Depth, src.Format, dstbuf); PixelConverter.BulkPixelConversion(src, dst); } } else { // Here it gets ugly. We're stuck with a pixel format that DevIL // can't do anything with. We will do a bulk pixel conversion and // then feed it to DevIL anyway. The problem is finding the best // format to convert to. // most general format supported by Axiom and DevIL var fmt = PixelUtil.HasAlpha(src.Format) ? PixelFormat.FLOAT32_RGBA : PixelFormat.FLOAT32_RGB; // Make up a pixel format // We don't have to consider luminance formats as they have // straight conversions to DevIL, just weird permutations of RGBA an LA var depths = PixelUtil.GetBitDepths(src.Format); // Native endian format with all bit depths<8 can safely and quickly be // converted to 24/32 bit if (PixelUtil.IsNativeEndian(src.Format) && depths[0] <= 8 && depths[1] <= 8 && depths[2] <= 8 && depths[3] <= 8) { if (PixelUtil.HasAlpha(src.Format)) { fmt = PixelFormat.A8R8G8B8; } else { fmt = PixelFormat.R8G8B8; } } // Let DevIL allocate the memory for us, then do the conversion ourselves ifmt = Convert(fmt); Il.ilTexImage(src.Width, src.Height, src.Depth, (byte)ifmt.Channels, ifmt.Format, ifmt.Type, IntPtr.Zero); // TAO 2.0 //Il.ilTexImage( src.Width, src.Height, src.Depth, (byte)ifmt.Channels, ifmt.Format, ifmt.Type, null ); using (var dstbuf = BufferBase.Wrap(Il.ilGetData(), Il.ilGetInteger(Il.IL_IMAGE_SIZE_OF_DATA))) { var dst = new PixelBox(src.Width, src.Height, src.Depth, fmt, dstbuf); PixelConverter.BulkPixelConversion(src, dst); } } }