Bad FBO Behavor in Intel HD 520

I am writing a Game in C# using OpenTK to interface with OpenGL. For all machines tested except for the windows surface pro 4 the code works as expected. On the surface pro no exceptions or warnings are thrown and yet the output is very incorrect (I was tempted to post this in the bug report section since either 1) There is a bug causing output to be rendered different then it should or 2) There is a bug in GLCheckFramebufferStatus because it is returning FramebufferComplete when it isn’t.)

Here is a shared google drive with the working and not working logs along with a clip of the unexpected behavior.

I am sorry, for the text dump… but I wanted to provide any relevent details I could think of.

I test that the FBO operations work correctly by:

var errCode = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (errCode != FramebufferErrorCode.FramebufferComplete)
    throw new Exception($"Expected FramebufferComplete, got {errCode}");

I also read that intel drivers sometimes have a bug due to “texture completeness” and so I have ensured that the color buffer I attach is “complete” by using Nearest instead of Linear (since I read intel drives never consider a texture with linear mipmaps to be complete)… but I would think that if this is the issue then I would not get the FrameBufferComplete code…

I have detailed logs of both a working machine and a failing machine, the logs consist of general Error from the application, exceptions obtained from GL.GetError and exceptions/warnings obtained through the debug call back function.

(In the video, the user is able to press “T” to toggle between using and not using FBOs… when the background is red it is using the FBO when it is blue it is not using the FBO). On all other tested machines the only difference between using and not using FBOs is the background color changes… positions and sprites all show up normally other then the red background)

The openGL Version should support FBOs

<Non working machine>

[9/22/2017 12:01:18 PM]&gt;Intel
[9/22/2017 12:01:18 PM]&gt;Intel(R) HD Graphics 520
[9/22/2017 12:01:18 PM]&gt;4.4.0 - Build 21.20.16.4627
[9/22/2017 12:01:18 PM]&gt;4.40 - Build 21.20.16.4627

<working Machine>

[9/22/2017 12:11:01 PM]&gt;ATI Technologies Inc.
[9/22/2017 12:11:01 PM]&gt;AMD Radeon HD 5450
[9/22/2017 12:11:01 PM]&gt;4.5.13399 Compatibility Profile Context 15.200.1062.1004
[9/22/2017 12:11:01 PM]&gt;4.40

I was concerned about the surface pro’s high resolution, but I have ensured that the window to render to is 1024x768 and I seperately ensured that the FBO is 1024x768 and I verified that the resolution of the FBO and the resolution of the window are not dependent (I.E, they are configured to both be 1024 but i have tested that out looks correct with any set of FBO resolutions or screen sizes)

The only Difference I noticed between the two Log files is:

<ON FAILING MACHINE>

[9/22/2017 12:01:18 PM]&gt;Actual Graphics Mode: 
[9/22/2017 12:01:18 PM]&gt;Index: 7
[9/22/2017 12:01:18 PM]&gt;ColorFormat: 32 (8888)
[9/22/2017 12:01:18 PM]&gt;AccumulatorFormat: 64 (16161616)
[9/22/2017 12:01:18 PM]&gt;Depth: 16
[9/22/2017 12:01:18 PM]&gt;Stencil: 0
[9/22/2017 12:01:18 PM]&gt;Samples: 0
[9/22/2017 12:01:18 PM]&gt;Stereo: False
[9/22/2017 12:01:18 PM]&gt;Buffers: 2

vs

<On working machine>

[9/22/2017 12:11:01 PM]&gt;Actual Graphics Mode: 
[9/22/2017 12:11:01 PM]&gt;Index: 8
[9/22/2017 12:11:01 PM]&gt;ColorFormat: 32 (8888)
[9/22/2017 12:11:01 PM]&gt;AccumulatorFormat: 0 (0000)
[9/22/2017 12:11:01 PM]&gt;Depth: 16
[9/22/2017 12:11:01 PM]&gt;Stencil: 0
[9/22/2017 12:11:01 PM]&gt;Samples: 0
[9/22/2017 12:11:01 PM]&gt;Stereo: False
[9/22/2017 12:11:01 PM]&gt;Buffers: 2

and <On another working machine>

[9/22/2017 12:01:18 PM]&gt;Actual Graphics Mode: 
[9/22/2017 12:01:18 PM]&gt;Index: 10
[9/22/2017 12:01:18 PM]&gt;ColorFormat: 32 (8888)
[9/22/2017 12:01:18 PM]&gt;AccumulatorFormat: 64 (16161616)
[9/22/2017 12:01:18 PM]&gt;Depth: 24
[9/22/2017 12:01:18 PM]&gt;Stencil: 0
[9/22/2017 12:01:18 PM]&gt;Samples: 0
[9/22/2017 12:01:18 PM]&gt;Stereo: False
[9/22/2017 12:01:18 PM]&gt;Buffers: 2

