glGenBuffers vs glGenTextures - opengl

What exactly is the difference between glGenBuffers and glGenTextures? I've noticed that both work just fine when I try to generate a texture:
int texture1 = GL30.glGenBuffers();
GL30.glBindTexture(GL30.GL_TEXTURE_2D,texture1);
int texture2 = GL30.glGenTextures();
GL30.glBindTexture(GL30.GL_TEXTURE_2D,texture2);
Both of these seem to behave exactly the same for me. Is there any advantage to using glGenTextures over glGenBuffers? And if not, why does glGenTextures even exist when glGenBuffers can just be used instead?

glGenTextures and glGenBuffers doesn't create any objects or buffers, they just marke object names as used. This means they reserve objects names.
While glGenTextures reserves texture names, glGenBuffers reserves buffer names, but the names returned by glGenTextures may be the same as the names returned by glGenBuffers.
glGenTextures just guarantees that the names which are returned are not used for the purpose of textures.
glGenBuffers guarantees that the names which are returned are not used for the purpose of buffers.
Note, a buffer object and a texture object may have the same value, but there are 2 completely different objects. A name which is returned by glGenBuffers is not marked used (or reserved) for the used as a texture object, but it is reserved for use as a buffer object.
OpenGL ES 3.2 Specification - 8.1 Texture Objects; page 140
The command
void GenTextures( sizei n, uint *textures );
returns n previously unused texture names in textures. These names are marked as used, for the purposes of GenTextures only, but they acquire texture state and a dimensionality only when they are first bound, just as if they were unused.
OpenGL ES 3.2 Specification - 6 Buffer Objects; page 50
The command
void GenBuffers( sizei n, uint *buffers );
returns n previously unused buffer object names in buffers. These names are marked as used, for the purposes of GenBuffers only, but they acquire buffer state only when they are first bound with BindBuffer (see below), just as if they were unused.
Note, the OpenGL ES specification differs here from the (desktop) OpenGL core profile specification.
In (desktop) OpenGL core profile, it is not valid to pass a value to glBindTexture, which was not return by glGenTexture.
See OpenGL 4.6 API Core Profile Specification - 8.1 Texture Objects; page 180
The binding is effected by calling
void BindTexture( enum target, uint texture );
[...]
Errors
[...]
An INVALID_OPERATION error is generated if texture is not zero or a name returned from a previous call to GenTextures, or if such a name has since been deleted.

Related

OpenGL Texture Usage

