What does glTexStorage do?
Asked Answered
D

2

17

The documentation indicates that this "allocates" storage for a texture and its levels. The pseudocode provided seems to indicate that this is for the mipmap levels.

How does usage of glTexStorage relate to glGenerateMipmap? glTexStorage seems to "lock" a texture's storage size. It seems to me this would only serve to make things less flexible. Are there meant to be performance gains to be had here?

It's pretty new and only available in 4.2 so I'm going to try to avoid using it, but I'm confused because its description makes it sound kind of important.

How is storage for textures managed in earlier GL versions? When i call glTexImage2D I effectively erase and free the storage previously associated with the texture handle, yes? and generating mipmaps also automatically handles storage for me as well.

I remember using the old-school glTexSubImage2D method to implement OpenGL 2-style render-to-texture to do some post-process effects in my previous engine experiment. It makes sense that glTexStorage will bring about a more sensible way of managing texture-related resources, now that we have better ways to do RTT.

Datnow answered 10/2, 2012 at 7:35 Comment(2)
"only available in 4.2" It's available in the ARB_texture_storage extension, which is widely available (or soon will be). NVIDIA supports it in everything going back to the GeForce 6600, and AMD supports it on all HD-class hardware. Bugs aside, you should use it whenever possible.Schall
Since the comment list on the answer is so long I will put it here. Happily, on Apple hardware, the corresponding EXT_texture_storage extension is supported on "all SGX Series 5 processors", and also I'll point out that glTexStorage is in core GL ES 3.0.Datnow
S
34

To understand what glTexStorage does, you need to understand what the glTexImage* functions do.

glTexImage2D does three things:

  1. It allocates OpenGL storage for a specific mipmap layer, with a specific size. For example, you could allocate a 64x64 2D image as mipmap level 2.
  2. It sets the internal format for the mipmap level.
  3. It uploads pixel data to the texture. The last step is optional; if you pass NULL as the pointer value (and no buffer object is bound to GL_PIXEL_UNPACK_BUFFER), then no pixel transfer takes place.

Creating a mipmapped texture by hand requires a sequence of glTexImage calls, one for each mipmap level. Each of the sizes of the mipmap levels needs to be the proper size based on the previous level's size.

Now, if you look at section 3.9.14 of the GL 4.2 specification, you will see two pages of rules that a texture object must follow to be "complete". A texture object that is incomplete cannot be accessed from.

Among those rules are things like, "mipmaps must have the appropriate size". Take the example I gave above: a 64x64 2D image, which is mipmap level 2. It would be perfectly valid OpenGL code to allocate a mipmap level 1 that used a 256x256 texture. Or a 16x16. Or a 10x345. All of those would be perfectly functional as far as source code is concerned. Obviously they would produce nonsense as a texture, since the texture would be incomplete.

Again consider the 64x64 mipmap 2. I create that as my first image. Now, I could create a 128x128 mipmap 1. But I could also create a 128x129 mipmap 1. Both of these are completely consistent with the 64x64 mipmap level 2 (mipmap sizes always round down). While they are both consistent, they're also both different sizes. If a driver has to allocate the full mipmap chain at once (which is entirely possible), which size does it allocate? It doesn't know. It can't know until you explicitly allocate the rest.

Here's another problem. Let's say I have a texture with a full mipmap chain. It is completely texture complete, according to the rules. And then I call glTexImage2D on it again. Now what? I could accidentally change the internal format. Each mipmap level has a separate internal format; if they don't all agree, then the texture is incomplete. I could accidentally change the size of the texture, again making the texture incomplete.

glTexStorage prevents all of these possible errors. It creates all the mipmaps you want up-front, given the base level's size. It allocates all of those mipmaps with the same image format, so you can't screw that up. It makes the texture immutable, so you can't come along and try to break the texture with a bad glTexImage2D call. And it prevents other errors I didn't even bother to cover.

The question isn't "what does glTexStorage do?" The question is "why did we go so long without it."

glTexStorage has no relation to glGenerateMipmap; they are orthogonal functionality. glTexStorage does exactly what it says: it allocates texture storage space. It does not fill that space with anything. So it creates a texture with a given size filled with uninitialized data. Much like glRenderbufferStorage allocates a renderbuffer with a given size filled with uninitialized data. If you use glTexStorage, you need to upload data with glTexSubImage (since glTexImage is forbidden on an immutable texture).

glTexStorage creates space for mipmaps. glGenerateMipmap creates the mipmap data itself (the smaller versions of the base layer). It can also create space for mipmaps if that space doesn't already exist. They're used for two different things.

Schall answered 10/2, 2012 at 8:10 Comment(12)
This is a wonderful answer, thanks! So I should be using glGenerateMipmap on a glTexStorage allocated texture (after I update the top level with glTexSubImage for instance) to perform the correct updating of the mipmap chain? What should I do if I want to change the size or format of a texture that I glTexStorage'd? Will I need to delete the texture entirely and re-create it using the new dimensions? Suppose I enforce the usage pattern in my code that I only ever set the topmost level using glTexImage2D, and always call glGenerateMipmap after. Is completeness ensured?Datnow
@StevenLu: One reason glTexStorage makes the texture immutable is as a big, giant hint that you shouldn't be trying to reallocate a texture's storage. If you want to change the data in the texture, you can do that easily enough with glTexSubImage. But you shouldn't have to make the same texture object bigger or smaller. If you do, then what you want is to create a new texture.Schall
"Is completeness ensured?" Until you break it. So it's ensured as long as you don't change anything once it's set up. I'm of the opinion that the best way to fix errors is to make it impossible for them to happen. If something in an API can cause problems, then change the API so that those problems can't be caused. glTexStorage does that.Schall
You are saying that the best course of action to avoid issues is to avoid reallocating texture storage entirely, rather than assume or pray that glTexImage handles it well for me. That is reasonable and I will keep that in mind.Datnow
You have been very helpful, and I appreciate this a lot. I got confused while reading about glTexStorage because it seemed to enforce things a bit better than what was available before, which made it sound important, yet its functionality overlaps with glTexImage. Now I can use glTexStorage and avoid glTexImage entirely, to avoid all those pitfalls!Datnow
I've got one more question. When I do not intend to ever use mipmaps (i.e. this texture is intended as target for FBO) I should still use glTexStorage with levels set to 1? How do I determine how many levels I need normally? Do I have to manually take the log2 of the largest dimension?Datnow
Wow GLEW 1.58 didn't have anything related to glTexStorage in it! The new version does have GL 4.2 though.Datnow
Maybe glTexStorage isn't ready for prime-time yet. On a Intel HD2000 machine (i3-2120), glTexStorage2D produces a segmentation fault with GLEW 1.7.0. The driver has not been updated since Sept of last year.Datnow
@StevenLu: What would you expect for hardware that hasn't had a driver update since September? glTexStorage didn't even exist until August of that same year. And Intel is not the kind of place where they'd be the first to implement this kind of stuff. In general, reliance on Intel drivers is a road to tears.Schall
I can't say I expected much. I guess I need to start checking the function pointers.Datnow
@StevenLu: Just check the extension, using whatever extension loader you're using.Schall
I am revisiting this question since I've transitioned to targeting iOS with my engine now, and damn, this is such a good answer.Datnow
H
2

Before calling glGenerateMipmap​, the base mipmap level must be established. (either with mutable or immutable storage).so...,you can using glTexImage2D+glGenerateMipmap only,more simple!

Haily answered 11/4, 2014 at 7:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.