To support dynamic sizing, capacity
is introduced to describe the total size of the buffer, and size
is used to describe the actual size that is used. Various buffers are introduced to support different use cases:
EscherBuffer
wraps around an escher::Buffer
and is able to grow dynamically when the content grows. It's used to hold data in StrokePath
as input to StrokeTessellator
.SharedBuffer
is shared between sketchy
and scenic
: it wraps around an escher::Buffer
and the corresponding fuchsia::ui::gfx::Buffer
. It does NOT change size once created.MeshBuffer
wraps around two ShardBuffer
's: one for vertex and the other for index. Dynamic sizing is handled here, rather than SharedBuffer
, to avoid duplicate semantics.Each MeshBuffer
belongs to a StrokeGroup
. It vendors portions of itself to Stroke
by MeshBuffer::Preserve()
. In addition, MeshBuffer
provides the vertex buffer, index buffer, and the bounding box to scenic
, so that scenic
could render the strokes as meshes.
Multi-buffering is required to handle the case where scenic
has not fully rendered the mesh in the last frame but the new Canvas::Present()
comes. It's implemented via a SharedBuffer
pool for efficient buffer usage. Think it in this way: sketchy
produces SharedBuffer
's and scenic
consumes them. In each frame, sketchy
returns the previous SharedBuffer
's to pool, and grab new ones. The pool monitors the returned SharedBuffer
's from scenic
, and once scenic
consumes them, they will be recycled for future use.
Notice that we only recycle SB1
when SB2
is consumed for the first time. It's safe to recycle SB1
because SB2
starts to get used. However, SB2
is not yet safe to be recycled because scenic
keeps consuming SB2
for rendering the following frames (for example, some other SB
triggers a ui::Session::Present()
but SB2
has its content unchanged). In that case, we have no signal when SB2
is finally consumed until a new SB3
comes and replaces it.