So recently I started reading through OpenGL wiki articles. This is how I picture OpenGL texturing described from here. Though, several points are not clear yet.
Will following statements be true, false or depends?
Binding two textures to same texture unit is impossible.
Binding two samplers to same texture unit is impossible.
Binding one texture to two different texture units is impossible.
Binding one sampler to two different texture units is impossible.
It is application's responsibility to be clear about what sampler type is passed to what uniform variable.
It is shader program's responsibility to make sure to take sampler as correct type of uniform variable.
number of texture units are large enough. Let each mesh loaded to application occupy as much texture unit as it please.
Some Sampler parameters are duplicate of texture parameters. They will override texture parameter setting.
Some Sampler parameters are duplicate of sampler description in shader program. Shader program's description will override samplers parameters.
I'm going through your statements in the following. Sometimes I will argue with quotes from the OpenGL 4.5 core profile specification. None of that is specific to GL 4.5, I just chose it because that is the most recent version.
1. Binding two textures to same texture unit is
impossible.
If I'd say "false", it would be probably misleading. The exact statement would be "Binding two textures to the same target of the same texture unit is impossible." Technically, you can say, bind a 2D texture and a 3D texture to the same unit. But you cannot use both in the same draw call. Note that this is a dynamic error condition which depends on what values you set the sampler uniforms to. Quote from section 7.10 "Samplers" of the GL spec:
It is not allowed to have variables of different sampler types
pointing to the same texture image unit within a program object. This
situation can only be detected at the next rendering command issued
which triggers shader invocations, and an INVALID_OPERATION error will
then be generated.
So the GL will detect this error condition as soon as you actually try to draw something (or otherwise trigger shader invocations) with that shaders while you configured it such that two sampler uniforms reference different targets of the same unit. But it is not an error before. If you temporarily set both uniforms to the same value but do not try to draw in that state, no error is ever generated.
2. Binding two samplers to same texture unit is impossible.
You probably mean Sampler Objects (as opposed to just "sampler" types in GLSL), so this is true.
3. Binding one texture to two different texture units is impossible.
False. You can bind the same texture object to as many units as there are available. However, that is quite a useless operation. Back in the days of the fixed-function pipeline, there were some corner cases where this was of limited use. For example, I've saw someone binding the same texture twice and use register combiners to multiply both together, because he needed some square operation. However, with shaders, you can sample the texture once and do anything you want with the result, so there is really no use case left for this.
4. Binding one sampler to two different texture units is impossible.
False. A single sampler object can be referenced by multiple texture units. You can just create a sampler object for each sampling state you need, no need to create redundant ones.
5. It is application's responsibility to be clear about what sampler type is passed to what uniform variable.
6. It is shader program's responsibility to make sure to take sampler as correct type of uniform variable.
I'm not really sure what exaclty you are asking here. The sampler variable in your shader selectes the texture target and must also match the internal data fromat of the texture object you want to use (i.e. for isampler or usampler, you'll need unnormalized integer texture formats otherwise results are undefined).
But I don't know what "what sampler type is passed to what uniform variable" is supposed to mean here. As far as the GL client side is concerned, the opaque sampler uniforms are just something which can be set to the index of the texture unit which is to be used, and that is done as an integer via glUniform1i or the like. There is no "sampler type" passed to a uniform variable.
7. number of texture units are large enough. Let each mesh loaded to application occupy as much texture unit as it please.
Not in the general case. The required GL_MAX_TEXTURE_IMAGE_UNITS (which defines how many different texture units a fragment shader can access) by the GL 4.5 spec is just 16. (There are separate limits per shder stage, so there is GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS and so on. They are all required to be at least 16 in the current spec.)
Usually, you have to switch textures inbetween draw calls. The usage of array textures and texture atlasses might allow one to further reduce the number of necessary state switches (and, ultimately, draw calls).
Very modern GPUs also support GL_ARB_bindless_texture, which completely bypasses the "texture unit" layer of indirection and allows the shader to directly reference a texture object by some opaque handle (which basically boils down to referencing some virtual GPU memory address under the hood). However, that feature is not yet part of the OpenGL standard.
8. Some Sampler parameters are duplicate of texture parameters. They will override texture parameter setting.
Yes. Traditionally, there were no separate sampler objects in the GL. Instead, the sampler states like filtering or wrap modes were part of the texture object itself. But modern hardware does not operate this way, so the sampler objects API has been introduced as the GL_ARB_sampler_objects extension (nowadays, a core feature of GL). If a sampler object is bound to a texture unit, its settings will override the sampler state present in the texture object.
9. Some Sampler parameters are duplicate of sampler description in shader program. Shader program's description will override samplers parameters.
I'm not sure what you mean by that. What "sampler descripitons" does a shader program define? There is only the declaration of the uniform and possibly the initialization via layout(binding=...). However, that is just the initial value. The client can update that any time by setting the uniform to another value, so that is not really "overriding" anything. But I'm not sure if you mean that.

Bind an SSBO to a fragment shader

