Difference between revisions of "Framebuffer Object"

From OpenGL.org
Jump to: navigation, search
(Attaching Images)
m (Semantics: spelling)
 
(32 intermediate revisions by 6 users not shown)
Line 5: Line 5:
 
}}
 
}}
  
'''Framebuffer Objects''' are a mechanism for rendering to images other than the default OpenGL [[Default Framebuffer]]. They are [[OpenGL Objects]] that allow you to render directly to textures, as well as blitting from one framebuffer to another.
+
'''Framebuffer Objects''' are [[OpenGL Object]]s, which allow for the creation of user-defined [[Framebuffer]]s. With them, one can render to non-[[Default Framebuffer]] locations, and thus render without disturbing the main screen.
  
 
== Semantics ==
 
== Semantics ==
Line 11: Line 11:
 
Framebuffer objects are very complicated. As such, we need to explicitly define certain terminology.
 
Framebuffer objects are very complicated. As such, we need to explicitly define certain terminology.
  
''Image'': For the purposes of this article, an image is a single 2D array of pixels. It has a [[Image Format|specific format]] for these pixels.
+
; Image
 
+
: For the purposes of this article, an image is a single 2D array of pixels. It has a [[Image Format|specific format]] for these pixels.
''Layered Image'': For the purposes of this article, a layered image is a sequence of ''images'' of a particular size and format. Layered images are packaged together within a single OpenGL object.
+
;Layered Image
 
+
: For the purposes of this article, a layered image is a sequence of ''images'' of a particular size and format. Layered images come from single mipmap levels of certain [[Texture]] types.
''[[Texture]]'': For the purposes of this article, a texture is an object that contains some number of ''images'', as defined above. All of the images have the same format, but they do not have to have the same size (different [[mip-map]]s, for example). Textures can be bound to [[shader]]s and rendered with.
+
;[[Texture]]
 
+
: For the purposes of this article, a texture is an object that contains some number of ''images'', as defined above. All of the images have the same format, but they do not have to have the same size (different [[mip-map]]s, for example). Textures can be accessed from [[Shader]]s via various methods.
''[[Renderbuffer Objects|Renderbuffer]]'': A renderbuffer is an object that contains a single image. Renderbuffers cannot be bound to shaders or otherwise rendered with; they can only be attached to FBOs.
+
;[[Renderbuffer Objects|Renderbuffer]]
 
+
: A renderbuffer is an object that contains a single image. Renderbuffers cannot be accessed by [[Shader]]s in any way. The only way to work with a renderbuffer, besides creating it, is to put it into an FBO.
''Framebuffer-attachable image'': Any image, as previously described, that can be attached to a framebuffer object.
+
;Attach
 
+
: To connect one [[OpenGL Objects|object]] to another. This term is used across all of OpenGL, but FBOs make the most use of the concept. Attachment is different from binding. Objects are ''bound'' to the [[OpenGL Context|context]]; objects are ''attached'' to one another.
''Framebuffer-attachable layered image'': Any layered image, as previously described, that can be attached to a framebuffer object.
+
;Attachment point
 
+
: A named location within a framebuffer object that a framebuffer-attachable image or layered image can be attached to. Attachment points restrict the general kind of [[Image Format]] for images attached to them.
''Attachment point'': A named location within a framebuffer object that a framebuffer-attachable image or layered image can be attached to. Attachment points can have limitations on the format of the images attached there.
+
;Framebuffer-attachable image
 
+
: Any image, as previously described, that can be attached to a framebuffer object.
''Attach'': To connect one [[OpenGL Objects|object]] to another. This is not limited to FBOs, but attaching is a big part of them. Attachment is different from binding. Objects are ''bound'' to the context; they are ''attached'' to each other.
+
;Framebuffer-attachable layered image
 +
: Any layered image, as previously described, that can be attached to a framebuffer object.
  
 
== Framebuffer Object Structure ==
 
== Framebuffer Object Structure ==
Line 31: Line 32:
 
As standard [[OpenGL Objects]], FBOs have the usual {{apifunc|glGenFramebuffers}} and {{apifunc|glDeleteFramebuffers}} functions. As expected, it also has the usual {{apifunc|glBindFramebuffer}} function, to bind an FBO to the context.
 
As standard [[OpenGL Objects]], FBOs have the usual {{apifunc|glGenFramebuffers}} and {{apifunc|glDeleteFramebuffers}} functions. As expected, it also has the usual {{apifunc|glBindFramebuffer}} function, to bind an FBO to the context.
  
The {{param|target}} parameter for this object can take one of 3 values: {{enum|GL_FRAMEBUFFER}}, {{enum|GL_READ_FRAMEBUFFER}}, or {{enum|GL_DRAW_FRAMEBUFFER}}. The last two allow you to bind an FBO so that reading commands ({{apifunc|glReadPixels}}, etc) and writing commands (any command of the form {{code|glDraw*}}) can happen to two different buffers. The {{enum|GL_FRAMEBUFFER}} target simply sets both the read and the write to the same FBO.
+
The {{param|target}} parameter for this object can take one of 3 values: {{enum|GL_FRAMEBUFFER}}, {{enum|GL_READ_FRAMEBUFFER}}, or {{enum|GL_DRAW_FRAMEBUFFER}}. The last two allow you to bind an FBO so that reading commands ({{apifunc|glReadPixels}}, etc) and writing commands (all [[Vertex Rendering|rendering commands]]) can happen to two different framebuffers. The {{enum|GL_FRAMEBUFFER}} binding target simply sets both the read and the write to the same FBO.
  
When an FBO is bound to a target, the available surfaces change. The default framebuffer has buffers like {{enum|GL_FRONT}}, {{enum|GL_BACK}}, {{enum|GL_AUXi}}, {{enum|GL_ACCUM}}, and so forth. FBOs do not have these.
+
When an FBO is bound to a target, the available buffer names. The default framebuffer has buffer names like {{enum|GL_FRONT}}, {{enum|GL_BACK}}, {{enum|GL_AUXi}}, {{enum|GL_ACCUM}}, and so forth. FBOs do not have these.
  
Instead, FBOs have a different set of images. Each FBO image represents an attachment point, a location in the FBO where an image can be attached. FBOs have the following attachment points:
+
Instead, FBOs have a different set of image names. Each FBO image represents an attachment point, a location in the FBO where an image can be attached. FBOs have the following attachment points:
  
