storage of mipmaps in OpenGL - c++

OpenGL version 450 introduces a new function which can be used to allocate memory for a texture2D:
glTextureStorage2D(textureObj,levels,internal_format,width,height);
//here, parameter 'levels' refers to the levels of mipmaps
//we need to set it 1 if we only want to use the original texture we loaded because then there is only one mipmap level
And, there is a function can help us generate mipmaps for a texture conveniently:
glGenerateTextureMipmap(textureObj);
So, I have a question: as I need to speciy the size of the storage when I use glTextureStorage2D, do I need to reserve extra space for later using of glGenerateTextureMipmap as mipmap requires extra memory?
I know that I can use glTexImage2D to avoid this problem, that I can first bind the texture to target GL_TEXTURE_2D, then copy the image's data to the texture's memory by using glTexImage2D which only asks me to give the target mipmap level instead of number of mipmap levels, and finally use glGenerateMipmap(GL_TEXTURE_2D).
I am a little confused about glGenerateMipmap. Will it allocate extra space for generated mipmap levels?

What do you mean by "reserve extra memory"? You told OpenGL how many mipmaps you wanted when you used glTextureStorage2D. When it comes to immutable storage, you don't get to renege. If you say a texture has width W, height H, and mipmap count L, then that's what that texture has. Forever.
As such, glGenerateTextureMipmaps will only generate data for the number of mipmaps you put into the texture (minus the base level).

Related

What is the use of creating texture having width and height equal to Zero?

If Opengl allows to create a texture of width = height = 0 then what is the use of specifying other parameters like Internal Format, Format etc. Secondly what is the use of such texture.
To understand why you would want this, recall that textures have multiple LODs.
By default you effectively have 1000 images with 0 width and 0 height per-texture because of the default Min/Max LOD. That is actually fine, as long as you do not try to apply a mipmap minification filter. Newer versions of GL will refer to a situation where some but not all LODs are allocated as mipmap incomplete rather than calling the entire texture incomplete.
If you look at glTexStorage2D (...) you will notice that it is not possible to create a texture with 0 width, 0 height or 0 LODs because it has to create storage for a complete texture.
You can create mipmap incomplete textures using glTexImage2D (...) if you want and in fact you usually do if you do not set the LOD parameters correctly. Likewise, sizing a texture LOD to 0x0 will effectively free its memory. This allows you to delete your mipmaps without having to re-allocate and send the base LOD to GL.
Whether you find that useful is another matter, but this is something that glTexStorage2D (...) cannot do.

How to determine the width and height of a GL framebuffer object given only the corresponding id

I want to determine the size (width, height) of a framebuffer object.
I created a framebuffer object via
// create the FBO.
glGenFramebuffers(1, &fboId);
How can I get the size of the first color attachment given only the framebuffer object id (fboId)?
Is this possible or do I have tor store the size of the color attachment in an external variable to know later the size of the FBO?
Your question is somewhat confused, as you ask for two different things.
Here's the easy question:
How can I get the size of the first color attachment given only the framebuffer object id (fboId)?
That's simple: get the texture/renderbuffer attached to that attachment, get what mipmap level and array layer is attached, then query the texture/renderbuffer for how big it is.
The first two steps are done with glGetFramebufferAttachmentParameter (note the key word "Attachment") for GL_COLOR_ATTACHMENT0. You query the GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE to get whether it's a renderbuffer or a texture. You can get the renderbuffer/texture name with GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME.
If the object is a renderbuffer, you can then bind the renderbuffer and use glGetRenderbufferParameter to fetch the renderbuffer's GL_RENDERBUFFER_WIDTH and GL_RENDERBUFFER_HEIGHT.
If the object is a texture, you'll need to do more work. You need to query the attachment parameter GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL to get the mipmap level.
Of course, now you need to know how to bind it. If you're using OpenGL versions before 4.4 or without certain extensions, then this is complicated. See, you need to know which texture target type to use. Silly and annoying as this may seem, the only way to determine the target from just the texture object name is to... try everything. Go through each target and check glGetError. The one for which GL_INVALID_OPERATION isn't returned is the right one.
If you have GL 4.4 or ARB_multi_bind available, you can just use glBindTextures (note the "s"), which does not require that you specify the target. And if you have 4.5 or ARB_direct_state_access, you don't need to bind the texture at all. The DSA-style functions don't need the texture target, and it also provides glBindTextureUnit, which binds a texture to its natural internal target.
Once you have the texture bound and it's mipmap level, you use glGetTexLevelParameter to query the GL_TEXTURE_WIDTH and GL_TEXTURE_HEIGHT for that level.
Now, that's the easy problem. The hard problem is what your title asks:
I want to determine the size (width, height) of a framebuffer object.
The size of the renderable area of an FBO is not the same as the size of GL_COLOR_ATTACHMENT0. The renderable area of an FBO is the intersection of all of the sizes of all of the images attached to the FBO.
Unless you have special knowledge of this FBO, you can't assume that the FBO contains only one image or that all of the images have the same size (and if you have special knowledge of the FBO, then quite frankly you should also have special knowledge of how big it is). So you'll need to repeat the above procedure for every attachment (if the type is GL_NONE, then nothing is attached). Then take the intersection of the returned values (ie: the smallest width and height).
In general, you shouldn't have to ask an FBO that you created how big it is. Just as you don't have to ask textures how big they are. You made them; by definition, you know how big they are. You put them in the FBO, so again you know how big it is.

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.