I have a an SSBO which stores vec4 colour values for each pixel on screen and is pre populated with values by a compute shader before the main loop.
I'm now trying to get this data onscreen which I guess involves using the fragment shader (Although if you know a better method for this I'm open to suggestions)
So I'm trying to get the buffer or at least the data in it to the fragment shader so that I can set the colour of each fragment to the corresponding value in the buffer but I cannot find any way of doing this?
I have been told that I can bind the SSBO to the fragment shader but I don't know how to do this? Other thoughts I had was somehow moving the data from the SSBO to a texture but I can't work that out either
UPDATE:
In response thokra's excellent answer and following comments here is the code to set up my buffer:
//Create the buffer
GLuint pixelBufferID;
glGenBuffers(1, &pixelBufferID);
//Bind it
glBindBuffer(GL_SHADER_STORAGE_BUFFER, pixelBufferID);
//Set the data of the buffer
glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4) * window.getNumberOfPixels, new vec4[window.getNumberOfPixels], GL_DYNAMIC_DRAW);
//Bind the buffer to the correct interface block number
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, pixelBufferID);
Then I call the compute shader and this part works, I check the data has been populated correctly. Then in my fragment shader, just as a test:
layout(std430, binding=0) buffer PixelBuffer
{
vec4 data[];
} pixelBuffer
void main()
{
gl_FragColor = pixelBuffer.data[660000];
}
What I've noticed is that it seems to take longer and longer the higher the index so at 660000 it doesn't actually crash its just taking an silly amount of time.
Storage buffers work quite similarly to uniform buffers. To get a sense of how those work I suggest something like this. The main differences are that storage buffer can hold substantially higher amounts of data and the you can randomly read from and write to them.
There are multiple angles of working this, but I'll start with the most basic one - the interface block inside your shader. I will only describe a subset of the possibilities when using interface blocks but it should be enough to get you started.
In contrast to "normal" variables, you cannot specify buffer variables in the global scope. You need to use an interface block (Section 4.3.9 - GLSL 4.40 Spec) as per Section 4.3.7 - GLSL 4.40 Spec:
The buffer qualifier can be used to declare interface blocks (section 4.3.9 “Interface Blocks”), which are then referred to as shader storage blocks. It is a compile-time error to declare buffer variables at global scope (outside a block).
Note that the above mentioned section differs slightly from the ARB extension.
So, to get access to stuff in your storage buffer you'll need to define a buffer interface block inside your fragment shader (or any other applicable stage):
layout (binding = 0) buffer BlockName
{
float values[]; // just as an example
};
Like with any other block without an instance name, you'll refer to the buffer storage as if values were at global scope, e.g.:
void main()
{
// ...
values[0] = 1.f;
// ...
}
On the application level the only thing you now need to know is that the buffer interface block BlockName has the binding 0 after the program has been successfully linked.
After creating a storage buffer object with your application, you first bind the buffer to the binding you specified for the corresponding interface block using
glBindBufferBase(GLenum target​, GLuint index​, GLuint buffer​);
for binding the complete buffer to the index or
glBindBufferRange(GLenum target​, GLuint index​, GLuint buffer​, GLintptr offset​, GLsizeiptr size​);
for binding a subset specified by an offset and a number of of the buffer to the index.
Note that index refers to the binding specified in your layout for the corresponding interface block.
And that's basically it. Be aware that there are certain limits for the storage buffer size, the number of binding points, maximum storage block sizes and so on. I refer you to the corresponding sections in the GL and GLSL specs.
Also, there is a minimal example in the ARB extension. Reading the issues sections of extension also often provides further insight into the exposed functionality and the rationale behind it. I advise you to read through it.
Leave a comment if you run into problems.

When should glVertexAttribPointer be called?

