io7m
io7m-jcanephora 0.50.0
3.11
JCGLFramebuffersType

- 3.11.1. Description
- 3.11.2. Usage examples
- 3.11.3. Feedback
- 3.11.4. State

3.11.1
Description
1
The JCGLFramebuffersType interface provides functions for creating and controlling framebuffers.
3.11.2
Usage examples
1
A framebuffer in OpenGL is an opaque structure with one or more attachments. Currently, attachments can only be textures. Textures are useful when the result of rendering to a framebuffer is going to be read back at some point, or perhaps used to texture other objects. For example, some 3D engines implement so-called "procedural textures" by rendering a generated pattern to a texture and then applying that texture to objects in the scene. Attachments are attached at specific points to any given framebuffer: Framebuffers can have a depth attachment, a stencil attachment, a depth+stencil attachment, and an implementation-defined maximum number of color attachments.
2
When rendering to a framebuffer, a shading program will write values to one or moredraw buffers, and each draw buffer is mapped to a color attachments. Multiple draw buffers cannot be mapped to the same color attachment.
3
In jcanephora, framebuffers are created via mutable builders which are then passed to the API functions, resulting in immutable framebuffers [5].
3.11.2.1. Framebuffer builder

    JCGLFramebuffersType g;
    JCGLFramebufferBuilderType b = g.framebufferNewBuilder();

4
To attach allocated textures/buffers to a framebuffer, the API requires the programmer to first obtain a list of the available attachment points:
3.11.2.2. Framebuffer color attachment points

    JCGLFramebuffersType g;

    List<JCGLFramebufferColorAttachmentPointType> points = g.framebufferGetColorAttachmentPoints();

5
Similarly, the API requires the programmer to obtain a list of the available draw buffers:
3.11.2.3. Framebuffer draw buffers

    JCGLFramebuffersType g;

    List<JCGLFramebufferDrawBufferType> buffers = g.framebufferGetDrawBuffers();

6
The programmer must pass values of type JCGLFramebufferColorAttachmentPointType to various attachment functions and is therefore statically prevented from trying to use more color attachments than the OpenGL implementation allows.
7
After allocating a color and depth/stencil texture, the textures must be attached at the relevant attachment points and draw buffers mapped to the color attachments.
3.11.2.4. Framebuffer attachments

    JCGLFramebuffersType g;
    JCGLTexturesType gt;
    JCGLTextureUnitType u;

    List<FramebufferColorAttachmentPointType> points = g.framebufferGetColorAttachmentPoints();
    List<JCGLFramebufferDrawBufferType> buffers = g.framebufferGetDrawBuffers();

    JCGLTexture2DType d = gt.texture2DAllocate(u, 128, 128, JCGLTextureFormat.TEXTURE_FORMAT_DEPTH_16_2BPP, ...);
    JCGLTexture2DType c = gt.texture2DAllocate(u, 128, 128, JCGLTextureFormat.TEXTURE_FORMAT_RGBA_8_4BPP, ...);
    gt.textureUnitUnbind(u);

    JCGLFramebufferBuilderType b = g.framebufferNewBuilder();
    b.attachColorTexture2DAt(points.get(0), buffers.get(0), c);
    b.attachDepthTexture2D(d);

8
All unspecified draw buffers are mapped to GL_NONE (meaning that any data written to the other draw buffers will go nowhere). The builders also raise exceptions if the programmer attempts to, for example, specify a non-color-renderable format for a color attachment.
9
To actually allocate a framebuffer, the mutable builder is passed to an allocation function:
3.11.2.5. Framebuffer attachment/buffer mappings

    JCGLFramebuffersType g;
    JCGLFramebufferBuilderType b;

    FramebufferType f = g.framebufferAllocate(b);

10
The function validates the framebuffer configuration upon allocation, raising an exception if the framebuffer is not usable on the current OpenGL implementation.
11
To render to the framebuffer, the framebuffer must be bound:
3.11.2.6. Framebuffer binding

    JCGLFramebuffersType g;
    JCGLFramebufferType f;

    g.framebufferDrawBind(f);
    {
      // Perform rendering.
    }
    g.framebufferDrawUnbind(f);

3.11.3
Feedback
1
The OpenGL specification explicitly states that feedback is illegal and results in undefined behaviour. Feedback is defined as occurring when a texture t is both attached to the current draw framebuffer and is also bound to a texture unit and being sampled. This would result in a feedback loop where data written to the framebuffer would be written to a texture currently being sampled.
2
The jcanephora attempts to detect and prevent feedback by raising exceptions:
3.11.3.1. Feedback

1. When a texture is bound, the current framebuffer (if any) is checked to see if the texture is attached to the framebuffer.
2. When a draw framebuffer is bound, a check is made to see if any of the attached textures are currently bound.

3.11.4
State
1
OpenGL specifies that at most one framebuffer can be bound on a context at any given time. Many API functions operate on the currently bound framebuffer and the jcanephora API avoids changing the current binding behind the programmer's back.

[5]
That is, the framebuffer attachments cannot be reconfigured once the framebuffer is created. This matches the typical use patterns with regards to framebuffers and is also a design choice taken from practical experience: On most OpenGL implementations, reconfiguring a framebuffer is a rather expensive operation.