# 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