It's not obvious from the documentation when glVertexAttribPointer should be called. It looks like it's part of VBO initialisation, but I notice example code calling it during rendering.
glVertexAttribPointer(vertexAttributeId, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2D), reinterpret_cast<const GLvoid*>(offsetof(Vertex2D, m_x)));
Should glVertexAttribPointer be called during initialisation of a GL_ARRAY_BUFFER or should it be called during rendering (after a call to glBindBuffer)?
The function glVertexAttribPointer specifies the format and source buffer (ignoring the deprecated usage of client arrays) of a vertex attribute that is used when rendering something (i.e. the next glDraw... call).
Now there are two scenarios. You either use vertex array objects (VAOs) or you don't (though not using VAOs is deprecated and discouraged/prohibited in modern OpenGL). If you're not using VAOs, then you would usually call glVertexAttribPointer (and the corresponding glEnableVertexAttribArray) right before rendering to setup the state properly. If using VAOs though, you actually call it (and the enable function) inside the VAO creation code (which is usually part of some initialization or object creation), since its settings are stored inside the VAO and all you need to do when rendering is bind the VAO and call a draw function.
But no matter when you call glVertexAttribPointer, you should bind the corresponding buffer right before (no matter when that was actually created and filled), since the glVertexAttribPointer function sets the currently bound GL_ARRAY_BUFFER as source buffer for this attribute (and stores this setting, so afterwards you can freely bind another VBO).
So in modern OpenGL using VAOs (which is recommended), it's usually similar to this workflow:
//initialization
glGenVertexArrays
glBindVertexArray
glGenBuffers
glBindBuffer
glBufferData
glVertexAttribPointer
glEnableVertexAttribArray
glBindVertexArray(0)
glDeleteBuffers //you can already delete it after the VAO is unbound, since the
//VAO still references it, keeping it alive (see comments below).
...
//rendering
glBindVertexArray
glDrawWhatever
When not using VAOs it would be something like that:
//initialization
glGenBuffers
glBindBuffer
glBufferData
...
//rendering
glBindBuffer
glVertexAttribPointer
glEnableVertexAttribArray
glDrawWhatever
glVertexAttribPointer is something that does not really belong to the Buffer nor to the Program it is - let's say - the glue between them. (The functionality of this is splitten in Opengl 4.3 in different functions VertexAttrib*Format, VertexAttribBinding and BindVertexBuffer aviable through the ARB_vertex_attrib_binding )
But if you want to say that it is part of something i would say it is part of the VAO that stores the state of which Buffer objects are bound, which attribs are enabled and how the Buffer data has to be passed to the Program.
So it belongs to part where you setup your VAOs.
EDIT
Simple setup that illustrates the order:
creating/setup of Buffers and creating programs
create VAO define which attribs are enabled, which buffers should be bound when the VAO is used and how that data is passed to the program (glVertexAttribPointer)
The association of buffer, generic vertex attribute and shader attribute variable are quite subtle. glVertexAttribPointer establishes this association. See OpenGL-Terminology for a detailed explanation.
Also, the link OpenGL-VBO,shader,VAO shows a working example with the necessary sequence of API calls.
glVertexAttribPointer has to be called (in most cases) when the appropriate (i.e. the one you want to use) VBO is bound. Then last parameter to it is offset in said buffer.
The last parameter is defined particularly nice in the reference manual:
Specifies a offset of the first component of the first generic vertex
attribute in the array in the data store of the buffer currently bound
to the GL_ARRAY_BUFFER target. The initial value is 0.
Appropriate Vertex Pointer Bindings with VBO sources are stored inside VAO, and you should use that if possible.
Short example (excuse my pseudocode):
// Setup
CreateVAO(); BindVAO();
CreateVBO(); BindVBO();
VertexAttribPointer(/*id*/ 0, 3, GL_FLOAT, /*starting at offset*/ 0);
// We have specified Vertex attribute bound to location 0,
// with size of 3 floats, starting at offset 0 of VBO we've just created.
//Draw
BindVAO();
Draw();

Differences and relationship between glActiveTexture and glBindTexture

