miniquad/
graphics.rs

1//mod texture;
2
3use crate::native::gl::*;
4
5use std::{error::Error, fmt::Display};
6
7//pub use texture::{FilterMode, TextureAccess, TextureFormat, TextureParams, TextureWrap};
8
9mod gl;
10
11pub use gl::raw_gl;
12
13#[cfg(target_vendor = "apple")]
14mod metal;
15
16pub use gl::GlContext;
17
18#[cfg(target_vendor = "apple")]
19pub use metal::MetalContext;
20
21#[derive(Clone, Copy, Debug)]
22pub enum UniformType {
23    /// One 32-bit wide float (equivalent to `f32`)
24    Float1,
25    /// Two 32-bit wide floats (equivalent to `[f32; 2]`)
26    Float2,
27    /// Three 32-bit wide floats (equivalent to `[f32; 3]`)
28    Float3,
29    /// Four 32-bit wide floats (equivalent to `[f32; 4]`)
30    Float4,
31    /// One unsigned 32-bit integers (equivalent to `[u32; 1]`)
32    Int1,
33    /// Two unsigned 32-bit integers (equivalent to `[u32; 2]`)
34    Int2,
35    /// Three unsigned 32-bit integers (equivalent to `[u32; 3]`)
36    Int3,
37    /// Four unsigned 32-bit integers (equivalent to `[u32; 4]`)
38    Int4,
39    /// Four by four matrix of 32-bit floats
40    Mat4,
41}
42
43impl UniformType {
44    /// Byte size for a given UniformType
45    pub fn size(&self) -> usize {
46        match self {
47            UniformType::Float1 => 4,
48            UniformType::Float2 => 8,
49            UniformType::Float3 => 12,
50            UniformType::Float4 => 16,
51            UniformType::Int1 => 4,
52            UniformType::Int2 => 8,
53            UniformType::Int3 => 12,
54            UniformType::Int4 => 16,
55            UniformType::Mat4 => 64,
56        }
57    }
58}
59
60#[derive(Debug, Clone)]
61pub struct UniformDesc {
62    pub name: String,
63    pub uniform_type: UniformType,
64    pub array_count: usize,
65}
66
67#[derive(Debug, Clone)]
68pub struct UniformBlockLayout {
69    pub uniforms: Vec<UniformDesc>,
70}
71
72impl UniformDesc {
73    pub fn new(name: &str, uniform_type: UniformType) -> UniformDesc {
74        UniformDesc {
75            name: name.to_string(),
76            uniform_type,
77            array_count: 1,
78        }
79    }
80
81    pub fn array(self, array_count: usize) -> UniformDesc {
82        UniformDesc {
83            array_count,
84            ..self
85        }
86    }
87}
88
89#[derive(Clone)]
90pub struct ShaderMeta {
91    pub uniforms: UniformBlockLayout,
92    pub images: Vec<String>,
93}
94
95#[derive(Clone, Copy, PartialEq, Debug)]
96pub enum VertexFormat {
97    /// One 32-bit wide float (equivalent to `f32`)
98    Float1,
99    /// Two 32-bit wide floats (equivalent to `[f32; 2]`)
100    Float2,
101    /// Three 32-bit wide floats (equivalent to `[f32; 3]`)
102    Float3,
103    /// Four 32-bit wide floats (equivalent to `[f32; 4]`)
104    Float4,
105    /// One unsigned 8-bit integer (equivalent to `u8`)
106    Byte1,
107    /// Two unsigned 8-bit integers (equivalent to `[u8; 2]`)
108    Byte2,
109    /// Three unsigned 8-bit integers (equivalent to `[u8; 3]`)
110    Byte3,
111    /// Four unsigned 8-bit integers (equivalent to `[u8; 4]`)
112    Byte4,
113    /// One unsigned 16-bit integer (equivalent to `u16`)
114    Short1,
115    /// Two unsigned 16-bit integers (equivalent to `[u16; 2]`)
116    Short2,
117    /// Tree unsigned 16-bit integers (equivalent to `[u16; 3]`)
118    Short3,
119    /// Four unsigned 16-bit integers (equivalent to `[u16; 4]`)
120    Short4,
121    /// One unsigned 32-bit integers (equivalent to `[u32; 1]`)
122    Int1,
123    /// Two unsigned 32-bit integers (equivalent to `[u32; 2]`)
124    Int2,
125    /// Three unsigned 32-bit integers (equivalent to `[u32; 3]`)
126    Int3,
127    /// Four unsigned 32-bit integers (equivalent to `[u32; 4]`)
128    Int4,
129    /// Four by four matrix of 32-bit floats
130    Mat4,
131}
132
133impl VertexFormat {
134    /// Number of components in this VertexFormat
135    /// it is called size in OpenGl, but do not confuse this with bytes size
136    /// basically, its an N from FloatN/IntN
137    pub fn components(&self) -> i32 {
138        match self {
139            VertexFormat::Float1 => 1,
140            VertexFormat::Float2 => 2,
141            VertexFormat::Float3 => 3,
142            VertexFormat::Float4 => 4,
143            VertexFormat::Byte1 => 1,
144            VertexFormat::Byte2 => 2,
145            VertexFormat::Byte3 => 3,
146            VertexFormat::Byte4 => 4,
147            VertexFormat::Short1 => 1,
148            VertexFormat::Short2 => 2,
149            VertexFormat::Short3 => 3,
150            VertexFormat::Short4 => 4,
151            VertexFormat::Int1 => 1,
152            VertexFormat::Int2 => 2,
153            VertexFormat::Int3 => 3,
154            VertexFormat::Int4 => 4,
155            VertexFormat::Mat4 => 16,
156        }
157    }
158
159    /// Size in bytes
160    pub fn size_bytes(&self) -> i32 {
161        match self {
162            VertexFormat::Float1 => 1 * 4,
163            VertexFormat::Float2 => 2 * 4,
164            VertexFormat::Float3 => 3 * 4,
165            VertexFormat::Float4 => 4 * 4,
166            VertexFormat::Byte1 => 1,
167            VertexFormat::Byte2 => 2,
168            VertexFormat::Byte3 => 3,
169            VertexFormat::Byte4 => 4,
170            VertexFormat::Short1 => 1 * 2,
171            VertexFormat::Short2 => 2 * 2,
172            VertexFormat::Short3 => 3 * 2,
173            VertexFormat::Short4 => 4 * 2,
174            VertexFormat::Int1 => 1 * 4,
175            VertexFormat::Int2 => 2 * 4,
176            VertexFormat::Int3 => 3 * 4,
177            VertexFormat::Int4 => 4 * 4,
178            VertexFormat::Mat4 => 16 * 4,
179        }
180    }
181
182    fn type_(&self) -> GLuint {
183        match self {
184            VertexFormat::Float1 => GL_FLOAT,
185            VertexFormat::Float2 => GL_FLOAT,
186            VertexFormat::Float3 => GL_FLOAT,
187            VertexFormat::Float4 => GL_FLOAT,
188            VertexFormat::Byte1 => GL_UNSIGNED_BYTE,
189            VertexFormat::Byte2 => GL_UNSIGNED_BYTE,
190            VertexFormat::Byte3 => GL_UNSIGNED_BYTE,
191            VertexFormat::Byte4 => GL_UNSIGNED_BYTE,
192            VertexFormat::Short1 => GL_UNSIGNED_SHORT,
193            VertexFormat::Short2 => GL_UNSIGNED_SHORT,
194            VertexFormat::Short3 => GL_UNSIGNED_SHORT,
195            VertexFormat::Short4 => GL_UNSIGNED_SHORT,
196            VertexFormat::Int1 => GL_UNSIGNED_INT,
197            VertexFormat::Int2 => GL_UNSIGNED_INT,
198            VertexFormat::Int3 => GL_UNSIGNED_INT,
199            VertexFormat::Int4 => GL_UNSIGNED_INT,
200            VertexFormat::Mat4 => GL_FLOAT,
201        }
202    }
203}
204
205#[derive(Clone, Copy, Debug, Default, PartialEq)]
206pub enum VertexStep {
207    #[default]
208    PerVertex,
209    PerInstance,
210}
211
212#[derive(Clone, Debug)]
213pub struct BufferLayout {
214    pub stride: i32,
215    pub step_func: VertexStep,
216    pub step_rate: i32,
217}
218
219impl Default for BufferLayout {
220    fn default() -> BufferLayout {
221        BufferLayout {
222            stride: 0,
223            step_func: VertexStep::PerVertex,
224            step_rate: 1,
225        }
226    }
227}
228
229#[derive(Clone, Debug)]
230pub struct VertexAttribute {
231    pub name: &'static str,
232    pub format: VertexFormat,
233    pub buffer_index: usize,
234    /// This flag affects integer VertexFormats, Byte*, Short*, Int*
235    /// Taking Byte4 as an example:
236    /// On Metal, it might be received as either `float4` or `uint4`
237    /// On OpenGl and `gl_pass_as_float = true` shaders should receive it as `vec4`
238    /// With `gl_pass_as_float = false`, as `uvec4`
239    ///
240    /// Note that `uvec4` requires at least `150` glsl version
241    /// Before setting `gl_pass_as_float` to false, better check `context.info().has_integer_attributes()` and double check that shaders are at least `150`
242    pub gl_pass_as_float: bool,
243}
244
245impl VertexAttribute {
246    pub const fn new(name: &'static str, format: VertexFormat) -> VertexAttribute {
247        Self::with_buffer(name, format, 0)
248    }
249
250    pub const fn with_buffer(
251        name: &'static str,
252        format: VertexFormat,
253        buffer_index: usize,
254    ) -> VertexAttribute {
255        VertexAttribute {
256            name,
257            format,
258            buffer_index,
259            gl_pass_as_float: true,
260        }
261    }
262}
263
264#[derive(Clone, Debug)]
265pub struct PipelineLayout {
266    pub buffers: &'static [BufferLayout],
267    pub attributes: &'static [VertexAttribute],
268}
269
270#[derive(Clone, Debug, Copy)]
271pub enum ShaderType {
272    Vertex,
273    Fragment,
274}
275
276impl Display for ShaderType {
277    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
278        match self {
279            Self::Vertex => write!(f, "Vertex"),
280            Self::Fragment => write!(f, "Fragment"),
281        }
282    }
283}
284
285#[derive(Clone, Debug)]
286pub enum ShaderError {
287    CompilationError {
288        shader_type: ShaderType,
289        error_message: String,
290    },
291    LinkError(String),
292    /// Shader strings should never contains \00 in the middle
293    FFINulError(std::ffi::NulError),
294}
295
296impl From<std::ffi::NulError> for ShaderError {
297    fn from(e: std::ffi::NulError) -> ShaderError {
298        ShaderError::FFINulError(e)
299    }
300}
301
302impl Display for ShaderError {
303    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
304        match self {
305            Self::CompilationError {
306                shader_type,
307                error_message,
308            } => write!(f, "{shader_type} shader error:\n{error_message}"),
309            Self::LinkError(msg) => write!(f, "Link shader error:\n{msg}"),
310            Self::FFINulError(e) => write!(f, "{e}"),
311        }
312    }
313}
314
315impl Error for ShaderError {}
316
317/// List of all the possible formats of input data when uploading to texture.
318/// The list is built by intersection of texture formats supported by 3.3 core profile and webgl1.
319#[repr(u8)]
320#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
321pub enum TextureFormat {
322    RGB8,
323    RGBA8,
324    RGBA16F,
325    Depth,
326    Depth32,
327    Alpha,
328}
329impl TextureFormat {
330    /// Returns the size in bytes of texture with `dimensions`.
331    pub fn size(self, width: u32, height: u32) -> u32 {
332        let square = width * height;
333        match self {
334            TextureFormat::RGB8 => 3 * square,
335            TextureFormat::RGBA8 => 4 * square,
336            TextureFormat::RGBA16F => 8 * square,
337            TextureFormat::Depth => 2 * square,
338            TextureFormat::Depth32 => 4 * square,
339            TextureFormat::Alpha => 1 * square,
340        }
341    }
342}
343
344/// Sets the wrap parameter for texture.
345#[derive(Debug, PartialEq, Eq, Clone, Copy)]
346pub enum TextureWrap {
347    /// Samples at coord x + 1 map to coord x.
348    Repeat,
349    /// Samples at coord x + 1 map to coord 1 - x.
350    Mirror,
351    /// Samples at coord x + 1 map to coord 1.
352    Clamp,
353}
354
355#[derive(Clone, Copy, Debug, PartialEq, Hash)]
356pub enum FilterMode {
357    Linear,
358    Nearest,
359}
360
361#[derive(Clone, Copy, Debug, PartialEq, Hash)]
362pub enum MipmapFilterMode {
363    None,
364    Linear,
365    Nearest,
366}
367
368#[derive(Debug, PartialEq, Eq, Clone, Copy)]
369pub enum TextureAccess {
370    /// Used as read-only from GPU
371    Static,
372    /// Can be written to from GPU
373    RenderTarget,
374}
375
376#[derive(Debug, Copy, Clone, PartialEq)]
377pub enum TextureKind {
378    Texture2D,
379    CubeMap,
380}
381
382#[derive(Debug, Copy, Clone)]
383pub struct TextureParams {
384    pub kind: TextureKind,
385    pub format: TextureFormat,
386    pub wrap: TextureWrap,
387    pub min_filter: FilterMode,
388    pub mag_filter: FilterMode,
389    pub mipmap_filter: MipmapFilterMode,
390    pub width: u32,
391    pub height: u32,
392    // All miniquad API could work without this flag being explicit.
393    // We can decide if mipmaps are required by the data provided
394    // And reallocate non-mipmapped texture(on metal) on generateMipmaps call
395    // But! Reallocating cubemaps is too much struggle, so leave it for later.
396    pub allocate_mipmaps: bool,
397    /// Only used for render textures. `sample_count > 1` allows anti-aliased render textures.
398    ///
399    /// On OpenGL, for a `sample_count > 1` render texture, render buffer object will
400    /// be created instead of a regulat texture.
401    ///
402    pub sample_count: i32,
403}
404
405impl Default for TextureParams {
406    fn default() -> Self {
407        TextureParams {
408            kind: TextureKind::Texture2D,
409            format: TextureFormat::RGBA8,
410            wrap: TextureWrap::Clamp,
411            min_filter: FilterMode::Linear,
412            mag_filter: FilterMode::Linear,
413            mipmap_filter: MipmapFilterMode::None,
414            width: 0,
415            height: 0,
416            allocate_mipmaps: false,
417            sample_count: 1,
418        }
419    }
420}
421
422#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)]
423pub struct ShaderId(usize);
424
425// Inner hence we can't have private data in enum fields
426#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)]
427pub(crate) enum TextureIdInner {
428    Managed(usize),
429    Raw(RawId),
430}
431
432#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)]
433pub struct TextureId(TextureIdInner);
434
435impl TextureId {
436    /// Wrap raw platform texture into a TextureId acceptable for miniquad
437    /// Without allocating any miniquad memory and without letting miniquad
438    /// manage the texture.
439    pub fn from_raw_id(raw_id: RawId) -> TextureId {
440        TextureId(TextureIdInner::Raw(raw_id))
441    }
442}
443
444/// Pixel arithmetic description for blending operations.
445/// Will be used in an equation:
446/// `equation(sfactor * source_color, dfactor * destination_color)`
447/// Where source_color is the new pixel color and destination color is color from the destination buffer.
448///
449/// Example:
450///```
451///# use miniquad::{BlendState, BlendFactor, BlendValue, Equation};
452///BlendState::new(
453///    Equation::Add,
454///    BlendFactor::Value(BlendValue::SourceAlpha),
455///    BlendFactor::OneMinusValue(BlendValue::SourceAlpha)
456///);
457///```
458/// This will be `source_color * source_color.a + destination_color * (1 - source_color.a)`
459/// Wich is quite common set up for alpha blending.
460#[derive(Debug, Copy, Clone, PartialEq)]
461pub struct BlendState {
462    equation: Equation,
463    sfactor: BlendFactor,
464    dfactor: BlendFactor,
465}
466
467impl BlendState {
468    pub fn new(equation: Equation, sfactor: BlendFactor, dfactor: BlendFactor) -> BlendState {
469        BlendState {
470            equation,
471            sfactor,
472            dfactor,
473        }
474    }
475}
476
477#[derive(Debug, Copy, Clone, PartialEq)]
478pub struct StencilState {
479    pub front: StencilFaceState,
480    pub back: StencilFaceState,
481}
482
483#[derive(Debug, Copy, Clone, PartialEq)]
484pub struct StencilFaceState {
485    /// Operation to use when stencil test fails
486    pub fail_op: StencilOp,
487
488    /// Operation to use when stencil test passes, but depth test fails
489    pub depth_fail_op: StencilOp,
490
491    /// Operation to use when both stencil and depth test pass,
492    /// or when stencil pass and no depth or depth disabled
493    pub pass_op: StencilOp,
494
495    /// Used for stencil testing with test_ref and test_mask: if (test_ref & test_mask) *test_func* (*stencil* && test_mask)
496    /// Default is Always, which means "always pass"
497    pub test_func: CompareFunc,
498
499    /// Default value: 0
500    pub test_ref: i32,
501
502    /// Default value: all 1s
503    pub test_mask: u32,
504
505    /// Specifies a bit mask to enable or disable writing of individual bits in the stencil planes
506    /// Default value: all 1s
507    pub write_mask: u32,
508}
509
510/// Operations performed on current stencil value when comparison test passes or fails.
511#[derive(Debug, PartialEq, Eq, Clone, Copy)]
512pub enum StencilOp {
513    /// Default value
514    Keep,
515    Zero,
516    Replace,
517    IncrementClamp,
518    DecrementClamp,
519    Invert,
520    IncrementWrap,
521    DecrementWrap,
522}
523
524/// Depth and stencil compare function
525#[derive(Debug, Copy, Clone, PartialEq)]
526pub enum CompareFunc {
527    /// Default value
528    Always,
529    Never,
530    Less,
531    Equal,
532    LessOrEqual,
533    Greater,
534    NotEqual,
535    GreaterOrEqual,
536}
537
538type ColorMask = (bool, bool, bool, bool);
539
540pub enum PassAction {
541    Nothing,
542    Clear {
543        color: Option<(f32, f32, f32, f32)>,
544        depth: Option<f32>,
545        stencil: Option<i32>,
546    },
547}
548
549impl PassAction {
550    pub fn clear_color(r: f32, g: f32, b: f32, a: f32) -> PassAction {
551        PassAction::Clear {
552            color: Some((r, g, b, a)),
553            depth: Some(1.),
554            stencil: None,
555        }
556    }
557}
558
559impl Default for PassAction {
560    fn default() -> PassAction {
561        PassAction::Clear {
562            color: Some((0.0, 0.0, 0.0, 0.0)),
563            depth: Some(1.),
564            stencil: None,
565        }
566    }
567}
568
569#[derive(Clone, Copy, Debug, PartialEq)]
570pub struct RenderPass(usize);
571
572pub const MAX_VERTEX_ATTRIBUTES: usize = 16;
573pub const MAX_SHADERSTAGE_IMAGES: usize = 12;
574
575#[derive(Clone, Debug)]
576pub struct Features {
577    pub instancing: bool,
578    /// Does current rendering backend support automatic resolve of
579    /// multisampled render passes on end_render_pass.
580    /// Would be false on WebGl1 and GL2.
581    ///
582    /// With resolve_attachments: false, not-none resolve_img in new_render_pass will
583    /// result in a runtime panic.
584    pub resolve_attachments: bool,
585}
586
587impl Default for Features {
588    fn default() -> Features {
589        Features {
590            instancing: true,
591            resolve_attachments: true,
592        }
593    }
594}
595
596/// Specify whether front- or back-facing polygons can be culled.
597#[derive(Debug, PartialEq, Eq, Clone, Copy)]
598pub enum CullFace {
599    Nothing,
600    Front,
601    Back,
602}
603
604/// Define front- and back-facing polygons.
605#[derive(Debug, PartialEq, Eq, Clone, Copy)]
606pub enum FrontFaceOrder {
607    Clockwise,
608    CounterClockwise,
609}
610
611/// A pixel-wise comparison function.
612#[derive(Debug, PartialEq, Eq, Clone, Copy)]
613pub enum Comparison {
614    Never,
615    Less,
616    LessOrEqual,
617    Greater,
618    GreaterOrEqual,
619    Equal,
620    NotEqual,
621    Always,
622}
623
624impl From<Comparison> for GLenum {
625    fn from(cmp: Comparison) -> Self {
626        match cmp {
627            Comparison::Never => GL_NEVER,
628            Comparison::Less => GL_LESS,
629            Comparison::LessOrEqual => GL_LEQUAL,
630            Comparison::Greater => GL_GREATER,
631            Comparison::GreaterOrEqual => GL_GEQUAL,
632            Comparison::Equal => GL_EQUAL,
633            Comparison::NotEqual => GL_NOTEQUAL,
634            Comparison::Always => GL_ALWAYS,
635        }
636    }
637}
638
639/// Specifies how incoming RGBA values (source) and the RGBA in framebuffer (destination)
640/// are combined.
641#[derive(Debug, Default, PartialEq, Eq, Clone, Copy)]
642pub enum Equation {
643    /// Adds source and destination. Source and destination are multiplied
644    /// by blending parameters before addition.
645    #[default]
646    Add,
647    /// Subtracts destination from source. Source and destination are
648    /// multiplied by blending parameters before subtraction.
649    Subtract,
650    /// Subtracts source from destination. Source and destination are
651    /// multiplied by blending parameters before subtraction.
652    ReverseSubtract,
653}
654
655/// Blend values.
656#[derive(Debug, PartialEq, Eq, Clone, Copy)]
657pub enum BlendValue {
658    SourceColor,
659    SourceAlpha,
660    DestinationColor,
661    DestinationAlpha,
662}
663
664/// Blend factors.
665#[derive(Debug, PartialEq, Eq, Clone, Copy)]
666pub enum BlendFactor {
667    Zero,
668    One,
669    Value(BlendValue),
670    OneMinusValue(BlendValue),
671    SourceAlphaSaturate,
672}
673
674#[derive(Debug, PartialEq, Clone, Copy)]
675pub enum PrimitiveType {
676    Triangles,
677    Lines,
678    Points,
679}
680
681impl From<PrimitiveType> for GLenum {
682    fn from(primitive_type: PrimitiveType) -> Self {
683        match primitive_type {
684            PrimitiveType::Triangles => GL_TRIANGLES,
685            PrimitiveType::Lines => GL_LINES,
686            PrimitiveType::Points => GL_POINTS,
687        }
688    }
689}
690
691#[derive(Debug, PartialEq, Clone, Copy)]
692pub struct PipelineParams {
693    pub cull_face: CullFace,
694    pub front_face_order: FrontFaceOrder,
695    pub depth_test: Comparison,
696    pub depth_write: bool,
697    pub depth_write_offset: Option<(f32, f32)>,
698    /// Color (RGB) blend function. If None - blending will be disabled for this pipeline.
699    /// Usual use case to get alpha-blending:
700    ///```
701    ///# use miniquad::{PipelineParams, BlendState, BlendValue, BlendFactor, Equation};
702    ///PipelineParams {
703    ///    color_blend: Some(BlendState::new(
704    ///        Equation::Add,
705    ///        BlendFactor::Value(BlendValue::SourceAlpha),
706    ///        BlendFactor::OneMinusValue(BlendValue::SourceAlpha))
707    ///    ),
708    ///    ..Default::default()
709    ///};
710    ///```
711    pub color_blend: Option<BlendState>,
712    /// Alpha blend function. If None - alpha will be blended with same equation than RGB colors.
713    /// One of possible separate alpha channel blend settings is to avoid blending with WebGl background.
714    /// On webgl canvas's resulting alpha channel will be used to blend the whole canvas background.
715    /// To avoid modifying only alpha channel, but keep usual transparency:
716    ///```
717    ///# use miniquad::{PipelineParams, BlendState, BlendValue, BlendFactor, Equation};
718    ///PipelineParams {
719    ///    color_blend: Some(BlendState::new(
720    ///        Equation::Add,
721    ///        BlendFactor::Value(BlendValue::SourceAlpha),
722    ///        BlendFactor::OneMinusValue(BlendValue::SourceAlpha))
723    ///    ),
724    ///    alpha_blend: Some(BlendState::new(
725    ///        Equation::Add,
726    ///        BlendFactor::Zero,
727    ///        BlendFactor::One)
728    ///    ),
729    ///    ..Default::default()
730    ///};
731    ///```
732    /// The same results may be achieved with ColorMask(true, true, true, false)
733    pub alpha_blend: Option<BlendState>,
734    pub stencil_test: Option<StencilState>,
735    pub color_write: ColorMask,
736    pub primitive_type: PrimitiveType,
737}
738
739// TODO(next major version bump): should be PipelineId
740#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
741pub struct Pipeline(usize);
742
743impl Default for PipelineParams {
744    fn default() -> PipelineParams {
745        PipelineParams {
746            cull_face: CullFace::Nothing,
747            front_face_order: FrontFaceOrder::CounterClockwise,
748            depth_test: Comparison::Always, // no depth test,
749            depth_write: false,             // no depth write,
750            depth_write_offset: None,
751            color_blend: None,
752            alpha_blend: None,
753            stencil_test: None,
754            color_write: (true, true, true, true),
755            primitive_type: PrimitiveType::Triangles,
756        }
757    }
758}
759
760/// Geometry bindings
761#[derive(Clone, Debug)]
762pub struct Bindings {
763    /// Vertex buffers. Data contained in the buffer must match layout
764    /// specified in the `Pipeline`.
765    ///
766    /// Most commonly vertex buffer will contain `(x,y,z,w)` coordinates of the
767    /// vertex in 3d space, as well as `(u,v)` coordinates that map the vertex
768    /// to some position in the corresponding `Texture`.
769    pub vertex_buffers: Vec<BufferId>,
770    /// Index buffer which instructs the GPU in which order to draw vertices
771    /// from a vertex buffer, with each subsequent 3 indices forming a
772    /// triangle.
773    pub index_buffer: BufferId,
774    /// Textures to be used with when drawing the geometry in the fragment
775    /// shader.
776    pub images: Vec<TextureId>,
777}
778
779#[derive(Clone, Copy, Debug, PartialEq)]
780pub enum BufferType {
781    VertexBuffer,
782    IndexBuffer,
783}
784
785#[derive(Clone, Copy, Debug, PartialEq)]
786pub enum BufferUsage {
787    Immutable,
788    Dynamic,
789    Stream,
790}
791
792fn gl_buffer_target(buffer_type: &BufferType) -> GLenum {
793    match buffer_type {
794        BufferType::VertexBuffer => GL_ARRAY_BUFFER,
795        BufferType::IndexBuffer => GL_ELEMENT_ARRAY_BUFFER,
796    }
797}
798
799fn gl_usage(usage: &BufferUsage) -> GLenum {
800    match usage {
801        BufferUsage::Immutable => GL_STATIC_DRAW,
802        BufferUsage::Dynamic => GL_DYNAMIC_DRAW,
803        BufferUsage::Stream => GL_STREAM_DRAW,
804    }
805}
806
807#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
808pub struct BufferId(usize);
809
810/// `ElapsedQuery` is used to measure duration of GPU operations.
811///
812/// Usual timing/profiling methods are difficult apply to GPU workloads as draw calls are submitted
813/// asynchronously effectively hiding execution time of individual operations from the user.
814/// `ElapsedQuery` allows to measure duration of individual rendering operations, as though the time
815/// was measured on GPU rather than CPU side.
816///
817/// The query is created using [`ElapsedQuery::new()`] function.
818/// ```
819/// use miniquad::graphics::ElapsedQuery;
820/// // initialization
821/// let mut query = ElapsedQuery::new();
822/// ```
823/// Measurement is performed by calling [`ElapsedQuery::begin_query()`] and
824/// [`ElapsedQuery::end_query()`]
825///
826/// ```
827/// # use miniquad::graphics::ElapsedQuery;
828/// # let mut query = ElapsedQuery::new();
829///
830/// query.begin_query();
831/// // one or multiple calls to miniquad::GraphicsContext::draw()
832/// query.end_query();
833/// ```
834///
835/// Retreival of measured duration is only possible at a later point in time. Often a frame or
836/// couple frames later. Measurement latency can especially be high on WASM/WebGL target.
837///
838/// ```
839/// // couple frames later:
840/// # use miniquad::graphics::ElapsedQuery;
841/// # let mut query = ElapsedQuery::new();
842/// # query.begin_query();
843/// # query.end_query();
844/// if query.is_available() {
845///   let duration_nanoseconds = query.get_result();
846///   // use/display duration_nanoseconds
847/// }
848/// ```
849///
850/// And during finalization:
851/// ```
852/// // clean-up
853/// # use miniquad::graphics::ElapsedQuery;
854/// # let mut query = ElapsedQuery::new();
855/// # query.begin_query();
856/// # query.end_query();
857/// # if query.is_available() {
858/// #   let duration_nanoseconds = query.get_result();
859/// #   // use/display duration_nanoseconds
860/// # }
861/// query.delete();
862/// ```
863///
864/// It is only possible to measure single query at once.
865///
866/// On OpenGL/WebGL platforms implementation relies on [`EXT_disjoint_timer_query`] extension.
867///
868/// [`EXT_disjoint_timer_query`]: https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_disjoint_timer_query.txt
869///
870#[derive(Clone, Copy)]
871pub struct ElapsedQuery {
872    gl_query: GLuint,
873}
874
875impl Default for ElapsedQuery {
876    fn default() -> Self {
877        Self::new()
878    }
879}
880
881impl ElapsedQuery {
882    pub fn new() -> ElapsedQuery {
883        ElapsedQuery { gl_query: 0 }
884    }
885
886    /// Submit a beginning of elapsed-time query.
887    ///
888    /// Only a single query can be measured at any moment in time.
889    ///
890    /// Use [`ElapsedQuery::end_query()`] to finish the query and
891    /// [`ElapsedQuery::get_result()`] to read the result when rendering is complete.
892    ///
893    /// The query can be used again after retriving the result.
894    ///
895    /// Implemented as `glBeginQuery(GL_TIME_ELAPSED, ...)` on OpenGL/WebGL platforms.
896    ///
897    /// Use [`ElapsedQuery::is_supported()`] to check if functionality is available and the method can be called.
898    pub fn begin_query(&mut self) {
899        if self.gl_query == 0 {
900            unsafe { glGenQueries(1, &mut self.gl_query) };
901        }
902        unsafe { glBeginQuery(GL_TIME_ELAPSED, self.gl_query) };
903    }
904
905    /// Submit an end of elapsed-time query that can be read later when rendering is complete.
906    ///
907    /// This function is usd in conjunction with [`ElapsedQuery::begin_query()`] and
908    /// [`ElapsedQuery::get_result()`].
909    ///
910    /// Implemented as `glEndQuery(GL_TIME_ELAPSED)` on OpenGL/WebGL platforms.
911    pub fn end_query(&mut self) {
912        unsafe { glEndQuery(GL_TIME_ELAPSED) };
913    }
914
915    /// Retreieve measured duration in nanonseconds.
916    ///
917    /// Note that the result may be ready only couple frames later due to asynchronous nature of GPU
918    /// command submission. Use [`ElapsedQuery::is_available()`] to check if the result is
919    /// available for retrieval.
920    ///
921    /// Use [`ElapsedQuery::is_supported()`] to check if functionality is available and the method can be called.
922    pub fn get_result(&self) -> u64 {
923        // let mut time: GLuint64 = 0;
924        // assert!(self.gl_query != 0);
925        // unsafe { glGetQueryObjectui64v(self.gl_query, GL_QUERY_RESULT, &mut time) };
926        // time
927        0
928    }
929
930    /// Reports whenever elapsed timer is supported and other methods can be invoked.
931    pub fn is_supported() -> bool {
932        unimplemented!();
933        //unsafe { sapp_is_elapsed_timer_supported() }
934    }
935
936    /// Reports whenever result of submitted query is available for retrieval with
937    /// [`ElapsedQuery::get_result()`].
938    ///
939    /// Note that the result may be ready only couple frames later due to asynchrnous nature of GPU
940    /// command submission.
941    ///
942    /// Use [`ElapsedQuery::is_supported()`] to check if functionality is available and the method can be called.
943    pub fn is_available(&self) -> bool {
944        // let mut available: GLint = 0;
945
946        // // begin_query was not called yet
947        // if self.gl_query == 0 {
948        //     return false;
949        // }
950
951        //unsafe { glGetQueryObjectiv(self.gl_query, GL_QUERY_RESULT_AVAILABLE, &mut available) };
952        //available != 0
953
954        false
955    }
956
957    /// Delete query.
958    ///
959    /// Note that the query is not deleted automatically when dropped.
960    ///
961    /// Implemented as `glDeleteQueries(...)` on OpenGL/WebGL platforms.
962    pub fn delete(&mut self) {
963        unsafe { glDeleteQueries(1, &self.gl_query) }
964        self.gl_query = 0;
965    }
966}
967
968/// A vtable-erased generic argument.
969/// Basically, the same thing as `fn f<U>(a: &U)`, but
970/// trait-object friendly.
971pub struct Arg<'a> {
972    ptr: *const std::ffi::c_void,
973    element_size: usize,
974    size: usize,
975    is_slice: bool,
976    _phantom: std::marker::PhantomData<&'a ()>,
977}
978
979pub enum TextureSource<'a> {
980    Empty,
981    Bytes(&'a [u8]),
982    /// Array of `[cubemap_face][mipmap_level][bytes]`
983    Array(&'a [&'a [&'a [u8]]]),
984}
985
986pub enum BufferSource<'a> {
987    Slice(Arg<'a>),
988    Empty { size: usize, element_size: usize },
989}
990impl<'a> BufferSource<'a> {
991    /// Empty buffer of `size * size_of::<T>` bytes
992    ///
993    /// Platform specific note, OpenGL:
994    /// For VertexBuffer T could be anything, it is only used to calculate total size,
995    /// but for IndexBuffers T should be either u8, u16 or u32, other
996    /// types are not supported.
997    ///
998    /// For vertex buffers it is OK to use `empty::<u8>(byte_size);`
999    pub fn empty<T>(size: usize) -> BufferSource<'a> {
1000        let element_size = std::mem::size_of::<T>();
1001        BufferSource::Empty {
1002            size: size * std::mem::size_of::<T>(),
1003            element_size,
1004        }
1005    }
1006
1007    pub fn slice<T>(data: &'a [T]) -> BufferSource<'a> {
1008        BufferSource::Slice(Arg {
1009            ptr: data.as_ptr() as _,
1010            size: std::mem::size_of_val(data),
1011            element_size: std::mem::size_of::<T>(),
1012            is_slice: true,
1013            _phantom: std::marker::PhantomData,
1014        })
1015    }
1016
1017    pub unsafe fn pointer(ptr: *const u8, size: usize, element_size: usize) -> BufferSource<'a> {
1018        BufferSource::Slice(Arg {
1019            ptr: ptr as _,
1020            size,
1021            element_size,
1022            is_slice: true,
1023            _phantom: std::marker::PhantomData,
1024        })
1025    }
1026}
1027
1028pub struct UniformsSource<'a>(Arg<'a>);
1029impl<'a> UniformsSource<'a> {
1030    pub fn table<T>(data: &'a T) -> UniformsSource<'a> {
1031        Self(Arg {
1032            ptr: data as *const T as _,
1033            size: std::mem::size_of_val(data),
1034            element_size: std::mem::size_of::<T>(),
1035            is_slice: false,
1036            _phantom: std::marker::PhantomData,
1037        })
1038    }
1039}
1040
1041#[derive(Debug)]
1042pub enum ShaderSource<'a> {
1043    Glsl { vertex: &'a str, fragment: &'a str },
1044    Msl { program: &'a str },
1045}
1046
1047#[derive(Debug, Clone, Copy, PartialEq, Hash, Eq)]
1048pub enum RawId {
1049    OpenGl(crate::native::gl::GLuint),
1050    #[cfg(target_vendor = "apple")]
1051    Metal(*mut objc::runtime::Object),
1052}
1053unsafe impl Send for RawId {}
1054unsafe impl Sync for RawId {}
1055
1056#[derive(Clone, Debug, Default)]
1057pub struct GlslSupport {
1058    pub v130: bool,
1059    pub v150: bool,
1060    pub v330: bool,
1061    pub v300es: bool,
1062    pub v100_ext: bool,
1063    pub v100: bool,
1064}
1065
1066#[derive(PartialEq, Clone, Copy, Debug)]
1067pub enum Backend {
1068    Metal,
1069    OpenGl,
1070}
1071
1072#[derive(Clone, Debug)]
1073pub struct ContextInfo {
1074    pub backend: Backend,
1075    /// GL_VERSION_STRING from OpenGL. Would be empty on metal.
1076    pub gl_version_string: String,
1077    /// OpenGL provides an enumeration over GL_SHADING_LANGUAGE_VERSION,
1078    /// allowing to see which glsl versions are actually supported.
1079    /// Unfortunately, it only works on GL4.3+... and even there it is not quite correct.
1080    ///
1081    /// miniquad will take a guess based on GL_VERSION_STRING, current platform and implementation
1082    /// details. Would be all false on metal.
1083    pub glsl_support: GlslSupport,
1084    /// List of platform-dependent features that miniquad failed to make cross-platforms
1085    /// and therefore they might be missing.
1086    pub features: Features,
1087}
1088
1089impl ContextInfo {
1090    pub fn has_integer_attributes(&self) -> bool {
1091        match self.backend {
1092            Backend::Metal => true,
1093            Backend::OpenGl => {
1094                self.glsl_support.v150 | self.glsl_support.v300es | self.glsl_support.v330
1095            }
1096        }
1097    }
1098}
1099
1100pub trait RenderingBackend {
1101    fn info(&self) -> ContextInfo;
1102    /// For metal context's ShaderSource should contain MSL source string, for GL - glsl.
1103    ///
1104    /// If in doubt, _most_ OpenGL contexts support "#version 100" glsl shaders.
1105    /// So far miniquad never encountered where it can create a rendering context,
1106    /// but `version 100` shaders are not supported.
1107    ///
1108    /// Typical `new_shader` invocation for an MSL and `glsl version 100` sources:
1109    /// ```ignore
1110    /// let source = match ctx.info().backend {
1111    ///    Backend::OpenGl => ShaderSource::Glsl {
1112    ///        vertex: display_shader::VERTEX,
1113    ///        fragment: display_shader::FRAGMENT,
1114    ///    },
1115    ///    Backend::Metal => ShaderSource::Msl {
1116    ///        program: display_shader::METAL
1117    ///    },
1118    /// };
1119    /// let shader = ctx.new_shader(source, display_shader::meta()).unwrap();
1120    /// ```
1121    /// Or just
1122    /// ```ignore
1123    /// let shader = ctx.new_shader(ShaderSource::Glsl {...}, ...);
1124    /// ```
1125    /// for GL-only.
1126    fn new_shader(
1127        &mut self,
1128        shader: ShaderSource,
1129        meta: ShaderMeta,
1130    ) -> Result<ShaderId, ShaderError>;
1131    fn new_texture(
1132        &mut self,
1133        access: TextureAccess,
1134        data: TextureSource,
1135        params: TextureParams,
1136    ) -> TextureId;
1137    fn new_render_texture(&mut self, params: TextureParams) -> TextureId {
1138        self.new_texture(TextureAccess::RenderTarget, TextureSource::Empty, params)
1139    }
1140    fn new_texture_from_data_and_format(
1141        &mut self,
1142        bytes: &[u8],
1143        params: TextureParams,
1144    ) -> TextureId {
1145        self.new_texture(TextureAccess::Static, TextureSource::Bytes(bytes), params)
1146    }
1147    fn new_texture_from_rgba8(&mut self, width: u16, height: u16, bytes: &[u8]) -> TextureId {
1148        assert_eq!(width as usize * height as usize * 4, bytes.len());
1149
1150        self.new_texture_from_data_and_format(
1151            bytes,
1152            TextureParams {
1153                kind: TextureKind::Texture2D,
1154                width: width as _,
1155                height: height as _,
1156                format: TextureFormat::RGBA8,
1157                wrap: TextureWrap::Clamp,
1158                min_filter: FilterMode::Linear,
1159                mag_filter: FilterMode::Linear,
1160                mipmap_filter: MipmapFilterMode::None,
1161                allocate_mipmaps: false,
1162                sample_count: 1,
1163            },
1164        )
1165    }
1166    fn texture_params(&self, texture: TextureId) -> TextureParams;
1167    fn texture_size(&self, texture: TextureId) -> (u32, u32) {
1168        let params = self.texture_params(texture);
1169        (params.width, params.height)
1170    }
1171
1172    /// Get OpenGL's GLuint texture ID or metals ObjcId
1173    unsafe fn texture_raw_id(&self, texture: TextureId) -> RawId;
1174
1175    /// Update whole texture content
1176    /// bytes should be width * height * 4 size - non rgba8 textures are not supported yet anyway
1177    fn texture_update(&mut self, texture: TextureId, bytes: &[u8]) {
1178        let (width, height) = self.texture_size(texture);
1179        self.texture_update_part(texture, 0 as _, 0 as _, width as _, height as _, bytes)
1180    }
1181    fn texture_set_filter(
1182        &mut self,
1183        texture: TextureId,
1184        filter: FilterMode,
1185        mipmap_filter: MipmapFilterMode,
1186    ) {
1187        self.texture_set_min_filter(texture, filter, mipmap_filter);
1188        self.texture_set_mag_filter(texture, filter);
1189    }
1190    fn texture_set_min_filter(
1191        &mut self,
1192        texture: TextureId,
1193        filter: FilterMode,
1194        mipmap_filter: MipmapFilterMode,
1195    );
1196    fn texture_set_mag_filter(&mut self, texture: TextureId, filter: FilterMode);
1197    fn texture_set_wrap(&mut self, texture: TextureId, wrap_x: TextureWrap, wrap_y: TextureWrap);
1198    /// Metal-specific note: if texture was created without `params.generate_mipmaps`
1199    /// `generate_mipmaps` will do nothing.
1200    ///
1201    /// Also note that if MipmapFilter is set to None, mipmaps will not be visible, even if
1202    /// generated.
1203    fn texture_generate_mipmaps(&mut self, texture: TextureId);
1204    fn texture_resize(&mut self, texture: TextureId, width: u32, height: u32, bytes: Option<&[u8]>);
1205    fn texture_read_pixels(&mut self, texture: TextureId, bytes: &mut [u8]);
1206    fn texture_update_part(
1207        &mut self,
1208        texture: TextureId,
1209        x_offset: i32,
1210        y_offset: i32,
1211        width: i32,
1212        height: i32,
1213        bytes: &[u8],
1214    );
1215    fn new_render_pass(
1216        &mut self,
1217        color_img: TextureId,
1218        depth_img: Option<TextureId>,
1219    ) -> RenderPass {
1220        self.new_render_pass_mrt(&[color_img], None, depth_img)
1221    }
1222    /// Same as "new_render_pass", but allows multiple color attachments.
1223    /// if `resolve_img` is set, MSAA-resolve operation will happen in `end_render_pass`
1224    /// this operation require `color_img` to have sample_count > 1,resolve_img have
1225    /// sample_count == 1, and color_img.len() should be equal to resolve_img.len()
1226    ///
1227    /// Note that resolve attachments may be not supported by current backend!
1228    /// They are only available when `ctx.info().features.resolve_attachments` is true.
1229    fn new_render_pass_mrt(
1230        &mut self,
1231        color_img: &[TextureId],
1232        resolve_img: Option<&[TextureId]>,
1233        depth_img: Option<TextureId>,
1234    ) -> RenderPass;
1235    /// panics for depth-only or multiple color attachment render pass
1236    /// This function is, mostly, legacy. Using "render_pass_color_attachments"
1237    /// is recommended instead.
1238    fn render_pass_texture(&self, render_pass: RenderPass) -> TextureId {
1239        let textures = self.render_pass_color_attachments(render_pass);
1240        #[allow(clippy::len_zero)]
1241        if textures.len() == 0 {
1242            panic!("depth-only render pass");
1243        }
1244        if textures.len() != 1 {
1245            panic!("multiple render target render pass");
1246        }
1247        textures[0]
1248    }
1249    /// For depth-only render pass returns empty slice.
1250    fn render_pass_color_attachments(&self, render_pass: RenderPass) -> &[TextureId];
1251    fn delete_render_pass(&mut self, render_pass: RenderPass);
1252    fn new_pipeline(
1253        &mut self,
1254        buffer_layout: &[BufferLayout],
1255        attributes: &[VertexAttribute],
1256        shader: ShaderId,
1257        params: PipelineParams,
1258    ) -> Pipeline;
1259    fn apply_pipeline(&mut self, pipeline: &Pipeline);
1260    fn delete_pipeline(&mut self, pipeline: Pipeline);
1261
1262    /// Create a buffer resource object.
1263    /// ```ignore
1264    /// #[repr(C)]
1265    /// struct Vertex {
1266    ///     pos: Vec2,
1267    ///     uv: Vec2,
1268    /// }
1269    /// let vertices: [Vertex; 4] = [
1270    ///     Vertex { pos : Vec2 { x: -0.5, y: -0.5 }, uv: Vec2 { x: 0., y: 0. } },
1271    ///     Vertex { pos : Vec2 { x:  0.5, y: -0.5 }, uv: Vec2 { x: 1., y: 0. } },
1272    ///     Vertex { pos : Vec2 { x:  0.5, y:  0.5 }, uv: Vec2 { x: 1., y: 1. } },
1273    ///     Vertex { pos : Vec2 { x: -0.5, y:  0.5 }, uv: Vec2 { x: 0., y: 1. } },
1274    /// ];
1275    ///    let buffer = ctx.new_buffer(
1276    ///        BufferType::VertexBuffer,
1277    ///        BufferUsage::Immutable,
1278    ///        BufferSource::slice(&vertices),
1279    ///    );
1280    /// ```
1281    fn new_buffer(&mut self, type_: BufferType, usage: BufferUsage, data: BufferSource)
1282        -> BufferId;
1283    fn buffer_update(&mut self, buffer: BufferId, data: BufferSource);
1284
1285    /// Size of buffer in bytes.
1286    /// For 1 element, u16 buffer this will return 2.
1287    fn buffer_size(&mut self, buffer: BufferId) -> usize;
1288
1289    /// Delete GPU buffer, leaving handle unmodified.
1290    ///
1291    /// More high-level code on top of miniquad probably is going to call this in Drop
1292    /// implementation of some more RAII buffer object.
1293    ///
1294    /// There is no protection against using deleted buffers later. However its not an UB in OpenGl
1295    /// and thats why this function is not marked as unsafe
1296    fn delete_buffer(&mut self, buffer: BufferId);
1297
1298    /// Delete GPU texture, leaving handle unmodified.
1299    ///
1300    /// More high-level code on top of miniquad probably is going to call this in Drop
1301    /// implementation of some more RAII buffer object.
1302    ///
1303    /// There is no protection against using deleted textures later. However its not a CPU-level UB
1304    /// and thats why this function is not marked as unsafe
1305    fn delete_texture(&mut self, texture: TextureId);
1306
1307    /// Delete GPU program, leaving handle unmodified.
1308    ///
1309    /// More high-level code on top of miniquad probably is going to call this in Drop
1310    /// implementation of some more RAII buffer object.
1311    ///
1312    /// There is no protection against using deleted programs later. However its not a CPU-level
1313    /// Porgram and thats why this function is not marked as unsafe
1314    fn delete_shader(&mut self, program: ShaderId);
1315
1316    /// Set a new viewport rectangle.
1317    /// Should be applied after begin_pass.
1318    fn apply_viewport(&mut self, x: i32, y: i32, w: i32, h: i32);
1319
1320    /// Set a new scissor rectangle.
1321    /// Should be applied after begin_pass.
1322    fn apply_scissor_rect(&mut self, x: i32, y: i32, w: i32, h: i32);
1323
1324    fn apply_bindings_from_slice(
1325        &mut self,
1326        vertex_buffers: &[BufferId],
1327        index_buffer: BufferId,
1328        textures: &[TextureId],
1329    );
1330
1331    fn apply_bindings(&mut self, bindings: &Bindings) {
1332        self.apply_bindings_from_slice(
1333            &bindings.vertex_buffers,
1334            bindings.index_buffer,
1335            &bindings.images,
1336        );
1337    }
1338
1339    fn apply_uniforms(&mut self, uniforms: UniformsSource) {
1340        self.apply_uniforms_from_bytes(uniforms.0.ptr as _, uniforms.0.size)
1341    }
1342    fn apply_uniforms_from_bytes(&mut self, uniform_ptr: *const u8, size: usize);
1343
1344    fn clear(
1345        &mut self,
1346        color: Option<(f32, f32, f32, f32)>,
1347        depth: Option<f32>,
1348        stencil: Option<i32>,
1349    );
1350    /// start rendering to the default frame buffer
1351    fn begin_default_pass(&mut self, action: PassAction);
1352    /// start rendering to an offscreen framebuffer
1353    fn begin_pass(&mut self, pass: Option<RenderPass>, action: PassAction);
1354
1355    fn end_render_pass(&mut self);
1356
1357    fn commit_frame(&mut self);
1358
1359    /// Draw elements using currently applied bindings and pipeline.
1360    ///
1361    /// + `base_element` specifies starting offset in `index_buffer`.
1362    /// + `num_elements` specifies length of the slice of `index_buffer` to draw.
1363    /// + `num_instances` specifies how many instances should be rendered.
1364    ///
1365    /// NOTE: num_instances > 1 might be not supported by the GPU (gl2.1 and gles2).
1366    /// `features.instancing` check is required.
1367    fn draw(&self, base_element: i32, num_elements: i32, num_instances: i32);
1368}