* {{enum|GL_COLOR_ATTACHMENT''i''}}: These are an implementation-dependent number of attachment points. You can query {{enum|GL_MAX_COLOR_ATTACHMENTS}} to determine the number of color attachments that an implementation will allow. The minimum value for this is 1, so you are guaranteed to be able to have at least color attachment 0. These attachment points can only have images bound to them with color-renderable formats. All [[Image Formats#Compressed formats|compressed image formats]] are not color-renderable, and thus cannot be attached to an FBO.
+
* {{enum|GL_COLOR_ATTACHMENT''i''}}: These are an implementation-dependent number of attachment points. You can query {{enum|GL_MAX_COLOR_ATTACHMENTS}} to determine the number of color attachments that an implementation will allow. The minimum value for this is 8, so you are guaranteed to be able to have at least color attachments 0-7. These attachment points can only have images bound to them with color-renderable formats. All [[Image Formats#Compressed formats|compressed image formats]] are not color-renderable, and thus cannot be attached to an FBO.
* {{enum|GL_DEPTH_ATTACHMENT}}: This attachment point can only have images with depth formats bound to it. The image attached becomes the [[Depth Buffer]] for the FBO.
+
* {{enum|GL_DEPTH_ATTACHMENT}}: This attachment point can only have images with depth formats bound to it. The image attached becomes the [[Depth Buffer]] for the FBO. '''**NOTE**''' Even if you don't plan on reading from this depth_attachment, an off screen buffer that will be rendered to should have a depth attachment.
 
* {{enum|GL_STENCIL_ATTACHMENT}}: This attachment point can only have images with stencil formats bound to it. The image attached becomes the [[Stencil Test|stencil buffer]] for the FBO.
 
* {{enum|GL_STENCIL_ATTACHMENT}}: This attachment point can only have images with stencil formats bound to it. The image attached becomes the [[Stencil Test|stencil buffer]] for the FBO.
 
* {{enum|GL_DEPTH_STENCIL_ATTACHMENT}}: This is shorthand for "both depth and stencil". The image attached becomes both the depth and stencil buffers.
 
* {{enum|GL_DEPTH_STENCIL_ATTACHMENT}}: This is shorthand for "both depth and stencil". The image attached becomes both the depth and stencil buffers.
Line 46: Line 47:
 
== Attaching Images ==
 
== Attaching Images ==
  
Now that we know where images can be attached to FBOs, we can start talking about how to actually attach images to these. Of course, in order to attach images to an FBO, we must first bind the FBO to the context.
+
Now that we know where images can be attached to FBOs, we can start talking about how to actually attach images to these. In order to attach images to an FBO, we must first bind the FBO to the context with {{apifunc|glBindFramebuffer}}.
  
You can attach images from any kind of texture to the framebuffer object.
+
You can attach images from any kind of texture to the framebuffer object. However, framebuffers are designed for 2D rendering. So there is a need to consider how different texture types map to framebuffer images. Remember that textures are a set of images. Textures can have mipmaps, and each individual mipmap level can contain one or more images.
  
Remember that textures are a set of images. Textures can have mipmaps; thus, each individual mipmap level can contain one or more images.
+
The way different texture types map to framebuffer images is as follows:
  
A 1D texture contains 2D images that have the vertical height of 1. Each individual image can be uniquely identified by a mipmap {{param|level}}.
+
* Images in a 1D texture are considered 2D images with a vertical height of 1. Each individual image can be uniquely identified by a mipmap {{param|level}}.
 +
* Images in a 2D texture are taken as normal. Each individual image can be uniquely identified by a mipmap {{param|level}}.
 +
* A mipmap level of a 3D texture is considered to be a set of 2D images, with the number of these being the extent of the Z coordinate for that mipmap level. Each integer value for the Z of a 3D texture mipmap level is a separate 2D layer. So each image in a 3D texture is uniquely identified by a {{param|layer}} and a mipmap {{param|level}}. Recall that different mipmap levels in a 3D texture will have different counts of Z coordinates.
 +
* [[Rectangle Texture]]s contain a single 2D image, and thus is identified by mipmap {{param|level}} 0.
 +
* [[Cubemap Texture]]s contain 6 2D images per mipmap. Thus, each image in a cubemap texture can be uniquely identified by a face {{param|target}} and a mipmap {{param|level}}. However, in some API functions, individual faces in a mipmap level are identified by a {{param|layer}} index.
 +
* Each mipmap level of 1D or 2D [[Array Texture]]s contains a number of images, equal to the count images in the array. Thus, each individual image is uniquely identified by a {{param|layer}} (the array index) and a mipmap {{param|level}}. For 1D array textures, each image has a height of 1. Unlike 3D textures, the {{param|layer}} doesn't change when going down the mipmap hierarchy.
 +
* [[Cubemap Array Texture]]s work like 2D array textures, only with 6 times the number of images. Thus a 2D image in the array is identified by the array {{param|layer}} (technically layer-face) and a mipmap {{param|level}}.
 +
* [[Buffer Texture]]s work like 1D texture, only they have a single image, identified by mipmap {{param|level}} 0.
  
A 2D texture contains 2D images. Each individual image can be uniquely identified by a mipmap {{param|level}}.
+
The highlighted words above are significant, as they match the parameters of the following functions used for attaching textures:
  
A [[Rectangle Texture]] has a single 2D image, and thus is identified by mipmap {{param|level}} 0.
+
{{funcdef|void {{apifunc|glFramebufferTexture|1D}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLenum {{param|textarget}}, GLuint {{param|texture}}, GLint {{param|level}});
  
Each mipmap level of a 3D texture is considered a set of 2D images, with the number of these being the extent of the Z coordinate. Each integer value for the depth of a 3D texture mipmap level is a layer. So each image in a 3D texture is uniquely identified by a {{param|layer}} and a mipmap {{param|level}}.
+
void {{apifunc|glFramebufferTexture|2D}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLenum {{param|textarget}}, GLuint {{param|texture}}, GLint {{param|level}});
  
[[Cubemap Textures|Cubemaps]] contain 6 targets, each of which is a 2D image. Thus, each image in a cubemap texture can be uniquely identified by a {{param|target}} and a mipmap {{param|level}}.
+
void {{apifunc|glFramebufferTextureLayer}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLuint {{param|texture}}, GLint {{param|level}}, GLint {{param|layer}});}}
 
+
Each mipmap level of a 1D [[Array Texture]]s contains a number of images, equal to the count images in the array. While these images are technically one-dimensional, they are promoted to 2D status for FBO purposes in the same way as a non-array 1D texture: by using a height of 1. Thus, each individual image is uniquely identified by a {{param|layer}} (the array index) and a mipmap {{param|level}}.
+
 
+
2D [[Array Textures|Array textures]] are much like 3D textures, except instead of the number of Z slices, it is the array count. Each 2D image in an array texture can be uniquely identified by a {{param|layer}} (the array index) and a mipmap {{param|level}}. Unlike 3D textures, the array count doesn't change when going down the mipmap hierarchy.
+
 
+
Cubemap array textures work like 2D array textures, only with 6 times the number of images. Thus a 2D image in the array is identified by the array {{param|layer}} (technically layer-face) and a mipmap {{param|level}}.
+
 
+
[[Buffer Texture]]s work like 1D texture, only they have a single image, identified by mipmap {{param|level}} 0.
+
 
+
The highlighted words above are significant, as they match the parameters of the following functions used for attaching textures:
+
  
  void {{apifunc|glFramebufferTexture|1D}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLenum {{param|textarget}}, GLuint {{param|texture}}, GLint {{param|level}});
 
  void {{apifunc|glFramebufferTexture|2D}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLenum {{param|textarget}}, GLuint {{param|texture}}, GLint {{param|level}});
 
  void {{apifunc|glFramebufferTextureLayer}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLuint {{param|texture}}, GLint {{param|level}}, GLint {{param|layer}});
 
  
 
The {{param|target}} parameter here is the same as the one for bind. However, GL_FRAMEBUFFER doesn't mean both read and draw (as that would make no sense); instead, it is the same as GL_DRAW_FRAMEBUFFER. The {{param|attachment}} parameter is one of the above attachment points.
 
The {{param|target}} parameter here is the same as the one for bind. However, GL_FRAMEBUFFER doesn't mean both read and draw (as that would make no sense); instead, it is the same as GL_DRAW_FRAMEBUFFER. The {{param|attachment}} parameter is one of the above attachment points.
Line 82: Line 77:
 
Because texture objects can hold multiple images, you must specify exactly which image to attach to this attachment point. The parameters match their above definitions, with the exception of {{param|textarget}}.
 
Because texture objects can hold multiple images, you must specify exactly which image to attach to this attachment point. The parameters match their above definitions, with the exception of {{param|textarget}}.
  
When attaching a non-cubemap, {{param|textarget}} should be the proper texture type: GL_TEXTURE_1D, GL_TEXTURE_2D_MULTISAMPLE, etc. When attaching a cubemap, you must use the Texture2D function, and the {{param|textarget}} must be one of the 6 targets for [[Cubemap Textures|cubemap binding]].
+
When attaching a non-cubemap, {{param|textarget}} should be the proper texture type: GL_TEXTURE_1D, GL_TEXTURE_2D_MULTISAMPLE, etc. When attaching a (non-array) cubemap, you must use the Texture2D function, and the {{param|textarget}} must be one of the 6 targets for [[Cubemap Textures|cubemap binding]]. When attaching an image from a [[Cubemap Array Texture|cubemap array]], you must use TextureLayer, with the {{param|layer}} being a layer-face.
  
: '''Legacy Note:''' There is a function, {{apifunc|glFramebufferTexture|3D}}, specifically for 3D textures. However, you shouldn't bother with it, as the TextureLayer function can do everything it can and more.
+
{{note|If {{require|4.5|direct_state_access}} is available, then {{apifunc|glFramebufferTextureLayer}} may take non-array cubemap textures. They are treated as though they were an array cubemap with one layer (so 6 layer-faces). This means that you never need to use the {{param|Texture2D}} or {{param|Texture1D}} functions for anything.}}
 +
 
 +
{{legacy note|There is a function, {{apifunc|glFramebufferTexture|3D}}, specifically for 3D textures. However, you shouldn't bother with it, as the TextureLayer function can do everything it can and more.}}
  
 
[[Renderbuffer Objects|Renderbuffers]] can also be attached to FBOs. Indeed, this is the only way to use them besides just creating the storage for them.
 
[[Renderbuffer Objects|Renderbuffers]] can also be attached to FBOs. Indeed, this is the only way to use them besides just creating the storage for them.
Line 90: Line 87:
 
Once you have created a renderbuffer object and made storage for it (given a size and format), you can attach it to an FBO with this function:
 
Once you have created a renderbuffer object and made storage for it (given a size and format), you can attach it to an FBO with this function:
  
  void {{apifunc|glFramebufferRenderbuffer}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLenum {{param|renderbuffertarget}}, GLuint {{param|renderbuffer}});
+
{{funcdef|void {{apifunc|glFramebufferRenderbuffer}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLenum {{param|renderbuffertarget}}, GLuint {{param|renderbuffer}});}}
  
 
The parameters work mostly the same as with texture attachment. The {{param|renderbuffertarget}} param must be {{enum|GL_RENDERBUFFER}}. The {{param|renderbuffer}} parameter is the renderbuffer object's name.
 
The parameters work mostly the same as with texture attachment. The {{param|renderbuffertarget}} param must be {{enum|GL_RENDERBUFFER}}. The {{param|renderbuffer}} parameter is the renderbuffer object's name.
Line 98: Line 95:
 
A layered image, as previously defined, is an ordered sequence of images of a particular size. A number of different kinds of textures can be considered layered.
 
A layered image, as previously defined, is an ordered sequence of images of a particular size. A number of different kinds of textures can be considered layered.
  
A single mipmap level of a 1D or 2D array texture is a layered image, where the number of layers is the array size. A single mipmap level of a 3D texture is likewise a layered image, where the number of layers is the depth of that particular mipmap level. Also, a mipmap level of a cubemap is a layered image. For cubemaps, you get exactly 6 layers, one for each face. And the order of the faces is the same as the order of the enumerators:
+
A single mipmap level of a 1D or 2D [[Array Texture]] is a layered image, where the number of layers is the array size. A single mipmap level of a 3D texture is likewise a layered image, where the number of layers is the depth of that particular mipmap level. Also, a mipmap level of a [[Cubemap Texture]] is a layered image. For cubemaps, you get exactly 6 layers, one for each face. And the order of the faces is the same as the order of the enumerators:
  
{| class="wikitable" border="1"
+
{{cubemap layer face ordering}}
|-
+
!  Layer number
+
!  Cubemap face
+
|-
+
|  0
+
|  GL_TEXTURE_CUBEMAP_POSITIVE_X
+
|-
+
|  1
+
|  GL_TEXTURE_CUBEMAP_NEGATIVE_X
+
|-
+
|  2
+
|  GL_TEXTURE_CUBEMAP_POSITIVE_Y
+
|-
+
|  3
+
|  GL_TEXTURE_CUBEMAP_NEGATIVE_Y
+
|-
+
|  4
+
|  GL_TEXTURE_CUBEMAP_POSITIVE_Z
+
|-
+
|  5
+
|  GL_TEXTURE_CUBEMAP_NEGATIVE_Z
+
|}
+
  
For [[Cubemap Texture#Cubemap array textures|cubemap arrays]], the value that {{code|gl_Layer}} represents is the layer-face index. Thus it is the face within a layer, ordered as above. So if you want to render to the 3rd layer, +z face, you would set {{code|gl_Layer}} to (2 * 6) + 4, or 16.
+
For [[Cubemap Array Texture|cubemap arrays]], the value that {{code|gl_Layer}} represents is the layer-face index. Thus it is the face within a layer, ordered as above. So if you want to render to the 3rd layer, +z face, you would set {{code|gl_Layer}} to (2 * 6) + 4, or 16.
  
 
Each texture, when taken as a layered image, has a specific number of layers. For array and 3D textures, this is the depth of the texture. For cubemaps, this is always exactly 6 layers: one per face. Cubemap arrays have 6 * the number of layers, which is the number of layer-faces.
 
Each texture, when taken as a layered image, has a specific number of layers. For array and 3D textures, this is the depth of the texture. For cubemaps, this is always exactly 6 layers: one per face. Cubemap arrays have 6 * the number of layers, which is the number of layer-faces.
  
To bind a texture as a layered image, use the following command:
+
To bind a mipmap level of a texture as a layered image, use the following command:
  
  void {{apifunc|glFramebufferTexture}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLuint {{param|texture}}, GLint {{param|level}});
+
{{funcdef|void {{apifunc|glFramebufferTexture}}(GLenum {{param|target}}, GLenum {{param|attachment}}, GLuint {{param|texture}}, GLint {{param|level}});}}
  
 
The parameters have the same meaning as above. Indeed, this function can replace many of the uses for {{apifunc|glFramebufferTexture|1D, 2D, or Layer}}, as long as you do not intend to attach specific layers of array textures, cubemaps, or 3D textures as regular, non-layered images. If the {{param|texture}} is one of these kinds of textures, then the given mipmap {{param|level}} will be attached as a layered image with the number of layers that the given texture has.
 
The parameters have the same meaning as above. Indeed, this function can replace many of the uses for {{apifunc|glFramebufferTexture|1D, 2D, or Layer}}, as long as you do not intend to attach specific layers of array textures, cubemaps, or 3D textures as regular, non-layered images. If the {{param|texture}} is one of these kinds of textures, then the given mipmap {{param|level}} will be attached as a layered image with the number of layers that the given texture has.
  
Layered image rendering is used with [[Geometry Shaders]].
+
Layered images are used with [[Layered Rendering]], which sends different primitives to different layers within the framebuffer.
  
 
== Empty framebuffers ==
 
== Empty framebuffers ==
Line 143: Line 118:
 
}}
 
}}
  
It is possible to render to a framebuffer object that has no attachments. Obviously none of the fragment shader outputs will be written to anywhere in this case, but rendering can otherwise proceed as normal. This is useful for using [[Image Load Store|arbitrary reading and writing of image data]], instead of writing to a bound framebuffer.
+
It is possible to render to a framebuffer object that has no attachments. Obviously none of the fragment shader outputs will be written to anywhere in this case, but rendering can otherwise proceed as normal. This is useful for using [[Image Load Store|arbitrary reading and writing of image data]] from shaders, rather than writing to a bound framebuffer.
  
However, the rasterization of primitives is always based on the area and characteristics of the bound framebuffer. Normally, these characteristics (size, number of samples for [[Multisample|multisample rendering]], etc) are defined by the attached images. If no images are attached, these characteristics must be defined in some other fashion.
+
However, the rasterization of primitives is always based on the area and characteristics of the bound framebuffer. These characteristics (size, number of samples for [[Multisample|multisample rendering]], etc) would normally be defined by the attached images. If no images are attached, these characteristics must be defined in some other fashion.
  
The width and height of an FBO with no attachments can be set with this function:
+
The characteristics for an FBO with no attachments can be set with this function:
  
<br style="clear: both" />
 
 
  void {{apifunc|glFramebufferParameter|i}}(GLenum {{param|target}}, GLenum {{param|pname}}, GLint {{param|param}});
 
  void {{apifunc|glFramebufferParameter|i}}(GLenum {{param|target}}, GLenum {{param|pname}}, GLint {{param|param}});
  
{{param|target}} is the location where the framebuffer object is bound. To set the width, set {{param|pname}} to {{enum|GL_FRAMEBUFFER_DEFAULT_WIDTH?}}; to set the height, use {{enum|GL_FRAMEBUFFER_DEFAULT_HEIGHT}}.
+
{{param|target}} is the location where the framebuffer object is bound. To set the width, set {{param|pname}} to {{enum|GL_FRAMEBUFFER_DEFAULT_WIDTH}}; to set the height, use {{enum|GL_FRAMEBUFFER_DEFAULT_HEIGHT}}.
  
Layered framebuffers can be simulated by using {{enum|GL_FRAMEBUFFER_DEFAULT_LAYERS}}. Multisample framebuffers can be simulated using {{enum|GL_FRAMEBUFFER_DEFAULT_SAMPLES}} to set the number of samples. Fixed multisample location can similarly be simulated with {{enum|GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS?}}.
+
Layered framebuffers can be simulated by setting {{enum|GL_FRAMEBUFFER_DEFAULT_LAYERS}} to a layer count other than 0. Multisample framebuffers can be simulated by setting {{enum|GL_FRAMEBUFFER_DEFAULT_SAMPLES}} to a number of samples other than 0. Fixed multisample location can similarly be simulated by setting {{enum|GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS}} to a non-zero value.
  
 
Note that rendering is ''only'' limited to these parameters if no images are attached to the FBO. If images are attached, then these parameters are ignored. You should only set these values if you intend to use the FBO without images.
 
Note that rendering is ''only'' limited to these parameters if no images are attached to the FBO. If images are attached, then these parameters are ignored. You should only set these values if you intend to use the FBO without images.
Line 184: Line 158:
 
These are the rules for framebuffer completeness. The order of these rules matters.
 
These are the rules for framebuffer completeness. The order of these rules matters.
  
# If the {{param|target}} of {{apifunc|glCheckFramebufferStatus}} references the default framebuffer (ie: FBO object number 0 is bound), and the default framebuffer does not exist, then you will get {{enum|GL_FRAMEBUFFER_UNDEFINED}}. If the default framebuffer exists, then you always get {{enum|GL_FRAMEBUFFER_COMPLETE}}. The rest of the rules apply when an FBO is bound.
+
# If the {{param|target}} of {{apifunc|glCheckFramebufferStatus}} references the [[Default Framebuffer]] (ie: FBO object number 0 is bound), and the default framebuffer does not exist, then you will get {{enum|GL_FRAMEBUFFER_UNDEFINED}}. If the default framebuffer exists, then you always get {{enum|GL_FRAMEBUFFER_COMPLETE}}. The rest of the rules apply when an FBO is bound.
# All attachments that are set as a draw buffer or read buffer (see below) must be attachment complete, as defined above. ({{enum|GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT}} when false).
+
# All attachments must be [[#Attachment Completeness|attachment complete]]. ({{enum|GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT}} when false).
# There must be at least one image attached to the FBO, or if GL 4.3/ARB_framebuffer_no_attachment is available, the {{enum|GL_FRAMEBUFFER_DEFAULT_WIDTH?}} and {{enum|GL_FRAMEBUFFER_DEFAULT_HEIGHT}} parameters of the framebuffer must both be non-zero.({{enum|GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT}} when false).
+
# There must be at least one image attached to the FBO, or if {{require|4.3|framebuffer_no_attachments}} is available, [[#Empty framebuffers|the {{enum|GL_FRAMEBUFFER_DEFAULT_WIDTH}} and {{enum|GL_FRAMEBUFFER_DEFAULT_HEIGHT}} parameters]] of the framebuffer must both be non-zero. ({{enum|GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT}} when false).
# All draw buffers (see below) must specify color attachment points that have images attached. ({{enum|GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER}} when false). Note that this test is not performed if GL 4.2/{{extref|ES2_compatibility}} is available.
+
# Each [[Framebuffer Draw Buffer|draw buffers]] must either specify color attachment points that have images attached or must be {{enum|GL_NONE}}. ({{enum|GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER}} when false). Note that this test is not performed if {{require|4.1|ES2_compatibility}} is available.
# If the read buffer is set, then it must specify an attachment point that has an image attached. ({{enum|GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER}} when false). Note that this test is not performed if GL 4.2/{{extref|ES2_compatibility}} is available.
+
# If the [[Framebuffer Read Buffer|read buffer]] is set, then it must specify an attachment point that has an image attached. ({{enum|GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER}} when false). Note that this test is not performed if {{require|4.1|ES2_compatibility}} is available.
 
# All images must have the same number of [[Multisampling|multisample samples]]. ({{enum|GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE}} when false).
 
# All images must have the same number of [[Multisampling|multisample samples]]. ({{enum|GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE}} when false).
 
# If a layered image is attached to one attachment, then all attachments must be layered attachments. The attached layers do not have to have the same number of layers, nor do the layers have to come from the same kind of texture (a cubemap color texture can be paired with an array depth texture) ({{enum|GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS}} when false).
 
# If a layered image is attached to one attachment, then all attachments must be layered attachments. The attached layers do not have to have the same number of layers, nor do the layers have to come from the same kind of texture (a cubemap color texture can be paired with an array depth texture) ({{enum|GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS}} when false).
Line 202: Line 176:
 
OpenGL allows implementations to state that they do not support some combination of image formats for the attached images; they do this by returning {{enum|GL_FRAMEBUFFER_UNSUPPORTED}} when you attempt to use an unsupported format combination.
 
OpenGL allows implementations to state that they do not support some combination of image formats for the attached images; they do this by returning {{enum|GL_FRAMEBUFFER_UNSUPPORTED}} when you attempt to use an unsupported format combination.
  
However, the OpenGL specification also requires that implementations support certain formats; that is, if you use these formats, implementations are forbidden to return {{enum|GL_FRAMEBUFFER_UNSUPPORTED}}. This list of required formats is also the list of required [[Image Formats|image formats]] that all OpenGL implementations must support. These are most of the useful formats. Basically, don't concern yourself with {{enum|GL_FRAMEBUFFER_UNSUPPORTED}} too much. Check for it, but you'll be fine as long as you stick to the required formats.
+
However, the OpenGL specification also requires that implementations support certain format combinations; if you use these, implementations are forbidden to return {{enum|GL_FRAMEBUFFER_UNSUPPORTED}}. Implementations must allow any combination of color formats, so long as all of those color formats come from the [[Required Image Format|required set of color formats]].
  
{{legacy note|{{enum|GL_FRAMEBUFFER_UNSUPPORTED}} was initially, in the days of EXT_framebuffer_object, much less forgiving. The specification didn't have a list of required image formats. Indeed, the only guarantee that the EXT_FBO spec made was that there was at least ''one'' combination of formats that implementations supported; it provided no hints as to what that combination might be. The core extension ARB_framebuffer_object does differ from the core specification in one crucial way: it uses the EXT wording for {{enum|GL_FRAMEBUFFER_UNSUPPORTED}}. So if you're using 3.0, you don't have to worry much about unsupported. If you're using ARB_framebuffer_object, then you should be concerned and do appropriate testing.}}
+
These color formats can be combined with a depth attachment with any of the required depth formats. Stencil attachments can also be used, again with the required stencil formats, as well as the combined depth/stencil formats. However, implementations are only required to support both a depth and stencil attachment simultaneously '''if''' both attachments refer to the same image.
  
== Multiple Render Targets ==
+
This means that if you want stencil with no depth, you can use one of the required stencil formats. If you want depth with no stencil, you can use one of the required depth formats. But if you want depth and stencil, you must use a depth/stencil format and the same image in that texture must be attached to both the depth and stencil attachments.
  
Modern [[GLSL|shaders]] allow the user to render to multiple render targets simultaneously. To facilitate this, FBOs (and the default framebuffer) have a mapping that allows the user to define which fragment shader outputs go to which buffers. The way this works is somewhat complicated.
+
Staying within these limits means you won't see {{enum|GL_FRAMEBUFFER_UNSUPPORTED}}. Going outside of these limits makes it entirely possible to get this incompleteness.
  
When linking a fragment shader, the user will assign each fragment shader output variable to a number. This number is between 0 and {{enum|GL_MAX_DRAW_BUFFERS}}-1 under normal circumstances, or between 0 and {{enum|GL_MAX_DUAL_SOURCE_DRAW_BUFFERS}} - 1 when a fragment shader is outputting values to the second color of a buffer, for [[Blending#Dual Source Blending|dual source blending]]. The draw buffers list in the FBO (or the default framebuffer) is used to map between the values set into the fragment shader and the attachment names in the FBO (or buffers in the default framebuffer).
+
{{legacy note|{{enum|GL_FRAMEBUFFER_UNSUPPORTED}} was, in the days of {{extref|framebuffer_object|EXT}}, much less forgiving. The specification didn't have a list of required image formats. Indeed, the only guarantee that the EXT_FBO spec made was that there was at least ''one'' combination of formats that implementations supported; it provided no hints as to what that combination might be. The core extension {{extref|framebuffer_object}} does differ from the core specification in one crucial way: it uses the EXT wording for {{enum|GL_FRAMEBUFFER_UNSUPPORTED}}. So if you're using 3.0, just use the required formats as above. If you're using ARB_framebuffer_object, then you should be concerned and do appropriate testing.}}
 
+
For example, let's say your fragment shader defines the following outputs:
+
 
+
  out vec4 mainColor;
+
  out vec2 subsideraryInfo;
+
 
+
When you link your shader, you use {{apifunc|glBindFragDataLocation}} or {{apifunc|glBindFragDataLocationIndexed}} to assign 0 to {{code|mainColor}} and 1 to {{code|subsideraryInfo}}. You can also use {{code|layout}} syntax to define this directly in the shader, as you would for attribute indices:
+
 
+
  layout(location = 0) out vec4 mainColor;
+
  layout(location = 1) out vec2 subsideraryInfo;
+
 
+
It is up to the draw buffers state in the FBO to state where these get rendered to. To set this mapping, you use this function:
+
 
+
  void {{apifunc|glDrawBuffers}}( GLsizei {{param|n}}, const GLenum *{{param|bufs}} );
+
 
+
This function sets up the entire mapping table in one shot. The indices in the list correspond to the values set with {{apifunc|glBindFragDataLocation}} or {{apifunc|glBindFragDataLocationIndexed}}. This means that the list can only be as large as {{enum|GL_MAX_DRAW_BUFFERS}} or {{enum|GL_MAX_DUAL_SOURCE_DRAW_BUFFERS}} when using [[Blending#Dual_Source_Blending|dual source blending]]. The entries in the {{param|bufs}} array are enumerators referring to buffer names in the framebuffer.
+
 
+
The default framebuffer and FBOs have different names for their attached images. The default framebuffer uses {{enum|GL_AUX''i''}}, {{enum|GL_BACK_LEFT}}, and so on. FBOs use {{enum|GL_COLOR_ATTACHMENT''i''}} values, where ''i'' is less than {{enum|GL_MAX_COLOR_ATTACHMENTS}}. These attachments are passed to {{apifunc|glDrawBuffers}}. An entry in the list can be {{enum|GL_NONE}}, which means that the output (if the shader outputs a value for it at all) is discarded.
+
 
+
If you are only setting up one draw buffer, you may use {{apifunc|glDrawBuffer}}. It takes one enumeration value and sets the fragment data location 0 to draw to that buffer. All other fragment data location values are set to {{enum|GL_NONE}}.
+
 
+
The state set by {{apifunc|glDrawBuffers}} is part of the state of the FBO (or default framebuffer). So you can generally set this up once and leave it set.
+
 
+
== Framebuffer Blitting ==
+
 
+
The reason for the separation of {{enum|GL_DRAW_FRAMEBUFFER}} and {{enum|GL_READ_FRAMEBUFFER}} bindings is to allow data in one buffer to be blitted to another buffer.
+
 
+
A blit operation is a special form of copy operation; it copies a rectangular area of pixels from one framebuffer to another. This function also has some very specific properties with regard to [[Multisampling|multisampling]].
+
 
+
You bind the source framebuffer to {{enum|GL_READ_FRAMEBUFFER}}, then bind the destination framebuffer to {{enum|GL_DRAW_FRAMEBUFFER}}.
+
It is possible to use the same source and target buffer.
+
After that, you call this function:
+
 
+
  void {{apifunc|glBlitFramebuffer}}(GLint {{param|srcX0}}, GLint {{param|srcY0}}, GLint {{param|srcX1}}, GLint {{param|srcY1}},
+
    GLint {{param|dstX0}}, GLint {{param|dstY0}}, GLint {{param|dstX1}}, GLint {{param|dstY1}},
+
    GLbitfield {{param|mask}}, GLenum {{param|filter}});
+
 
+
The pixels in the rectangular area specified by the {{param|src}} values are copied to the rectangular area specified by the {{param|dst}} values. The {{param|mask}} parameter is a bitfield that specifies which kinds of buffers you want copied: {{enum|GL_COLOR_BUFFER_BIT}}, {{enum|GL_DEPTH_BUFFER_BIT}}, {{enum|GL_STENCIL_BUFFER_BIT}}, or some combination. The {{param|filter}} parameter specifies how you want filtering performed if the two rectangles are not the same size.
+
 
+
One thing to keep in mind is this: blit operations only read from the color buffer specified by {{apifunc|glReadBuffer}} in the read FBO and will only write to the color buffers specified by {{apifunc|glDrawBuffers}} in the write FBO. If multiple draw buffers are specified, then multiple color buffers are updated. This assumes that {{param|mask}} included the color buffer. The depth and stencil buffers of the source framebuffers are blitted to the destination if the {{param|mask}} specifies them.
+
 
+
The {{apifunc|glReadBuffer}} state is stored with the FBO/default framebuffer, just like the {{apifunc|glDrawBuffers}} state.
+
 
+
Note that it is perfectly valid to read from the default framebuffer and write to an FBO, or vice-versa.
+
 
+
=== Format Considerations ===
+
 
+
Blitting is not the same as performing a [[Pixel Transfer|pixel transfer operation]]. The conversion between source and destination format is more limited. Blitting depth and stencil buffers works as expected: values are converted from one bitdepth to the other as needed. Conversion between color formats is different.
+
 
+
A blit operation can only convert between formats within 3 groups. Signed integral and unsigned integral formats make up two groups, with all normalized and floating-point formats making up the third. Thus, it is legal to blit from an GL_RGB8 buffer to a GL_RGB32F and vice versa. But it is not legal to blit a GL_RGB8 from or to a GL_RGBI8 format image.
+
 
+
The data during blitting is converted according to simple rules. Blitting from a floating-point format to a normalized integer format will cause clamping, either to [0, 1] for unsigned normalized or [-1, 1] for signed normalized.
+
 
+
=== Multisampling Considerations ===
+
 
+
Multisampling is supported with the default framebuffer (through WGL/GLX_multisample) and/or FBOs (through multisampled [[Renderbuffer Objects|renderbuffers]] or [[Multisample Textures|textures]], where supported).
+
 
+
As explained in the article on [[Multisampling]], a multisampled buffer must be resolved into a single sample before it can be displayed. When the default framebuffer uses multisampling, this resolving operation is automatic, occurring during framebuffer swapping (though reading from the framebuffer can cause it to happen anyway).
+
 
+
Each FBO or framebuffer has a specific number of multisample samples (remember: an FBO cannot be framebuffer-complete if all of the attached images do not have the same number of samples). When you blit between two FBOs with the same number of samples, the copy is done directly; the destination buffer gets the same information the source had.
+
 
+
It is an error to blit between buffers with different numbers of samples, ''unless'' one of them has zero samples. You get this by not attaching multisampled images to that FBO, or not using multisampled default framebuffers.
+
 
+
In this special case, two things can happen. If the read framebuffer is the one with zero samples, then the draw buffer has all of its samples per-pixel replaced with the values from the read framebuffer. However, if the draw framebuffer is the one with zero samples, then it causes the multisampled framebuffer to have its multisamples resolved into a single sample per pixel. This explicit resolution is very useful when dealing with multisampled buffers.
+
 
+
As with all multisample behavior, none of this works at all unless {{apifunc|glEnable|(GL_MULTISAMPLE)}} is in effect (which is the default).
+
  
 
== Feedback Loops ==
 
== Feedback Loops ==
 +
{{main|Memory Model#Framebuffer objects}}
  
 
It is possible to bind a texture to an FBO, bind that same texture to a shader, and then try to render with it at the same time.
 
It is possible to bind a texture to an FBO, bind that same texture to a shader, and then try to render with it at the same time.
 
This can cause problems.
 
  
 
It is perfectly valid to bind one ''image'' from a texture to an FBO and then render with that texture, as long as you prevent yourself from ''sampling'' from that image. If you do try to read and write to the same image, you get undefined results. Meaning it may do what you want, the sampler may get old data, the sampler may get ''half'' old and half new data, or it may get garbage data. Any of these are possible outcomes.
 
It is perfectly valid to bind one ''image'' from a texture to an FBO and then render with that texture, as long as you prevent yourself from ''sampling'' from that image. If you do try to read and write to the same image, you get undefined results. Meaning it may do what you want, the sampler may get old data, the sampler may get ''half'' old and half new data, or it may get garbage data. Any of these are possible outcomes.
  
Do not try this.
+
Do not do this. What you will get is undefined behavior.
 
+
Instead, you will have to switch back and forth between different images. One for reading, the other for writing. Alternatively, the [http://www.opengl.org/registry/specs/NV/texture_barrier.txt NV_texture_barrier extension] (supported widely on AMD hardware as well as NVIDIA) allows you some ''limited'' ability to read and write to the same image.
+
  
 
== EXT_Framebuffer_object ==
 
== EXT_Framebuffer_object ==

Latest revision as of 18:20, 2 July 2015

Framebuffer Object
Core in version 4.5
Core since version 3.0
Core ARB extension GL_ARB_framebuffer_object
EXT extension GL_EXT_framebuffer_object, GL_EXT_framebuffer_blit, GL_EXT_framebuffer_multisample, GL_EXT_packed_depth_stencil

Framebuffer Objects are OpenGL Objects, which allow for the creation of user-defined Framebuffers. With them, one can render to non-Default Framebuffer locations, and thus render without disturbing the main screen.

Semantics

Framebuffer objects are very complicated. As such, we need to explicitly define certain terminology.

Image
For the purposes of this article, an image is a single 2D array of pixels. It has a specific format for these pixels.
Layered Image
For the purposes of this article, a layered image is a sequence of images of a particular size and format. Layered images come from single mipmap levels of certain Texture types.
Texture
For the purposes of this article, a texture is an object that contains some number of images, as defined above. All of the images have the same format, but they do not have to have the same size (different mip-maps, for example). Textures can be accessed from Shaders via various methods.
Renderbuffer
A renderbuffer is an object that contains a single image. Renderbuffers cannot be accessed by Shaders in any way. The only way to work with a renderbuffer, besides creating it, is to put it into an FBO.
Attach
To connect one object to another. This term is used across all of OpenGL, but FBOs make the most use of the concept. Attachment is different from binding. Objects are bound to the context; objects are attached to one another.
Attachment point
A named location within a framebuffer object that a framebuffer-attachable image or layered image can be attached to. Attachment points restrict the general kind of Image Format for images attached to them.
Framebuffer-attachable image
Any image, as previously described, that can be attached to a framebuffer object.
Framebuffer-attachable layered image
Any layered image, as previously described, that can be attached to a framebuffer object.

Framebuffer Object Structure

As standard OpenGL Objects, FBOs have the usual glGenFramebuffers and glDeleteFramebuffers functions. As expected, it also has the usual glBindFramebuffer function, to bind an FBO to the context.

The target​ parameter for this object can take one of 3 values: GL_FRAMEBUFFER, GL_READ_FRAMEBUFFER, or GL_DRAW_FRAMEBUFFER. The last two allow you to bind an FBO so that reading commands (glReadPixels, etc) and writing commands (all rendering commands) can happen to two different framebuffers. The GL_FRAMEBUFFER binding target simply sets both the read and the write to the same FBO.

When an FBO is bound to a target, the available buffer names. The default framebuffer has buffer names like GL_FRONT, GL_BACK, GL_AUXi, GL_ACCUM, and so forth. FBOs do not have these.

Instead, FBOs have a different set of image names. Each FBO image represents an attachment point, a location in the FBO where an image can be attached. FBOs have the following attachment points:

  • GL_COLOR_ATTACHMENTi: These are an implementation-dependent number of attachment points. You can query GL_MAX_COLOR_ATTACHMENTS to determine the number of color attachments that an implementation will allow. The minimum value for this is 8, so you are guaranteed to be able to have at least color attachments 0-7. These attachment points can only have images bound to them with color-renderable formats. All compressed image formats are not color-renderable, and thus cannot be attached to an FBO.
  • GL_DEPTH_ATTACHMENT: This attachment point can only have images with depth formats bound to it. The image attached becomes the Depth Buffer for the FBO. **NOTE** Even if you don't plan on reading from this depth_attachment, an off screen buffer that will be rendered to should have a depth attachment.
  • GL_STENCIL_ATTACHMENT: This attachment point can only have images with stencil formats bound to it. The image attached becomes the stencil buffer for the FBO.
  • GL_DEPTH_STENCIL_ATTACHMENT: This is shorthand for "both depth and stencil". The image attached becomes both the depth and stencil buffers.
Note: If you use GL_DEPTH_STENCIL_ATTACHMENT, you should use a packed depth-stencil internal format for the texture or renderbuffer you are attaching.

Attaching Images

Now that we know where images can be attached to FBOs, we can start talking about how to actually attach images to these. In order to attach images to an FBO, we must first bind the FBO to the context with glBindFramebuffer.

You can attach images from any kind of texture to the framebuffer object. However, framebuffers are designed for 2D rendering. So there is a need to consider how different texture types map to framebuffer images. Remember that textures are a set of images. Textures can have mipmaps, and each individual mipmap level can contain one or more images.

The way different texture types map to framebuffer images is as follows:

  • Images in a 1D texture are considered 2D images with a vertical height of 1. Each individual image can be uniquely identified by a mipmap level​.
  • Images in a 2D texture are taken as normal. Each individual image can be uniquely identified by a mipmap level​.
  • A mipmap level of a 3D texture is considered to be a set of 2D images, with the number of these being the extent of the Z coordinate for that mipmap level. Each integer value for the Z of a 3D texture mipmap level is a separate 2D layer. So each image in a 3D texture is uniquely identified by a layer​ and a mipmap level​. Recall that different mipmap levels in a 3D texture will have different counts of Z coordinates.
  • Rectangle Textures contain a single 2D image, and thus is identified by mipmap level​ 0.
  • Cubemap Textures contain 6 2D images per mipmap. Thus, each image in a cubemap texture can be uniquely identified by a face target​ and a mipmap level​. However, in some API functions, individual faces in a mipmap level are identified by a layer​ index.
  • Each mipmap level of 1D or 2D Array Textures contains a number of images, equal to the count images in the array. Thus, each individual image is uniquely identified by a layer​ (the array index) and a mipmap level​. For 1D array textures, each image has a height of 1. Unlike 3D textures, the layer​ doesn't change when going down the mipmap hierarchy.
  • Cubemap Array Textures work like 2D array textures, only with 6 times the number of images. Thus a 2D image in the array is identified by the array layer​ (technically layer-face) and a mipmap level​.
  • Buffer Textures work like 1D texture, only they have a single image, identified by mipmap level​ 0.

The highlighted words above are significant, as they match the parameters of the following functions used for attaching textures:

void glFramebufferTexture1D(GLenum target​, GLenum attachment​, GLenum textarget​, GLuint texture​, GLint level​);

void glFramebufferTexture2D(GLenum target​, GLenum attachment​, GLenum textarget​, GLuint texture​, GLint level​);

void glFramebufferTextureLayer(GLenum target​, GLenum attachment​, GLuint texture​, GLint level​, GLint layer​);


The target​ parameter here is the same as the one for bind. However, GL_FRAMEBUFFER doesn't mean both read and draw (as that would make no sense); instead, it is the same as GL_DRAW_FRAMEBUFFER. The attachment​ parameter is one of the above attachment points.

The texture​ argument is the texture object name you want to attach from. If you pass zero as texture​, this has the effect of clearing the attachment for this attachment​, regardless of what kind of image was attached there.

Because texture objects can hold multiple images, you must specify exactly which image to attach to this attachment point. The parameters match their above definitions, with the exception of textarget​.

When attaching a non-cubemap, textarget​ should be the proper texture type: GL_TEXTURE_1D, GL_TEXTURE_2D_MULTISAMPLE, etc. When attaching a (non-array) cubemap, you must use the Texture2D function, and the textarget​ must be one of the 6 targets for cubemap binding. When attaching an image from a cubemap array, you must use TextureLayer, with the layer​ being a layer-face.

Note: If OpenGL 4.5 or ARB_direct_state_access is available, then glFramebufferTextureLayer may take non-array cubemap textures. They are treated as though they were an array cubemap with one layer (so 6 layer-faces). This means that you never need to use the Texture2D​ or Texture1D​ functions for anything.
Legacy Note: There is a function, glFramebufferTexture3D, specifically for 3D textures. However, you shouldn't bother with it, as the TextureLayer function can do everything it can and more.

Renderbuffers can also be attached to FBOs. Indeed, this is the only way to use them besides just creating the storage for them.

Once you have created a renderbuffer object and made storage for it (given a size and format), you can attach it to an FBO with this function:

void glFramebufferRenderbuffer(GLenum target​, GLenum attachment​, GLenum renderbuffertarget​, GLuint renderbuffer​);

The parameters work mostly the same as with texture attachment. The renderbuffertarget​ param must be GL_RENDERBUFFER. The renderbuffer​ parameter is the renderbuffer object's name.

Layered Images

A layered image, as previously defined, is an ordered sequence of images of a particular size. A number of different kinds of textures can be considered layered.

A single mipmap level of a 1D or 2D Array Texture is a layered image, where the number of layers is the array size. A single mipmap level of a 3D texture is likewise a layered image, where the number of layers is the depth of that particular mipmap level. Also, a mipmap level of a Cubemap Texture is a layered image. For cubemaps, you get exactly 6 layers, one for each face. And the order of the faces is the same as the order of the enumerators:

Layer number Cubemap face
0 GL_TEXTURE_CUBE_MAP_POSITIVE_X
1 GL_TEXTURE_CUBE_MAP_NEGATIVE_X
2 GL_TEXTURE_CUBE_MAP_POSITIVE_Y
3 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
4 GL_TEXTURE_CUBE_MAP_POSITIVE_Z
5 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z

For cubemap arrays, the value that gl_Layer​ represents is the layer-face index. Thus it is the face within a layer, ordered as above. So if you want to render to the 3rd layer, +z face, you would set gl_Layer​ to (2 * 6) + 4, or 16.

Each texture, when taken as a layered image, has a specific number of layers. For array and 3D textures, this is the depth of the texture. For cubemaps, this is always exactly 6 layers: one per face. Cubemap arrays have 6 * the number of layers, which is the number of layer-faces.

To bind a mipmap level of a texture as a layered image, use the following command:

void glFramebufferTexture(GLenum target​, GLenum attachment​, GLuint texture​, GLint level​);

The parameters have the same meaning as above. Indeed, this function can replace many of the uses for glFramebufferTexture1D, 2D, or Layer, as long as you do not intend to attach specific layers of array textures, cubemaps, or 3D textures as regular, non-layered images. If the texture​ is one of these kinds of textures, then the given mipmap level​ will be attached as a layered image with the number of layers that the given texture has.

Layered images are used with Layered Rendering, which sends different primitives to different layers within the framebuffer.

Empty framebuffers

Empty Framebuffers
Core in version 4.5
Core since version 4.3
Core ARB extension ARB_framebuffer_no_attachments

It is possible to render to a framebuffer object that has no attachments. Obviously none of the fragment shader outputs will be written to anywhere in this case, but rendering can otherwise proceed as normal. This is useful for using arbitrary reading and writing of image data from shaders, rather than writing to a bound framebuffer.

However, the rasterization of primitives is always based on the area and characteristics of the bound framebuffer. These characteristics (size, number of samples for multisample rendering, etc) would normally be defined by the attached images. If no images are attached, these characteristics must be defined in some other fashion.

The characteristics for an FBO with no attachments can be set with this function:

void glFramebufferParameteri(GLenum target​, GLenum pname​, GLint param​);

target​ is the location where the framebuffer object is bound. To set the width, set pname​ to GL_FRAMEBUFFER_DEFAULT_WIDTH; to set the height, use GL_FRAMEBUFFER_DEFAULT_HEIGHT.

Layered framebuffers can be simulated by setting GL_FRAMEBUFFER_DEFAULT_LAYERS to a layer count other than 0. Multisample framebuffers can be simulated by setting GL_FRAMEBUFFER_DEFAULT_SAMPLES to a number of samples other than 0. Fixed multisample location can similarly be simulated by setting GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS to a non-zero value.

Note that rendering is only limited to these parameters if no images are attached to the FBO. If images are attached, then these parameters are ignored. You should only set these values if you intend to use the FBO without images.

Framebuffer Completeness

Each attachment point in a FBO has specific restrictions on the format of images that can be attached to it. However, it is not an immediate GL error to attach an image to an attachment point that doesn't support that format. It is an error to try to use an FBO that has been improperly set up. There are also a number of other issues with regard to sizes of images and so forth that must be detected in order to be able to safely use the FBO.

An FBO that is valid for use is said to be "framebuffer complete". To test framebuffer completeness, call this function:

 GLenum glCheckFramebufferStatus(GLenum target​);

You are not required to call this manually. However, using an incomplete FBO is an error, so it's always a good idea to check.

The return value is GL_FRAMEBUFFER_COMPLETE if the FBO can be used. If it is something else, then there is a problem. Below are the rules for completeness and the associated return values you will receive if they are not followed.

Attachment Completeness

Each attachment point itself must be complete according to these rules. Empty attachments (attachments with no image attached) are complete by default. If an image is attached, it must adhere to the following rules:

  • The source object for the image still exists and has the same type it was attached with.
  • The image has a non-zero width and height (the height of a 1D image is assumed to be 1). The width/height must also be less than GL_MAX_FRAMEBUFFER_WIDTH and GL_MAX_FRAMEBUFFER_HEIGHT respectively (if GL 4.3/ARB_framebuffer_no_attachments).
  • The layer for 3D or array textures attachments is less than the depth of the texture. It must also be less than GL_MAX_FRAMEBUFFER_LAYERS (if GL 4.3/ARB_framebuffer_no_attachments).
  • The number of samples must be less than GL_MAX_FRAMEBUFFER_SAMPLES (if GL 4.3/ARB_framebuffer_no_attachments).
  • The image's format must match the attachment point's requirements, as defined above. Color-renderable formats for color attachments, etc.

Completeness Rules

These are the rules for framebuffer completeness. The order of these rules matters.

  1. If the target​ of glCheckFramebufferStatus references the Default Framebuffer (ie: FBO object number 0 is bound), and the default framebuffer does not exist, then you will get GL_FRAMEBUFFER_UNDEFINED. If the default framebuffer exists, then you always get GL_FRAMEBUFFER_COMPLETE. The rest of the rules apply when an FBO is bound.
  2. All attachments must be attachment complete. (GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT when false).
  3. There must be at least one image attached to the FBO, or if OpenGL 4.3 or ARB_framebuffer_no_attachments is available, the GL_FRAMEBUFFER_DEFAULT_WIDTH and GL_FRAMEBUFFER_DEFAULT_HEIGHT parameters of the framebuffer must both be non-zero. (GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT when false).
  4. Each draw buffers must either specify color attachment points that have images attached or must be GL_NONE. (GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER when false). Note that this test is not performed if OpenGL 4.1 or ARB_ES2_compatibility is available.
  5. If the read buffer is set, then it must specify an attachment point that has an image attached. (GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER when false). Note that this test is not performed if OpenGL 4.1 or ARB_ES2_compatibility is available.
  6. All images must have the same number of multisample samples. (GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE when false).
  7. If a layered image is attached to one attachment, then all attachments must be layered attachments. The attached layers do not have to have the same number of layers, nor do the layers have to come from the same kind of texture (a cubemap color texture can be paired with an array depth texture) (GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS when false).

Notice that there is no restriction based on size. The effective size of the FBO is the intersection of all of the sizes of the bound images (ie: the smallest in each dimension).

These rules are all code-based. If you ever get any of these values from glCheckFramebufferStatus, it is because your program has done something wrong in setting up the FBO. Each one has a specific remedy for it.

There's one more rule that can trip you up:

  • The implementation likes your combination of attached image formats. (GL_FRAMEBUFFER_UNSUPPORTED when false).

OpenGL allows implementations to state that they do not support some combination of image formats for the attached images; they do this by returning GL_FRAMEBUFFER_UNSUPPORTED when you attempt to use an unsupported format combination.

However, the OpenGL specification also requires that implementations support certain format combinations; if you use these, implementations are forbidden to return GL_FRAMEBUFFER_UNSUPPORTED. Implementations must allow any combination of color formats, so long as all of those color formats come from the required set of color formats.

These color formats can be combined with a depth attachment with any of the required depth formats. Stencil attachments can also be used, again with the required stencil formats, as well as the combined depth/stencil formats. However, implementations are only required to support both a depth and stencil attachment simultaneously if both attachments refer to the same image.

This means that if you want stencil with no depth, you can use one of the required stencil formats. If you want depth with no stencil, you can use one of the required depth formats. But if you want depth and stencil, you must use a depth/stencil format and the same image in that texture must be attached to both the depth and stencil attachments.

Staying within these limits means you won't see GL_FRAMEBUFFER_UNSUPPORTED. Going outside of these limits makes it entirely possible to get this incompleteness.

Legacy Note: GL_FRAMEBUFFER_UNSUPPORTED was, in the days of EXT_framebuffer_object, much less forgiving. The specification didn't have a list of required image formats. Indeed, the only guarantee that the EXT_FBO spec made was that there was at least one combination of formats that implementations supported; it provided no hints as to what that combination might be. The core extension ARB_framebuffer_object does differ from the core specification in one crucial way: it uses the EXT wording for GL_FRAMEBUFFER_UNSUPPORTED. So if you're using 3.0, just use the required formats as above. If you're using ARB_framebuffer_object, then you should be concerned and do appropriate testing.

Feedback Loops

It is possible to bind a texture to an FBO, bind that same texture to a shader, and then try to render with it at the same time.

It is perfectly valid to bind one image from a texture to an FBO and then render with that texture, as long as you prevent yourself from sampling from that image. If you do try to read and write to the same image, you get undefined results. Meaning it may do what you want, the sampler may get old data, the sampler may get half old and half new data, or it may get garbage data. Any of these are possible outcomes.

Do not do this. What you will get is undefined behavior.

EXT_Framebuffer_object

The original form of FBOs was this extension. It lacked quite a bit of the above functionality, which later extensions granted. The biggest difference is that it has more hard-coded restrictions on framebuffer completeness. All of the images have to be the same size in the EXT spec, for example. Some of these limitations were hardware-based. So there may be hardware that supports EXT_FBO and not ARB_FBO, even thought they support things like EXT_FBO_blit and other parts of ARB_FBO.

See Also

Reference