flo_render_canvas 0.3.1

Converts flo_canvas streams to flo_render streams
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
use super::fill_state::*;
use super::layer_state::*;
use super::render_entity::*;
use super::renderer_layer::*;
use super::renderer_worker::*;
use super::stroke_settings::*;

use flo_canvas as canvas;
use flo_render as render;

use lyon::tessellation::{FillRule};

use std::mem;
use std::sync::*;
use std::collections::{HashMap};

///
/// Handle referencing a renderer layer
///
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
pub struct LayerHandle(pub u64);

///
/// Used to indicate the state of a texture
///
/// A 'loading' texture is one where we're still writing data, where a 'Ready' texture is one where we've
/// generated the mipmap and are using it somewhere in the core
///
#[derive(Clone, Copy)]
pub enum RenderTexture {
    Loading(render::TextureId),
    Ready(render::TextureId)
}

///
/// Ued to indicate the state of a gradient: these are loaded as 1-dimensional textures when they are used
///
#[derive(Clone)]
pub enum RenderGradient {
    Defined(Vec<canvas::GradientOp>),
    Ready(render::TextureId, Vec<canvas::GradientOp>)
}

impl Into<render::TextureId> for &RenderTexture {
    fn into(self) -> render::TextureId {
        match self {
            RenderTexture::Loading(texture_id)  => *texture_id,
            RenderTexture::Ready(texture_id)    => *texture_id
        }
    }
}

///
/// Parts of the renderer that are shared with the workers
///
pub struct RenderCore {
    /// Number of times that StartFrame has been specified without a corresponding ShowFrame
    pub frame_starts: usize,

    /// One-time setup actions that are waiting to be rendered
    pub setup_actions: Vec<render::RenderAction>,

    /// The definition for the layers
    pub layers: Vec<LayerHandle>,

    /// The background colour to clear to when rendering the canvas
    pub background_color: render::Rgba8,

    /// The definition for the sprites
    pub sprites: HashMap<canvas::SpriteId, LayerHandle>,

    /// The number of times each render texture is being used by the layers or by the canvas itself (0 = ready to free)
    pub used_textures: HashMap<render::TextureId, usize>,

    /// Maps canvas textures to render textures
    pub canvas_textures: HashMap<canvas::TextureId, RenderTexture>,

    /// Maps canvas gradients to render gradients
    pub canvas_gradients: HashMap<canvas::GradientId, RenderGradient>,

    /// The alpha value to use for each texture, next time it's used
    pub texture_alpha: HashMap<canvas::TextureId, f32>,

    /// The actual layer definitions
    pub layer_definitions: Vec<Layer>,

    /// Available layer handles
    pub free_layers: Vec<LayerHandle>,

    /// The first unused vertex buffer ID
    pub unused_vertex_buffer: usize,

    /// Vertex buffers that were previously used but are now free
    pub free_vertex_buffers: Vec<usize>,

    /// The first unused texture ID
    pub unused_texture_id: usize,

    /// Textures that were previously used but are now free
    pub free_textures: Vec<render::TextureId>
}

impl RenderCore {
    ///
    /// Frees all entities from an existing layer
    ///
    pub fn free_layer_entities(&mut self, mut layer: Layer) {
        for entity in layer.render_order.drain(..) {
            self.free_entity(entity);
        }
    }

    ///
    /// Adds the resources used by a render entity to the free pool
    ///
    pub fn free_entity(&mut self, render_entity: RenderEntity) {
        use self::RenderEntity::*;

        match render_entity {
            Missing                                 => { }
            Tessellating(_entity_id)                => { }
            VertexBuffer(_buffers, _)               => { }
            SetTransform(_)                         => { }
            SetBlendMode(_)                         => { }
            SetFlatColor                            => { }
            SetDashPattern(_)                       => { }
            RenderSprite(_, _)                      => { }
            DisableClipping                         => { }

            SetFillTexture(texture_id, _, _, _)     => { 
                self.used_textures.get_mut(&texture_id)
                    .map(|usage_count| *usage_count -= 1);
            }

            SetFillGradient(texture_id, _, _, _)    => { 
                self.used_textures.get_mut(&texture_id)
                    .map(|usage_count| *usage_count -= 1);
            }

            EnableClipping(render::VertexBufferId(vertex_id), render::IndexBufferId(index_id), _num_vertices)   |
            DrawIndexed(render::VertexBufferId(vertex_id), render::IndexBufferId(index_id), _num_vertices)      => {
                // Each buffer is only used by one drawing operation, so we can always free them here
                self.free_vertex_buffers.push(vertex_id);
                if index_id != vertex_id {
                    self.free_vertex_buffers.push(index_id);
                }
            }
        }
    }

