Search code examples
c++openglsegmentation-faulttexturesmipmaps

Generating the MipMap levels for a 3D texture after imageStore()


I want to create a 3D texture, set the lowest (level 0) mipmap level to some data that is generated in shaders, and then auto-populate the rest of the mipmap levels.

I create the texture as follows:

//Initialize texture dimensions
width = w;
height = h;
depth = d;
//set the texture rendering target, always GL_TEXTURE3D for 3D images
target = GL_TEXTURE_3D;
//Create the texture
glGenTextures(1, &textureID);
glBindTexture(target, textureID);
glObjectLabel(GL_TEXTURE, textureID, -1, "\"3D Texture\"");
//Set the texture sampling parameters
glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//Allocate VRAM storage for the texture
vector<GLbyte> empty = vector<GLbyte>(width*height*depth*(32));
glTexImage3D(target, 0, GL_RGBA8, width, height, depth, 0,
    GL_RGBA, GL_FLOAT, empty.data());

I then write to it in the shaders using imageStore (works as intended for LOD 0).

And then I attempt to generate the mipmap levels like this:

glDrawArrays(GL_TRIANGLE_STRIP,0,4);
glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);
glGenerateTextureMipmap(textureID);

However, this results in a segmentation fault generated right at glGenerateTextureMipmap().

Am I missing a bit in the memory barrier or am I not allocating enough memory when creating the texture? What am I doing wrong?


Solution

  • You are using glMemoryBarrier in a wrong way. The bitfield you should give to this function is the way you want to use the result. For mipmap generation, there is no need to use memory barrier.

    You are using glGenerateTextureMipmap, but you are not using glCreateTextures. Why do you want to use DSA only sometimes. Use DSA everywhere or do not use it (the same happen for glTextureParameteri, glTextureStorage3D...).

    You are using glTexImage3D, use glTextureStorage3D instead. It will save you the construction of your "useless" vector

    You are using non mipmap filtering, so please use mipmap filtering like GL_NEAREST_MIPMAP_NEAREST. I don't know if it is the cause of the crash, but it is a first idea.

    Tell us what happen when you correct the code ;). Maybe you could give us the output of ARB_DEBUG_OUTPUT if it tells you anything.


    About the crash, it seems that use glTexStorage3D solves the problem. I have no proof and I may be wrong, but I suspect this kind of working : glTexImage3D does not allocate memory, it is the use of the texture that makes the allocation. (That is why I prefer Vulkan, because it is explicit).

    so, when you do a glTexImage3D without glGenerateMipmap3D, here is what happen :

    Use glTexImage3D : say we need the image at this size. Use the texture : driver see that there is no need for mipmapping, so it allocates only one driver despite the GL_TEXTURE_MAX_LEVEL. Call generateMipmap : crash because the driver try to reach the other layers that have not been allocated

    Second way, use generateMipmap before use :

    glTexImage3D + generateMipmap : I need one image to this size with mipmap. When you use it, the driver see that you really need all layers so it will allocates the layers needed.

    When you are using glTextureStorage3D you explicitly ask for the layers, so when the driver makes the allocation, it will allocate everything and not just one