Repeating sub texture images

Although, this might be doable in a fragment shader(never tried myself), a simple way to declare that a sub rectangle of a texture image will be repeated across just that sub rectangles uvs (i.e. without repeating into its neigbor’s space), or from the API point of view, to be able to treat sub texture rectangles as full fledged textures with unique texture ids and uvs ranging from 0 to 1 and the wrap modes clamp, and of course repeat, and whatever else makes sense. This would have helped me when I was working on a widget library whose skins were stored in a texture atlas. If this is already doable with some older technique, then just shoot me (but explain it to me first please).

If ou really need this. then it could be done by repeating geometry. Instead of one quad with such sub-texture repeated you should draw multiple rectangles with the same fragment of texture.
Proper GUI library should automatically assign given theme images to textures, and if necessarry put them in separate textures.

There is also this new extension called EXT_texture_array, it allows you to bind a whole array of textures that are the same size into one texture, (think of these as 3D textures that can have individual mipmaps).
Though, no individual wrap mode.
GL_EXT_texture_array.txt

Originally posted by crouchingchicken:
…from the API point of view, to be able to treat sub texture rectangles as full fledged textures with unique texture
So, what would your proposed API actually look like?

I took a shot at what a basic texture atlas opengl api might look like.

//first bind the texture you'll use for your atlas
//the texture was created beforehand using glTexImage2D
glBindTexture(GL_TEXTURE_2D, texture);

//generate a texture atlas from bound texture
GLuint atlas;
glGenTextureAtlases(1, &atlas);

//bind the atlas so sub texture can be generated from it
glBindTextureAtlas(atlas);

//generate a sub texture for say, a button
GLuint button1;
glGenTextureAtlasSubTextures(1, &button1);

//bind the sub texture
glBindTextureAtlasSubTexture(button1);//or can I get away with just glBindTexture?

//set whatever properties i like (repeat is nice)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );

//now define where in the atlas the sub texture lives 
//here i must know the texel rectangle in advance(loaded from resource file most likely)
glTextureAtlasSubTexture(xoffset, yoffset, width, height);

//now draw stuff using the atlas
//I don't know if opengl can/should totally abstract the atlas

//case a - user must explicitly call for the atlas
glBindTextureAtlas(atlas);//bind the atlas of the sub textures you intend to draw
glBindTextureAtlasSubTexture(button1);//bind the sub texture and draw
glBegin(GL_QUADS);
	glTexCoord2i(0,0);//uvs are transformed by opengl so that [0,1] maps to the sub texture
	glVertex2i(0,0);
	glTexCoord2i(2,0);//will repeat 2 times
	glVertex2i(20,0);
	glTexCoord2i(2,1);
	glVertex2i(20,10);
	glTexCoord2i(0,1);
	glVertex2i(0,10);
glEnd()
//...bind other sub texture from bound atlas and draw...
//...bind other atlases as needed...

//case b - opengl abstracts the atlas
glBindTexture(GL_TEXTURE_2D, button1);//opengl knows button1 is from an atlas and ensures the atlas texture gets bound
glBegin(GL_QUADS);
	glTexCoord2i(0,0);//uvs are transformed by opengl so that [0,1] maps to the sub texture
	glVertex2i(0,0);
	glTexCoord2i(2,0);//will repeat 2 times
	glVertex2i(20,0);
	glTexCoord2i(2,1);
	glVertex2i(20,10);
	glTexCoord2i(0,1);
	glVertex2i(0,10);
glEnd()

//...
glDeleteTextureAtlases(1, &atlas);
glDeleteTextureAtlasSubTexture(1, &button1);

This can easily be done in the shader so I don’t see the need for adding it to the API.

This is easy to do in the shader for the easy cases. It is very hard to do in the shader for hard cases.

Consider if the texture has mipmap filtering and MIRROR_CLAMP wrap mode on, with some constant border color. You end up writing an entire texture sampler.

When you create that texture, do the mirroring yourself. It certainly is easier than adding a new hw feature.

