Name EXT_framebuffer_multisample Name Strings GL_EXT_framebuffer_multisample Contributors Pat Brown Michael Gold Evan Hart Jeff Juliano Jon Leech Bill Licea-Kane Barthold Lichtenbelt Kent Lin Ian Romanick John Rosasco Jeremy Sandmel Contacts Jeff Juliano, NVIDIA Corporation (jjuliano 'at' nvidia.com) Jeremy Sandmel, Apple Computer (jsandmel 'at' apple.com) Status Complete Approved by the ARB "superbuffers" Working Group on November 8, 2005 Version Last Modified Date: January 10, 2007 Revision: #7 Number 317 Dependencies Requires GL_EXT_framebuffer_object. Requires GL_EXT_framebuffer_blit. Written based on the wording of the OpenGL 1.5 specification. Overview This extension extends the EXT_framebuffer_object framework to enable multisample rendering. The new operation RenderbufferStorageMultisampleEXT() allocates storage for a renderbuffer object that can be used as a multisample buffer. A multisample render buffer image differs from a single-sample render buffer image in that a multisample image has a number of SAMPLES that is greater than zero. No method is provided for creating multisample texture images. All of the framebuffer-attachable images attached to a framebuffer object must have the same number of SAMPLES or else the framebuffer object is not "framebuffer complete". If a framebuffer object with multisample attachments is "framebuffer complete", then the framebuffer object behaves as if SAMPLE_BUFFERS is one. In traditional multisample rendering, where DRAW_FRAMEBUFFER_BINDING_EXT is zero and SAMPLE_BUFFERS is one, the GL spec states that "the color sample values are resolved to a single, displayable color each time a pixel is updated." There are, however, several modern hardware implementations that do not actually resolve for each sample update, but instead postpones the resolve operation to a later time and resolve a batch of sample updates at a time. This is OK as long as the implementation behaves "as if" it had resolved a sample-at-a-time. Unfortunately, however, honoring the "as if" rule can sometimes degrade performance. In contrast, when DRAW_FRAMEBUFFER_BINDING_EXT is an application-created framebuffer object, MULTISAMPLE is enabled, and SAMPLE_BUFFERS is one, there is no implicit per-sample-update resolve. Instead, the application explicitly controls when the resolve operation is performed. The resolve operation is affected by calling BlitFramebufferEXT (provided by the EXT_framebuffer_blit extension) where the source is a multisample application-created framebuffer object and the destination is a single-sample framebuffer object (either application-created or window-system provided). This design for multisample resolve more closely matches current hardware, but still permits implementations which choose to resolve a single sample at a time. If hardware that implementes the multisample resolution "one sample at a time" exposes EXT_framebuffer_multisample, it could perform the implicit resolve to a driver-managed hidden surface, then read from that surface when the application calls BlitFramebufferEXT. Another motivation for granting the application explicit control over the multisample resolve operation has to do with the flexibility afforded by EXT_framebuffer_object. Previously, a drawable (window or pbuffer) had exclusive access to all of its buffers. There was no mechanism for sharing a buffer across multiple drawables. Under EXT_framebuffer_object, however, a mechanism exists for sharing a framebuffer-attachable image across several framebuffer objects, as well as sharing an image between a framebuffer object and a texture. If we had retained the "implicit" resolve from traditional multisampled rendering, and allowed the creation of "multisample" format renderbuffers, then this type of sharing would have lead to two problematic situations: * Two contexts, which shared renderbuffers, might perform competing resolve operations into the same single-sample buffer with ambiguous results. * It would have introduced the unfortunate ability to use the single-sample buffer as a texture while MULTISAMPLE is ENABLED. By using the BlitFramebufferEXT from EXT_framebuffer_blit as an explicit resolve to serialize access to the multisampled contents and eliminate the implicit per-sample resolve operation, we avoid both of these problems. Issues Breaking from past convention, the issues section has been moved to the end of the document. It can be found after Examples, before Revision History. New Procedures and Functions void RenderbufferStorageMultisampleEXT( enum target, sizei samples, enum internalformat, sizei width, sizei height); New Types None. New Tokens Accepted by the parameter of GetRenderbufferParameterivEXT: RENDERBUFFER_SAMPLES_EXT 0x8CAB Returned by CheckFramebufferStatusEXT: FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56 Accepted by the parameter of GetBooleanv, GetIntegerv, GetFloatv, and GetDoublev: MAX_SAMPLES_EXT 0x8D57 Additions to Chapter 2 of the 1.5 Specification (OpenGL Operation) Additions to Chapter 3 of the OpenGL 1.5 Specification (Rasterization) Additions to Chapter 4 of the OpenGL 1.5 Specification (Per-Fragment Operations and the Framebuffer) Add to 4.3.2 (Reading Pixels), right before the subsection titled "Obtaining Pixels form the Framebuffer": "ReadPixels generates INVALID_OPERATION if READ_FRAMEBUFFER_BINDING (section 4.4) is non-zero, the read framebuffer is framebuffer complete, and the value of SAMPLE_BUFFERS for the read framebuffer is greater than zero." Modify the following text to section 4.3.3, page 194, that was added to the definition of CopyPixels by EXT_framebuffer_blit: "Finally, the behavior of several GL operations is specified "as if the arguments were passed to CopyPixels." These operations include: CopyTex{Sub}Image*, CopyColor{Sub}Table, and CopyConvolutionFilter*. INVALID_FRAMEBUFFER_OPERATION_EXT will be generated if an attempt is made to execute one of these operations, or CopyPixels, while the object bound to READ_FRAMEBUFFER_BINDING_EXT (section 4.4) is not "framebuffer complete" (as defined in section 4.4.4.2). INVALID_OPERATION will be generated if the object bound to READ_FRAMEBUFFER_BINDING_EXT is "framebuffer complete" and the value of SAMPLE_BUFFERS is greater than zero. Furthermore, an attempt to execute CopyPixels will generate INVALID_FRAMEBUFFER_OPERATION_EXT while the object bound to DRAW_FRAMEBUFFER_BINDING_EXT (section 4.4) is not "framebuffer complete". In 4.3.3 (Copying Pixels), add to the section describing BlitFramebuffer that was added by EXT_framebuffer_blit. "If SAMPLE_BUFFERS for the read framebuffer is greater than zero and SAMPLE_BUFFERS for the draw framebuffer is zero, the samples corresponding to each pixel location in the source are converted to a single sample before being written to the destination. If SAMPLE_BUFFERS for the read framebuffer is zero and SAMPLE_BUFFERS for the draw framebuffer is greater than zero, the value of the source sample is replicated in each of the destination samples. If SAMPLE_BUFFERS for both the read and draw framebuffers are greater than zero, and the values of SAMPLES for the read and draw framebuffers are identical, the samples are copied without modification from the read framebuffer to the draw framebuffer. Otherwise, no copy is performed and an INVALID_OPERATION error is generated. Furthermore, if SAMPLE_BUFFERS for either the read framebuffer or draw framebuffer is greater than zero, no copy is performed and an INVALID_OPERATION error is generated if the dimensions of the source and destination rectangles provided to BlitFramebuffer are not identical, or if the formats of the read and draw framebuffers are not identical." Modification to 4.4.2.1 (Renderbuffer Objects) Add, just above the definition of RenderbufferStorageEXT: "The command void RenderbufferStorageMultisampleEXT( enum target, sizei samples, enum internalformat, sizei width, sizei height); establishes the data storage, format, dimensions, and number of samples of a renderbuffer object's image. must be RENDERBUFFER_EXT. must be RGB, RGBA, DEPTH_COMPONENT, STENCIL_INDEX, or one of the internal formats from table 3.16 or table 2.nnn that has a base internal format of RGB, RGBA, DEPTH_COMPONENT, or STENCIL_INDEX. and are the dimensions in pixels of the renderbuffer. If either or is greater than MAX_RENDERBUFFER_SIZE_EXT, or if is greater than MAX_SAMPLES_EXT, then the error INVALID_VALUE is generated. If the GL is unable to create a data store of the requested size, the error OUT_OF_MEMORY is generated. Upon success, RenderbufferStorageMultisampleEXT deletes any existing data store for the renderbuffer image and the contents of the data store after calling RenderbufferStorageMultisampleEXT are undefined. RENDERBUFFER_WIDTH_EXT is set to , RENDERBUFFER_HEIGHT_EXT is set to , and RENDERBUFFER_INTERNAL_FORMAT_EXT is set to . If is zero, then RENDERBUFFER_SAMPLES_EXT is set to zero. Otherwise represents a request for a desired minimum number of samples. Since different implementations may support different sample counts for multisampled rendering, the actual number of samples allocated for the renderbuffer image is implementation dependent. However, the resulting value for RENDERBUFFER_SAMPLES_EXT is guaranteed to be greater than or equal to and no more than the next larger sample count supported by the implementation. Sized Base S Internal Format Internal format Bits --------------- --------------- ---- STENCIL_INDEX1_EXT STENCIL_INDEX 1 STENCIL_INDEX4_EXT STENCIL_INDEX 4 STENCIL_INDEX8_EXT STENCIL_INDEX 8 STENCIL_INDEX16_EXT STENCIL_INDEX 16 ------------------------------------------------------------------ Table 2.nnn Desired component resolution for each sized internal format that can be used only with renderbuffers. A GL implementation may vary its allocation of internal component resolution based on any RenderbufferStorage parameter (except target), but the allocation and chosen internal format must not be a function of any other state and cannot be changed once they are established." Modify the definiton of RenderbufferStorageEXT as follows: "The command void RenderbufferStorageEXT(enum target, enum internalformat, sizei width, sizei height); is equivalent to calling RenderbufferStorageMultisampleEXT with equal to zero." Modification to 4.4.4.2 (Framebuffer Completeness) Add an entry to the bullet list: * The value of RENDERBUFFER_SAMPLES_EXT is the same for all attached images. { FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT } Also add a paragraph to the end of the section: "The values of SAMPLE_BUFFERS and SAMPLES are derived from the attachments of the currently bound framebuffer object. If the current DRAW_FRAMEBUFFER_BINDING_EXT is not "framebuffer complete", then both SAMPLE_BUFFERS and SAMPLES are undefined. Otherwise, SAMPLES is equal to the value of RENDERBUFFER_SAMPLES_EXT for the attached images (which all must have the same value for RENDERBUFFER_SAMPLES_EXT). Further, SAMPLE_BUFFERS is one if SAMPLES is non-zero. Otherwise, SAMPLE_BUFFERS is zero. Additions to Chapter 5 of the OpenGL 1.5 Specification (Special Functions) Added to section 5.4, as part of the discussion of which commands are not compiled into display lists: "Certain commands, when called while compiling a display list, are not compiled into the display list but are executed immediately. These are: ..., RenderbufferStorageMultisampleEXT..." Additions to Chapter 6 of the OpenGL 1.5 Specification (State and State Requests) Modification to 6.1.3 (Enumerated Queries): In the list of state query functions, modify the definition of GetRenderbufferParameterivEXT as follows: "void GetRenderbufferParameterivEXT(enum target, enum pname, int* params); must be RENDERBUFFER_EXT. must be one of the symbolic values in table 8.nnn. If the renderbuffer currently bound to is zero, then INVALID_OPERATION is generated. Upon successful return from GetRenderbufferParameterivEXT, if is RENDERBUFFER_WIDTH_EXT, RENDERBUFFER_HEIGHT_EXT, RENDERBUFFER_INTERNAL_FORMAT_EXT, or RENDERBUFFER_SAMPLES_EXT, then will contain the width in pixels, height in pixels, internal format, or number of samples, respectively, of the renderbuffer currently bound to . Otherwise, INVALID_ENUM is generated." GLX Protocol RenderbufferStorageMultisampleEXT 2 24 rendering command length 2 4331 rendering command opcode 4 ENUM target 4 CARD32 samples 4 ENUM internalformat 4 CARD32 width 4 CARD32 height Dependencies on EXT_framebuffer_object EXT_framebuffer_object is required. Dependencies on EXT_framebuffer_blit EXT_framebuffer_blit is required. Technically, EXT_framebuffer_blit would not be required to support multisampled rendering, except for the fact that it provides the only method of doing a multisample resovle from a multisample renderbuffer. Errors The error INVALID_OPERATION_EXT is generated if ReadPixels, CopyPixels, CopyTex{Sub}Image*, CopyColor{Sub}Table, or CopyConvolutionFilter* is called while READ_FRAMEBUFFER_BINDING_EXT is non-zero, the read framebuffer is framebuffer complete, and the value of SAMPLE_BUFFERS for the read framebuffer is greater than zero. The error OUT_OF_MEMORY is generated when RenderbufferStorageMultisampleEXT cannot create storage of the specified size. If both the draw and read framebuffers are framebuffer complete and both have a value of SAMPLE_BUFFERS that is greater than zero, then the error INVALID_OPERATION is generated if BlitFramebufferEXT is called and the values of SAMPLES for the draw and read framebuffers do not match. If both the draw and read framebuffers are framebuffer complete and either has a value of SAMPLE_BUFFERS that is greater than zero, then the error INVALID_OPERATION is generated if BlitFramebufferEXT is called and the formats of the draw and read framebuffers are not identical. If either the draw or read framebuffer is framebuffer complete and has a value of SAMPLE_BUFFERS that is greater than zero, then the error INVALID_OPERATION is generated if BlitFramebufferEXT is called and the specified source and destination dimensions are not identical. If RenderbufferStorageMultisampleEXT is called with a value of that is greater than MAX_SAMPLES_EXT, then the error INVALID_VALUE is generated. New State (add to table 8.nnn, "Renderbuffers (state per renderbuffer object)") Get Value Type Get Command Initial Value Description Section Attribute ------------------------------- ------ ------------- ------------- -------------------- ------------ --------- RENDERBUFFER_SAMPLES_EXT Z+ GetRenderbufferParameterivEXT 0 number of samples 4.4.2.1 - To the table added by EXT_framebuffer_object called "Framebuffer Dependent Values", table 9.nnn, add the following new framebuffer dependent state. Get Value Type Get Command Minimum Value Description Section Attribute --------- ---- ----------- ------------- ------------------- ------- --------- MAX_SAMPLES_EXT Z+ GetIntegerv 1 Maximum number of 4.4.2.1 - samples supported for multisampling Usage Examples XXX add examples XXX Issues (1) Should this be a separate extension or should it be included in a revision of EXT_framebuffer_object? RESOLVED, separate extension Resolved by consensus, May 9, 2005 This extension requires EXT_framebuffer_object but the reverse is not true. In addition, the cross framebuffer copy operation that will be used to handle the multisample resolution operation may be generally useful for non-multisampled rendering, but is pretty much required for multisampled rendering to be useful. Since we don't want EXT_framebuffer_object to require that functionality either, we split EXT_framebuffer_multisample into its own extension. EXT_framebuffer_multisample might include the "cross framebuffer copy" operation or might simply require the presence of that third extension. See issue (8). (2) What happens when is zero or one? RESOLVED, 0 = single sample, 1 = minimum multisample Resolved by consensus, May 9, 2005 Zero means single sample, as if RenderbufferStorageEXT had been called instead of RenderbufferStorageMultisampleEXT. One means minimum number of samples supported by implementation. There was a question if one should mean the same thing as single-sample (one sample), or if it should mean the minimum supported number of samples for multisample rendering. The rules for rasterizing in "multisample" mode are different than "non-multisample" mode. In the end, we decided that some implementations may wish to support a "one-sample" multisample buffer to allow for multipass multisampling where the sample location can be varied either by the implementation or perhaps explicitly by a "multisample location" extension. (3) Is ReadPixels (or CopyPixels or CopyTexImage) permitted when bound to a multisample framebuffer object? RESOLVED, no Resolved by consensus, prior to May 9, 2005 No, those operations will produce INVALID_OPERATION. To read the contents of a multisample framebuffer, it must first be "downsampled" into a non-multisample destination, then read from there. For downsample, see EXT_framebuffer_blit. The concern is fallback due to out of memory conditions. Even if no memory is available to allocate a temporary buffer at the time ReadPixels is called, an implementation should be able to make this work by pre-allocating a small tile and doing the downsample in tiles, or by falling back to software to copy a pixel at a time. (4) Does the resolution from to RENDERBUFFER_SAMPLES_EXT depend on any other parameters to RenderbufferStorageMultisampleEXT, or must a given value of always resolve to the same number of actual samples? RESOLVED, no, further, user must get at least what they asked for, or Storage call fails: Resolved by consensus, May 23, 2005 Given the routine, void RenderbufferStorageMultisampleEXT( enum target, uint samples, enum internalformat, uint width, uint height); If an implementation supports several sample counts (say, 2x, 4x, 8x multisample), and the user requests a sample count of , the implementation must do one of the following: - succeed in giving the user exactly , or - succeed in giving the user a number of samples greater than but no more than the next highest number of samples supported by the implementation, or - fail the request to RenderbufferStorageMultisampleEXT with an OUT_OF_MEMORY error (5) Is an implementation allowed to create single-sample storage when RenderbufferStorageMultisampleEXT is called with larger than one? RESOLVED, no Resolved by consensus, May 23, 2005 No, by resolution of issue (4) above, the user must get at least what they asked for or higher, which precludes getting a single sampled format if they asked for a multisampled format. (6) Should OUT_OF_MEMORY be generated when RenderbufferStorageMultisampleEXT cannot create storage of the requested size? RESOLVED, yes Resolved by consensus, May 23, 2005 Yes. Success or failure is determined by , , , and , and the implementation can always return OUT_OF_MEMORY. Note that while an implementation may give a different internal format with either higher or lower resolution per component than the internal requested, by issue of resolution (4), it must give at least the number of samples requested or it must fail the RenderbufferStorageMultisampleEXT call. Update from June 2006 ARB meeting: The appropriate error for the case where the number of samples is larger than the maximum supported by the implementation is INVALID_VALUE. To allow an application to know the maximum legal value, we add a GetInteger query MAX_SAMPLES. (7) Is there a query for the maximum size of ? RESOLVED, Yes There was some discussion about whether it was useful to return a maximum sample count supported by the implementation as a convenenience to the developer so that the developer doesn't need to try increasingly smaller counts until it finds one that succeeds. Originally this query was ommitted, but later it was added (MAX_SAMPLES_EXT). (8) Does this extension require our new framebuffer-to-framebuffer copy extension, EXT_framebuffer_blit, or is it merely affected by the presence of that extension. RESOLVED, EXT_framebuffer_blit is required. EXT_framebuffer_multisample by itself enable the user to perform multisampled rendering. However, you can't copy or read from a multisampled renderbuffer using {Read|Copy}Pixels or CopyTex{Sub}Image - as per issue (3). Consequently, there is no way to actually use the results of multisampled rendering without EXT_framebuffer_blit. That makes the EXT_framebuffer_multisample extension arguably kind of useless without the EXT_framebuffer_blit. However, the reverse is not true. The EXT_framebuffer_blit is useful on its own, which is why it is a separate extension from this one. So we decided to state that EXT_framebuffer_multisample requires EXT_framebuffer_blit instead of merely stating that that extension affects this one. (9) Is DrawPixels allowed when the draw framebuffer is multisample? RESOLVED, yes This is no different than DrawPixels to a multisample window (framebuffer zero). Note that ReadPixels and CopyPixels are disallowed when the read framebuffer is multisample. Revision History #7, Jan 10, 2007: jjuliano - add missing constraint that a multisample blit requires identical formats for the read and draw framebuffers - correct the resolution of issue 7 (MAX_SAMPLES_EXT) - fix typos #6c, November 6, 2006: jjuliano - changes from June #6 merged back in #6b, October 13, 2006: Jon Leech - added token values for MAX_SAMPLES_EXT and FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT. #6a, September 6, 2006: jsandmel - added language describing MAX_SAMPLES query - clarified that RenderbufferStorageMultisampleEXT can fail with INVALID_VALUE if is greater than MAX_SAMPLES #6, June 1, 2006: jjuliano - add missing errors to Errors section - clarify the modifications to 4.3.2 and 4.3.3. - add issue 9 to document that multisample DrawPixels is allowed #5, December 22, 2005: Jon Leech - added GLX protocol, assigned enumerant values #4, September 28, 2005: jsandmel, jjuliano - moved the multisample languge from GL_EXT_framebuffer_blit to this spec. - added description of using BlitFramebufferEXT for resolving multisample buffer - added language referring to DRAW_/READ_FRAMEBUFFER_BINDING instead of just FRAMEBUFFER_BINDING. - minor updates to reflect new EXT_framebuffer_blit spec that provides the multisample resolve function - resolve issue (8) - rename framebuffer_object_multisample to framebuffer_multisample #3, May 26, 2005: jsandmel - added recent workgroup resolutions - resolved issues (4), (5), (6), (7) based on decisions from the work group on May 9 and 23, 2005 - added issue (8), does this extension require our new cross-framebuffer copy extension? - removed MAX_RENDERBUFFER_SAMPLES_EXT enum as per work group decision - issue (7) - changed prototype for RenderbufferStorageMultisampleEXT to use sizei for sample count #2, May 16, 2005: jsandmel - revised to account for recent work group meeting decisions - removed erroneous inclusion of GenerateMipmaps as a new function - resolved issue (1), this will be a separate extension - resolved issue (2), zero means non-multisample, one means minimum number of samples #1, May 9, 2005: jjuliano - first revision