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.
Related
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).
I have the following situation:
A non-power-of-two (NPOT) texture, in RGB format.
I add some padding at the right side of my texture to make sure the texture scanlines are a multiple of 4 bytes.
I need mipmap generation.
glGenerateMipmaps() is unreliable (I believe it is actually broken on the Intel HD Graphics 3000 driver from Apple, as it gives wrong results, but correct results on Linux, same device) and slow (again on the Apple driver for my chip, fast on Linux).
To address the last problem, I decided I want to do mipmap generation "manually" using framebuffers with a render to texture approach.
However, I'm stuck at how I should deal with the padding to make the scanlines multiples of four bytes, while having consitent mipmap sampling in the shader. Without mipmaps, I'm using a uniform vec2 that I use to multiply the uv with in order to compensate for the few columns of padding at the right side of the texture. Now, the problem is that at every level of mipmap, I have to do the padding to make the scanlines 4-bytes-aligned; but this padding can be different at every level, which would require me to use a different uv-multiplier for every level, which is something I can't do in a shader, because I want to use automatic LOD (level of detail) selection when sampling.
I guess that this question is equivalent to: "What does a succesfull glGenerateMipmaps algorithm do in my scenario?" The documenation on this function is very short. Actually I'm surprised the Linux driver does the job right, in my complex scenario.
Easy solutions that are not acceptable in my scenario (because of the increase in memory usage):
Use RGBA format such that the scanlines are always 4-bytes-aligned.
Use POT textures such that the scanlines are always 4-bytes-aligned.
I add some padding at the right side of my texture to make sure the texture scanlines are a multiple of 4 bytes.
Well, stop doing that. The article you link to doesn't say "always make your textures aligned to 4 bytes". It says to make sure that your byte alignment in your uploaded texture data matches the pixel pack byte alignment you give to OpenGL.
Just make your texture sizes what you need them to be, then upload the data with the proper alignment. Texture widths do not need to be multiples of 4.
Question:
Why does the same amount of pixels take dramatically less video memory if stored in a square texture than in a long rectangular texture?
Example:
I'm creating 360 4x16384 size textures with the glTexImage2D command. Internal format is GL_RGBA. Video memory: 1328 MB.
If I'm creating 360 256x256 textures with the same data, the memory usage is less than 100MB.
Using an integrated Intel HD4000 GPU.
It's not about the texture being rectangular. It's about one of the dimensions being extremely small.
In order to select texels from textures in an optimal fashion, hardware will employ what's known as swizzling. The general idea is that it will restructure the bytes in the texture so that pixels that neighbor each other in 2 dimensions will be neighbors in memory too. But doing this requires that the texture be of a certain minimum size in both dimensions.
Now, the texture filtering hardware can ignore this minimum size and only fetch from pixels within the texture's actual size is. But that extra storage is still there, taking up space to no useful purpose.
Given what you're seeing, there's a good chance that Intel's swizzling hardware has a base minimum size of 32 or 64 pixels.
In OpenGL, there's not much you can do to detect this incongruity other than what you've done here.
I got confused of how textures work with CUDA
as when I do device Query "on my GTX 780" I find this:
Maximum Texture Dimension Size (x,y,z) 1D=(65536), 2D=(65536, 65536), 3D=(4096, 4096, 4096)
now when I investigated CUDA "particles example", I found this:
checkCudaErrors(cudaBindTexture(0, oldPosTex, sortedPos, numParticles*sizeof(float4)));
where numParticles in my case I have raised it to 1024 * 1024 * 2 (around 2.1 millions)
how does this fit in the 1D texture??
also inside the kernels I've found this "need more explain please as everything here is connected"
texture<float4, 1, cudaReadModeElementType> oldPosTex;
#define FETCH(t, i) tex1Dfetch(t##Tex, i)
at kernel:
float4 pos = FETCH(oldPos, sortedIndex);
now what I need to know also, I can use this texture "with its defined size numParticles*sizeof(float4) in a frame buffer draw instead of drawing a VBO?
how does this fit in the 1D texture?
The texture hardware consists of two main parts, the texture filtering hardware and the texture cache. Texture filtering includes functionality such as interpolation, addressing by normalized floating point coordinates and handling out-of-bounds addresses (clamp, wrap, mirror and border addressing modes). The texture cache can store data in a space filling curve to maximize 2D spatial locality (and thereby the cache hit rate). It can also store data in a regular flat array.
The Maximum Texture Dimension Size refers to limitations in the texture filtering hardware, not the texture caching hardware. And so, it refers to limits you may hit when using functions like tex2D() but not when using functions like tex1Dfetch(), which performs an unfiltered texture lookup. So, code you gave is probably setting things up for tex1Dfetch().
need more explain please as everything here is connected
This question is too broad and may be why your question was downvoted.
now what I need to know also, I can use this texture "with its defined size numParticles*sizeof(float4) in a frame buffer draw instead of drawing a VBO?
This is not a CUDA question as CUDA cannot draw anything. You should look into CUDA OpenGL interop to see if your question is answered there. If it's not, you should create a new question and describe your question more clearly.
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.