From what I gather, glActiveTexture sets the active "texture unit". Each texture unit can have multiple texture targets (usually GL_TEXTURE_1D, 2D, 3D or CUBE_MAP).
If I understand correctly, you have to call glActiveTexture to set the texture unit first (initialized to GL_TEXTURE0), and then you bind (one or more) "texture targets" to that texture unit?
The number of texture units available is system dependent. I see enums for up to 32 in my library. I guess this essentially means I can have the lesser of my GPU's limit (which I think is 16 8) and 32 textures in GPU memory at any one time? I guess there's an additional limit that I don't exceed my GPU's maximum memory (supposedly 1 GB).
Am I understanding the relationship between texture targets and texture units correctly? Let's say I'm allowed 16 units and 4 targets each, does that mean there's room for 16*4=64 targets, or does it not work like that?
Next you typically want to load a texture. You can do this via glTexImage2D. The first argument of which is a texture target. If this works like glBufferData, then we essentially bind the "handle"/"texture name" to the texture target, and then load the texture data into that target, and thus indirectly associate it with that handle.
What about glTexParameter? We have to bind a texture target, and then choose that same target again as the first argument? Or does the texture target not need to be bound as long as we have the correct active texture unit?
glGenerateMipmap operates on a target too...that target has to still be bound to the texture name for it to succeed?
Then when we want to draw our object with a texture on it, do we have to both choose an active texture unit, and then a texture target? Or do we choose a texture unit, and then we can grab data from any of the 4 targets associated with that unit? This is the part that's really confusing me.
All About OpenGL Objects
The standard model for OpenGL objects is as follows.
Objects have state. Think of them as a struct. So you might have an object defined like this:
struct Object
{
int count;
float opacity;
char *name;
};
The object has certain values stored in it and it has state. OpenGL objects have state too.
Changing State
In C/C++, if you have an instance of type Object, you would change its state as follows: obj.count = 5; You would directly reference an instance of the object, get the particular piece of state you want to change, and shove a value into it.
In OpenGL, you don't do this.
For legacy reasons better left unexplained, to change the state of an OpenGL object, you must first bind it to the context. This is done with some from of glBind* call.
The C/C++ equivalent to this is as follows:
Object *g_objs[MAX_LOCATIONS] = {NULL};
void BindObject(int loc, Object *obj)
{
g_objs[loc] = obj;
}
Textures are interesting; they represent a special case of binding. Many glBind* calls have a "target" parameter. This represents different locations in the OpenGL context where objects of that type can be bound. For example, you can bind a framebuffer object for reading (GL_READ_FRAMEBUFFER) or for writing (GL_DRAW_FRAMEBUFFER). This affects how OpenGL uses the buffer. This is what the loc parameter above represents.
Textures are special because when you first bind them to a target, they get special information. When you first bind a texture as a GL_TEXTURE_2D, you are actually setting special state in the texture. You are saying that this texture is a 2D texture. And it will always be a 2D texture; this state cannot be changed ever. If you have a texture that was first bound as a GL_TEXTURE_2D, you must always bind it as a GL_TEXTURE_2D; attempting to bind it as GL_TEXTURE_1D will give rise to an error (while run-time).
Once the object is bound, its state can be changed. This is done via generic functions specific to that object. They too take a location that represents which object to modify.
In C/C++, this looks like:
void ObjectParameteri(int loc, ObjectParameters eParam, int value)
{
if(g_objs[loc] == NULL)
return;
switch(eParam)
{
case OBJECT_COUNT:
g_objs[loc]->count = value;
break;
case OBJECT_OPACITY:
g_objs[loc]->opacity = (float)value;
break;
default:
//INVALID_ENUM error
break;
}
}
Notice how this function sets whatever happens to be in currently bound loc value.
For texture objects, the main texture state changing functions are glTexParameter. The only other functions that change texture state are the glTexImage functions and their variations (glCompressedTexImage, glCopyTexImage, the recent glTexStorage). The various SubImage versions change the contents of the texture, but they do not technically change its state. The Image functions allocate texture storage and set the texture's format; the SubImage functions just copy pixels around. That is not considered the texture's state.
Allow me to repeat: these are the only functions that modify texture state. glTexEnv modifies environment state; it doesn't affect anything stored in texture objects.
Active Texture
The situation for textures is more complex, again for legacy reasons best left undisclosed. This is where glActiveTexture comes in.
For textures, there aren't just targets (GL_TEXTURE_1D, GL_TEXTURE_CUBE_MAP, etc). There are also texture units. In terms of our C/C++ example, what we have is this:
Object *g_objs[MAX_OBJECTS][MAX_LOCATIONS] = {NULL};
int g_currObject = 0;
void BindObject(int loc, Object *obj)
{
g_objs[g_currObject][loc] = obj;
}
void ActiveObject(int currObject)
{
g_currObject = currObject;
}
Notice that now, we not only have a 2D list of Objects, but we also have the concept of a current object. We have a function to set the current object, we have the concept of a maximum number of current objects, and all of our object manipulation functions are adjusted to select from the current object.
When you change the currently active object, you change the entire set of target locations. So you can bind something that goes into current object 0, switch to current object 4, and will be modifying a completely different object.
This analogy with texture objects is perfect... almost.
See, glActiveTexture does not take an integer; it takes an enumerator. Which in theory means that it can take anything from GL_TEXTURE0 to GL_TEXTURE31. But there's one thing you must understand:
THIS IS FALSE!
The actual range that glActiveTexture can take is governed by GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS. That is the maximum number of simultaneous multitextures that an implementation allows. These are each divided up into different groupings for different shader stages. For example, on GL 3.x class hardware, you get 16 vertex shader textures, 16 fragment shader textures, and 16 geometry shader textures. Therefore, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS will be 48.
But there aren't 48 enumerators. Which is why glActiveTexture doesn't really take enumerators. The correct way to call glActiveTexture is as follows:
glActiveTexture(GL_TEXTURE0 + i);
where i is a number between 0 and GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.
Rendering
So what does all of this have to do with rendering?
When using shaders, you set your sampler uniforms to a texture image unit (glUniform1i(samplerLoc, i), where i is the image unit). That represents the number you used with glActiveTexture. The sampler will pick the target based on the sampler type. So a sampler2D will pick from the GL_TEXTURE_2D target. This is one reason why samplers have different types.
Now this sounds suspiciously like you can have two GLSL samplers, with different types that use the same texture image unit. But you can't; OpenGL forbids this and will give you an error when you attempt to render.
I'll give it a try ! All this is not that complicated, just a question of terms, hope I'll make myself clear.
You can create roughly as many Texture Objects as there is available memory in your system. These objects hold the actual data (texels) of your textures, along with parameters, provided by glTexParameter (see FAQ).
When being created, you have to assign one Texture Target to one texture object, which represents the type of the texture (GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE, ...).
These two items, texture object and texture target represent the texture data. We'll come back to them later.
Texture units
Now, OpenGL provides an array of texture units, that can be used simultaneously while drawing. The size of the array depends of the OpenGL system, yours has 8.
You can bind a texture object to a texture unit to use the given texture while drawing.
In a simple and easy world, to draw with a given texture, you'd bind a texture object to the texture unit, and you'd do (pseudocode):
glTextureUnit[0] = textureObject
As GL is a state machine, it, alas, does not work this way. Supposing that our textureObject has data for the GL_TEXTURE_2D texture target, we'll express the previous assignment as :
glActiveTexture(GL_TEXTURE0); // select slot 0 of the texture units array
glBindTexture(GL_TEXTURE_2D, textureObject); // do the binding
Note that GL_TEXTURE_2D really depends on the type of the texture you want to bind.
Texture objects
In pseudo code, to set texture data or texture parameters, you'd do for example :
setTexData(textureObject, ...)
setTexParameter(textureObject, TEXTURE_MIN_FILTER, LINEAR)
OpenGL can't directly manipulate texture objects, to update/set their content, or change their parameters, you have to first bind them to the active texture unit (whichever it is). The equivalent code becomes :
glBindTexture(GL_TEXTURE_2D, textureObject) // this 'installs' textureObject in texture unit
glTexImage2D(GL_TEXTURE_2D, ...)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
Shaders
Shaders have access to all the texture units, they don't care about the active texture.
Sampler uniforms are int values representing the index of the texture unit to use for the sampler (and not the texture object to use).
So you have to bind your texture objects to the units you want to use.
The type of the sampler will do the match with the texture target that is used in the texture unit : Sampler2D for GL_TEXTURE_2D, and so on...
Imagine the GPU like some paint processing plant.
There are a number of tanks, which delivers dye to some painting machine. In the painting machine the dye is then applied to the object. Those tanks are the texture units
Those tanks can be equipped with different kinds of dye. Each kind of dye requires some other kind of solvent. The "solvent" is the texture target. For convenience each tank is connected to some solvent supply, and but only one kind of solvent can be used at a time in each tank. So there's a valve/switch TEXTURE_CUBE_MAP, TEXTURE_3D, TEXTURE_2D, TEXTURE_1D. You can fill all the dye types into the tank at the same time, but since only one kind of solvent goes in, it will "dilute" only the kind of dye matching. So you can have each kind of texture being bound, but the binding with the "most important" solvent will actually go into the tank and mix with the kind of dye it belongs to.
And then there's the dye itself, which comes from a warehouse and is filled into the tank by "binding" it. That's your texture.

glGenTextures - is there a limit to the number of textures?

Is there a limit to the number of textures that can be created in OpenGL - that is, with glGenTextures?
I know that there are some limits imposed by GL, eg. the number of textures that can be used in a fragment shader. However, I haven't been able to find any sort of documentation concerning the total number of integer "texture names" that are available to use.
The only limit of glGenTextures is given by the bit width of the texture name (GLint), which is 32 bit; indeed the number of texture names can be so great that you will probably never have problems when generating texture names.
The limit for textures is that of the graphics system's memory. The OpenGL implementation knows the texture size and format only when the application submits texture data using glTexImage2D (and other glTexImage* functions if available), which specifies the width, height and the internal texture format: having those parameters it's possible to determine the memory needed to store the texture data.
To check errors, you should query OpenGL error using glGetError, which returns GL_OUT_OF_MEMORY if the operation fails to allocate the required memory. This error can also be returned by glGenTextures and glTexImage2D etc.
This error is most likely to be returned by glTexImage2D etc., since the memory required for texture allocation is much larger than the memory required for marking a texture name as used.
There is no limit on the number of texture names you can generate. There is a limit on texture memory however, so an implementation can still fail a glGenTextures call due to memory limitations.
So don't create a bunch of texture names and then not use them. Create what you need.