cant write to imageCube from compute shader

hey!

i’m having trouble with image texture of type GL_TEXTURE_CUBE_MAP. i want to generate a random cubemap image using a compute shader. but it doesnt work as i’ve expected.

this is the compute shader:


#version 450 core

layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

layout (binding = 2) uniform writeonly imageCube img1;

layout (std430, binding = 3) buffer TESTBUFFER { vec4 testvalue[]; };

void main()
{
	/* check if i can write to shader storage buffer */
	testvalue[0] = vec4(5, 6, 7, 8);
	/* OK, that works, i've checked the buffer data offline */
	
	/* check if i can write a texel into a image cubemap */
	ivec3 texel = ivec3(0, 0, 0);
	vec4 color = vec4(1, 1, 1, 1);
	imageStore(img1, texel, color);
	/* NOT WORKING */
}

i compiled it and linked it successfully, i’m then running it once:


    glBindImageTexture(2, texture_skybox, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA8);

    vec4 testvalue(1, 2, 3, 4);
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 3, buffer_test);
    glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vec4), value_ptr(testvalue), GL_DYNAMIC_DRAW);

    glUseProgram(program_generate);
    glDispatchCompute(1, 1, 1);
    glUseProgram(0);

    vec4 result(0, 0, 0, 0);
    glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(vec4), value_ptr(result));
    cout << "" << result.x << "  " << result.y << "  " << result.z << "  " << result.w << "  " << endl;

    glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);

as you can see, i’m checking if the compute shader has been invoked, i’ve added a test SSBO and the compute shader writes a certain value into it, that value (5, 6, 7, 8) is what’s printed out to the console.

i’ve also bound the already made cubemap to image unit 2, but writing to it doesnt work at all
here is the cubemap:


    unsigned int resolution = 4;
    glBindTexture(GL_TEXTURE_CUBE_MAP, texture_skybox);
    glTexStorage2D(GL_TEXTURE_CUBE_MAP, 1, GL_RGBA8, resolution, resolution);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    struct Texel { GLubyte R, G, B, A; };
    vector<Texel> red(resolution * resolution, { 255, 0, 0, 255 });
    vector<Texel> green(resolution * resolution, { 0, 255, 0, 255 });
    vector<Texel> blue(resolution * resolution, { 0, 0, 255, 255 });
    //vector<Texel> yellow(resolution * resolution, { 255, 255, 0, 255 });
    glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 0, 0, 0, 0, resolution, resolution, GL_RGBA, GL_UNSIGNED_BYTE, red.data());
    glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 1, 0, 0, 0, resolution, resolution, GL_RGBA, GL_UNSIGNED_BYTE, red.data());
    glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 2, 0, 0, 0, resolution, resolution, GL_RGBA, GL_UNSIGNED_BYTE, green.data());
    glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 3, 0, 0, 0, resolution, resolution, GL_RGBA, GL_UNSIGNED_BYTE, green.data());
    glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 4, 0, 0, 0, resolution, resolution, GL_RGBA, GL_UNSIGNED_BYTE, blue.data());
    glTexSubImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + 5, 0, 0, 0, resolution, resolution, GL_RGBA, GL_UNSIGNED_BYTE, blue.data());
    glBindTexture(GL_TEXTURE_CUBE_MAP, 0);

    glBindTextureUnit(1, texture_skybox);

drawing the cubemap works just fine, the resolution is very low (4 x 4) so that i can see each texel. i’m looking to every corner but i dont see any changed texel :dejection:

i’m also checking for GL errors, i dont get any.

EDIT:
another test to verify that the image sampler has access to the texture: i’m writing:

testvalue[0] = vec4(imageSize(img1), 7, 8);

and it prints me 4, 4, 7, 8, to the console, which means that the computeshader has access to the cubemap texture

what else can i do to check / verify what could be wrong with my code ??

thanks in advance!

Either set the layered parameter to GL_TRUE, or change the variable type to image2D.

If a texture has multiple layers (cube map faces are considered layers) but you only bind a single layer, the GLSL image variable needs to match the “shape” of the layer rather than of the texture. For a cube map, each layer (face) is a 2D texture.

§8.26 of the OpenGL 4.5 specification says:

If the texture identified by texture is a one-dimensional array, two-dimensional array, three-dimensional, cube map, cube map array, or two-dimensional multisample array texture, it is possible to bind either the entire texture level or a single layer or face of the texture level. If layered is TRUE, the entire level is bound. If layered is FALSE, only the single layer identified by layer will be bound. When layered is FALSE, the single bound layer is treated as a different texture target for image accesses:

[ul]
[li] one-dimensional array texture layers are treated as one-dimensional textures;
[/li]> [li] two-dimensional array, three-dimensional, cube map, cube map array texture layers are treated as two-dimensional textures; and
[/li]> [li] two-dimensional multisample array textures are treated as two-dimensional multisample textures.
[/li]> [/ul]

and:

Additionally, there are a number of cases where image load, store, or atomic operations are considered to involve a format mismatch. In such cases, undefined values will be returned by image loads and atomic operations and undefined values will be written by stores and atomic operations. A format mismatch will occur if:

[ul]
[li] the type of image variable used to access the image unit does not match the target of a texture bound to the image unit with layered set to TRUE;
[/li]> [li] the type of image variable used to access the image unit does not match the target corresponding to a single layer of a multi-layer texture target bound to the image unit with layered set to FALSE;
[/li]> …
[/ul]

changed the layered parameter to GL_TRUE, and … it works!! :slight_smile: thanks very much, i thought its the other way around, changing it to true would only bind only a certain layer / face :doh: