Framebuffers¶
A framebuffer is an object that holds the output of a program that ran on the GPU. Usually it consists of a color buffer and a depth buffer. An application always has at least one framebuffer: the default framebuffer, which is the window of the application. For off-screen rendering, needed for post-processing, additional framebuffers can be used.
A framebuffer has one or more color buffers, and optionally a depth and/or a stencil buffer.
Info
The various objects described on this page are declared in
the package Orka.Rendering.Framebuffers
.
Use a frame graph instead
Use a frame graph instead to render a texture to the screen using one or more programs. It will manage the needed framebuffers for you and automatically update the state needed for each render pass.
Creating a framebuffer¶
A framebuffer object can be created by calling the function Create_Framebuffer
:
Framebuffer_1 : Framebuffer := Create_Framebuffer (Width, Height, Samples);
The given parameters are stored so that when textures are attached (explained below), it can be verified whether they are compatible.
The default framebuffer can be created with the function Create_Default_Framebuffer
:
Framebuffer_Default : Framebuffer :=
Create_Default_Framebuffer (Window.Width, Window.Height);
A framebuffer has one discriminant named Default
, which specifies whether it is
the default framebuffer or a regular framebuffer object. Thus a framebuffer object
can be stored in a record as following:
type Record_1 is record
Framebuffer_1 : Orka.Rendering.Framebuffers.Framebuffer (Default => False);
end record;
The width, height, and samples of a framebuffer can be queried with the functions
Width
, Height
, and Samples
.
Attaching textures¶
To give the framebuffer a color, depth, or stencil buffer, a texture must be attached to the framebuffer. At most one depth or stencil buffer can be attached. A framebuffer supports up to 8 color buffers, but usually a framebuffer has just one.
To add a texture to the first color buffer, to the depth buffer, or to the
stencil buffer, call the procedure Attach
:
Framebuffer_1.Attach (Texture_Color_1);
Framebuffer_1.Attach (Texture_Depth);
The texture is attached to the attachment point based on the internal format
of the texture or or to the given attachment point if the texture is color renderable.
The parameter Attachment
can be used to specify the attachment point and it
has the default value Color_Attachment_0
.
The attachment point is ignored for textures with a depth or stencil format,
since a framebuffer supports at most one buffer for these kinds.
If the texture is layered and you want to attach a specific layer,
then the procedure Attach_Layer
should be called instead:
Framebuffer_1.Attach_Layer (Texture_Cube_Map_1, Color_Attachment_0, Layer => 5);
The function Has_Attachment
can be used to query whether an attachment point
has a texture attached to it.
Note
If one of the attached textures is layered (3D, 1D/2D array, cube map [array], or 2D multisampled array), then all attachments must have the same kind.
Note
All attachments of the framebuffer must have the same amount of samples and they must all have fixed sample locations, or none of them must have them.
Detaching a texture¶
To detach a texture from an attachment point, call the procedure Detach
:
Framebuffer_1.Detach (Color_Attachment_7);
Clearing the attached buffers¶
Every frame the buffers should be cleared. To clear the buffers, call the
procedure Clear
. Before the buffers can be cleared, the default values which
must be used when clearing must be set first by calling the procedure
Set_Default_Values
:
Framebuffer_1.Set_Default_Values ((Color => (1.0, 0.0, 0.0, 1.0), others => <>));
In this case the color of the color buffer after clearing will be red.
Procedure Set_Default_Values
needs to be called only once. It is not
needed to call it every frame.
A good place to call it is right after creating the framebuffer.
The current default values can be queried with the function Default_Values
.
After the default values have been set, the buffers can and should be cleared
before rendering geometry by calling the procedure Clear
.
For example, the following statement will clear the color and depth buffer:
Framebuffer_1.Clear ((Color | Depth => True, others => False));
The pixels in the buffers will be reset to the values previously set by Set_Default_Values
.
Note
The default value of Depth
is 0.0
because Orka uses a reversed depth
buffer (reversed Z) for greater precision of geometry at great distances
from the camera.
Using a framebuffer¶
To use a framebuffer so that rendering geometry will be drawn on the attached
color textures, and the depth of each fragment (pixel) is stored in the attached
depth texture, call the procedure Use_Framebuffer
:
Framebuffer_1.Use_Framebuffer;
If an application uses only the default framebuffer, then this procedure does not
need to be called. If an application uses the default framebuffer and one or more
regular framebuffers, then, each frame, Use_Framebuffer
must be called before
using each framebuffer.
Scaling and resolving multiple samples¶
If a texture must be scaled down to a lower resolution, or if it has multiple samples
which must be resolved, then the way to do this is to attach the source and destination
textures to two different framebuffers and then use the procedure Resolve_To
to copy
the content of the color, depth, or stencil buffers to the second framebuffer.
This process is called blitting.
If a buffer is specified in the mask, then the buffer should exist
in both framebuffers, otherwise the buffer is not copied. Call
Set_Read_Buffer
and Set_Draw_Buffers
to control which buffer is read
from and which buffers are written to.
If the framebuffers have just one color buffer then these procedures do not
need to be called.
Format of the color buffers may differ and will be converted (if supported). However, formats of depth and stencil buffers must match.
For example, to blit the color buffer from Framebuffer_1
to Framebuffer_2
,
call Resolve_To
as following:
Framebuffer_1.Resolve_To (Framebuffer_2);
Warning
Simultaneously resolving multiple samples and scaling
of color buffers requires EXT_framebuffer_multisample_blit_scaled
.
If this extension is not present, then two separate calls to Resolve_To
are needed.