The question is what problem are we trying to solve? Why do you store textures in an atlas to begin with? Normally this is done to reduce the number of draw calls and/or state changes. But with a glBindTextureAtlasSubTexture() call, then what did we gain? Why not just store it in separate textures to begin with then?

Additionally, if you have mipmaps, defining subrectangles get really tricky to define sensible behavior. If your texture is 4x4, and you defined a 3x3 subtexture, then what texels in the 2x2 mipmap should be included in the mipmapping? How does repeat work in that situation?

As for mirror clamp, that’s easy to implement, you just do clamp(abs(texCoord), 0, 1), then scale-bias to the subrectangle.

No, that’s MIRROR_CLAMP_TO_EDGE. CLAMP is supposed to filter half of the edge texel and half of the constant border color, if LINEAR filtering is used.

Really, it is not trivial to write this in a shader.

Well, I’d say that if(repeat IF) texture atlasing proves to be a useful feature, it ought to be a simple set of fixed functions --not a shader that you must custom write. OpenGL is nice because for basic things it is really easy to use, and I would consider texture atlasing a basic feature.

The main issue it solved for us was limiting video memory use and limiting texture rebinds. If I have 1k small images of varying non-po2 size, is it more memory efficient to pack them as tightly as possible in large textures, limiting white space as much as possible? And will this technique give us better performance by reducing texture binds? We thought that the answer was yes to both these questions so we went the atlas route. A happy side note was that the artists liked this method as well.

I suppose, by the time you guys could add texture atlasing, non-po2 texture support will be common place and the texture memory issue, less important (though it still seems possibly wasteful, and difficult for artists, to put hundreds of little 5x6 or 7x4 or whatever images into individual files). The rebind issue will remain important however(and I don’t think glBindTextureAtlasSubTexture() would have too much overhead if the underlying atlas texture was already bound).

Having said all that, i am definitely going to explorer the shader route on my own accord to see how that will work out, but I wouldn’t force users to write shaders to do this - just provide a simple api to do it for them – that’s basically all I’m requesting.

Originally posted by arekkusu:
[b] No, that’s MIRROR_CLAMP_TO_EDGE. CLAMP is supposed to filter half of the edge texel and half of the constant border color, if LINEAR filtering is used.

Really, it is not trivial to write this in a shader. [/b]
Ok, fine. But then I’d like to hear a usage scenario where you’d see yourself using this particular filter.

Originally posted by crouchingchicken:
Well, I’d say that if(repeat IF) texture atlasing proves to be a useful feature, it ought to be a simple set of fixed functions --not a shader that you must custom write.
Programmability is the future. Fixed function is the past. We don’t need more toggles and switches in the texture units, they are already pretty bloated. If you have a proposal for programmable texture units though I’m all ears.

Originally posted by crouchingchicken:
OpenGL is nice because for basic things it is really easy to use, and I would consider texture atlasing a basic feature.
Texture atlasing is not a basic feature. OpenGL has no such concept. It knows about texturing, and atlasing is just one of many texturing tricks.

Originally posted by crouchingchicken:
The main issue it solved for us was limiting video memory use and limiting texture rebinds. If I have 1k small images of varying non-po2 size, is it more memory efficient to pack them as tightly as possible in large textures, limiting white space as much as possible? And will this technique give us better performance by reducing texture binds?
The answers would be “Yes, probably” and most likely “Not really”. Sure, the overhead might be slightly lower, but you’re still issuing as many draw calls, which is the problem texture atlasing normally tries to solve.

Originally posted by Humus:
I’d like to hear a usage scenario where you’d see yourself using this particular filter.
I don’t have one, and I think it is dubious at best to expect a driver to deal with automatic atlasing.

My point was simply that writing a shader to emulate everything a texture sampler does is hard: eight possible wrap modes * separate S, T, R wrap modes * border color or border texel * two mag filters, six min filters (can have mixed nearest/linear filtering) * per object/unit/fragment bias, and explicit lod or derivatives * base/max level and min/max lod * 1D, 2D, RECT, 3D, CUBE targets * shadow comparison with eight functions = hard, even without anisotropic filtering.