Handmade Hero»Forums»Code
60 posts
None
[day 381] problem with passing framebuffer texture to shader
Edited by erpeo93 on
Hi everyone,
yesterday I basically wasted 8 hours trying to figure out what's wrong with the code.
I've followed the depth peeling videos, and everything is ok if I try to blit the separate textures to the screen:

1
2
3
4
5
6
7
8
glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBufferHandles[0] );
    glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
    glViewport(drawRegion.minX, drawRegion.minY, windowWidth, windowHeight);
    glBlitFramebuffer(0, 0, GetWidth(drawRegion), GetHeight(drawRegion),
                      drawRegion.minX, drawRegion.minY,
                      drawRegion.maxX, drawRegion.maxY,
                      GL_COLOR_BUFFER_BIT,
                      GL_LINEAR);


So the framebuffer texture is correctly rendered.

On the other side, I have a stupid shader that just sample a texture and blit it to the screen.
This shader of course works with any other texture, but as soon as I try to pass the handles of the framebuffer color attachment, it's all black.

I really don't know what's happening, on both side everything seems to be working fine, it's the "connection" that isn't working, but I don't know why... those textureHandles are associated to the frame buffer, here is the frameBuffer creation code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
GLuint texHandle[2];
            glGenTextures(2, texHandle);
            glBindTexture( slot, texHandle[0] );
            Assert( glGetError() == GL_NO_ERROR );
            
            glTexImage2D( slot, 0,
                         opengl.defaultFramebufferTextureFormat,
                         GetWidth( drawRegion ), GetHeight( drawRegion ), 0,
                         GL_BGRA_EXT, GL_UNSIGNED_BYTE, 0);
        
            
            Assert(glGetError() == GL_NO_ERROR);
            glBindTexture(slot, texHandle[1]);
            
            glTexImage2D( slot, 0,
                         GL_DEPTH_COMPONENT24,
                         GetWidth( drawRegion ), GetHeight( drawRegion ), 0,
                         GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0);
            
            Assert(glGetError() == GL_NO_ERROR);
            
            glBindTexture(slot, 0);
            
            frameBufferTextures[targetIndex] = texHandle[0];
            frameBufferDepth[targetIndex] = texHandle[1];
            glBindFramebuffer(GL_FRAMEBUFFER, frameBufferHandles[targetIndex]);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, slot, texHandle[0], 0);
            glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, slot, texHandle[1], 0);
            
            GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
            Assert(Status == GL_FRAMEBUFFER_COMPLETE);


And then:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#if 0
    glBindFramebuffer( GL_READ_FRAMEBUFFER, frameBufferHandles[0] );
    glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
    glViewport(drawRegion.minX, drawRegion.minY, windowWidth, windowHeight);
    glBlitFramebuffer(0, 0, GetWidth(drawRegion), GetHeight(drawRegion),
                      drawRegion.minX, drawRegion.minY,
                      drawRegion.maxX, drawRegion.maxY,
                      GL_COLOR_BUFFER_BIT,
                      GL_LINEAR);
#else
    glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 );
    glDisable(GL_DEPTH_TEST);
    RenderSetup setup = {};
    TexturedVertex vertices[] = 
    {
        {{-1.0f, 1.0f, 0, 1.0f} ,{0.0f, 1.0f}, 0xffffffff},
        {{-1.0f, -1.0f, 0, 1.0f} ,{0.0f, 0.0f}, 0xffffffff},
        {{1.0f, 1.0f, 0, 1.0f} ,{1.0f, 1.0f}, 0xffffffff},
        {{1.0f, -1.0f, 0, 1.0f} ,{1.0f, 0.0f}, 0xffffffff},
    };
    
    glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STREAM_DRAW );
    OpenGLUseProgramBegin(&opengl.peelComposite, &setup);
    
    glViewport(drawRegion.minX, drawRegion.minY, windowWidth, windowHeight);
    glClearColor( 1, 0, 0, 1 );
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
    
#if 0
    glActiveTexture( GL_TEXTURE0 );
    glBindTexture( GL_TEXTURE_2D, ( GLuint ) U32FromPointer( opengl.whiteBitmap.textureHandle ) );
    glActiveTexture( GL_TEXTURE1 );
    glBindTexture( GL_TEXTURE_2D, ( GLuint ) U32FromPointer( opengl.whiteBitmap.textureHandle ) );
