| Name | |
| IMG_framebuffer_downsample | |
| Name Strings | |
| GL_IMG_framebuffer_downsample | |
| Contributors | |
| Tobias Hector, Imagination Technologies (tobias.hector 'at' imgtec.com) | |
| Contact | |
| Tobias Hector (tobias.hector 'at' imgtec.com) | |
| Status | |
| Complete | |
| Version | |
| Last Modified Date: August 20, 2015 | |
| Revision: 11 | |
| Number | |
| OpenGL ES Extension #255 | |
| Dependencies | |
| OpenGL ES 2.0 or OES_framebuffer_object are required. | |
| This extension is written against the OpenGL ES 3.0.4 Specification | |
| (August 27, 2014). | |
| This extension has interactions with GL_EXT_multisampled_render_to_texture. | |
| This extension has interactions with OpenGL ES 3.1. | |
| This extension has interactions with GL_EXT_color_buffer_float. | |
| This extension has interactions with GL_EXT_color_buffer_half_float. | |
| Overview | |
| This extension introduces the ability to attach color buffers to a | |
| framebuffer that are at a lower resolution than the framebuffer itself, with | |
| the GPU automatically downsampling the color 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. | |
| IP Status | |
| No known IP claims. | |
| New Procedures and Functions | |
| void FramebufferTexture2DDownsampleIMG( | |
| enum target, enum attachment, | |
| enum textarget, uint texture, | |
| int level, int xscale, int yscale); | |
| void FramebufferTextureLayerDownsampleIMG( | |
| enum target, enum attachment, | |
| uint texture, int level, | |
| int layer, int xscale, int yscale); | |
| New Tokens | |
| Returned by CheckFramebufferStatus: | |
| FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG 0x913C | |
| Accepted by the <pname> parameter of GetBooleanv, GetIntegerv, GetFloatv, | |
| GetInteger64v, and GetInternalFormativ: | |
| NUM_DOWNSAMPLE_SCALES_IMG 0x913D | |
| Accepted by the <target> parameter of GetIntegerv, GetInteger64v, | |
| GetIntegeri_v, GetInteger64i_v and GetInternalFormativ: | |
| DOWNSAMPLE_SCALES_IMG 0x913E | |
| Accepted by the <pname> parameter of GetFramebufferAttachmentParameteriv: | |
| FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG 0x913F | |
| Additions to Chapter 4 of the OpenGL ES 3.0 Specification: | |
| Modify figure 4.1, "Per-Fragment Operations.", to add an additional box | |
| "Downscaling" after "Additional Multisample Fragment Operations". | |
| Add a new section 4.1.11, "Downscaling": | |
| If no multisampling was performed, and downscaling is enabled, fragment | |
| outputs may be optionally downscaled in a similar way to how multiple | |
| samples are resolved. If the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_- | |
| SCALE_IMG is not {1,1}, fragment values are written to an intermediate | |
| buffer. After all other fragment operations have completed, they are | |
| then combined to a produce a single color value, and that value is | |
| written into the corresponding color buffer selected by DrawBuffers. An | |
| implementation may defer the writing of color buffers until a later | |
| time, but the state of the framebuffer must behave as if the color | |
| buffers were updated as each fragment is processed. The method of | |
| combination is not specified. If the framebuffer contains sRGB values, | |
| then it is recommended that an average of samples is computed in a | |
| linearized space, as for blending (see section 4.1.7). Otherwise, a | |
| simple average computed independently for each color component is | |
| recommended. | |
| Add the following to Section 4.4.2 "Attaching Images to Framebuffer Objects" | |
| after the paragraph describing FramebufferTexture2D: | |
| The command | |
| void FramebufferTexture2DDownsampleIMG( | |
| enum target, enum attachment, | |
| enum textarget, uint texture, | |
| int level, uint xscale, uint yscale); | |
| allows a rendering into the image of a texture object that has a lower | |
| resolution than the framebuffer. | |
| target, textarget, texture, and level correspond to the same | |
| parameters for FramebufferTexture2D and have the same restrictions. | |
| attachment corresponds to the same parameter for FramebufferTexture2D, | |
| but must be COLOR_ATTACHMENTn. | |
| xscale and yscale are multiplied by texture's width and height, | |
| respectively, to produce the effective size of the attachment when | |
| rendering. For example, a texture width of 128 with an xscale of 2 would | |
| produce a color attachment with the effective width of 256. xscale and | |
| yscale must be one of the value pairs in DOWNSAMPLE_SCALES_IMG. If the | |
| xscale and yscale value pair is not available on the implementation, | |
| then the error INVALID_VALUE is generated. | |
| The implementation allocates an implicit color buffer for the same | |
| internalformat as the specified texture, and widths and heights from the | |
| specified texture level, multiplied by xscale and yscale. This buffer is | |
| used as the target for rendering instead of the specified texture level. | |
| The buffer is associated with the attachment and gets deleted after the | |
| attachment is broken. | |
| When the texture level is used as a source or destination for any | |
| operation, the attachment is flushed, or when the attachment is broken, | |
| an implicit downsample of the color data from the color buffer to the | |
| texture level may be performed. After such a downsample, the contents | |
| of the color buffer become undefined. | |
| The operations which may cause a resolve include: | |
| * Drawing with the texture bound to an active texture unit | |
| * ReadPixels or CopyTex[Sub]Image* while the texture is | |
| attached to the framebuffer | |
| * CopyTex[Sub]Image*, Tex[Sub]Image*, | |
| CompressedTex[Sub]Image* with the specified level as | |
| destination | |
| * GenerateMipmap | |
| * Flush or Finish while the texture is attached to the | |
| framebuffer | |
| * BindFramebuffer while the texture is attached to the currently | |
| bound framebuffer. | |
| Whether each of the above cause a resolve or not is implementation- | |
| dependent. | |
| Add the following to the sub-section "Attaching Texture Images to a | |
| Framebuffer" after the paragraph describing FramebufferTextureLayer: | |
| The command | |
| void FramebufferTextureLayerDownsampleIMG( | |
| enum target, enum attachment, | |
| uint texture, int level, | |
| int layer, uint xscale, uint yscale); | |
| allows a rendering into a single layer of a texture object that has a | |
| lower resolution than the framebuffer. It operates like a combination of | |
| FramebufferTexture2DDownsampleIMG and FramebufferTextureLayer; it allows | |
| the developer to set scaling values and attaches a single layer of a | |
| three-dimensional or two-dimensional array texture level. | |
| target, attachment, level, xscale and yscale correspond to the same | |
| parameters for FramebufferTexture2DDownsampleIMG and have the same | |
| restrictions. | |
| texture can only be a two-dimensional array texture, but otherwise has | |
| the same restrictions as it does for FramebufferTextureLayer. | |
| layer corresponds to the same parameter for FramebufferTextureLayer and | |
| has the same restrictions. | |
| In the sub-section "Effects of Attaching a Texture Image", change the bullet | |
| list to the following: | |
| * The value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is set to TEXTURE. | |
| * The value of FRAMEBUFFER_ATTACHMENT_OBJECT_NAME is set to texture. | |
| * The value of FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL is set to level. | |
| * If FramebufferTexture2D is called and texture is a cube map texture, | |
| then the value of FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE is set | |
| to textarget; otherwise it is set to the default (NONE). | |
| * If FramebufferTextureLayer is called, then the value of FRAMEBUFFER_- | |
| ATTACHMENT_TEXTURE_LAYER is set to layer; otherwise it is set to zero. | |
| * If FramebufferTexture2DDownsampleIMG or | |
| FramebufferTextureLayerDownsampleIMG is called, then the value of | |
| FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG is set to {xscale, yscale}; | |
| otherwise it is set to {1, 1}. | |
| In section 4.4.4 "Framebuffer Completeness", add the following bullet to the | |
| end of the list in subsection "Framebuffer Attachment Completeness": | |
| * If the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is TEXTURE and the | |
| value of FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG is supported by the | |
| internal format of the attachment (see GetInternalFormativ in section | |
| 6.1.15). | |
| In section 4.4.4 "Framebuffer Completeness", add the following bullet to the | |
| end of the list in subsection "Whole Framebuffer Completeness": | |
| * The value of FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG for all | |
| attachments is {1,1}, or if not, the value of TEXTURE_SAMPLES_EXT or | |
| RENDERBUFFER_SAMPLES for all attachments is zero. | |
| FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_AND_DOWNSAMPLE_IMG | |
| Additions to Chapter 6 of the OpenGL ES 3.0 Specification: | |
| Add the following bullet point to the list in Section 6.1.13 "Framebuffer | |
| Object Queries" describing valid pname values when FRAMEBUFFER_ATTACHMENT_- | |
| OBJECT_TYPE is TEXTURE: | |
| * If pname is FRAMEBUFFER_ATTACHMENT_TEXTURE_SCALE_IMG, then params will | |
| contain two integer values - the downsample scale pair for that | |
| attachment. | |
| Change the paragraph in Section 6.1.15 "Internal Format Queries" describing | |
| valid target values to: | |
| target indicates the usage of the internalformat, and must be one of | |
| RENDERBUFFER, TEXTURE_2D, TEXTURE_CUBE_MAP or TEXTURE_2D_ARRAY. | |
| Add the following paragraphs to Section 6.1.15 "Internal Format Queries" to | |
| the paragraphs describing valid pname values: | |
| If pname is NUM_DOWNSAMPLE_SCALES_IMG, the number of downscales that | |
| would be returned by querying DOWNSAMPLE_SCALES_IMG is returned in params. | |
| If pname is DOWNSAMPLE_SCALES_IMG, the available downscale pairs for the | |
| format are written into params. | |
| Formats that don't support downsampling will still return one valid | |
| downsample scale pair - {1,1}. A value of one for NUM_DOWNSAMPLE_SCALES_IMG | |
| will always mean no downscaling available, as {1,1} must be supported by | |
| every format. Targets that don't support downscaling (e.g. RENDERBUFFER) | |
| will return no downsample scale pairs. | |
| Interactions with OpenGL ES 2.0 | |
| In section 4.4.5 of the OpenGL ES 2.0 Specification "Framebuffer | |
| Completeness", subsection "Framebuffer Attachment Completeness", replace: | |
| * All attached images have the same width and height. | |
| FRAMEBUFFER_INCOMPLETE_DIMENSIONS | |
| with: | |
| * All attached images have the same value of width * xscale and | |
| height * yscale. | |
| FRAMEBUFFER_INCOMPLETE_DIMENSIONS | |
| Interactions with OpenGL ES 3.1 | |
| If OpenGL ES 3.1 is supported, replace TEXTURE_SAMPLES_EXT with TEXTURE_- | |
| SAMPLES, and add TEXTURE_2D_MULTISAMPLE to the list of valid targets for | |
| GetInternalFormativ. | |
| Interactions with EXT_multisampled_render_to_texture | |
| If EXT_multisampled_render_to_texture is not supported: | |
| - ignore references to TEXTURE_SAMPLES_EXT | |
| - the sample counts returned by GetInternalFormativ with a target of | |
| TEXTURE* will be the sample values available to be used with | |
| FramebufferTexture2DMultisampleEXT | |
| Dependencies on OpenGL ES 3.0 | |
| If OpenGL ES 3.0 or higher is not supported, ignore references to | |
| glFramebufferTextureLayerDownsample and glGetIntegeri_v. | |
| Interactions with EXT_color_buffer_float and EXT_color_buffer_half_float | |
| If either of these extensions are supported, it is not guaranteed that | |
| downscale of these formats is supported, but it may be - users will have to | |
| check with the GetInternalFormat query. | |
| This equally applies to any other additional render formats provided by | |
| extension. | |
| Errors | |
| The error INVALID_VALUE is generated if FramebufferTextureLayerDownsampleIMG | |
| or FramebufferTexture2DDownsampleIMG are are called with an <xscale> and | |
| <yscale> value pair that isn't reported by DOWNSAMPLE_SCALES_IMG. | |
| The error INVALID_ENUM is generated if FramebufferTextureLayerDownsampleIMG | |
| or FramebufferTexture2DDownsampleIMG are called with an <attachment> that is | |
| not COLOR_ATTACHMENTn. | |
| New State | |
| Add to Table 6.14 "Framebuffer (state per attachment point)" | |
| Initial | |
| Get Value Type Get Command Value Description Sec. | |
| ----------------- ----------- --------------------- ------- --------------- ---- | |
| FRAMEBUFFER_- 2 x Z+ GetFramebuffer- {1,1} Framebuffer 4.4.2 | |
| ATTACHMENT_- AttachmentParameteriv texture scale | |
| TEXTURE_SCALE_IMG | |
| New Implementation Dependent State | |
| Add to Table 6.35 "Framebuffer Dependent Values" | |
| Minimum | |
| Get Value Type Get Command Value Description Sec. | |
| ----------------- ----------- ------------------ ------- --------------- ---- | |
| NUM_DOWNSAMPLE_- 2 x Z+ GetIntegerv 2 Number of 4.4.2 | |
| SCALES_IMG scale value | |
| pairs available | |
| DOWNSAMPLE_- 1* x 2 x Z+ GetIntegeri_v ** Scale value 4.4.2 | |
| SCALES_IMG pairs available | |
| ** At least {1,1} and {2,2} must be supported as a minimum to support this extension. | |
| 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); | |
| ... | |
| Issues | |
| 1) Should renderbuffers be resolvable in this way too? | |
| RESOLVED | |
| No, renderbuffers are considered somewhat legacy and thus will | |
| not be supported by this extension. | |
| 2) Should any scale values other than {1,1} be mandated as minimum? | |
| RESOLVED | |
| Yes, {2,2} will also be required. Implementations may support additional | |
| values though, so a query is also added for other values. | |
| 3) What formats support downscaling? | |
| RESOLVED | |
| Formats that are guaranteed color-renderable by the core ES 3.1 | |
| specification, excluding integer and signed integer formats, support all | |
| available downscale modes. Other formats only support {1,1} (no | |
| downscaling). | |
| 4) What should happen if an application calls GetInternalFormativ with a | |
| target of TEXTURE* (not TEXTURE_2D_MULTISAMPLE)? | |
| RESOLVED | |
| For standard OpenGL ES, NUM_SAMPLE_COUNTS should be zero. However, if | |
| EXT_multisampled_render_to_texture is supported, valid configurations | |
| for FramebufferTexture2DMultisampleEXT should be returned here. | |
| Revision History | |
| Revision 1, 2014/08/27 | |
| - First draft | |
| Revision 2, 2015/03/16 | |
| - Mandated {2,2} as a required downsample scale. | |
| - Coupled x and y scale values into pairs | |
| Revision 3, 2015/03/19 | |
| - Moved framebuffer completeness information to correct (whole framebuffer | |
| completeness) section, and corrected wording. | |
| - Added note about minimum support in the overview. | |
| Revision 4, 2015/03/19 | |
| - Added a specific revision of the OpenGL ES 3.0 specification | |
| - Added an error that only COLOR_ATTACHMENTn can be used as an attachment | |
| point | |
| Revision 5, 2015/06/02 | |
| - Added internalformat query capability, so that formats can opt into | |
| downscaling support | |
| - Added section on downscaling to per-fragment operations. | |
| - Added issue about what formats support downscaling. | |
| - Restricted layer downscaling to 2D array textures. | |
| Revision 6, 2015/06/03 | |
| - Fixed typo in incomplete framebuffer condition | |
| - Added a bullet point to describe the FRAMEBUFFER_ATTACHMENT_TEXTURE_- | |
| SCALE_IMG parameter to GetFramebufferAttachmentiv | |
| - Clarified targets to GetInternalFormativ | |
| Revision 7, 2015/06/17 | |
| - Clarified interactions with EXT_color_buffer_float and | |
| EXT_color_buffer_half_float | |
| Revision 8, 2015/06/22 | |
| - Added NUM_DOWNSAMPLE_SCALES_IMG as a parameter to GetInternalFormativ | |
| - Added framebuffer attachment incomplete message and removed error when | |
| scale pair isn't supported by textures' internalformat, as | |
| internalformat is not necessarily known at attachment time. | |
| Revision 9, 2015/08/19 | |
| - Assigned enum values | |
| Revision 10, 2015/08/20 | |
| - Allowed DOWNSAMPLE_SCALES_IMG to be used with GetIntegerv/GetInteger64v | |
| Revision 11, 2015/12/18 | |
| - Fixed example - "tempScale" is an array so doesn't need to be dereferenced. |