Very strange problem with Texture Units

Started by
10 comments, last by CirdanValen 7 years, 1 month ago

I have the following code:


    BindTextureUnit(&editor->devTexture, 0);
    BindTextureUnit(&editor->renderBuffer, 1);
    BindTextureUnit(&editor->lightBuffer, 2);
    BindTextureUnit(&editor->uiSprites, 3);
    GLenum err = glGetError();    

Which consists of:


_INTERNAL void
BindTextureUnit(Texture* texture, u32 unit)
{
    glActiveTexture(GL_TEXTURE0 + unit);
    glBindTexture(GL_TEXTURE_2D, texture->handle);
    texture->unit = unit;
}

This section before the game loop is the only place where I bind textures to texture units. Rest of the time I set the sampler in shaders. Also note that the GL Error is set to 0 through all of this.

The first three textures work as expected, no problems. I recently added the fourth texture "uiSprites". When I render anything with that texture, it comes out white. Now supposedly my GPU can handle 192 texture units, so I'm not running out...but for some reason the texture units above 2 don't work properly.

Here is what I've found in my investigations

- I know for sure that the textures are being loaded correctly. If I put uiSprites into the first texture unit, it renders correctly. Similarly, if I put devTexture into the 3rd unit, it renders white.

- If I comment out the first line, where devTexture is being bound, then I bind uiSprites to unit 0 AFTER binding the renderBuffer and lightBuffer...the texture is rendered as white. This means that the only time binding to texture unit 0 works is if I do it before the other two.

renderBuffer and lightBuffer are both Framebuffers and work correctly the whole time while testing this. I'm wracking my brain trying to figure out why a) the 3rd texture unit is white b) why is this order dependent?

Advertisement

RenderDoc may give you some insight into what exactly the pipeline is seeing and where. Personally, I'm suspicious that you're not setting the sampler assignments correctly for the shader, since you still need to assign samplers to units.

SlimDX | Ventspace Blog | Twitter | Diverse teams make better games. I am currently hiring capable C++ engine developers in Baltimore, MD.

Basically, I store the assigned texture unit in the Texture struct as seen above. When I go to set the uniform in the texture, I use that texture.unit.


_INTERNAL void
UseTexture(RenderContext* context, Texture texture, u32 loc)
{
    if(context->cmdBufferSize > 0)
    {
        ASSERT(!"InvalidPath");
    }
    glUniform1i(loc, texture.unit);
}

The render part looks like this


glClearColor(0.0f, 0.0f, 0.0f, 1.f);
BeginRenderPass(&editor->renderContext, editor->spriteShader, SPRITE_SHADER_UNIFORM_TRANSFORM_MAT, viewMatrix, editor->renderBuffer);
{
    UseTexture(&editor->renderContext, editor->devTexture, SPRITE_SHADER_UNIFORM_TEXTURE);
    PushVertexBuffer(&editor->renderContext, editor->floorVbo, 6, RenderMode_Triangles);  
}
EndRenderPass(&editor->renderContext); 

So all I do to test this is change editor->devTexture to editor->uiSprite. devTexture works, uiSprite doesn't. The same shader is used, so the sampler location doesn't change.

Renderdoc doesn't work on my application for some reason (Doesn't support OpenGL 4.5?). But i can use GLintercept to post the GL calls log if needed.

Quick update: I went through and did glBindTexture(GL_TEXTURE_2D, 0) after creating the frame buffers. Now instead of being white, the texture comes out as black. Same order dependency as before. Calling glGetError() at the end of the game loop still returns 0.

random guess from the dark: it's trying to mipmap a texture that doesn't have mipmaps, i.e. it has nothing to do with texture units and all to do with how you're using the texture bound to the unit.

Are you using OpenGL sampler objects, or traditional glTexParameter ?

If you can't find anything, look for something else.

regular tex parameters


_INTERNAL Texture
CreateTexture(Bitmap bitmap, b32 convertToLinear) 
{
    Texture result = {};
    result.handle = UINT_MAX;
    result.width = bitmap.width;
    result.height = bitmap.height;




    glGenTextures(1, &result.handle);
    glBindTexture(GL_TEXTURE_2D, result.handle);


    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);


GLenum colorType = (convertToLinear) ? GL_SRGB8_ALPHA8 : GL_RGBA;


    glTexImage2D(GL_TEXTURE_2D, 0, colorType, bitmap.width, bitmap.height, 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, bitmap.pixels);


    glBindTexture(GL_TEXTURE_2D, 0);


    return result;
}

EDIT: here's the GL command call log http://pastebin.com/0xxVqDQq

Couple more points to add:

Another strange discovery I found is that if I comment out the last texture bind, by doing this:


    BindTextureUnit(&editor->devTexture, 0);
    BindTextureUnit(&editor->renderBuffer, 1);
    BindTextureUnit(&editor->lightBuffer, 2);
    //BindTextureUnit(&editor->uiSprites, 3);

The first texture, devTexture at unit 0, renders as black. If I uncomment it, it works fine.

Secondly, I have a previous revision of this code that works with all four texture units bound. The difference between this code base and the previous one, is this one I have converted to 3D rendering with depth testing. This is how I build the frame buffers with depth texture:


_INTERNAL RenderBuffer 
CreateRenderBuffer(u32 width, u32 height, b32 hasDepthBuffer = true) 
{
    RenderBuffer result = {};


    result.width = width;
    result.height = height;


    glGenFramebuffers(1, &result.fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, result.fbo);


    glGenTextures(1, &result.texture);
    glBindTexture(GL_TEXTURE_2D, result.texture);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);


    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
                 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, result.texture, 0);


    
    if(hasDepthBuffer)
    {
        glGenTextures(1, &result.depth);
        glBindTexture(GL_TEXTURE_2D, result.depth);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);        


        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0,
                     GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);    


        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, result.depth, 0);        
    } 


    GLenum drawBuffers[1] = {
       GL_COLOR_ATTACHMENT0
    };    


    glDrawBuffers(1, drawBuffers);
    
    GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    ASSERT(fboStatus == GL_FRAMEBUFFER_COMPLETE);
    
    glBindTexture(GL_TEXTURE_2D, 0);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);


    return result;
}

Could the two be somehow related? I've double checked the generated texture IDs and none of them are overlapping. No gl errors even after multiple frames and the frambuffers don't trigger the assert.

Hi, do you sample your depth texture with a samplerShadow ?
This is usually what I use the compare func for, and except for that, I don't use it.

If you can't find anything, look for something else.

I don't touch the depth texture at all after creating it, aside from clearing it every frame.

This topic is closed to new replies.

Advertisement