How do you use textures with direct state access in OpenGL?

I have the following in my code, which seems to work:

GLuint textureHandle;
glGenTextures(1, &textureHandle);
glBindTexture(GL_TEXTURE_2D, textureHandle);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, imageW, imageH, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);

However, when I replace it with the following everything just becomes black:

GLuint textureHandle;
glCreateTextures(GL_TEXTURE_2D, 1, &textureHandle);
glTextureImage2DEXT(textureHandle, GL_TEXTURE_2D, 0, GL_RGBA8, imageW, imageH, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
glTextureParameteri(textureHandle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

3 Answers 3


You still have to bind the desired texture to the texture unit to use it for rendering. In your current code, you're not specifying which texture to use for rendering, so the GL driver doesn't know which one you want to use and is defaulting to "no texture".

There are a few ways to bind a texture. You can keep using glActiveTexture+glBindTexture as in your non-DSA code, or you can use either glBindTextures or glBindTextureUnit.

For example, with glBindTextureUnit, do this:

glBindTextureUnit(0, textureHandle);

The first parameter is the texture unit to bind to.

By the way, instead of using glTextureImage2DEXT (which is from the old and deprecated EXT_direct_state_access extension), it's probably better to stick with core OpenGL calls. You can initialize the texture by using glTextureStorage2D to allocate the memory and set the format, then glTextureSubImage2D to upload the data.

(Here's an article with more on the differences between EXT_direct_state_access and the newer core version of the functionality, if you're interested.)

  • 1
    $\begingroup$ "You might want to convert your code to use that if possible" His code is using that. glCreateTextures is specific to the ARB_DSA function. He's using an odd mixture of the two, likely because he couldn't find a glTextureImage2D in the ARB version (since the ARB wants to discourage non-immutable textures). $\endgroup$ Jan 6, 2017 at 1:11
  • 1
    $\begingroup$ @NicolBolas Aha, thanks, I hadn't caught that. I've updated the answer again. $\endgroup$ Jan 6, 2017 at 3:12
  • $\begingroup$ hey please help, can i use gltexturesubimage2d without using gltexturestorage2d? because i need to re set data with different width and heights $\endgroup$
    – ihsan
    Dec 30, 2022 at 15:25
  • $\begingroup$ @ihsan You can use glTexImage2D in that case. $\endgroup$ Dec 30, 2022 at 23:21

I have now replaced it with the following, which works:

GLuint textureHandle;
glCreateTextures(GL_TEXTURE_2D, 1, &textureHandle);
glTextureStorage2D(textureHandle, 1, GL_RGBA8, imageW, imageH);
glTextureSubImage2D(textureHandle, 0, 0, 0, imageW, imageH, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
glTextureParameteri(textureHandle, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTextureUnit(0, textureHandle);

Just to show a 1:1 comparison to help people easily understand the new functions:
1). create 2). bind 3). allocate 4). upload

1: glGenTextures(1,&tex);
2: glBindTexture(GL_TEXTURE_2D,tex);
3: glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, w,h, 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);
4: glTexSubImage2D(GL_TEXTURE_2D, level, x,y,w,h, GL_BGRA, GL_UNSIGNED_BYTE, data);

1: glCreateTextures(GL_TEXTURE_2D,1,&tex);
2: // glBindTextureUnit(unit, tex);
3: glTextureStorage2D(tex, levels, GL_RGBA8, w,h);
4: glTextureSubImage2D(tex, level, x,y,w,h, GL_BGRA, GL_UNSIGNED_BYTE, data);

Much cleaner. We don't need to bind. We just allocate our texture levels, then upload to them.

Also with glBindTextureUnit we don't need glActiveTexture.
And the equivalent of glTextureStorage2D in the old code would actually be:

for(int i=0; i<levels; i++) glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, max(1,w>>i),max(1,h>>i), 0, GL_BGRA, GL_UNSIGNED_BYTE, nullptr);

Of course you'd still need such a loop if you are uploading different levels manually.

Also here's some other dsa texture functions to use instead:
glTextureParameteri and glGenerateTextureMipmap


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.