GL_IMG_framebuffer_downsample#

Supported Hardware#

Series6, Series6XE, Series6XT

Valid APIs#

OpenGL ES 2.0, 3.0, 3.1

Description#

This extension introduces the ability to attach colour buffers to a framebuffer that are at a lower resolution than the framebuffer itself, with the GPU automatically downsampling the colour attachment to fit.

This can be useful for various post-process rendering techniques where it is desirable to generate downsampled images in an efficient manner, or for a lower resolution post-process technique.

This extension exposes at least a 2 x 2 downscale. Other downsampling modes may be exposed on the system and this can be queried.

Example#

GLint xDownscale = 1;
GLint yDownscale = 1;
// Select a downscale amount if possible
if (extension_is_supported("GL_IMG_framebuffer_downsample")
{
    // Query the number of available scales
    GLint numScales;
    glGetIntegerv(GL_NUM_DOWNSAMPLE_SCALES_IMG, &numScales);
    // 2 scale modes are supported as minimum, so only need to check for
    // better than 2x2 if more modes are exposed.
    if (numScales > 2)
    {
        // Try to select most aggressive scaling.
        GLint bestScale = 1;
        GLint tempScale[2];
        GLint i;
        for (i = 0; i < numScales; ++i)
        {
            glGetIntegeri_v(GL_DOWNSAMPLE_SCALES_IMG, i, tempScale);
            // If the scaling is more aggressive, update our x/y scale values.
            if (tempScale[0] * tempScale[1] > bestScale)
            {
                xDownscale = tempScale[0];
                yDownscale = tempScale[1];
            }
        }
    }
    else
    {
        xDownscale = 2;
        yDownscale = 2;
    }
}
// Create depth texture. Depth and stencil buffers must be full size
GLuint depthTexture;
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT16, width, height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// Create a full size RGBA texture with single mipmap level
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// Scale the width and height appropriately.
GLint scaledWidth = width / xDownscale;
GLint scaledHeight = height / yDownscale;
// Create a reduced size RGBA texture with single mipmap level
GLuint scaledTexture;
glGenTextures(1, &scaledTexture);
glBindTexture(GL_TEXTURE_2D, scaledTexture);
glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGBA4, scaledWidth, scaledHeight);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
// Create framebuffer object, attach textures
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_TEXTURE_2D, depthTexture);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, texture, 0);
glFramebufferTexture2DDownsampleIMG(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
GL_TEXTURE_2D, scaledTexture, 0, xDownscale, yDownscale);
// Handle unsupported cases
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
    ...
}
// Draw to the texture
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
...
// Discard the depth renderbuffer contents if possible/available
if (extension_supported("GL_EXT_discard_framebuffer"))
{
    GLenum discard_attachments[] = { GL_DEPTH_ATTACHMENT };
    glDiscardFramebufferEXT(GL_FRAMEBUFFER, 1, discard_attachments);
}
/*
Draw to the default framebuffer using the textures with various post
processing effects.
*/
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, scaledTexture);