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);