    ///
    /// Finds any render textures that are not in use and marks them as freed
    ///
    pub fn free_unused_textures(&mut self) -> Vec<render::RenderAction> {
        // Collect the list of unused textures
        let unused_textures = self.used_textures.iter()
            .filter(|(_texture_id, count)| **count <= 0)
            .map(|(texture_id, _count)| *texture_id)
            .collect::<Vec<_>>();

        // Free them
        let mut render_actions = vec![];

        for free_texture_id in unused_textures.into_iter() {
            // Remove from the 'used textures' hash
            self.used_textures.remove(&free_texture_id);

            // Add as a texture ID we can reallocate
            self.free_textures.push(free_texture_id);

            // Generate a 'free texture' action to release the graphics memory used by this texture
            render_actions.push(render::RenderAction::FreeTexture(free_texture_id));
        }

        render_actions
    }

    ///
    /// Stores the result of a worker job in this core item
    ///
    pub fn store_job_result(&mut self, entity_ref: LayerEntityRef, render_entity: RenderEntity) {
        let LayerHandle(layer_idx)  = entity_ref.layer_id;
        let layer_idx               = layer_idx as usize;

        // Do nothing if the layer no longer exists
        if self.layer_definitions.len() <= layer_idx {
            self.free_entity(render_entity);
            return;
        }

        // Do nothing if the entity index no longer exists
        if self.layer_definitions[layer_idx].render_order.len() <= entity_ref.entity_index {
            self.free_entity(render_entity);
            return;
        }

        // The existing entity should be a 'tessellating' entry that matches the entity_ref ID
        let entity = &mut self.layer_definitions[layer_idx].render_order[entity_ref.entity_index];
        if let RenderEntity::Tessellating(entity_id) = entity {
            if *entity_id != entity_ref.entity_id {
                self.free_entity(render_entity);
                return;
            }
        } else {
            return;
        }

        // Store the render entity
        self.layer_definitions[layer_idx]
            .render_order[entity_ref.entity_index] = render_entity;
    }

    ///
    /// Allocates a free vertex buffer ID
    ///
    pub fn allocate_vertex_buffer(&mut self) -> usize {
        self.free_vertex_buffers.pop()
            .unwrap_or_else(|| {
                let buffer_id = self.unused_vertex_buffer;
                self.unused_vertex_buffer += 1;
                buffer_id
            })
    }

    ///
    /// Allocates a texture ID
    ///
    pub fn allocate_texture(&mut self) -> render::TextureId {
        self.free_textures.pop()
            .unwrap_or_else(|| {
                let texture_id = self.unused_texture_id;
                self.unused_texture_id += 1;
                render::TextureId(texture_id)
            })
    }

    ///
    /// Returns the render actions required to send a vertex buffer (as a stack, so in reverse order)
    ///
    pub fn send_layer_vertex_buffer(&mut self, layer_id: LayerHandle, render_index: usize) -> Vec<render::RenderAction> {
        let LayerHandle(layer_idx)  = layer_id;
        let layer_idx               = layer_idx as usize;

        // Remove the action from the layer
        let mut vertex_action = RenderEntity::Missing;
        mem::swap(&mut self.layer_definitions[layer_idx].render_order[render_index], &mut vertex_action);

        // The action we just removed should be a vertex buffer action
        match vertex_action {
            RenderEntity::VertexBuffer(vertices, intent) => {
                // Allocate a buffer
                let buffer_id = self.allocate_vertex_buffer();

                // Draw these buffers as the action at this position
                match intent {
                    VertexBufferIntent::Draw    => {
                        self.layer_definitions[layer_idx].render_order[render_index] = RenderEntity::DrawIndexed(render::VertexBufferId(buffer_id), render::IndexBufferId(buffer_id), vertices.indices.len());
                    }

                    VertexBufferIntent::Clip    => {
                        self.layer_definitions[layer_idx].render_order[render_index] = RenderEntity::EnableClipping(render::VertexBufferId(buffer_id), render::IndexBufferId(buffer_id), vertices.indices.len());
                    }
                }

                // Send the vertices and indices to the rendering engine
                vec![
                    render::RenderAction::CreateIndexBuffer(render::IndexBufferId(buffer_id), vertices.indices),
                    render::RenderAction::CreateVertex2DBuffer(render::VertexBufferId(buffer_id), vertices.vertices),
                ]
            }

            _ => panic!("send_vertex_buffer must be used on a vertex buffer item")
        }
    }