(I have since made updates that these logs don’t reflect in which the depth value for the non working machine is 24 rather then 16 and yet the problem persists)

Here is how the FBO is created

[highlight=C#]
//Create a new frame buffer object
fboHandle = GL.GenFramebuffer();
//Bind the new frame buffer object so commands affect it
GL.BindFramebuffer(FramebufferTarget.Framebuffer, fboHandle);

//Create the texture the frame buffer will draw to
colorTextureHandle = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, colorTextureHandle);
GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba8, resolution.X, resolution.Y, 0, PixelFormat.Bgra, PixelType.UnsignedByte, IntPtr.Zero);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest);
GL.BindTexture(TextureTarget.Texture2D, 0);
//attach the texture to the framebuffer
GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, colorTextureHandle, 0);
outputTexture = new Util.Texture() { Handle = colorTextureHandle, Size= new Vector2(resolution.X, resolution.Y) };
//Create a render buffer
renderBufferHandle = GL.GenRenderbuffer();
GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, renderBufferHandle);
GL.RenderbufferStorage(RenderbufferTarget.Renderbuffer, RenderbufferStorage.DepthStencil, resolution.X, resolution.Y);
//Attach it to the framebuffer
GL.FramebufferRenderbuffer(FramebufferTarget.Framebuffer, FramebufferAttachment.DepthAttachment, RenderbufferTarget.Renderbuffer, renderBufferHandle);

GL.BindRenderbuffer(RenderbufferTarget.Renderbuffer, 0);

//Check for success
var errCode = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);
if (errCode != FramebufferErrorCode.FramebufferComplete)
throw new Exception("Expected FramebufferComple, got {errCode}"); else { Console.WriteLine(“Succesfully obtained FrameBuffer with CheckFramebufferStatus: {errCode}”);
}
GL.BindFramebuffer(FramebufferTarget.Framebuffer, 0);

Other GL drivers exhibit that too, and I don’t think it is a bug. IIRC, a texture you render to needs to be MIPmap complete. That means if you have a mipmapping minfilter set, then your texture needs to have MIPmaps, even if you’re not going to render into them with the FBO.

In other words, minfilter = GL_LINEAR or GL_NEAREST should be fine regardless, whereas…

A mipmap-referencing minfilter = GL_LINEAR_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_LINEAR_MIPMAP_LINEAR, or GL_NEAREST_MIPMAP_NEAREST may not work if the texture did not have MIPmaps.

It’s interesting how much more time it takes to read C# GL than C/C++ GL. Compare to the pseudo-C++:



// Create a new frame buffer object
fboHandle = glGenFramebuffer();

// Bind the new frame buffer object so commands affect it
glBindFramebuffer( GL_FRAMEBUFFER, fboHandle );

// Create the texture the frame buffer will draw to
colorTex = glGenTexture();
glBindTexture ( GL_TEXTURE_2D, colorTex );
glTexImage2D  ( GL_TEXTURE_2D, 0, GL_RGBA8, resolution.X, resolution.Y, 0, GL_BGRA, GL_UNSIGNED_BYTE, 0 );
glTexParameter( GL_TEXTURE_2D, GL_MIN_FILTER, GL_NEAREST );
glTexParameter( GL_TEXTURE_2D, GL_MAX_FILTER, GL_NEAREST );
glBindTexture ( GL_TEXTURE_2D, 0 );

// attach the texture to the framebuffer
glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0 );
...

// Create a render buffer
depthRB = glGenRenderbuffer();
glBindRenderbuffer       ( GL_RENDERBUFFER, depthRB );
glRenderbufferStorage    ( GL_RENDERBUFFER, GL_DEPTH_STENCIL, resolution.X, resolution.Y );

// Attach it to the framebuffer
glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRB );

glBindRenderbuffer( GL_RENDERBUFFER, 0 );

// Check for success
errCode = glCheckFramebufferStatus( GL_FRAMEBUFFER );
if ( errCode != GL_FRAMEBUFFER_COMPLETE )
    ...error();
glBindFramebuffer( GL_FRAMEBUFFER, 0 );

One thing that’s immediately obvious is that you’re creating a DEPTH_STENCIL renderbuffer and only attaching it to the DEPTH attachment. You might try attaching it to the GL_DEPTH_STENCIL_ATTACHMENT. Also, check for GL errors.

On the surface pro no exceptions or warnings are thrown and yet the output is very incorrect …

So please spell it out (in case I missed it): what’s incorrect exactly?

Differences I see (besides the background color):

  1. The apparent sizes of the things rendered in the FBO case (red) is larger vs. the window render (blue).
  2. There’s this odd purple ellipse feature at the same window offset that doesn’t seem to render consistently in both cases.
  3. There’s a white “shell” feature down and right of the ellipse that doesn’t seem to be rendered in the FBO view (or it’s off-screen due to the magnification.

See Issue (43) in EXT_fbo.