Name NV_coverage_sample Name Strings GL_NV_coverage_sample EGL_NV_coverage_sample Contact Gary King, NVIDIA Corporation (gking 'at' nvidia.com) Notice Copyright NVIDIA Corporation, 2005 - 2007 Status NVIDIA Proprietary Version Last Modified Date: 2007/03/20 NVIDIA Revision: 1.0 Number EGL Extension #17 OpenGL ES Extension #72 Dependencies Written based on the wording of the OpenGL 2.0 specification and the EXT_framebuffer_object specification. Written based on the wording of the EGL 1.2 specification. Requires OpenGL-ES 2.0 and OES_framebuffer_object. Requires EGL 1.1. Overview Anti-aliasing is a critical component for delivering high-quality OpenGL rendering. Traditionally, OpenGL implementations have implemented two anti-aliasing algorithms: edge anti-aliasing and multisampling. Edge anti-aliasing computes fractional fragment coverage for all primitives in a rendered frame, and blends edges of abutting and/or overlapping primitives to produce smooth results. The image quality produced by this approach is exceptionally high; however, applications are render their geometry perfectly ordered back-to-front in order to avoid artifacts such as bleed-through. Given the algorithmic complexity and performance cost of performing exact geometric sorts, edge anti-aliasing has been used very sparingly, and almost never in interactive games. Multisampling, on the other hand, computes and stores subpixel (a.k.a. "sample") coverage for rasterized fragments, and replicates all post-alpha test operations (e.g., depth test, stencil test, alpha blend) for each sample. After the entire scene is rendered, the samples are filtered to compute the final anti-aliased image. Because the post-alpha test operations are replicated for each sample, all of the bleed-through and ordering artifacts that could occur with edge anti-aliasing are avoided completely; however, since each sample must be computed and stored separately, anti-aliasing quality is limited by framebuffer storage and rendering performance. This extension introduces a new anti-aliasing algorithm to OpenGL, which dramatically improves multisampling quality without adversely affecting multisampling's robustness or significantly increasing the storage required, coverage sampling. Coverage sampling adds an additional high-precision geometric coverage buffer to the framebuffer, which is used to produce high-quality filtered results (with or without the presence of a multisample buffer). This coverage information is computed and stored during rasterization; since applications may render objects where the specified geometry does not correspond to the visual result (examples include alpha-testing for "imposters," or extruded volume rendering for stencil shadow volumes), coverage buffer updates may be masked by the application, analagous to masking the depth buffer. IP Status NVIDIA Proprietary New Procedures and Functions void CoverageMaskNV( boolean mask ) void CoverageOperationNV( enum operation ) New Tokens Accepted by the parameter of eglChooseConfig and eglCreatePbufferSurface, and by the parameter of eglGetConfigAttrib EGL_COVERAGE_BUFFERS_NV 0x30E0 EGL_COVERAGE_SAMPLES_NV 0x30E1 Accepted by the parameter of RenderbufferStorageEXT and the parameter of ReadPixels COVERAGE_COMPONENT_NV 0x8ED0 Accepted by the parameter of RenderbufferStorageEXT COVERAGE_COMPONENT4_NV 0x8ED1 Accepted by the parameter of CoverageOperationNV COVERAGE_ALL_FRAGMENTS_NV 0x8ED5 COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6 COVERAGE_AUTOMATIC_NV 0x8ED7 Accepted by the parameter of FramebufferRenderbuffer, and GetFramebufferAttachmentParameteriv COVERAGE_ATTACHMENT_NV 0x8ED2 Accepted by the parameter of Clear COVERAGE_BUFFER_BIT_NV 0x8000 Accepted by the parameter of GetIntegerv COVERAGE_BUFFERS_NV 0x8ED3 COVERAGE_SAMPLES_NV 0x8ED4 Changes to Chapter 4 of the OpenGL 2.0 Specification Insert a new section, after Section 3.2.1 (Multisampling) "3.2.2 Coverage Sampling Coverage sampling is a mechanism to antialias all GL primitives: points, lines, polygons, bitmaps and images. The technique is similar to multisampling, with all primitives being sampled multiple times at each pixel, and a sample resolve applied to compute the color values stored in the framebuffer's color buffers. As with multisampling, coverage sampling resolves color sample and coverage values to a single, displayable color each time a pixel is updated, so antialiasing appears to be automatic at the application level. Coverage sampling may be used simultaneously with multisampling; however, this is not required. An additional buffer, called the coverage buffer, is added to the framebuffer. This buffer stores additional coverage information that may be used to produce higher-quality antialiasing than what is provided by conventional multisampling. When the framebuffer includes a multisample buffer (3.5.6), the samples contain this coverage information, and the framebuffer does not include the coverage buffer. If the value of COVERAGE_BUFFERS_NV is one, the rasterization of all primitives is changed, and is referred to as coverage sample rasterization. Otherwise, primitive rasterization is referred to as multisample rasterization (if SAMPLE_BUFFERS is one) or single-sample rasterization (otherwise). The value of COVERAGE_BUFFERS_NV is queried by calling GetIntegerv with set to COVERAGE_BUFFERS_NV. During coverage sample rasterization the pixel fragment contents are modified to include COVERAGE_SAMPLES_NV coverage values. The value of COVERAGE_SAMPLES_NV is an implementation-dependent constant, and is queried by calling GetIntegerv with set to COVERAGE_SAMPLES_NV. The command CoverageOperationNV(enum operation) may be used to modify the manner in which coverage sampling is performed for all primitives. If is COVERAGE_ALL_FRAGMENTS_NV, coverage sampling will be performed and the coverage buffer updated for all fragments generated during rasterization. If is COVERAGE_EDGE_FRAGMENTS_NV, coverage sampling will only be performed for fragments generated at the edge of the primitive (by only updating fragments at the edges of primitives, applications may get better visual results when rendering partially transparent objects). If is COVERAGE_AUTOMATIC_NV, the GL will automatically select the appropriate coverage operation, dependent on the GL blend mode and the use of gl_LastFragColor / gl_LastFragData in the bound fragment program. If blending is enabled, or gl_LastFragColor / gl_LastFragData appears in the bound fragment program, COVERAGE_AUTOMATIC_NV will behave identically to COVERAGE_EDGE_FRAGMENTS_NV; otherwise, COVERAGE_AUTOMATIC_NV will behave identically to COVERAGE_ALL_FRAGMENTS_NV. The default coverage operation is COVERAGE_AUTOMATIC_NV." Insert a new section, after Section 3.3.3 (Point Multisample Rasterization) "3.3.4 Point Coverage Sample Rasterization If the value of COVERAGE_BUFFERS_NV is one, then points are rasterized using the following algorithm, regardless of whether point antialiasing (POINT_SMOOTH) is enabled or disabled. Point rasterization produces fragments using the same algorithm described in section 3.3.3; however, sample points are divided into SAMPLES multisample points and COVERAGE_SAMPLES_NV coverage sample points. Rasterization for multisample points uses the algorithm described in section 3.3.3. Rasterization for coverage sample points uses implementation-dependent algorithms, ultimately storing the results in the coverage buffer." Insert a new section, after Section 3.4.4 (Line Multisample Rasterization) "3.4.5 Line Coverage Sample Rasterization If the value of COVERAGE_BUFFERS_NV is one, then lines are rasterized using the following algorithm, regardless of whether line antialiasing (LINE_SMOOTH) is enabled or disabled. Line rasterization produces fragments using the same algorithm described in section 3.4.4; however, sample points are divided into SAMPLES multisample points and COVERAGE_SAMPLES_NV coverage sample points. Rasterization for multisample points uses the algorithm described in section 3.4.4. Rasterization for coverage sample points uses implementation-dependent algorithms, ultimately storing results in the coverage buffer." Insert a new section, after Section 3.5.6 (Polygon Multisample Rasterization) "3.5.7 Polygon Coverage Sample Rasterization If the value of COVERAGE_BUFFERS_NV is one, then polygons are rasterized using the following algorithm, regardless of whether polygon antialiasing (POLYGON_SMOOTH) is enabled or disabled. Polygon rasterization produces fragments using the same algorithm described in section 3.5.6; however, sample points are divided into SAMPLES multisample points and COVERAGE_SAMPLES_NV coverage sample points. Rasterization for multisample points uses the algorithm described in section 3.5.7. Rasterization for coverage sample points uses implementation-dependent algorithms, ultimately storing results in the coverage buffer." Insert a new section, after Section 3.6.6 (Pixel Rectangle Multisample Rasterization) "3.6.7 Pixel Rectangle Coverage Sample Rasterization If the value of COVERAGE_BUFFERS_NV is one, then pixel rectangles are rasterized using the algorithm described in section 3.6.6." Modify the first sentence of the second-to-last paragraph of section 3.7 (Bitmaps) to read: "Bitmap Multisample and Coverage Sample Rasterization If MULTISAMPLE is enabled, and the value of SAMPLE_BUFFERS is one; or if the value of COVERAGE_BUFFERS_NV is one, then bitmaps are rasterized using the following algorithm. [...]" Insert after the first paragraph of Section 4.2.2 (Fine Control of Buffer Updates): "The coverage buffer can be enabled or disabled for writing coverage sample values using void CoverageMaskNV( boolean mask ); If is non-zero, the coverage buffer is enabled for writing; otherwise, it is disabled. In the initial state, the coverage buffer is enabled for writing." And change the text of the last 2 paragraphs of Section 4.2.2 to read: "The state required for the various masking operations is three integers and two bits: an integer for color indices, an integer for the front and back stencil values, a bit for depth values, and a bit for coverage sample values. A set of four bits is also required indicating which components of an RGBA value should be written. In the initial state, the integer masks are all ones, as are the bits controlling the depth value, coverage sample value and RGBA component writing. Fine Control of Multisample Buffer Updates When the value of SAMPLE_BUFFERS is one, ColorMask, DepthMask, CoverageMask, and StencilMask or StencilMaskSeparate control the modification of values in the multisample buffer. [...]" Change paragraph 2 of Section 4.2.3 (Clearing the Buffers) to read: "is the bitwise OR of a number of values indicating which buffers are to be cleared. The values are COLOR_BUFFER_BIT, DEPTH_BUFFER_BIT, STENCIL_BUFFER_BIT, ACCUM_BUFFER_BIT and COVERAGE_BUFFER_BIT_NV, indicating the buffers currently enabled for color writing, the depth buffer, the stencil buffer, the accumulation buffer and the virtual-coverage buffer, respectively. [...]" Insert a new paragraph after paragraph 4 of Section 4.3.2 (Reading Pixels) (beginning with "If there is a multisample buffer ..."): "If the is COVERAGE_COMPONENT_NV, then values are taken from the coverage buffer; again, if there is no coverage buffer, the error INVALID_OPERATION occurs. When is COVERAGE_COMPONENT_NV, must be GL_UNSIGNED_BYTE. Any other value for will generate the error INVALID_ENUM. If there is a multisample buffer, the values are undefined." Modifications to the OES_framebuffer_object specification Add a new table at the end of Section 4.4.2.1 (Renderbuffer Objects) "+-------------------------+-----------------------+-----------+ | Sized internal format | Base Internal Format | C Samples | +-------------------------+-----------------------+-----------+ | COVERAGE_COMPONENT4_NV | COVERAGE_COMPONENT_NV | 4 | +-------------------------+-----------------------+-----------+ Table 1.ooo Desired component resolution for each sized internal format that can be used only with renderbuffers" Add to the bullet list in Section 4.4.4 (Framebuffer Completeness) "An internal format is 'coverage-renderable' if it is COVERAGE_COMPONENT_NV or one of the COVERAGE_COMPONENT_NV formats from table 1.ooo. No other formats are coverage-renderable" Add to the bullet list in Section 4.4.4.1 (Framebuffer Attachment Completeness) "If is COVERAGE_ATTACHMENT_NV, then must have a coverage-renderable internal format." Add a paragraph at the end of Section 4.4.4.2 (Framebuffer Completeness) "The values of COVERAGE_BUFFERS_NV and COVERAGE_SAMPLES_NV are derived from the attachments of the currently bound framebuffer object. If the current FRAMEBUFFER_BINDING_OES is not 'framebuffer-complete', then both COVERAGE_BUFFERS_NV and COVERAGE_SAMPLES_NV are undefined. Otherwise, COVERAGE_SAMPLES_NV is equal to the number of coverage samples for the image attached to COVERAGE_ATTACHMENT_NV, or zero if COVERAGE_ATTACHMENT_NV is zero." Additions to the EGL 1.2 Specification Add to Table 3.1 (EGLConfig attributes) +---------------------------+---------+-----------------------------------+ | Attribute | Type | Notes | +---------------------------+---------+-----------------------------------+ | EGL_COVERAGE_BUFFERS_NV | integer | number of coverage buffers | | EGL_COVERAGE_SAMPLES_NV | integer | number of coverage samples per | | | | pixel | +---------------------------+---------+-----------------------------------+ Modify the first sentence of the last paragraph of the "Buffer Descriptions and Attributes" subsection of Section 3.4 (Configuration Management), p. 16 "There are no single-sample depth, stencil or coverage buffers for a multisample EGLConfig; the only depth, stencil and coverage buffers are those in the multisample buffer. [...]" And add the following text at the end of that paragraph: "The is used only by OpenGL ES. It contains primitive coverage information that is used to produce a high-quality anti-aliased image. The format of the coverage buffer is not specified, and its contents are not directly accessible. Only the existence of the coverage buffer, and the number of coverage samples it contains, are exposed by EGL. EGL_COVERAGE_BUFFERS_NV indicates the number of coverage buffers, which must be zero or one. EGL_COVERAGE_SAMPLES_NV gives the number of coverage samples per pixel; if EGL_COVERAGE_BUFFERS_NV is zero, then EGL_COVERAGE_SAMPLES_NV will also be zero." Add to Table 3.4 (Default values and match criteria for EGLConfig attributes) +---------------------------+-----------+-------------+---------+---------+ | Attribute | Default | Selection | Sort | Sort | | | | Criteria | Order | Priority| +---------------------------+-----------+-------------+---------+---------+ | EGL_COVERAGE_BUFFERS_NV | 0 | At Least | Smaller | 7 | | EGL_COVERAGE_SAMPLES_NV | 0 | At Least | Smaller | 8 | +---------------------------+-----------+-------------+---------+---------+ And renumber existing sort priorities 7-11 as 9-13. Modify the list in "Sorting of EGLConfigs" (Section 3.4.1, pg 20) " [...] 5. Smaller EGL_SAMPLE_BUFFERS 6. Smaller EGL_SAMPLES 7. Smaller EGL_COVERAGE_BUFFERS_NV 8. Smaller EGL_COVERAGE_SAMPLES_NV 9. Smaller EGL_DEPTH_SIZE 10. Smaller EGL_STENCIL_SIZE 11. Smaller EGL_ALPHA_MASK_SIZE 12. Special: [...] 13. Smaller EGL_CONFIG_ID [...]" Usage Examples (1) Basic Coverage Sample Rasterization glCoverageMaskNV(GL_TRUE); glDepthMask(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); while (1) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_COVERAGE_BUFFER_BIT_NV); glDrawElements(...); eglSwapBuffers(...); } (2) Multi-Pass Rendering Algorithms while (1) { glDepthMask(GL_TRUE); glCoverageMaskNV(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_COVERAGE_BUFFER_BIT_NV); // first render pass: render Z-only (occlusion surface), with // coverage info. color writes are disabled glCoverageMaskNV(GL_TRUE); glDepthMask(GL_TRUE); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); glDepthFunc(GL_LESS); glDrawElements(...); // second render pass: set Z test to Z-equals, disable Z-writes & // coverage writes. enable color writes. coverage may be // disabled, because subsequent rendering passes are rendering // identical geometry -- since the final coverage buffer will be // unchanged, we can disable coverage writes as an optimization. glCoverageMaskNV(GL_FALSE); glDepthMask(GL_FALSE); glDepthFunc(GL_EQUAL); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glDrawElements(...); eglSwapBuffers(); } (3) Rendering Translucent Objects on Top of Opaque Objects while (1) { glDepthMask(GL_TRUE); glCoverageMaskNV(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_COVERAGE_BUFFER_BIT_NV); // render opaque, Z-buffered geometry with coverage info for the // entire primitive. Overwrite coverage data for all fragments, so // that interior fragments do not get resolved incorrectly. glDepthFunc(GL_LESS); glCoverageOperationNV(GL_COVERAGE_ALL_FRAGMENTS_NV); glDrawElements(...); // render translucent, Z-buffered geometry. to ensure that visible // edges of opaque geometry remain anti-aliased, change the // coverage operation to just edge fragments. this will maintain // the coverage information underneath the translucent geometry, // except at translucent edges. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glCoverageOperationNV(GL_COVERAGE_EDGE_FRAGMENTS_NV); glEnable(GL_BLEND); glDrawElements(...); glDisable(GL_BLEND); eglSwapBuffers(); } (4) Rendering Opacity-Mapped Particle Systems & HUDs on Top of Opaque Geometry while (1) { glDepthMask(GL_TRUE); glCoverageMaskNV(GL_TRUE); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_COVERAGE_BUFFER_BIT_NV); // render opaque, Z-buffered geometry, with coverage info. glDepthFunc(GL_LESS); glDrawElements(...); // render opacity-mapped geometry. disable Z writes, enable alpha // blending. also, disable coverage writes -- the edges of the // geometry used for the HUD/particle system have alpha values // tapering to zero, so edge coverage is uninteresting, and // interior coverage should still refer to the underlying opaque // geometry, so that opaque edges visible through the translucent // regions remain anti-aliased. glCoverageMaskNV(GL_FALSE); glDepthMask(GL_FALSE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glDrawElements(...); glDisable(GL_BLEND); eglSwapBuffers(); } Issues 1. Is any specific discussion of coverage sampling resolves required, particularly with respect to application-provided framebuffer objects? RESOLVED: No. Because the coverage sampling resolve is an implementation-dependent algorithm, it is always legal behavior for framebuffer read / copy functions to return the value in the selected ReadBuffer as if COVERAGE_BUFFERS_NV was zero. This allows textures attached to the color attachment points of framebuffer objects to behave predictably, even when COVERAGE_BUFFERS_NV is one. Implementations are encouraged, whenever possible, to use the highest- quality coverage sample resolve supported for calls to eglSwapBuffers, eglCopyBuffers, ReadPixels, CopyPixels and CopyTex{Sub}Image. 2. Should all render buffer & texture types be legal sources for image resolves and coverage attachment? RESOLVED: This spec should not place any arbitrary limits on usage; however, there are many reasons why implementers may not wish to support coverage sampling for all surface types. Implementations may return FRAMEBUFFER_UNSUPPORTED_OES from CheckFramebufferStatusOES if an object bound to COVERAGE_ATTACHMENT_NV is incompatible with one or more objects bound to DEPTH_ATTACHMENT_OES, STENCIL_ATTACHMENT_OES, or COLOR_ATTACHMENTi_OES. Revision History #1.0 - 20.03.2007 Renumbered enumerants. Reformatted to 80 columns.