# Rendering

* Multi frame rendering: 1 Canvas, each frame creates Canvas
* trait **Renderable** implementors: Grid, Cartesian2D, Cartesian3D
  * fn encode(\&self, ctx: \&mut Canvas)
  * fn layout(\&self, solver: \&mut Solver, theme: \&Theme)
  * fn size(\&self) -> \&WidgetSizeVars
* struct **Canvas**<'a>
  * \&Easel
  * \&TextureView
  * area: Box2
  * layout: \&Solver
  * BindGroupLayout
  * renderers
    * MarkerRenderer
    * VanillaRenderer
    * TextRenderer
  * layout\_cache: HashMap<\*const dyn Renderable, Box2>
* struct **Easel**
  * wgpu::Instance
  * wgpu::Adapter
  * wgpu::Device
  * wgpu::Queue
  * RenderStateDetail
  * size
  * wgpu::CommandBuffer
  * wgpu::SurfaceTexture
  * layout\_cache
* Each Plot has its own PrimitiveRenderer, CommandEncoder, RenderPass instance to produce the CommandBuffer.
* CommandBuffer from each plot is collected and submitted to the queue at once.
* FontSystem is a global resource behind mutex. This is because the font loading is expensive.
* Easel consists of several sub renderers, where each has its own shader responsible for a specific type of primitives.

Grid::render\_to\_buffer (new Easel, new Canvas)\
->Grid::render\_root\
->Grid::layout()\
->Child1::layout()\
->Child2::layout()\
-> put Solver in ctx\
->Child1::render(ctx)\
->create Easel (takes one viewport, holds primitives + transform)\
->RenderPass::new()\
->pass.set\_scissor\_rect()\
->encoder.finish()\
->render\_context.push(CommandBuffer)\
->Child2::render()\
->RenderPass::new()\
->pass.set\_scissor\_rect()\
->encoder.finish()\
->return CommandBuffer\
->Queue::submit(&\[cmd\_buf1, cmd\_buf2])\
->Easel.present()

Grid::render\_svg\
->Grid::render\_root\
->Grid::layout()\
..\
->Child1::render(SVGRenderContext)\
->render\_context.push(a tree of SVG elements)\
->Child2::render()\
->return a tree of SVG elements\
->aggregate all SVG elements

Easel (1 per app)

* wgpu::Device, wgpu::Surface, ..

Canvas (1 per frame, create view on the root, states mutated down the tree)

* link to Easel
* \&view
* transform
* mouse cursor
* theme (theme = node.theme or theme)
* layout: \&Solver

PrimtiveRenderer (1 per node, 3D, scissor)

* new(view)
* LineRenderer - 1 encoder + 1 render pass -> CommandBuffer -> ctx.submit(cmd\_buf)
* TextRenderer - 1 encoder + 1 render pass -> CommandBuffer -> ctx.submit(cmd\_buf)
* finish() -> CommandBuffer
* theme

Renderable

* save() (provided)
  * create Easel, Canvas
* render\_root(ctx) (provided)
* layout
* render(ctx)
  * fn render(\&self, ctx: \&Canvas)
  * create PrimitiveRenderer
  * ctx.submit(CommandBuffer)

Cartesian2D::render()

* for geom in geometries:
  * geom.render(\&mut PrimitiveRenderer)

Cartesian2D::scatter() -> Cartesian2D::push(Geometry::Scatter{..}) -> Vec\
Cartesian2D::line() -> Cartesian2D::push(Geometry::Line{..}) -> Path

have 2 primtiive renderers:\
Primitives in data coordinates - uniform - zoom, pan, ..\
Primitives in pixel coordinates


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ezel.rustic.dev/dev/rendering.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
