Flutter Impeller
dl_dispatcher.h
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef FLUTTER_IMPELLER_DISPLAY_LIST_DL_DISPATCHER_H_
6 #define FLUTTER_IMPELLER_DISPLAY_LIST_DL_DISPATCHER_H_
7 
8 #include <map>
9 #include <memory>
10 
11 #include "flutter/display_list/dl_op_receiver.h"
12 #include "flutter/display_list/geometry/dl_geometry_types.h"
13 #include "flutter/display_list/geometry/dl_path.h"
14 #include "flutter/display_list/utils/dl_receiver_utils.h"
15 #include "fml/logging.h"
20 #include "impeller/geometry/rect.h"
21 
22 #include "flutter/display_list/image/dl_image.h"
23 
24 namespace impeller {
25 
26 #include "impeller/core/texture.h"
27 
35 
36 //////////////////////////////////////////////////////////////////////////
37 /// Important implementation note.
38 ///
39 /// The Impeller DisplayList Dispatcher implementation is divided into
40 /// two parts and conducted in two passes.
41 ///
42 /// The first pass is conducted using the FirstPassDispatcher which
43 /// examines the rendering ops for important conditions needed by the
44 /// rendering pass and computes some needed information for them.
45 ///
46 /// The second pass is conducted using CanvasDlDispatcher to perform the
47 /// actual rendering using a Canvas and data provided by the first pass.
48 ///
49 /// @important It is important to note that the 2 passes perform slightly
50 /// different DisplayList culling and may process different subsets of the
51 /// frame's operations.
52 /// See https://github.com/flutter/flutter/issues/182639
53 ///
54 /// Given the above issue any data precomputed by the first pass should
55 /// be presented in a way that doesn't assume a 1:1 correlation of the
56 /// rendering operations in both passes (perhaps provide it in a map
57 /// instead of a vector). While we have not yet observed and cases where
58 /// an operation is missed during the first pass but still processed in
59 /// the rendering pass, it would be wise to include a backup plan in
60 /// the canvas dispatcher for when the data was not forwarded.
61 //////////////////////////////////////////////////////////////////////////
62 
63 /// Base (virtual) dispatcher utility class to implement most DlOpReceiver
64 /// operations for other specific classes.
65 class DlDispatcherBase : public flutter::DlOpReceiver {
66  public:
67  explicit DlDispatcherBase() {}
68 
69  virtual ~DlDispatcherBase() = default;
70 
71  // |flutter::DlOpReceiver|
72  void setAntiAlias(bool aa) override;
73 
74  // |flutter::DlOpReceiver|
75  void setDrawStyle(flutter::DlDrawStyle style) override;
76 
77  // |flutter::DlOpReceiver|
78  void setColor(flutter::DlColor color) override;
79 
80  // |flutter::DlOpReceiver|
81  void setStrokeWidth(DlScalar width) override;
82 
83  // |flutter::DlOpReceiver|
84  void setStrokeMiter(DlScalar limit) override;
85 
86  // |flutter::DlOpReceiver|
87  void setStrokeCap(flutter::DlStrokeCap cap) override;
88 
89  // |flutter::DlOpReceiver|
90  void setStrokeJoin(flutter::DlStrokeJoin join) override;
91 
92  // |flutter::DlOpReceiver|
93  void setColorSource(const flutter::DlColorSource* source) override;
94 
95  // |flutter::DlOpReceiver|
96  void setColorFilter(const flutter::DlColorFilter* filter) override;
97 
98  // |flutter::DlOpReceiver|
99  void setInvertColors(bool invert) override;
100 
101  // |flutter::DlOpReceiver|
102  void setBlendMode(flutter::DlBlendMode mode) override;
103 
104  // |flutter::DlOpReceiver|
105  void setMaskFilter(const flutter::DlMaskFilter* filter) override;
106 
107  // |flutter::DlOpReceiver|
108  void setImageFilter(const flutter::DlImageFilter* filter) override;
109 
110  // |flutter::DlOpReceiver|
111  void save(uint32_t total_content_depth) override;
112 
113  // |flutter::DlOpReceiver|
114  void saveLayer(const DlRect& bounds,
115  const flutter::SaveLayerOptions& options,
116  uint32_t total_content_depth,
117  flutter::DlBlendMode max_content_mode,
118  const flutter::DlImageFilter* backdrop,
119  std::optional<int64_t> backdrop_id) override;
120 
121  // |flutter::DlOpReceiver|
122  void restore() override;
123 
124  // |flutter::DlOpReceiver|
125  void translate(DlScalar tx, DlScalar ty) override;
126 
127  // |flutter::DlOpReceiver|
128  void scale(DlScalar sx, DlScalar sy) override;
129 
130  // |flutter::DlOpReceiver|
131  void rotate(DlScalar degrees) override;
132 
133  // |flutter::DlOpReceiver|
134  void skew(DlScalar sx, DlScalar sy) override;
135 
136  // |flutter::DlOpReceiver|
137  void transform2DAffine(DlScalar mxx,
138  DlScalar mxy,
139  DlScalar mxt,
140  DlScalar myx,
141  DlScalar myy,
142  DlScalar myt) override;
143 
144  // |flutter::DlOpReceiver|
146  DlScalar mxy,
147  DlScalar mxz,
148  DlScalar mxt,
149  DlScalar myx,
150  DlScalar myy,
151  DlScalar myz,
152  DlScalar myt,
153  DlScalar mzx,
154  DlScalar mzy,
155  DlScalar mzz,
156  DlScalar mzt,
157  DlScalar mwx,
158  DlScalar mwy,
159  DlScalar mwz,
160  DlScalar mwt) override;
161 
162  // |flutter::DlOpReceiver|
163  void transformReset() override;
164 
165  // |flutter::DlOpReceiver|
166  void clipRect(const DlRect& rect,
167  flutter::DlClipOp clip_op,
168  bool is_aa) override;
169 
170  // |flutter::DlOpReceiver|
171  void clipOval(const DlRect& bounds,
172  flutter::DlClipOp clip_op,
173  bool is_aa) override;
174 
175  // |flutter::DlOpReceiver|
176  void clipRoundRect(const DlRoundRect& rrect,
177  flutter::DlClipOp clip_op,
178  bool is_aa) override;
179 
180  // |flutter::DlOpReceiver|
182  flutter::DlClipOp clip_op,
183  bool is_aa) override;
184 
185  // |flutter::DlOpReceiver|
186  void clipPath(const DlPath& path,
187  flutter::DlClipOp clip_op,
188  bool is_aa) override;
189 
190  // |flutter::DlOpReceiver|
191  void drawColor(flutter::DlColor color, flutter::DlBlendMode mode) override;
192 
193  // |flutter::DlOpReceiver|
194  void drawPaint() override;
195 
196  // |flutter::DlOpReceiver|
197  void drawLine(const DlPoint& p0, const DlPoint& p1) override;
198 
199  // |flutter::DlOpReceiver|
200  void drawDashedLine(const DlPoint& p0,
201  const DlPoint& p1,
202  DlScalar on_length,
203  DlScalar off_length) override;
204 
205  // |flutter::DlOpReceiver|
206  void drawRect(const DlRect& rect) override;
207 
208  // |flutter::DlOpReceiver|
209  void drawOval(const DlRect& bounds) override;
210 
211  // |flutter::DlOpReceiver|
212  void drawCircle(const DlPoint& center, DlScalar radius) override;
213 
214  // |flutter::DlOpReceiver|
215  void drawRoundRect(const DlRoundRect& rrect) override;
216 
217  // |flutter::DlOpReceiver|
218  void drawDiffRoundRect(const DlRoundRect& outer,
219  const DlRoundRect& inner) override;
220 
221  // |flutter::DlOpReceiver|
222  void drawRoundSuperellipse(const DlRoundSuperellipse& rse) override;
223 
224  // |flutter::DlOpReceiver|
225  void drawPath(const DlPath& path) override;
226 
227  // |flutter::DlOpReceiver|
228  void drawArc(const DlRect& oval_bounds,
229  DlScalar start_degrees,
230  DlScalar sweep_degrees,
231  bool use_center) override;
232 
233  // |flutter::DlOpReceiver|
234  void drawPoints(flutter::DlPointMode mode,
235  uint32_t count,
236  const DlPoint points[]) override;
237 
238  // |flutter::DlOpReceiver|
239  void drawVertices(const std::shared_ptr<flutter::DlVertices>& vertices,
240  flutter::DlBlendMode dl_mode) override;
241 
242  // |flutter::DlOpReceiver|
243  void drawImage(const sk_sp<flutter::DlImage> image,
244  const DlPoint& point,
245  flutter::DlImageSampling sampling,
246  bool render_with_attributes) override;
247 
248  // |flutter::DlOpReceiver|
249  void drawImageRect(const sk_sp<flutter::DlImage> image,
250  const DlRect& src,
251  const DlRect& dst,
252  flutter::DlImageSampling sampling,
253  bool render_with_attributes,
254  flutter::DlSrcRectConstraint constraint) override;
255 
256  // |flutter::DlOpReceiver|
257  void drawImageNine(const sk_sp<flutter::DlImage> image,
258  const DlIRect& center,
259  const DlRect& dst,
260  flutter::DlFilterMode filter,
261  bool render_with_attributes) override;
262 
263  // |flutter::DlOpReceiver|
264  void drawAtlas(const sk_sp<flutter::DlImage> atlas,
265  const RSTransform xform[],
266  const DlRect tex[],
267  const flutter::DlColor colors[],
268  int count,
269  flutter::DlBlendMode mode,
270  flutter::DlImageSampling sampling,
271  const DlRect* cull_rect,
272  bool render_with_attributes) override;
273 
274  // |flutter::DlOpReceiver|
275  void drawDisplayList(const sk_sp<flutter::DisplayList> display_list,
276  DlScalar opacity) override;
277 
278  // |flutter::DlOpReceiver|
279  void drawText(const std::shared_ptr<flutter::DlText>& text,
280  DlScalar x,
281  DlScalar y) override;
282 
283  // |flutter::DlOpReceiver|
284  void drawShadow(const DlPath& path,
285  const flutter::DlColor color,
286  const DlScalar elevation,
287  bool transparent_occluder,
288  DlScalar dpr) override;
289 
290  virtual Canvas& GetCanvas() = 0;
291 
292  virtual const ContentContext& GetContentContext() const = 0;
293 
294  std::shared_ptr<Texture> GetTexture(const sk_sp<flutter::DlImage>& image);
295 
296  protected:
299 
300  static void SimplifyOrDrawPath(Canvas& canvas,
301  const DlPath& cache,
302  const Paint& paint);
303 };
304 
305 /// Specific non-virtual dispatcher utility class that uses DlDispatcherBase
306 /// to implement most operations but provides additional implementation of
307 /// operations that are specific to the rendering pass of the Impeller
308 /// 2-pass rendering procedure.
310  public:
312  RenderTarget& render_target,
313  bool is_onscreen,
314  bool has_root_backdrop_filter,
315  flutter::DlBlendMode max_root_blend_mode,
316  IRect32 cull_rect);
317 
318  ~CanvasDlDispatcher() = default;
319 
320  void SetBackdropData(std::unordered_map<int64_t, BackdropData> backdrop,
321  size_t backdrop_count);
322 
323  // |flutter::DlOpReceiver|
324  void save() override {
325  // This dispatcher should never be used with the save() variant
326  // that does not include the content_depth parameter.
327  FML_UNREACHABLE();
328  }
330 
331  // |flutter::DlOpReceiver|
332  void saveLayer(const DlRect& bounds,
333  const flutter::SaveLayerOptions options,
334  const flutter::DlImageFilter* backdrop,
335  std::optional<int64_t> backdrop_id) override {
336  // This dispatcher should never be used with the saveLayer() variant
337  // that does not include the content_depth parameter.
338  FML_UNREACHABLE();
339  }
341 
342  void FinishRecording() { canvas_.EndReplay(); }
343 
344  // |flutter::DlOpReceiver|
345  void drawVertices(const std::shared_ptr<flutter::DlVertices>& vertices,
346  flutter::DlBlendMode dl_mode) override;
347 
348  private:
349  Canvas canvas_;
350  const ContentContext& renderer_;
351 
352  Canvas& GetCanvas() override;
353  const ContentContext& GetContentContext() const override;
354 };
355 
356 /// Performs a first pass over the display list to collect information
357 /// that will be useful in a second pass by the CanvasDlDispatcher.
358 /// This class collects things like text frames and backdrop filters.
359 class FirstPassDispatcher : public flutter::IgnoreAttributeDispatchHelper,
360  public flutter::IgnoreClipDispatchHelper,
361  public flutter::IgnoreDrawDispatchHelper {
362  public:
363  FirstPassDispatcher(const ContentContext& renderer,
364  const Matrix& initial_matrix,
365  const Rect cull_rect);
366 
368 
369  void save() override;
370 
371  void saveLayer(const DlRect& bounds,
372  const flutter::SaveLayerOptions options,
373  const flutter::DlImageFilter* backdrop,
374  std::optional<int64_t> backdrop_id) override;
375 
376  void restore() override;
377 
378  void translate(DlScalar tx, DlScalar ty) override;
379 
380  void scale(DlScalar sx, DlScalar sy) override;
381 
382  void rotate(DlScalar degrees) override;
383 
384  void skew(DlScalar sx, DlScalar sy) override;
385 
386  // clang-format off
387  // 2x3 2D affine subset of a 4x4 transform in row major order
388  void transform2DAffine(DlScalar mxx, DlScalar mxy, DlScalar mxt,
389  DlScalar myx, DlScalar myy, DlScalar myt) override;
390  // clang-format on
391 
392  // clang-format off
393  // full 4x4 transform in row major order
395  DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt,
396  DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt,
397  DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt,
398  DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) override;
399  // clang-format on
400 
401  void transformReset() override;
402 
403  void drawText(const std::shared_ptr<flutter::DlText>& text,
404  DlScalar x,
405  DlScalar y) override;
406 
407  void drawDisplayList(const sk_sp<flutter::DisplayList> display_list,
408  DlScalar opacity) override;
409 
410  // |flutter::DlOpReceiver|
411  void setDrawStyle(flutter::DlDrawStyle style) override;
412 
413  // |flutter::DlOpReceiver|
414  void setColor(flutter::DlColor color) override;
415 
416  // |flutter::DlOpReceiver|
417  void setStrokeWidth(DlScalar width) override;
418 
419  // |flutter::DlOpReceiver|
420  void setStrokeMiter(DlScalar limit) override;
421 
422  // |flutter::DlOpReceiver|
423  void setStrokeCap(flutter::DlStrokeCap cap) override;
424 
425  // |flutter::DlOpReceiver|
426  void setStrokeJoin(flutter::DlStrokeJoin join) override;
427 
428  // |flutter::DlOpReceiver|
429  void setImageFilter(const flutter::DlImageFilter* filter) override;
430 
431  std::pair<std::unordered_map<int64_t, BackdropData>, size_t>
433 
434  private:
435  const Rect GetCurrentLocalCullingBounds() const;
436 
437  const ContentContext& renderer_;
438  Matrix matrix_;
439  std::vector<Matrix> stack_;
440  std::unordered_map<int64_t, BackdropData> backdrop_data_;
441  // note: cull rects are always in the global coordinate space.
442  std::vector<Rect> cull_rect_state_;
443  bool has_image_filter_ = false;
444  size_t backdrop_count_ = 0;
445  Paint paint_;
446 };
447 
448 /// Render the provided display list to a texture with the given size.
449 std::shared_ptr<Texture> DisplayListToTexture(
450  const sk_sp<flutter::DisplayList>& display_list,
451  ISize size,
453  bool reset_host_buffer = true,
454  bool generate_mips = false,
455  std::optional<PixelFormat> target_pixel_format = std::nullopt);
456 
457 /// @brief Render the provided display list to the render target.
458 ///
459 /// If [is_onscreen] is true, then the onscreen command buffer will be
460 /// submitted via Context::SubmitOnscreen.
462  RenderTarget render_target,
463  const sk_sp<flutter::DisplayList>& display_list,
464  Rect cull_rect,
465  bool reset_host_buffer,
466  bool is_onscreen = true);
467 
468 } // namespace impeller
469 
470 #endif // FLUTTER_IMPELLER_DISPLAY_LIST_DL_DISPATCHER_H_
void saveLayer(const DlRect &bounds, const flutter::SaveLayerOptions options, const flutter::DlImageFilter *backdrop, std::optional< int64_t > backdrop_id) override
CanvasDlDispatcher(ContentContext &renderer, RenderTarget &render_target, bool is_onscreen, bool has_root_backdrop_filter, flutter::DlBlendMode max_root_blend_mode, IRect32 cull_rect)
void drawVertices(const std::shared_ptr< flutter::DlVertices > &vertices, flutter::DlBlendMode dl_mode) override
void SetBackdropData(std::unordered_map< int64_t, BackdropData > backdrop, size_t backdrop_count)
void EndReplay()
Definition: canvas.cc:2607
void drawLine(const DlPoint &p0, const DlPoint &p1) override
void drawText(const std::shared_ptr< flutter::DlText > &text, DlScalar x, DlScalar y) override
void drawAtlas(const sk_sp< flutter::DlImage > atlas, const RSTransform xform[], const DlRect tex[], const flutter::DlColor colors[], int count, flutter::DlBlendMode mode, flutter::DlImageSampling sampling, const DlRect *cull_rect, bool render_with_attributes) override
void drawPoints(flutter::DlPointMode mode, uint32_t count, const DlPoint points[]) override
virtual Canvas & GetCanvas()=0
void drawDashedLine(const DlPoint &p0, const DlPoint &p1, DlScalar on_length, DlScalar off_length) override
void drawOval(const DlRect &bounds) override
void setImageFilter(const flutter::DlImageFilter *filter) override
void drawPath(const DlPath &path) override
void setStrokeCap(flutter::DlStrokeCap cap) override
void clipOval(const DlRect &bounds, flutter::DlClipOp clip_op, bool is_aa) override
std::shared_ptr< Texture > GetTexture(const sk_sp< flutter::DlImage > &image)
void drawRoundSuperellipse(const DlRoundSuperellipse &rse) override
void clipRoundRect(const DlRoundRect &rrect, flutter::DlClipOp clip_op, bool is_aa) override
void skew(DlScalar sx, DlScalar sy) override
void clipRect(const DlRect &rect, flutter::DlClipOp clip_op, bool is_aa) override
void setAntiAlias(bool aa) override
void transformFullPerspective(DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt, DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt, DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) override
void setStrokeWidth(DlScalar width) override
void drawDiffRoundRect(const DlRoundRect &outer, const DlRoundRect &inner) override
void drawRoundRect(const DlRoundRect &rrect) override
void setStrokeJoin(flutter::DlStrokeJoin join) override
void rotate(DlScalar degrees) override
void setColorFilter(const flutter::DlColorFilter *filter) override
void scale(DlScalar sx, DlScalar sy) override
void setDrawStyle(flutter::DlDrawStyle style) override
void drawShadow(const DlPath &path, const flutter::DlColor color, const DlScalar elevation, bool transparent_occluder, DlScalar dpr) override
void drawImage(const sk_sp< flutter::DlImage > image, const DlPoint &point, flutter::DlImageSampling sampling, bool render_with_attributes) override
void clipPath(const DlPath &path, flutter::DlClipOp clip_op, bool is_aa) override
void drawImageRect(const sk_sp< flutter::DlImage > image, const DlRect &src, const DlRect &dst, flutter::DlImageSampling sampling, bool render_with_attributes, flutter::DlSrcRectConstraint constraint) override
void clipRoundSuperellipse(const DlRoundSuperellipse &rse, flutter::DlClipOp clip_op, bool is_aa) override
void drawArc(const DlRect &oval_bounds, DlScalar start_degrees, DlScalar sweep_degrees, bool use_center) override
virtual ~DlDispatcherBase()=default
void saveLayer(const DlRect &bounds, const flutter::SaveLayerOptions &options, uint32_t total_content_depth, flutter::DlBlendMode max_content_mode, const flutter::DlImageFilter *backdrop, std::optional< int64_t > backdrop_id) override
void drawDisplayList(const sk_sp< flutter::DisplayList > display_list, DlScalar opacity) override
void transform2DAffine(DlScalar mxx, DlScalar mxy, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myt) override
void setInvertColors(bool invert) override
virtual const ContentContext & GetContentContext() const =0
void setColor(flutter::DlColor color) override
void save(uint32_t total_content_depth) override
void setStrokeMiter(DlScalar limit) override
void translate(DlScalar tx, DlScalar ty) override
void drawVertices(const std::shared_ptr< flutter::DlVertices > &vertices, flutter::DlBlendMode dl_mode) override
void drawCircle(const DlPoint &center, DlScalar radius) override
void setMaskFilter(const flutter::DlMaskFilter *filter) override
void setColorSource(const flutter::DlColorSource *source) override
void drawImageNine(const sk_sp< flutter::DlImage > image, const DlIRect &center, const DlRect &dst, flutter::DlFilterMode filter, bool render_with_attributes) override
void transformReset() override
void setBlendMode(flutter::DlBlendMode mode) override
void drawColor(flutter::DlColor color, flutter::DlBlendMode mode) override
void drawRect(const DlRect &rect) override
static void SimplifyOrDrawPath(Canvas &canvas, const DlPath &cache, const Paint &paint)
void setColor(flutter::DlColor color) override
void setStrokeCap(flutter::DlStrokeCap cap) override
void saveLayer(const DlRect &bounds, const flutter::SaveLayerOptions options, const flutter::DlImageFilter *backdrop, std::optional< int64_t > backdrop_id) override
void setDrawStyle(flutter::DlDrawStyle style) override
std::pair< std::unordered_map< int64_t, BackdropData >, size_t > TakeBackdropData()
void rotate(DlScalar degrees) override
void setImageFilter(const flutter::DlImageFilter *filter) override
void setStrokeMiter(DlScalar limit) override
void transformFullPerspective(DlScalar mxx, DlScalar mxy, DlScalar mxz, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myz, DlScalar myt, DlScalar mzx, DlScalar mzy, DlScalar mzz, DlScalar mzt, DlScalar mwx, DlScalar mwy, DlScalar mwz, DlScalar mwt) override
void drawText(const std::shared_ptr< flutter::DlText > &text, DlScalar x, DlScalar y) override
void scale(DlScalar sx, DlScalar sy) override
void translate(DlScalar tx, DlScalar ty) override
void skew(DlScalar sx, DlScalar sy) override
FirstPassDispatcher(const ContentContext &renderer, const Matrix &initial_matrix, const Rect cull_rect)
void drawDisplayList(const sk_sp< flutter::DisplayList > display_list, DlScalar opacity) override
void setStrokeWidth(DlScalar width) override
void setStrokeJoin(flutter::DlStrokeJoin join) override
void transform2DAffine(DlScalar mxx, DlScalar mxy, DlScalar mxt, DlScalar myx, DlScalar myy, DlScalar myt) override
int32_t x
flutter::DlRect DlRect
Definition: dl_dispatcher.h:30
flutter::DlIRect DlIRect
Definition: dl_dispatcher.h:31
std::shared_ptr< Texture > DisplayListToTexture(const sk_sp< flutter::DisplayList > &display_list, ISize size, AiksContext &context, bool reset_host_buffer, bool generate_mips, std::optional< PixelFormat > target_pixel_format)
Render the provided display list to a texture with the given size.
flutter::DlRoundRect DlRoundRect
Definition: dl_dispatcher.h:32
flutter::DlPoint DlPoint
Definition: dl_dispatcher.h:29
flutter::DlRoundSuperellipse DlRoundSuperellipse
Definition: dl_dispatcher.h:33
flutter::DlPath DlPath
Definition: dl_dispatcher.h:34
bool RenderToTarget(ContentContext &context, RenderTarget render_target, const sk_sp< flutter::DisplayList > &display_list, Rect cull_rect, bool reset_host_buffer, bool is_onscreen)
Render the provided display list to the render target.
flutter::DlScalar DlScalar
Definition: dl_dispatcher.h:28
std::shared_ptr< ContextGLES > context
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
std::vector< Point > points