What is the typical use case for rendering to an image through imageStore? The typical scenario for using a texture would simply be:

//Create texture
glGenTextures(1, &amp;textureID);
glBindTexture(target, textureID);
glTexImage2D(target, 0, color_format, width, height, 0,
    color_format, GL_UNSIGNED_BYTE, data);

glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

//load to program
glActiveTexture(texture_unit);
glBindTexture(target, textureID);
//Get the uniform location in the program and attach the texture unit
GLuint location = /*get_uniform_location*/;
glUniform1i(location,texture_unit - GL_TEXTURE0);

//Draw
render();


However image load store are somewhat different. First, they don't use texture units but image units. Second you need to manually set memory barriers yourself to ensure completion of writing stage before reading. Amgon other things.

I have read the documentation and attempted to implement things myself but It seems I am doing things wrong. I'd rather just forget about what I have tried and understand properly how this needs to be done step by step.

I want to know what a typical, minimum example use of image load stores qould be.

So creation of the image, writing to the image, reading from the image.
I've used imageStore as part of compute shaders doing surface extraction. I've only ever used it in compute shaders, to store the calculated data in a texture to be consumed by another shader - I know it's possible to do imageStore in a fragment shader as well but I haven't come across a use case for it yet.

I also haven't used imageLoad at all, since apparently texelFetch is often faster (benefits from using the texture cache), and at worst no slower, so I simply bound the same texture to both an image and a texture unit, and used imageStore for writes and texelFetch for reads.

The code to get it all working looked something like this (using OpenGL 4.5 and DSA, and assuming cShdr holds a compute program that does imageStore on channel 0, cShdr2 is a second compute program that samples the generated texture on channel 0, and rShdr is a rendering program that samples the texture on channel 0 - of course, if you don't want to hardcode the texture channel in the shader you can use glGetUniformLocation):

//setting up texture and binding to image unit 0
GLuint tex;
glCreateTextures(GL_TEXTURE_2D, 1, &amp;tex);
glTextureStorage2D(tex, 1, GL_RGBA32F, 256, 256)
glBindImageTexture(0, tex, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);

//Dispatch a compute shader to imageStore to the texture
//wait for completion before allowing sampling
glDispatchCompute(cShdr, numX, numY, numZ);
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);

//code that samples the texture in render loop
glBindVertexArray(vao);
glBindTextureUnit(0, tex);
glUseProgram(rShdr);
glDrawArrays(GL_TRIANGLES, 0, numVerts);

//or if consuming data in second compute shader using texelFetch
glBindTextureUnit(0, tex); 
glDispatchCompute(cShdr2, numX, numY, numZ); 


The first 3 parameters to glBindImageTexture are image unit, texture, and mip level. The next two deal with binding arrays of textures, and should just be set to GL_FALSE, 0 when binding a single texture. The final two are access and format (for stores). 

Note that although I've used the GL 4.5-specific functions for creating textures and binding the texture unit, the glBindImageTexture works with every version that supports load/store - 4.2 and above.