In “vanilla” bound textures mode, you bind a texture, you bind a sampler object to a texture unit, you draw.
In bindless textures…what happens with the sampler? Sampler objects are convenient for changing the texture filtering mode on the fly with little hassle.
So… is there any way to somehow “attach” a sampler object when using bindless? Or should I just alter all bindless textures’ filtering parameters individually?
See this page in the OpenGL wiki:
and search for+highlight the word “sampler”.
A bindless texture handle can be generated from a texture and sampler object. But bindless texture handles need to be immutable; you can’t change their state. So the sampler state is permanently baked into the bindless texture handle at the moment you create it.
So you don’t have the ability to willy-nilly change what sampler you’re using whenever. You can create multiple handles with the same texture using different sampler objects, but that’s it.
Thanks a lot for all the replies. I originally read the ARB text but after going back to the wiki page, here’s the critical piece of information that I missed:
glGetTextureSamplerHandleARB(GLuint texture, GLuint sampler);
I missed the
GLuint texture parameter and thus I was unable to figure out how both a bindless texture and sampler object could work with each other.
About the immutable state, I guess I’ll have to experiment with making non-resident, changing state, making resident again and see if this is reasonably applicable in real-time. Ending up with a different handle value is no big deal in my use case.
You can’t do that. It becomes immutable when you get a handle, not when you make it resident. The immutability is permanent; it cannot be undone.
The linked article says all of this as well.
Understood. I have created a set of sampler objects for each combination of texture filtering and texture repeat (8 in my case). Thus, for each texture, we get 8 handles.
Now I have to think whether I should make all of them resident for each texture (it helps if one changes filtering/wrapping for all textures) or just have users set these properties for an individual texture and make the appropriate handle resident and all the rest non-resident (is this OK in real-time?)
I am using texture atlases so I don’t expect the engine to end up with thousands of small textures (and thus lots of handles). I’m not sure what the best approach is here.
Why would you do that? It’s rare to use a single texture with multiple wrap modes or multiple filter modes. Typically, the nature of the texture determines whether you want wrapping and what type of filter you want.
If you’re trying to design an ultra-general-purpose system where all decisions get deferred to the point of use … don’t do that. The hardware wants to be told what it’s going to do well in advance of actually doing it.
Unfortunately I don’t have a choice. This is about a (mostly) 2D engine and users should have the option to change texture filter mode as they see fit at any point. I have released several commercial games and I have found that at some point I needed to do the same thing. So what remains is to find the best solution when using bindless textures.
Bonus question: If I have a texture T and samplers S1 and S2 and I do this:
- Create handle H1 from T + S1, make resident
- Make H1 non-resident, delete S1
- Create handle H2 from T + S2, make resident
Can I reasonably expect H1 to be removed from memory? The doc says:
Texture and image handles are not
deleted until either the underlying texture or sampler object used to
create the handle are deleted.
I guess this means that even if one of the two components is deleted, the handle goes away. Right?
It’s best to just keep S1 around. There aren’t that many useful permutations of samplers anyway (outside of depth comparison values), so you may as well just keep it there. And if you use the same texture+sampler, you get the same handle value back. So if there’s a chance you’re going to need T + S1 (or a sampler equivalent to it) again, just don’t get rid of S1 to begin with.
This is actually what I ended up doing. I have a permanent set of 8 samplers for all the state combinations I need. A single handle is created for each texture using the “default” sampler (linear + wrap) and is made resident.
If a user wants to switch to another filtering mode for example, another handle is generated using another of these 8 samplers. The former handle becomes non-resident and the new handle becomes resident.
Usually when users need to switch filtering modes each frame (for a special effect/shader) they just go between nearest and linear. Since the provided handle is the same for the same objects, I don’t expect any unnecessary memory bloat. An initial run where an object’s Draw event has this kind of constant filtering switch each frame shows no adverse effects. I will test some more and report back if I find any negative side effects.