Writing to a compressed texture using a compute shader, with no extra copies
After looking into this for a while, I found out a couple of things:


You cannot avoid a memcpy: You cannot write directly into texture storage allocated for a compressed texture using only OpenGL API calls. This means that you cannot avoid the call to glCompressedTexImage2D with a bound PBO. That being said, you may be able to use a 16-bit RGBA texture and a GLSL image type in your compute shader.
You do need to synchronize memory: In order to make sure that your compute shader finishes writing to your storage buffer, you must make sure that all reads and writes to it finish. This is done by calling glMemoryBarrier with GL_SHADER_STORAGE_BARRIER_BIT.


The full code for something that writes into a buffer to be used as a compressed texture looks like this:

GLuint buffer;
glGenBuffers(1, &amp;buffer);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, buffer);
glBufferStorage(GL_SHADER_STORAGE_BUFFER, tex_size_in_bytes, 0, 0);

glUseProgram(compute_shader_prog);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, compute_shader_bind_point, buffer);
glDispatchCompute(wg_x, wg_y, wg_z);
glMemoryBarrier(GL_SHADER_STORAGE_BUFFER_BIT);

glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer);
glCompressedTexImage2D(GL_TEXTURE_2D, 0, fmt, w, h, 0, tex_size_in_bytes, 0);