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.
Registry Link#
https://www.khronos.org/registry/gles/extensions/IMG/IMG_framebuffer_downsample.txt
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);