pub trait Output {
type Error: BackendError;
// Required methods
fn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
where I: Iterator<Item = DrawCell<'a>>;
fn flush(&mut self) -> Result<(), Self::Error>;
fn size(&self) -> Size<u16>;
fn clear(&mut self) -> Result<(), Self::Error>;
// Provided methods
fn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
where I: Iterator<Item = DrawCell<'a>> { ... }
fn compositing(&self) -> Compositing { ... }
fn resize(&mut self, size: Size<u16>) { ... }
}Expand description
Draws grid content to a display and reports its dimensions.
This is the only one of the three backend facets (Output, Input, Cursor) that’s
fallible: writing to a real display can fail (a broken pipe, a closed terminal, a lost
surface), so every mutating method here returns Result<(), Self::Error>.
§Examples
use retroglyph_core::backend::{DrawCell, Output};
use retroglyph_core::grid::Size;
struct NullOutput;
impl Output for NullOutput {
type Error = core::convert::Infallible;
fn draw_layers<'a, I>(&mut self, _content: I) -> Result<(), Self::Error>
where
I: Iterator<Item = DrawCell<'a>>,
{
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
fn size(&self) -> Size {
Size::new(4, 2)
}
fn clear(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}Required Associated Types§
Sourcetype Error: BackendError
type Error: BackendError
Error type returned by fallible operations.
Required Methods§
Sourcefn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
fn draw_layers<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
Draw changed cells across all layers.
crate::terminal::Terminal::present always calls this method, never draw
directly, for every backend. A backend that returns Compositing::CellFlattened
(the default, from compositing) receives a stream present has
already pre-flattened onto layer 0 (all allocated layers composited into one frame first,
so layers 1+ still appear on every backend, not only pixel ones); implementing this is no
different from what implementing single-layer draw used to mean. A pixel/GPU backend
that returns Compositing::PixelLayered receives the real,
multi-layer stream here and does its own compositing (per-pixel or per-quad, plus
sub-cell offsets and transparency as needed).
When compositing returns PixelLayered { needs_full_frame: true },
this receives all cells from every allocated layer, and the backend should clear its
output surface before drawing; PixelLayered { needs_full_frame: false } and
CellFlattened both receive only the changed cells.
Items are the same DrawCell draw receives, read through
DrawCell::layer rather than a separate element.
§Errors
Self::Error is implementation-defined (a broken pipe or closed terminal for a
process-backed display, a lost surface for a windowed one); implementations do not
roll back cells already written before the failure. Because
crate::terminal::Terminal::present only swaps its diff buffers into previous after the
call that reached this method succeeds, a failed draw leaves the same cells marked
dirty, so they are resent on the next successful present rather than silently
dropped.
Sourcefn flush(&mut self) -> Result<(), Self::Error>
fn flush(&mut self) -> Result<(), Self::Error>
Flush buffered output to the display.
§Errors
Self::Error is implementation-defined (a broken pipe, a closed terminal, a lost
surface). crate::terminal::Terminal::present calls this only after
draw/draw_layers succeed, and swaps its diff
buffers only after flush also succeeds; a failed flush therefore leaves the
current frame’s cells buffered but unconfirmed, and they are resent on the next
successful present.
Sourcefn clear(&mut self) -> Result<(), Self::Error>
fn clear(&mut self) -> Result<(), Self::Error>
Clear the entire display.
§Errors
Self::Error is implementation-defined (a broken pipe, a closed terminal, a lost
surface). Unlike draw/flush, this is not part of
crate::terminal::Terminal::present’s per-frame path; callers that invoke it directly
(some backends also call it internally on resize) should treat a failure as leaving
the display in an unknown, possibly partially cleared state and retry or tear down
rather than assume the previous contents are still intact.
Provided Methods§
Sourcefn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
fn draw<'a, I>(&mut self, content: I) -> Result<(), Self::Error>
Draw changed cells to the output surface, layer 0 only.
Every cell arrives as a DrawCell, which carries the out-of-line state a Tile
cannot: its full grapheme cluster and its tint. Both live in a side table on
Grid
rather than in the tile, so a backend that needs either must read it from here.
The default implementation forwards to draw_layers, which every
backend implements. crate::terminal::Terminal::present never calls this method directly (it
always goes through draw_layers, pre-flattened onto layer 0 for a backend that doesn’t
composite; see compositing), so overriding this is
only worthwhile if a backend has a cheaper direct path for the known-single-layer case
than its own draw_layers would take.
§Errors
See draw_layers, which this forwards to by default and shares
its error contract with.
Sourcefn compositing(&self) -> Compositing
fn compositing(&self) -> Compositing
How this backend wants layers handed to draw_layers.
Backends that render one glyph per cell return Compositing::CellFlattened
(the default) and receive a pre-flattened, single-layer stream:
crate::terminal::Terminal::present composites all allocated layers into one frame
first. This makes layers 1+ appear on every backend, not only pixel backends. Pixel/GPU
backends return Compositing::PixelLayered and composite the
layers themselves; its needs_full_frame field asks for all cells on every
draw_layers call (all cells on all layers) rather than just the
changed ones, because pixel-based backends (e.g. SoftwareRenderer) can spill glyph
pixels from sub-cell offsets into adjacent cells: without a full redraw, orphaned pixels
from the previous frame linger.
Sourcefn resize(&mut self, size: Size<u16>)
fn resize(&mut self, size: Size<u16>)
Notify the backend of a resize to size, updating what size reports.
Called automatically by crate::terminal::Terminal::resize after both grids are resized.
Backends that maintain internal state tied to terminal dimensions (such as
Headless) should override this to update that state. The default
implementation is a no-op.
A driver may also call this directly, ahead of and independent from
crate::terminal::Terminal::resize, to keep size in sync with an underlying
surface the moment it changes (a windowed backend reacting to an OS resize, for
example) without waiting for the app to resize the terminal’s grid content in
response. Doing so does not resize the grid; only crate::terminal::Terminal::resize does that.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementations on Foreign Types§
Source§impl Output for GlRenderer
impl Output for GlRenderer
type Error = Infallible
fn draw_layers<'a, I>( &mut self, content: I, ) -> Result<(), <GlRenderer as Output>::Error>
fn compositing(&self) -> Compositing
fn flush(&mut self) -> Result<(), <GlRenderer as Output>::Error>
fn size(&self) -> Size<u16>
fn clear(&mut self) -> Result<(), <GlRenderer as Output>::Error>
fn resize(&mut self, size: Size<u16>)
§impl Output for SoftwareRenderer
impl Output for SoftwareRenderer
§fn draw_layers<'a, I>(
&mut self,
content: I,
) -> Result<(), <SoftwareRenderer as Output>::Error>
fn draw_layers<'a, I>( &mut self, content: I, ) -> Result<(), <SoftwareRenderer as Output>::Error>
Composite the raw layer stream into the pixel buffer.
Layers arrive layer-major (0 first), so painting them in order gives the
correct z-order. Layer 0 always fills its cell background; a higher layer’s
occupied (non-empty) tile always fills a background too, and an empty tile
never does: see the private resolve_bg_fill helper for the exact color each of those
cases paints (it is not always the tile’s own background, to mirror
Grid::flatten_into’s background-inheritance rule exactly). The is_empty
guard matters because this receives the full frame (see
Compositing::PixelLayered), including empty
higher-layer cells that must not overwrite layer 0.
This matches cell backends (retroglyph#304): an occupied space with a
Color::Default background on a higher layer erases the glyph beneath it
when flattened, and this backend now does too, by repainting that cell’s
background (see the private resolve_bg_fill helper) even though the occupied tile’s own
background is the default one.
A TileFlags::SPAN_COVERED cell (retroglyph#412) paints its background but not its
glyph: the span’s anchor already drew one sprite across the whole footprint, and the
covered cell’s glyph is that sprite’s text fallback, for backends that cannot draw it. The
sprite-transparency rule that decides whether a background is painted at all is resolved
against the anchor (see resolve_cell_bg), so one span never sits on two different
backdrops.