    ///
    /// Returns the render actions needed to prepare the render buffers for the specified layer (and updates the layer
    /// so that the buffers are not sent again)
    ///
    pub fn send_vertex_buffers(&mut self, layer_handle: LayerHandle) -> Vec<render::RenderAction> {
        use self::RenderEntity::*;

        let mut send_vertex_buffers = vec![];
        let mut layer               = self.layer(layer_handle);

        for render_idx in 0..layer.render_order.len() {
            match &layer.render_order[render_idx] {
                VertexBuffer(_buffers, _)                   => { 
                    send_vertex_buffers.extend(self.send_layer_vertex_buffer(layer_handle, render_idx)); 
                    layer = self.layer(layer_handle);
                },

                RenderSprite(sprite_id, _sprite_transform)  => { 
                    let sprite_id           = *sprite_id;
                    let sprite_layer_handle = self.sprites.get(&sprite_id).cloned();

                    if let Some(sprite_layer_handle) = sprite_layer_handle {
                        send_vertex_buffers.extend(self.send_vertex_buffers(sprite_layer_handle));
                    }

                    layer = self.layer(layer_handle);
                },

                _                                           => { }
            }
        }

        send_vertex_buffers
    }

    ///
    /// Returns a render texture for a canvas texture
    ///
    pub fn texture_for_rendering(&mut self, texture_id: canvas::TextureId) -> Option<render::TextureId> {
        // 'Ready' textures are set up for rendering: 'Loading' textures need to be finished to render
        match self.canvas_textures.get(&texture_id)? {
            RenderTexture::Ready(render_texture)    => Some(*render_texture),
            RenderTexture::Loading(render_texture)  => {
                let render_texture = *render_texture;

                // Finish the texture
                self.setup_actions.push(render::RenderAction::CreateMipMaps(render_texture));

                // Mark as finished
                self.canvas_textures.get_mut(&texture_id)
                    .map(|texture| *texture = RenderTexture::Ready(render_texture));

                Some(render_texture)
            }
        }
    }

    ///
    /// Returns a (1D) render texture for a canvas gradient
    ///
    pub fn gradient_for_rendering(&mut self, gradient_id: canvas::GradientId) -> Option<render::TextureId> {
        match self.canvas_gradients.get(&gradient_id)? {
            RenderGradient::Ready(gradient_texture, _)  => Some(*gradient_texture),
            RenderGradient::Defined(definition)         => {
                // Define a new texture
                let definition  = definition.clone();
                let texture_id  = self.allocate_texture();

                // Starts at a usage count of 0
                self.used_textures.insert(texture_id, 0);

                // Get the bytes for this gradient
                let bytes       = canvas::gradient_scale::<_, 256>(definition.clone());
                let bytes       = bytes.iter().flatten().cloned().collect::<Vec<_>>();

                // Define as a 1D texture
                self.setup_actions.extend(vec![
                    render::RenderAction::Create1DTextureBgra(texture_id, 256),
                    render::RenderAction::WriteTexture1D(texture_id, 0, 256, Arc::new(bytes)),
                    render::RenderAction::CreateMipMaps(texture_id)
                ]);

                // Update the texture to 'ready'
                self.canvas_gradients.insert(gradient_id, RenderGradient::Ready(texture_id, definition));

                // The new texture is the one that will be used for rendering
                Some(texture_id)
            }
        }
    }

    ///
    /// Allocates a new layer handle to a blank layer
    ///
    pub fn allocate_layer_handle(&mut self, layer: Layer) -> LayerHandle {
        if let Some(LayerHandle(idx)) = self.free_layers.pop() {
            // Overwrite the existing layer with the new layer
            self.layer_definitions[idx as usize] = layer;
            LayerHandle(idx)
        } else {
            // Define a new layer
            self.layer_definitions.push(layer);
            LayerHandle((self.layer_definitions.len()-1) as u64)
        }
    }

    ///
    /// Releases a layer from the core (returning the layer that had this handle)
    ///
    pub fn release_layer_handle(&mut self, layer_handle: LayerHandle) -> Layer {
        // Swap in an old layer for the new layer
        let LayerHandle(layer_idx)  = layer_handle;
        let mut old_layer           = Layer {
            render_order:       vec![RenderEntity::SetTransform(canvas::Transform2D::identity())],
            state:              LayerState {
                is_sprite:          false,
                fill_color:         FillState::Color(render::Rgba8([0, 0, 0, 255])),
                winding_rule:       FillRule::NonZero,
                stroke_settings:    StrokeSettings::new(),
                current_matrix:     canvas::Transform2D::identity(),
                sprite_matrix:      canvas::Transform2D::identity(),
                scale_factor:       1.0,
                blend_mode:         canvas::BlendMode::SourceOver,
                restore_point:      None
            },
            stored_states:      vec![]
        };

        mem::swap(&mut old_layer, &mut self.layer_definitions[layer_idx as usize]);

        // Add the handle to the list of free layer handles
        self.free_layers.push(layer_handle);

        // Result is the layer that was released
        old_layer
    }

    ///
    /// Returns a reference to the layer with the specified handle
    ///
    #[inline] pub fn layer(&mut self, layer_handle: LayerHandle) -> &mut Layer {
        let LayerHandle(layer_idx)  = layer_handle;
        let layer_idx               = layer_idx as usize;

        &mut self.layer_definitions[layer_idx]
    }
}