KhronosGroup / OpenGL-Registry

OpenGL, OpenGL ES, and OpenGL ES-SC API and Extension Registry
678 stars 274 forks source link

Blit layered framebuffers #532

Closed bl4ckb0ne closed 1 year ago

bl4ckb0ne commented 2 years ago

I'm trying to copy a cubemap texture between 2 framebuffers using blits. Both framebuffers are complete layered framebuffers with 6 layers each, with the same size.

When doing a simple blit operation, as seen below, only one face is copied.

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst);
glClearColor(1.f, 1.f, 1.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);

glBindFramebuffer(GL_READ_FRAMEBUFFER, dst);
glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);

According to the GLES 3.2 spec 1 9.8 Layered framebuffers

When commands such as ReadPixels read from a layered framebuffer, theimage at layer zero of the selected attachment is always used to obtain pixel values

But the glClear call before the blit behaves differently

When theClearorClearBuffer*commands described in section 15.2.3 areused to clear a layered framebuffer attachment, all layers of the attachment arecleared.

Why is the blit operation only possible on the first layer but the clear is possible on all layers? I there another way to achieve what I want to do? Could an extension fix this?

I'd be happy to draft something if needed to fix this issue.

pdaniell-nv commented 2 years ago

On page 540 of the OpenGL 4.6 core specification when describing glBlitFramebuffer it says:

If the read framebuffer is layered (see section 9.8), pixel values are read from layer zero. If the draw framebuffer is layered, pixel values are written to layer zero. If both read and draw framebuffers are layered, the blit operation is still performed only on layer zero.

To blit non-zero layers you can attach the texture to the framebuffer with glFramebufferTexture3D() or glFramebufferTextureLayer() and specify the layer parameter as non-zero.

bl4ckb0ne commented 2 years ago

I have the following piece of code to achieve what I want but it feels heavy


glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst);
glBindFramebuffer(GL_READ_FRAMEBUFFER, src);

for (int i = 0; i < 6; ++i) {
    glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
        GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, src_tex, 0);

    glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
        GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, dst_tex, 0);

    glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, 
        GL_COLOR_BUFFER_BIT, GL_NEAREST);
}

I'd prefer to have something like this

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst);
glBindFramebuffer(GL_READ_FRAMEBUFFER, src);

// Return GL_INVALID_OPERATION if the number of layers don't match
glBlitFramebufferLayers(0, 0, width, height, 0, 0, width, height, 
        GL_COLOR_BUFFER_BIT, GL_NEAREST);

or this

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst);
glBindFramebuffer(GL_READ_FRAMEBUFFER, src);

for (int i = 0; i < 6; ++i) {
    glBlitFramebufferLayer(0, 0, width, height, 0, 0, width, height, /*layer*/ i,
        GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
pdaniell-nv commented 2 years ago

If you proposed a new extension, what platform(s) would you need it supported? You may need to convince those platforms owners to implement it.

bl4ckb0ne commented 2 years ago

My main target is MESA/Linux, I don't mind going with a MESA extension if other platforms are not interested in this feature.

bl4ckb0ne commented 2 years ago

Im about to draft the extension, what prefix should I use? MESA or anything else?

cubanismo commented 2 years ago

Discussed internally and NVIDIA is interested in this one if it's done as an EXT.

bl4ckb0ne commented 2 years ago

Awesome, I'll be pushing my draft in the beginning of next week.

bl4ckb0ne commented 1 year ago

Should the extension be made against ES2 or ES3? ES2 has GL_NV_framebuffer_blit and GL_ANGLE_framebuffer_blit that could serve as dependancies, but ES3 has glBlitFramebuffer natively.

I also noticed that the file GLES3/gl3ext.h doesnt seems to be generated from the repo.

Perksey commented 1 year ago

I personally don't think EXT extensions should depend on non-EXT/ARB extensions, so ES3 is probably the best one.

bl4ckb0ne commented 1 year ago

I'll prepare a patch to get properly the gl3ext header.

oddhack commented 1 year ago

Should the extension be made against ES2 or ES3? ES2 has GL_NV_framebuffer_blit and GL_ANGLE_framebuffer_blit that could serve as dependancies, but ES3 has glBlitFramebuffer natively.

I also noticed that the file GLES3/gl3ext.h doesnt seems to be generated from the repo.

We don't generate a gl3ext.h - there is an empty one floating about that has some ancient history of being related to Mesa though I don't recall the details any more. In any event, extensions in gl.xml are tagged for gles2, gles1, gl, glcore, but nothing else.

bl4ckb0ne commented 1 year ago

Yeah that's what i understood when trying to generate the header with gles3. Is the file not generated because nobody made a gles3 ext yet?