Possible to glTexImage2d an NPOT image onto a Pow-2 texture without extra allocation?

I have discovered that there are still a fair number of drivers out there that don't support NPOT textures so I'm trying to retro-fit my 2D engine (based on OpenTK, which is in turn based on OpenGL) with Texture2D support instead of relying on GL_ARB_texture_rectangle. As part of this I am forcing all NPOTS texture bitmaps to allocate extra space up to the next power-of-2 size so they won't cause errors on these drivers. My question is, do I really have to resize the real bitmap and texture and allocate all that extra memory, or is there a way to tell OpenGL that I want a power-of-2 size texture, but I'm only going to use a portion of it in the upper left?
Right now my call looks like this:
GL.TexImage2D(texTarget, 0, PixelInternalFormat.Rgba8, bmpUse.Width, bmpUse.Height, 0, PixelFormat.Bgra, PixelType.UnsignedByte, bits.Scan0);
This is after I have made bmpUse be a copy of my real texture bitmap with extra space on the right and bottom.
Use glTexImage2D with empty data to initialize the texture and glTexSubImage2D to fill a portion of it with data. Technically OpenGL allows the data parameter given to glTexImage{1,2,3}D to be a null pointer, indicating that the texture object is just to be initializd. It depends on the language binding, if that feature remains supported in the target language – just test what happens if you pass a null pointer.
datenwolf is right on how to initialize the texture with just a partial image, but there are 2 issues with this you need to be aware of:
you need to remap the texture coordinates of your mesh, as the [0-1] texture range of the full texture now also contains uninitialized data, as opposed to your full texture. The useful range is now [0-orig_width/padded_width]
wrapping of your texture will only wrap the whole texture, not your sub-part.

Finding OpenGL texture size in bytes after it was loaded

Hey, I have a texture loaded with glTextImage2D.
I want to get the texture's size after it was loaded to the VRAM, what do I need to do?
My internal format is RGBA and the texture's format varies.
This might be helpful to you and you can probably infer the actual memory usage from it. However, I believe this still is rather an approximation:
http://www.geeks3d.com/20100531/programming-tips-how-to-know-the-graphics-memory-size-and-usage-in-opengl/
(query the total memory usage of OpenGL using NVIDIA or ATI specific extensions)
Also note that from my experience, approximating the memory usage by rough calculation was usually sufficient. Textures "should" be stored either 1,2 or 4 components without any significant overhead. Therefore for a WxH RGBA texture, calculate W*H*4. If you store float textures (i.e. GL_RGBA32F), calculate W*H*4*4. For Mip-Maps, add (1/3) additional memory consumption. Be aware however, that - at least to my knowledge - texture memory can also fragment, possibly leaving you with less available memory as estimated.
Use GetTexLevelParameter, which can give you (for each level):
Width and height *
Depth
Internal format *
Compressed format and relative size
(*) Uses these parameters for computing the texture size (for the specified level).
The single texture memory usage is dependent on the generated mipmaps. Indeed to compute correctly the memory used by a single texture you have to determine the mipmaps related to the textures, and then sum the memory usage for each level.
The mipmap count is determined by the OpenGL specification depending on the texture target: texture arrays elements has their own mipmaps set, each cube face texture has its own mipmap set.
The dimension of the mipmaps are halfed for each level, untill they goes to 1. In the case the dimension are not power of two, they are rounded to the lower integer.