Expand description
Graphics pipelines.
Graphics pipelines are the means used to describe — and hence perform — renders. They provide a way to describe how resources should be shared and used to produce a single pixel frame.
Pipelines and graphs
luminance has a very particular way of doing graphics. It represents a typical graphics pipeline via a typed graph that is embedded into your code. Graphs are used to create a dependency between resources your GPU needs to have in order to perform a render. It might be weird at first but you’ll see how simple and easy it actually is. If you want to perform a simple draw call of a triangle, you need several resources:
- A
Tess
that represents the triangle — assuming you don’t cheat with an attributeless render ;). It holds three vertices. - A shader
Program
, for shading the triangle with a constant color, for short and simple. - A
Framebuffer
, to accept and hold the actual render. - A
RenderState
, to state how the render should be performed. - And finally, a
PipelineState
, which allows even more customization on how the pipeline runs.
The terminology used in luminance is as follows: a graphics pipeline is a graph in which nodes
are called gates. A gate represents a particular resource exposed as a shared scarce resource
for child, nested nodes. For instance, you can share framebuffer in a PipelineGate
: all
nodes that are children of that framebuffer node will then be able to render into that
framebuffer.
This design is well-typed: when you enter a given gate, the set of operations and children nodes you can create is directly dependent on the parent node.
PipelineGate and Pipeline
A PipelineGate
is the gate allowing to share a Framebuffer
.
A PipelineGate
represents a whole graphics pipeline as seen as just above. It is created by
a GraphicsContext
when you ask to create a pipeline gate. A PipelineGate
is typically
destroyed at the end of the current frame, but that’s not a general rule.
Such an object gives you access, via the PipelineGate::pipeline
, to two other objects:
- A
ShadingGate
, explained below. - A
Pipeline
.
A Pipeline
is a special object you can use to handle some specific scarce resources, such as
textures and _shader data. Those are treated a bit specifically on the backend, so you have to
use the Pipeline
interface to deal with them. Those scarce resources can be shared at different
depth in the graphics pipeline, which is the reason why they are exposed via this Pipeline
object, that you can pass down the graph.
Creating a PipelineGate
requires two resources: a Framebuffer
to render to, and a
PipelineState
, allowing to customize how the pipeline will perform renders at runtime. This gate
will then do a couple of things on the backend, depending mainly on the PipelineState
you pass.
For instance, framebuffer clearing, sRGB conversion or scissor test is done at that level.
ShadingGate
A ShadingGate
is the gate allowing to share a shader Program
.
When you enter a PipelineGate
, you’re handed a ShadingGate
. A ShadingGate
is an object
that allows you to create shader nodes in the graphics pipeline. You have no other way to go deeper
in the graph.
A shader Program
is typically an object you create at initialization or at specific moment in time
(i.e. you don’t create them on each frame, that would be super costly) that tells the GPU how vertices
should be transformed; how primitives should be moved and generated, how tessellation occurs and
how fragment (i.e. pixels) are computed / shaded — hence the name.
At that level (i.e. in that closure), you are given three objects:
- A
RenderGate
, discussed below. - A
ProgramInterface
, which has as type parameter the type of uniform your shaderProgram
defines. - The uniform interface the
Program
was made to work with.
The ProgramInterface
is the only way for you to access your uniform interface. More on
this in the dedicated section. It also provides you with the ProgramInterface::query
method, that allows you to perform dynamic uniform lookup.
Once you have entered this gate, you know that everything nested will be shaded with the shared shader
Program
.
RenderGate
A RenderGate
is the gate allowing to prepare renders by sharing RenderState
.
A RenderGate
is the second to last gate you will be handling. It allows you to create
render state nodes in your graph, creating a new level for you to render tessellations with
an obvious, final gate: the TessGate
.
The kind of object that node manipulates is RenderState
. A RenderState
— a bit like for
PipelineGate
with PipelineState
— enables to customize how a render of a specific set
of objects (i.e. tessellations) will occur. It’s a bit more specific to renders than pipelines and
will allow customizing aspects like blending, depth test, backface culling, etc.
TessGate
A TessGate
is the final gate, allowing to share Tess
.
The TessGate
is the final gate you use in a graphics pipeline. It’s used to create tessellation
nodes. Those are used to render actual Tess
. You cannot go any deeper in the graph at that stage.
TessGate
s don’t immediately use Tess
as inputs. They use TessView
. That type is
a simple immutable view into a Tess
. It can be obtained from a Tess
via the View
trait or
built explicitly.
Structs
A bound ShaderData
.
A bound Texture
.
A GPU pipeline handle.
Top-most node in a graphics pipeline.
Various customization options for pipelines.
Output of a PipelineGate
.
Opaque shader data binding.
Opaque texture binding.
Enums
Possible errors that might occur in a graphics Pipeline
.
The viewport being part of the PipelineState
.