pub enum PixelFormat {
Rgba8Unorm,
Rgba8UnormSrgb,
Bgra8Unorm,
Bgra8UnormSrgb,
Rgb10A2Unorm,
Rgba16Float,
R8Unorm,
}Expand description
Pixel formats the renderer can target.
Color is sRGB-encoded f32 internally; these describe storage at the API boundary and at target write, and no transfer function sits between the two.
Variants§
Rgba8Unorm
8-bit RGBA, unsigned normalized.
Rgba8UnormSrgb
8-bit RGBA with sRGB transfer on write.
Bgra8Unorm
8-bit BGRA, the common scanout order.
Bgra8UnormSrgb
8-bit BGRA with sRGB transfer on write.
Rgb10A2Unorm
10-bit color with 2-bit alpha, preferred when the pipeline is HDR-aware.
Rgba16Float
16-bit float per channel, for intermediate targets.
R8Unorm
One 8-bit channel, unsigned normalized.
For data that is coverage rather than color — a glyph atlas is the case — where storing the same byte four times costs four times the memory and four times the bandwidth to sample it.
Implementations§
Source§impl PixelFormat
impl PixelFormat
pub const fn bytes_per_pixel(self) -> u32
Sourcepub const fn intermediate(self) -> Self
pub const fn intermediate(self) -> Self
The format an offscreen layer takes when the frame lands in this one.
Following the root is what keeps the cost where the choice was made: a caller who asks for a floating-point surface gets layers that can hold what it holds, and a caller who does not pays nothing. A layer is an intermediate of this frame, so it should carry at least what the frame it composites into can carry.
Stated as a match rather than as identity because two formats here would make bad layers. A single-channel one has nowhere to put color at all. And ten-bit color with two-bit alpha is worse for a layer than the eight-bit target it would replace, because a layer’s alpha is group opacity – a value that gets composited – rather than a scanout channel nothing reads back.
Never an sRGB format, whatever the root is. The pipeline carries encoded components, so a target that encodes on write would encode them a second time and a layer would come back paler than the same content drawn straight onto the frame.
This followed the root for a while, and was right to: color was light then, eight bits of linear color band visibly in the darks, and a dark ramp resolving forty distinct tones drawn straight into an sRGB frame came back as six through a layer holding linear eight-bit color. Neither half of that can happen now – a layer’s eight bits are spaced by the transfer function because the values arriving already are.
Sourcepub const fn quantization_step(self) -> f32
pub const fn quantization_step(self) -> f32
How far apart two representable values are in this format’s storage, or zero where the question does not apply.
The distance a dither has to bridge. It is stated in storage units
rather than in light, which for Self::Rgba8UnormSrgb and its sibling
is not the same thing: the hardware encodes on write, so a step there is
a step of the encoded value and the light it stands for varies across
the range by a factor of about thirty. Anything acting on this number
therefore has to know which space it is in, which is what
Self::is_srgb answers.
Zero for Self::Rgba16Float, where there is no fixed quantum to
bridge – half’s precision is relative, so a step near black is minute
and a dither sized for one near white would swamp it. Zero for
Self::R8Unorm as well, which holds coverage rather than color.
Sourcepub const fn is_drawable(self) -> bool
pub const fn is_drawable(self) -> bool
Whether the renderer can draw into this format.
It cannot draw into one that encodes on write. The pipeline carries sRGB-encoded components from the API boundary onward, so a target applying the transfer function would apply it a second time and the picture would come back over a third too bright at mid gray.
Stated once and consulted from three places, because it has been got wrong at two of them and neither showed up in a test that renders pixels. The swapchain preferred an sRGB surface format and DRM scanout rendered through an sRGB image view, both for the same reason – they were written while the pipeline carried light, where encoding on write was exactly what was wanted. A rule that lives in one place can be re-read; three copies of an argument get updated one at a time.