#else
    glActiveTexture( GL_TEXTURE0 );
    glBindTexture( GL_TEXTURE_2D, frameBufferTextures[0] );
    glActiveTexture( GL_TEXTURE1 );
    glBindTexture( GL_TEXTURE_2D, frameBufferTextures[0] );
#endif
    
    glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );
    
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, 0);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, 0);
    
    OpenGLUseProgramEnd(&opengl.peelComposite);
#endif


Both of the if 0 works fine if switched: The first blits directly the framebuffer to the screen, the second one sample from a simple white texture.
I really don't have any idea what could be happening here.
The white texture is generated in the same exact way:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
GLuint handle;
    glGenTextures( 1, &handle );
    glBindTexture( GL_TEXTURE_2D, handle );
    glTexImage2D(GL_TEXTURE_2D, 0, opengl.defaultSpriteTextureFormat, width, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, data );
    
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );    
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );    
    
    glBindTexture( GL_TEXTURE_2D, 0 );
    


If anyone knows what's happening it would be of real help for me.
Thank you,
Leonardo
Mārtiņš Možeiko
2559 posts / 2 projects
[day 381] problem with passing framebuffer texture to shader
Edited by Mārtiņš Možeiko on
Are you sure you need to bind same texture (frameBufferTextures[0]) to both texture units (GL_TEXTURE0 and GL_TEXTURE1)? I don't remember exactly how this worked in day 381. But I see in video that Casey is binding two different textures - GlobalFramebufferTextures[0] and GlobalFramebufferTextures[1]. See https://youtu.be/JZIQHygH2cc?t=6356

Try following steps:
1) replace shader by pass-through - just sample first texture and draw it to output, nothing else. Does it appear normal?
2) if not, replace output with constant color (red, or blue, whatever) to check if shader and framebuffer bindings work at all.
3) if both things work, do pass-throgh for just second texture. Does it look reasonable?
4) if not, then save textures to disk (bmp or similar) to verify if they look reasonble.
5) modify shader to do something simple, and step by step replace put everything back from original shader until you find line that is wrong (assuming something is wrong with shader).

Btw, have you enabled OpenGL debug reporting? No errors are happening?

60 posts
None
[day 381] problem with passing framebuffer texture to shader
Edited by erpeo93 on
Thank you Martins, actually I tried to bind the same texture to both sample to eliminate one variable from the table.
If basically tried 1, 2 and 3, without success. (I'll try number 4 today and let you know ).

Basically it seems that I have some kind of problem in binding the framebuffer texture/depth buffers to the shaders. (I have the same problem with binding the depth buffer of the first framebuffer to the peel shader).
I have enabled the error reporting, No errors are thrown, in any case.

edit:
I'm also able to get the pixels of the texture in question, calling:

1
2
3
4
5
glBindTexture( GL_TEXTURE_2D, ( GLuint ) frameBufferTextures[0] );
    u8* pixels = ( u8* ) malloc( 1920 * 1080 * 4 );
    memset( pixels, 0, 1920 * 1080 * 4 );
    glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
    free( pixels );


I really don't know how to proceed.
60 posts
None
[day 381] problem with passing framebuffer texture to shader
Problem Found!

I was missing the texture parameters...
1
2
3
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


But why if I miss those I'm unable to see anything?
I mean, Casey didn't put them in episode 381, but he was able to do the composite.
Mārtiņš Možeiko
2559 posts / 2 projects
[day 381] problem with passing framebuffer texture to shader
Edited by Mārtiņš Možeiko on
I believe WRAP_S/T should not change result much, and default value of MAG_FILTER already is GL_LINEAR. That leaves only MIN_FILTER, because its default value is GL_NEAREST_MIPMAP_LINEAR. This means if texture size is smaller than its "native" size, then it will use mipmaps from texture. If you have not uploaded them (or generated) then everything will be black.

Not sure why Casey did not have this on stream though... Maybe his texture sizes or size the texture is being rendered is different from yours?
60 posts
None
[day 381] problem with passing framebuffer texture to shader
Casey had the same exact bug in day 382, and in fact he fixed the problem in the exact same way :)
He also gave his explanation of the bug during the Q&A, precisely at 2:24.
The strange thing is that with his graphic card the bug didn't show up with the first two peel, but appeared only adding multiple peels. (I guess it's not strange at all that different graphic cards behave differently in this kind of situations).

Thank you very much Martin.
Leonardo