Skip to main content

azul_core/
gl.rs

1//! OpenGL context wrappers, texture cache management, shader compilation,
2//! vertex buffer abstractions, and FFI-safe GL type aliases for the C/Python API.
3
4#![allow(unused_variables)]
5use alloc::{
6    boxed::Box,
7    rc::Rc,
8    string::{String, ToString},
9    vec::Vec,
10};
11use core::{
12    ffi, fmt,
13    hash::{Hash, Hasher},
14    sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
15};
16
17use azul_css::{
18    props::{
19        basic::{ColorF, ColorU},
20        style::StyleTransformVec,
21    },
22    AzString, OptionI32, OptionU32, OptionUsize, StringVec, U8Vec,
23};
24pub use gl_context_loader::{
25    ctypes::*, gl, GLeglImageOES, GLsync, GLvoid, GenericGlContext, GlType as GlContextGlType,
26};
27
28pub use crate::glconst::*;
29use crate::{
30    geom::PhysicalSizeU32,
31    hit_test::DocumentId,
32    resources::{Epoch, ExternalImageId, ImageDescriptor, ImageDescriptorFlags, RawImageFormat},
33    svg::{TessellatedGPUSvgNode, TessellatedSvgNode},
34    window::RendererType,
35    OrderedMap,
36};
37
38pub type GLuint = u32;
39pub type GLint = i32;
40pub type GLint64 = i64;
41pub type GLuint64 = u64;
42pub type GLenum = u32;
43pub type GLintptr = isize;
44pub type GLboolean = u8;
45pub type GLsizeiptr = isize;
46pub type GLbitfield = u32;
47pub type GLsizei = i32;
48pub type GLclampf = f32;
49pub type GLfloat = f32;
50
51pub const GL_RESTART_INDEX: u32 = core::u32::MAX;
52
53/// Passing *const c_void is not easily possible when generating APIs,
54/// so this wrapper struct is for easier API generation
55#[repr(C)]
56#[derive(Debug)]
57pub struct GlVoidPtrConst {
58    pub ptr: *const GLvoid,
59    pub run_destructor: bool,
60}
61
62impl Clone for GlVoidPtrConst {
63    fn clone(&self) -> Self {
64        Self {
65            ptr: self.ptr,
66            run_destructor: true,
67        }
68    }
69}
70
71impl Drop for GlVoidPtrConst {
72    fn drop(&mut self) {
73        self.run_destructor = false;
74    }
75}
76
77/// Struct returned from the C API
78///
79/// Because of Python, every object has to be clone-able,
80/// so yes there may exist more than one mutable reference
81#[repr(C)]
82#[derive(Debug)]
83pub struct GlVoidPtrMut {
84    pub ptr: *mut GLvoid,
85}
86
87impl Clone for GlVoidPtrMut {
88    fn clone(&self) -> Self {
89        Self { ptr: self.ptr }
90    }
91}
92
93/// FFI-safe wrapper for `&str`.
94#[repr(C)]
95pub struct Refstr {
96    pub ptr: *const u8,
97    pub len: usize,
98}
99
100impl Clone for Refstr {
101    fn clone(&self) -> Self {
102        Self {
103            ptr: self.ptr,
104            len: self.len,
105        }
106    }
107}
108
109impl core::fmt::Debug for Refstr {
110    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
111        self.as_str().fmt(f)
112    }
113}
114
115impl Refstr {
116    pub fn as_str(&self) -> &str {
117        unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(self.ptr, self.len)) }
118    }
119}
120
121impl From<&str> for Refstr {
122    fn from(s: &str) -> Self {
123        Self {
124            ptr: s.as_ptr(),
125            len: s.len(),
126        }
127    }
128}
129
130/// FFI-safe wrapper for `&[&str]`.
131#[repr(C)]
132pub struct RefstrVecRef {
133    pub ptr: *const Refstr,
134    pub len: usize,
135}
136
137impl Clone for RefstrVecRef {
138    fn clone(&self) -> Self {
139        Self {
140            ptr: self.ptr,
141            len: self.len,
142        }
143    }
144}
145
146impl core::fmt::Debug for RefstrVecRef {
147    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
148        self.as_slice().fmt(f)
149    }
150}
151
152impl RefstrVecRef {
153    pub fn as_slice(&self) -> &[Refstr] {
154        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
155    }
156}
157
158impl From<&[Refstr]> for RefstrVecRef {
159    fn from(s: &[Refstr]) -> Self {
160        Self {
161            ptr: s.as_ptr(),
162            len: s.len(),
163        }
164    }
165}
166
167/// FFI-safe wrapper for `&mut [GLint64]`.
168#[repr(C)]
169pub struct GLint64VecRefMut {
170    pub ptr: *mut i64,
171    pub len: usize,
172}
173
174impl Clone for GLint64VecRefMut {
175    fn clone(&self) -> Self {
176        Self {
177            ptr: self.ptr,
178            len: self.len,
179        }
180    }
181}
182
183impl core::fmt::Debug for GLint64VecRefMut {
184    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
185        self.as_slice().fmt(f)
186    }
187}
188
189impl From<&mut [GLint64]> for GLint64VecRefMut {
190    fn from(s: &mut [GLint64]) -> Self {
191        Self {
192            ptr: s.as_mut_ptr(),
193            len: s.len(),
194        }
195    }
196}
197
198impl GLint64VecRefMut {
199    pub fn as_slice(&self) -> &[GLint64] {
200        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
201    }
202    fn as_mut_slice(&mut self) -> &mut [GLint64] {
203        unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
204    }
205}
206
207/// FFI-safe wrapper for `&mut [GLfloat]`.
208#[repr(C)]
209pub struct GLfloatVecRefMut {
210    pub ptr: *mut f32,
211    pub len: usize,
212}
213
214impl Clone for GLfloatVecRefMut {
215    fn clone(&self) -> Self {
216        Self {
217            ptr: self.ptr,
218            len: self.len,
219        }
220    }
221}
222
223impl core::fmt::Debug for GLfloatVecRefMut {
224    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
225        self.as_slice().fmt(f)
226    }
227}
228
229impl From<&mut [GLfloat]> for GLfloatVecRefMut {
230    fn from(s: &mut [GLfloat]) -> Self {
231        Self {
232            ptr: s.as_mut_ptr(),
233            len: s.len(),
234        }
235    }
236}
237
238impl GLfloatVecRefMut {
239    pub fn as_slice(&self) -> &[GLfloat] {
240        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
241    }
242    fn as_mut_slice(&mut self) -> &mut [GLfloat] {
243        unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
244    }
245}
246
247/// FFI-safe wrapper for `&mut [GLint]`.
248#[repr(C)]
249pub struct GLintVecRefMut {
250    pub ptr: *mut i32,
251    pub len: usize,
252}
253
254impl Clone for GLintVecRefMut {
255    fn clone(&self) -> Self {
256        Self {
257            ptr: self.ptr,
258            len: self.len,
259        }
260    }
261}
262
263impl core::fmt::Debug for GLintVecRefMut {
264    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
265        self.as_slice().fmt(f)
266    }
267}
268
269impl From<&mut [GLint]> for GLintVecRefMut {
270    fn from(s: &mut [GLint]) -> Self {
271        Self {
272            ptr: s.as_mut_ptr(),
273            len: s.len(),
274        }
275    }
276}
277
278impl GLintVecRefMut {
279    pub fn as_slice(&self) -> &[GLint] {
280        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
281    }
282    fn as_mut_slice(&mut self) -> &mut [GLint] {
283        unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
284    }
285}
286
287/// FFI-safe wrapper for `&[GLuint]`.
288#[repr(C)]
289pub struct GLuintVecRef {
290    pub ptr: *const u32,
291    pub len: usize,
292}
293
294impl Clone for GLuintVecRef {
295    fn clone(&self) -> Self {
296        Self {
297            ptr: self.ptr,
298            len: self.len,
299        }
300    }
301}
302
303impl core::fmt::Debug for GLuintVecRef {
304    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
305        self.as_slice().fmt(f)
306    }
307}
308
309impl From<&[GLuint]> for GLuintVecRef {
310    fn from(s: &[GLuint]) -> Self {
311        Self {
312            ptr: s.as_ptr(),
313            len: s.len(),
314        }
315    }
316}
317
318impl GLuintVecRef {
319    pub fn as_slice(&self) -> &[GLuint] {
320        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
321    }
322}
323
324/// FFI-safe wrapper for `&[GLenum]`.
325#[repr(C)]
326pub struct GLenumVecRef {
327    pub ptr: *const u32,
328    pub len: usize,
329}
330
331impl Clone for GLenumVecRef {
332    fn clone(&self) -> Self {
333        Self {
334            ptr: self.ptr,
335            len: self.len,
336        }
337    }
338}
339
340impl core::fmt::Debug for GLenumVecRef {
341    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
342        self.as_slice().fmt(f)
343    }
344}
345
346impl From<&[GLenum]> for GLenumVecRef {
347    fn from(s: &[GLenum]) -> Self {
348        Self {
349            ptr: s.as_ptr(),
350            len: s.len(),
351        }
352    }
353}
354
355impl GLenumVecRef {
356    pub fn as_slice(&self) -> &[GLenum] {
357        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
358    }
359}
360
361/// FFI-safe wrapper for `&[u8]`.
362#[repr(C)]
363pub struct U8VecRef {
364    pub ptr: *const u8,
365    pub len: usize,
366}
367
368impl Clone for U8VecRef {
369    fn clone(&self) -> Self {
370        Self {
371            ptr: self.ptr,
372            len: self.len,
373        }
374    }
375}
376
377impl From<&[u8]> for U8VecRef {
378    fn from(s: &[u8]) -> Self {
379        Self {
380            ptr: s.as_ptr(),
381            len: s.len(),
382        }
383    }
384}
385
386impl U8VecRef {
387    pub fn as_slice(&self) -> &[u8] {
388        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
389    }
390}
391
392impl fmt::Debug for U8VecRef {
393    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394        self.as_slice().fmt(f)
395    }
396}
397
398impl PartialOrd for U8VecRef {
399    fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
400        self.as_slice().partial_cmp(rhs.as_slice())
401    }
402}
403
404impl Ord for U8VecRef {
405    fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
406        self.as_slice().cmp(rhs.as_slice())
407    }
408}
409
410impl PartialEq for U8VecRef {
411    fn eq(&self, rhs: &Self) -> bool {
412        self.as_slice().eq(rhs.as_slice())
413    }
414}
415
416impl Eq for U8VecRef {}
417
418impl core::hash::Hash for U8VecRef {
419    fn hash<H>(&self, state: &mut H)
420    where
421        H: core::hash::Hasher,
422    {
423        self.as_slice().hash(state)
424    }
425}
426
427/// FFI-safe wrapper for `&[f32]`.
428#[repr(C)]
429pub struct F32VecRef {
430    pub ptr: *const f32,
431    pub len: usize,
432}
433
434impl Clone for F32VecRef {
435    fn clone(&self) -> Self {
436        Self {
437            ptr: self.ptr,
438            len: self.len,
439        }
440    }
441}
442
443impl core::fmt::Debug for F32VecRef {
444    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
445        self.as_slice().fmt(f)
446    }
447}
448
449impl From<&[f32]> for F32VecRef {
450    fn from(s: &[f32]) -> Self {
451        Self {
452            ptr: s.as_ptr(),
453            len: s.len(),
454        }
455    }
456}
457
458impl F32VecRef {
459    pub fn as_slice(&self) -> &[f32] {
460        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
461    }
462}
463
464/// FFI-safe wrapper for `&[i32]`.
465#[repr(C)]
466pub struct I32VecRef {
467    pub ptr: *const i32,
468    pub len: usize,
469}
470
471impl Clone for I32VecRef {
472    fn clone(&self) -> Self {
473        Self {
474            ptr: self.ptr,
475            len: self.len,
476        }
477    }
478}
479
480impl core::fmt::Debug for I32VecRef {
481    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
482        self.as_slice().fmt(f)
483    }
484}
485
486impl From<&[i32]> for I32VecRef {
487    fn from(s: &[i32]) -> Self {
488        Self {
489            ptr: s.as_ptr(),
490            len: s.len(),
491        }
492    }
493}
494
495impl I32VecRef {
496    pub fn as_slice(&self) -> &[i32] {
497        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
498    }
499}
500
501/// FFI-safe wrapper for `&mut [GLboolean]` (i.e. `&mut [u8]`).
502#[repr(C)]
503pub struct GLbooleanVecRefMut {
504    pub ptr: *mut u8,
505    pub len: usize,
506}
507
508impl Clone for GLbooleanVecRefMut {
509    fn clone(&self) -> Self {
510        Self {
511            ptr: self.ptr,
512            len: self.len,
513        }
514    }
515}
516
517impl core::fmt::Debug for GLbooleanVecRefMut {
518    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
519        self.as_slice().fmt(f)
520    }
521}
522
523impl From<&mut [GLboolean]> for GLbooleanVecRefMut {
524    fn from(s: &mut [GLboolean]) -> Self {
525        Self {
526            ptr: s.as_mut_ptr(),
527            len: s.len(),
528        }
529    }
530}
531
532impl GLbooleanVecRefMut {
533    pub fn as_slice(&self) -> &[GLboolean] {
534        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
535    }
536    fn as_mut_slice(&mut self) -> &mut [GLboolean] {
537        unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
538    }
539}
540
541/// FFI-safe wrapper for `&mut [u8]`.
542#[repr(C)]
543pub struct U8VecRefMut {
544    pub ptr: *mut u8,
545    pub len: usize,
546}
547
548impl Clone for U8VecRefMut {
549    fn clone(&self) -> Self {
550        Self {
551            ptr: self.ptr,
552            len: self.len,
553        }
554    }
555}
556
557impl core::fmt::Debug for U8VecRefMut {
558    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
559        self.as_slice().fmt(f)
560    }
561}
562
563impl From<&mut [u8]> for U8VecRefMut {
564    fn from(s: &mut [u8]) -> Self {
565        Self {
566            ptr: s.as_mut_ptr(),
567            len: s.len(),
568        }
569    }
570}
571
572impl U8VecRefMut {
573    pub fn as_slice(&self) -> &[u8] {
574        unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
575    }
576    fn as_mut_slice(&mut self) -> &mut [u8] {
577        unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
578    }
579}
580
581impl_option!(
582    U8VecRef,
583    OptionU8VecRef,
584    copy = false,
585    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
586);
587
588#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
589#[repr(C)]
590pub struct DebugMessage {
591    pub message: AzString,
592    pub source: GLenum,
593    pub ty: GLenum,
594    pub id: GLenum,
595    pub severity: GLenum,
596}
597
598impl_option!(
599    DebugMessage,
600    OptionDebugMessage,
601    copy = false,
602    [Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash]
603);
604
605impl_vec!(DebugMessage, DebugMessageVec, DebugMessageVecDestructor, DebugMessageVecDestructorType, DebugMessageVecSlice, OptionDebugMessage);
606impl_vec_debug!(DebugMessage, DebugMessageVec);
607impl_vec_partialord!(DebugMessage, DebugMessageVec);
608impl_vec_ord!(DebugMessage, DebugMessageVec);
609impl_vec_clone!(DebugMessage, DebugMessageVec, DebugMessageVecDestructor);
610impl_vec_partialeq!(DebugMessage, DebugMessageVec);
611impl_vec_eq!(DebugMessage, DebugMessageVec);
612impl_vec_hash!(DebugMessage, DebugMessageVec);
613
614impl_vec!(GLint, GLintVec, GLintVecDestructor, GLintVecDestructorType, GLintVecSlice, OptionI32);
615impl_vec_debug!(GLint, GLintVec);
616impl_vec_partialord!(GLint, GLintVec);
617impl_vec_ord!(GLint, GLintVec);
618impl_vec_clone!(GLint, GLintVec, GLintVecDestructor);
619impl_vec_partialeq!(GLint, GLintVec);
620impl_vec_eq!(GLint, GLintVec);
621impl_vec_hash!(GLint, GLintVec);
622
623impl_vec!(GLuint, GLuintVec, GLuintVecDestructor, GLuintVecDestructorType, GLuintVecSlice, OptionU32);
624impl_vec_debug!(GLuint, GLuintVec);
625impl_vec_partialord!(GLuint, GLuintVec);
626impl_vec_ord!(GLuint, GLuintVec);
627impl_vec_clone!(GLuint, GLuintVec, GLuintVecDestructor);
628impl_vec_partialeq!(GLuint, GLuintVec);
629impl_vec_eq!(GLuint, GLuintVec);
630impl_vec_hash!(GLuint, GLuintVec);
631
632#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
633#[repr(C)]
634pub enum GlType {
635    Gl,
636    Gles,
637}
638
639impl From<GlContextGlType> for GlType {
640    fn from(a: GlContextGlType) -> GlType {
641        match a {
642            GlContextGlType::Gl => GlType::Gl,
643            GlContextGlType::GlEs => GlType::Gles,
644        }
645    }
646}
647
648// (U8Vec, u32)
649#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
650#[repr(C)]
651pub struct GetProgramBinaryReturn {
652    pub _0: U8Vec,
653    pub _1: u32,
654}
655
656// (i32, u32, AzString)
657#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
658#[repr(C)]
659pub struct GetActiveAttribReturn {
660    pub _0: i32,
661    pub _1: u32,
662    pub _2: AzString,
663}
664
665// (i32, u32, AzString)
666#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
667#[repr(C)]
668pub struct GetActiveUniformReturn {
669    pub _0: i32,
670    pub _1: u32,
671    pub _2: AzString,
672}
673
674#[repr(C)]
675pub struct GLsyncPtr {
676    pub ptr: *const c_void, /* *const __GLsync */
677    pub run_destructor: bool,
678}
679
680impl Clone for GLsyncPtr {
681    fn clone(&self) -> Self {
682        Self {
683            ptr: self.ptr,
684            run_destructor: true,
685        }
686    }
687}
688
689impl core::fmt::Debug for GLsyncPtr {
690    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
691        write!(f, "0x{:0x}", self.ptr as usize)
692    }
693}
694
695impl GLsyncPtr {
696    pub fn new(p: GLsync) -> Self {
697        Self {
698            ptr: p as *const c_void,
699            run_destructor: true,
700        }
701    }
702    pub fn get(self) -> GLsync {
703        self.ptr as GLsync
704    }
705}
706
707impl Drop for GLsyncPtr {
708    fn drop(&mut self) {
709        self.run_destructor = false;
710    }
711}
712
713/// Each pipeline (window) has its own OpenGL textures. GL Textures can technically
714/// be shared across pipelines, however this turns out to be very difficult in practice.
715pub type GlTextureStorage = OrderedMap<Epoch, OrderedMap<ExternalImageId, Texture>>;
716
717/// Non-cleaned up textures. When a GlTexture is registered, it has to stay active as long
718/// as WebRender needs it for drawing. To transparently do this, we store the epoch that the
719/// texture was originally created with, and check, **after we have drawn the frame**,
720/// if there are any textures that need cleanup.
721///
722/// Because the Texture2d is wrapped in an Rc, the destructor (which cleans up the OpenGL
723/// texture) does not run until we remove the textures
724///
725/// Note: Because textures could be used after the current draw call (ex. for scrolling),
726/// the ACTIVE_GL_TEXTURES are indexed by their epoch. Use `renderer.flush_pipeline_info()`
727/// to see which textures are still active and which ones can be safely removed.
728///
729/// See: https://github.com/servo/webrender/issues/2940
730///
731/// WARNING: Not thread-safe (however, the Texture itself is thread-unsafe, so it's unlikely to ever
732/// be misused)
733static mut ACTIVE_GL_TEXTURES: Option<OrderedMap<DocumentId, GlTextureStorage>> = None;
734
735/// Inserts a new texture into the OpenGL texture cache, returns a new image ID
736/// for the inserted texture
737///
738/// This function exists so azul doesn't have to use `lazy_static` as a dependency
739pub fn insert_into_active_gl_textures(
740    document_id: DocumentId,
741    epoch: Epoch,
742    texture: Texture,
743) -> ExternalImageId {
744    let external_image_id = ExternalImageId::new();
745
746    unsafe {
747        if ACTIVE_GL_TEXTURES.is_none() {
748            ACTIVE_GL_TEXTURES = Some(OrderedMap::new());
749        }
750        let active_textures = ACTIVE_GL_TEXTURES.as_mut().unwrap();
751        let active_epochs = active_textures
752            .entry(document_id)
753            .or_insert_with(|| OrderedMap::new());
754        let active_textures_for_epoch = active_epochs
755            .entry(epoch)
756            .or_insert_with(|| OrderedMap::new());
757        active_textures_for_epoch.insert(external_image_id, texture);
758    }
759
760    external_image_id
761}
762
763/// Destroys all textures from the given `document_id`
764/// where the texture is **older** than the given `epoch`.
765pub fn gl_textures_remove_epochs_from_pipeline(document_id: &DocumentId, epoch: Epoch) {
766    // TODO: Handle overflow of Epochs correctly (low priority)
767    unsafe {
768        let active_textures = match ACTIVE_GL_TEXTURES.as_mut() {
769            Some(s) => s,
770            None => return,
771        };
772
773        let active_epochs = match active_textures.get_mut(document_id) {
774            Some(s) => s,
775            None => return,
776        };
777
778        // NOTE: original code used retain() but that
779        // doesn't work on no_std
780        let mut epochs_to_remove = Vec::new();
781
782        for (gl_texture_epoch, _) in active_epochs.iter() {
783            if *gl_texture_epoch < epoch {
784                epochs_to_remove.push(*gl_texture_epoch);
785            }
786        }
787
788        for epoch in epochs_to_remove {
789            active_epochs.remove(&epoch);
790        }
791    }
792}
793
794// document_id, epoch, external_image_id
795pub fn remove_single_texture_from_active_gl_textures(
796    document_id: &DocumentId,
797    epoch: &Epoch,
798    external_image_id: &ExternalImageId,
799) -> Option<()> {
800    let mut active_textures = unsafe { ACTIVE_GL_TEXTURES.as_mut()? };
801    let mut epochs = active_textures.get_mut(document_id)?;
802    let mut images_in_epoch = epochs.get_mut(epoch)?;
803    images_in_epoch.remove(external_image_id);
804    Some(())
805}
806
807/// Removes a DocumentId from the active epochs
808pub fn gl_textures_remove_active_pipeline(document_id: &DocumentId) {
809    unsafe {
810        let active_textures = match ACTIVE_GL_TEXTURES.as_mut() {
811            Some(s) => s,
812            None => return,
813        };
814        active_textures.remove(document_id);
815    }
816}
817
818/// Destroys all textures, usually done before destroying the OpenGL context
819pub fn gl_textures_clear_opengl_cache() {
820    unsafe {
821        ACTIVE_GL_TEXTURES = None;
822    }
823}
824
825// Search all epoch hash maps for the given key
826// There does not seem to be a way to get the epoch for the key,
827// so we simply have to search all active epochs
828//
829// NOTE: Invalid textures can be generated on minimize / maximize
830// Luckily, webrender simply ignores an invalid texture, so we don't
831// need to check whether a window is maximized or minimized - if
832// we encounter an invalid ID, webrender simply won't draw anything,
833// but at least it won't crash. Usually invalid textures are also 0x0
834// pixels large - so it's not like we had anything to draw anyway.
835pub fn get_opengl_texture(image_key: &ExternalImageId) -> Option<(GLuint, (f32, f32))> {
836    let active_textures = unsafe { ACTIVE_GL_TEXTURES.as_ref()? };
837    active_textures
838        .values()
839        .flat_map(|active_document| active_document.values())
840        .find_map(|active_epoch| active_epoch.get(image_key))
841        .map(|tex| {
842            (
843                tex.texture_id,
844                (tex.size.width as f32, tex.size.height as f32),
845            )
846        })
847}
848
849/// For .get_gl_precision_format(), but ABI-safe - returning an array or a tuple is not ABI-safe
850#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
851#[repr(C)]
852pub struct GlShaderPrecisionFormatReturn {
853    pub _0: GLint,
854    pub _1: GLint,
855    pub _2: GLint,
856}
857
858#[repr(C)]
859pub struct GlContextPtr {
860    pub ptr: Box<Rc<GlContextPtrInner>>,
861    /// Whether to force a hardware or software renderer
862    pub renderer_type: RendererType,
863    pub run_destructor: bool,
864}
865
866impl Clone for GlContextPtr {
867    fn clone(&self) -> Self {
868        Self {
869            ptr: self.ptr.clone(),
870            renderer_type: self.renderer_type.clone(),
871            run_destructor: true,
872        }
873    }
874}
875
876impl Drop for GlContextPtr {
877    fn drop(&mut self) {
878        self.run_destructor = false;
879    }
880}
881
882impl GlContextPtr {
883    pub fn get_svg_shader(&self) -> GLuint {
884        self.ptr.svg_shader
885    }
886    pub fn get_fxaa_shader(&self) -> GLuint {
887        self.ptr.fxaa_shader
888    }
889}
890
891#[repr(C)]
892pub struct GlContextPtrInner {
893    pub ptr: Rc<GenericGlContext>,
894    /// SVG shader program (library-internal use)
895    pub svg_shader: GLuint,
896    /// SVG multicolor shader program (library-internal use)
897    pub svg_multicolor_shader: GLuint,
898    /// FXAA shader program (library-internal use)
899    pub fxaa_shader: GLuint,
900}
901
902impl Drop for GlContextPtrInner {
903    fn drop(&mut self) {
904        self.ptr.delete_program(self.svg_shader);
905        self.ptr.delete_program(self.svg_multicolor_shader);
906        self.ptr.delete_program(self.fxaa_shader);
907    }
908}
909
910impl_option!(
911    GlContextPtr,
912    OptionGlContextPtr,
913    copy = false,
914    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord]
915);
916
917impl core::fmt::Debug for GlContextPtr {
918    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
919        write!(f, "0x{:0x}", self.as_usize())
920    }
921}
922
923static SVG_VERTEX_SHADER: &[u8] = b"#version 150
924
925#if __VERSION__ != 100
926    #define varying out
927    #define attribute in
928#endif
929
930uniform vec2 vBboxSize;
931uniform mat4 vTransformMatrix;
932
933attribute vec2 vAttrXY;
934
935void main() {
936    vec4 vTransposed = vec4(vAttrXY, 1.0, 1.0) * vTransformMatrix;
937    vec2 vTransposedInScreen = vTransposed.xy / vBboxSize;
938    vec2 vCalcFinal = (vTransposedInScreen * vec2(2.0)) - vec2(1.0);
939    gl_Position = vec4(vCalcFinal, 1.0, 1.0);
940}";
941
942static SVG_FRAGMENT_SHADER: &[u8] = b"#version 150
943
944precision highp float;
945
946uniform vec4 fDrawColor;
947
948#if __VERSION__ == 100
949    #define oFragColor gl_FragColor
950#else
951    out vec4 oFragColor;
952#endif
953
954void main() {
955    oFragColor = fDrawColor;
956}";
957
958static SVG_MULTICOLOR_VERTEX_SHADER: &[u8] = b"#version 150
959
960#if __VERSION__ != 100
961    #define varying out
962    #define attribute in
963#endif
964
965uniform vec2 vBboxSize;
966uniform mat4 vTransformMatrix;
967
968attribute vec3 vAttrXY;
969attribute vec4 vColor;
970varying vec4 fColor;
971
972void main() {
973    vec4 vTransposed = vec4(vAttrXY.xy, 1.0, 1.0) * vTransformMatrix;
974    vec2 vTransposedInScreen = vTransposed.xy / vBboxSize;
975    vec2 vCalcFinal = (vTransposedInScreen * vec2(2.0)) - vec2(1.0);
976    gl_Position = vec4(vCalcFinal, vAttrXY.z, 1.0);
977    fColor = vColor;
978}";
979
980static SVG_MULTICOLOR_FRAGMENT_SHADER: &[u8] = b"#version 150
981
982precision highp float;
983
984#if __VERSION__ != 100
985    #define varying in
986#endif
987
988#if __VERSION__ == 100
989    #define oFragColor gl_FragColor
990#else
991    out vec4 oFragColor;
992#endif
993
994varying vec4 fColor;
995
996void main() {
997    oFragColor = fColor;
998}";
999
1000/// Checks if a shader compiled successfully. Logs an error under `std`.
1001fn check_shader_compile(gl_context: &GenericGlContext, shader: GLuint, _label: &str) {
1002    let mut status = [0_i32];
1003    unsafe { gl_context.get_shader_iv(shader, gl::COMPILE_STATUS, &mut status) };
1004    if status[0] != gl::TRUE as i32 {
1005        #[cfg(feature = "std")]
1006        {
1007            let log = gl_context.get_shader_info_log(shader);
1008            eprintln!("azul: {} shader compile error: {}", _label, log);
1009        }
1010    }
1011}
1012
1013/// Checks if a program linked successfully. Logs an error under `std`.
1014fn check_program_link(gl_context: &GenericGlContext, program: GLuint, _label: &str) {
1015    let mut status = [0_i32];
1016    unsafe { gl_context.get_program_iv(program, gl::LINK_STATUS, &mut status) };
1017    if status[0] != gl::TRUE as i32 {
1018        #[cfg(feature = "std")]
1019        {
1020            let log = gl_context.get_program_info_log(program);
1021            eprintln!("azul: {} program link error: {}", _label, log);
1022        }
1023    }
1024}
1025
1026impl GlContextPtr {
1027    pub fn new(renderer_type: RendererType, gl_context: Rc<GenericGlContext>) -> Self {
1028        // Compile basic shader
1029        let vertex_shader_object = gl_context.create_shader(gl::VERTEX_SHADER);
1030        gl_context.shader_source(vertex_shader_object, &[SVG_VERTEX_SHADER]);
1031        gl_context.compile_shader(vertex_shader_object);
1032        check_shader_compile(&gl_context, vertex_shader_object, "SVG vertex");
1033
1034        let fragment_shader_object = gl_context.create_shader(gl::FRAGMENT_SHADER);
1035        gl_context.shader_source(fragment_shader_object, &[SVG_FRAGMENT_SHADER]);
1036        gl_context.compile_shader(fragment_shader_object);
1037        check_shader_compile(&gl_context, fragment_shader_object, "SVG fragment");
1038
1039        let svg_program_id = gl_context.create_program();
1040
1041        gl_context.attach_shader(svg_program_id, vertex_shader_object);
1042        gl_context.attach_shader(svg_program_id, fragment_shader_object);
1043        gl_context.bind_attrib_location(svg_program_id, 0, "vAttrXY".into());
1044        gl_context.link_program(svg_program_id);
1045        check_program_link(&gl_context, svg_program_id, "SVG");
1046
1047        gl_context.delete_shader(vertex_shader_object);
1048        gl_context.delete_shader(fragment_shader_object);
1049
1050        // Compile multi-color SVG shader
1051        let vertex_shader_object = gl_context.create_shader(gl::VERTEX_SHADER);
1052        gl_context.shader_source(vertex_shader_object, &[SVG_MULTICOLOR_VERTEX_SHADER]);
1053        gl_context.compile_shader(vertex_shader_object);
1054        check_shader_compile(&gl_context, vertex_shader_object, "SVG multicolor vertex");
1055
1056        let fragment_shader_object = gl_context.create_shader(gl::FRAGMENT_SHADER);
1057        gl_context.shader_source(fragment_shader_object, &[SVG_MULTICOLOR_FRAGMENT_SHADER]);
1058        gl_context.compile_shader(fragment_shader_object);
1059        check_shader_compile(&gl_context, fragment_shader_object, "SVG multicolor fragment");
1060
1061        let svg_multicolor_program_id = gl_context.create_program();
1062
1063        gl_context.attach_shader(svg_multicolor_program_id, vertex_shader_object);
1064        gl_context.attach_shader(svg_multicolor_program_id, fragment_shader_object);
1065        gl_context.bind_attrib_location(svg_multicolor_program_id, 0, "vAttrXY".into());
1066        gl_context.bind_attrib_location(svg_multicolor_program_id, 1, "vColor".into());
1067        gl_context.link_program(svg_multicolor_program_id);
1068        check_program_link(&gl_context, svg_multicolor_program_id, "SVG multicolor");
1069
1070        gl_context.delete_shader(vertex_shader_object);
1071        gl_context.delete_shader(fragment_shader_object);
1072
1073        // Compile FXAA shader
1074        use crate::gl_fxaa::{FXAA_FRAGMENT_SHADER, FXAA_VERTEX_SHADER};
1075
1076        let vertex_shader_object = gl_context.create_shader(gl::VERTEX_SHADER);
1077        gl_context.shader_source(vertex_shader_object, &[FXAA_VERTEX_SHADER]);
1078        gl_context.compile_shader(vertex_shader_object);
1079        check_shader_compile(&gl_context, vertex_shader_object, "FXAA vertex");
1080
1081        let fragment_shader_object = gl_context.create_shader(gl::FRAGMENT_SHADER);
1082        gl_context.shader_source(fragment_shader_object, &[FXAA_FRAGMENT_SHADER]);
1083        gl_context.compile_shader(fragment_shader_object);
1084        check_shader_compile(&gl_context, fragment_shader_object, "FXAA fragment");
1085
1086        let fxaa_program_id = gl_context.create_program();
1087
1088        gl_context.attach_shader(fxaa_program_id, vertex_shader_object);
1089        gl_context.attach_shader(fxaa_program_id, fragment_shader_object);
1090        gl_context.bind_attrib_location(fxaa_program_id, 0, "vAttrXY".into());
1091        gl_context.link_program(fxaa_program_id);
1092        check_program_link(&gl_context, fxaa_program_id, "FXAA");
1093
1094        gl_context.delete_shader(vertex_shader_object);
1095        gl_context.delete_shader(fragment_shader_object);
1096
1097        Self {
1098            ptr: Box::new(Rc::new(GlContextPtrInner {
1099                svg_shader: svg_program_id,
1100                svg_multicolor_shader: svg_multicolor_program_id,
1101                fxaa_shader: fxaa_program_id,
1102                ptr: gl_context,
1103            })),
1104            renderer_type,
1105            run_destructor: true,
1106        }
1107    }
1108
1109    pub fn get<'a>(&'a self) -> &'a Rc<GenericGlContext> {
1110        &self.ptr.ptr
1111    }
1112    fn as_usize(&self) -> usize {
1113        (Rc::as_ptr(&self.ptr.ptr) as *const c_void) as usize
1114    }
1115}
1116
1117impl GlContextPtr {
1118    pub fn get_type(&self) -> GlType {
1119        self.get().get_type().into()
1120    }
1121    pub fn buffer_data_untyped(
1122        &self,
1123        target: GLenum,
1124        size: GLsizeiptr,
1125        data: GlVoidPtrConst,
1126        usage: GLenum,
1127    ) {
1128        self.get()
1129            .buffer_data_untyped(target, size, data.ptr, usage)
1130    }
1131    pub fn buffer_sub_data_untyped(
1132        &self,
1133        target: GLenum,
1134        offset: isize,
1135        size: GLsizeiptr,
1136        data: GlVoidPtrConst,
1137    ) {
1138        self.get()
1139            .buffer_sub_data_untyped(target, offset, size, data.ptr)
1140    }
1141    pub fn map_buffer(&self, target: GLenum, access: GLbitfield) -> GlVoidPtrMut {
1142        GlVoidPtrMut {
1143            ptr: self.get().map_buffer(target, access),
1144        }
1145    }
1146    pub fn map_buffer_range(
1147        &self,
1148        target: GLenum,
1149        offset: GLintptr,
1150        length: GLsizeiptr,
1151        access: GLbitfield,
1152    ) -> GlVoidPtrMut {
1153        GlVoidPtrMut {
1154            ptr: self.get().map_buffer_range(target, offset, length, access),
1155        }
1156    }
1157    pub fn unmap_buffer(&self, target: GLenum) -> GLboolean {
1158        self.get().unmap_buffer(target)
1159    }
1160    pub fn tex_buffer(&self, target: GLenum, internal_format: GLenum, buffer: GLuint) {
1161        self.get().tex_buffer(target, internal_format, buffer)
1162    }
1163    pub fn shader_source(&self, shader: GLuint, strings: StringVec) {
1164        fn str_to_bytes(input: &str) -> Vec<u8> {
1165            let mut v: Vec<u8> = input.into();
1166            v.push(0);
1167            v
1168        }
1169        let shaders_as_bytes = strings
1170            .iter()
1171            .map(|s| str_to_bytes(s.as_str()))
1172            .collect::<Vec<_>>();
1173        let shaders_as_bytes = shaders_as_bytes
1174            .iter()
1175            .map(|s| s.as_ref())
1176            .collect::<Vec<_>>();
1177        self.get().shader_source(shader, &shaders_as_bytes)
1178    }
1179    pub fn read_buffer(&self, mode: GLenum) {
1180        self.get().read_buffer(mode)
1181    }
1182    pub fn read_pixels_into_buffer(
1183        &self,
1184        x: GLint,
1185        y: GLint,
1186        width: GLsizei,
1187        height: GLsizei,
1188        format: GLenum,
1189        pixel_type: GLenum,
1190        mut dst_buffer: U8VecRefMut,
1191    ) {
1192        self.get().read_pixels_into_buffer(
1193            x,
1194            y,
1195            width,
1196            height,
1197            format,
1198            pixel_type,
1199            dst_buffer.as_mut_slice(),
1200        )
1201    }
1202    pub fn read_pixels(
1203        &self,
1204        x: GLint,
1205        y: GLint,
1206        width: GLsizei,
1207        height: GLsizei,
1208        format: GLenum,
1209        pixel_type: GLenum,
1210    ) -> U8Vec {
1211        self.get()
1212            .read_pixels(x, y, width, height, format, pixel_type)
1213            .into()
1214    }
1215    pub fn read_pixels_into_pbo(
1216        &self,
1217        x: GLint,
1218        y: GLint,
1219        width: GLsizei,
1220        height: GLsizei,
1221        format: GLenum,
1222        pixel_type: GLenum,
1223    ) {
1224        unsafe {
1225            self.get()
1226                .read_pixels_into_pbo(x, y, width, height, format, pixel_type)
1227        }
1228    }
1229    pub fn sample_coverage(&self, value: GLclampf, invert: bool) {
1230        self.get().sample_coverage(value, invert)
1231    }
1232    pub fn polygon_offset(&self, factor: GLfloat, units: GLfloat) {
1233        self.get().polygon_offset(factor, units)
1234    }
1235    pub fn pixel_store_i(&self, name: GLenum, param: GLint) {
1236        self.get().pixel_store_i(name, param)
1237    }
1238    pub fn gen_buffers(&self, n: GLsizei) -> GLuintVec {
1239        self.get().gen_buffers(n).into()
1240    }
1241    pub fn gen_renderbuffers(&self, n: GLsizei) -> GLuintVec {
1242        self.get().gen_renderbuffers(n).into()
1243    }
1244    pub fn gen_framebuffers(&self, n: GLsizei) -> GLuintVec {
1245        self.get().gen_framebuffers(n).into()
1246    }
1247    pub fn gen_textures(&self, n: GLsizei) -> GLuintVec {
1248        self.get().gen_textures(n).into()
1249    }
1250    pub fn gen_vertex_arrays(&self, n: GLsizei) -> GLuintVec {
1251        self.get().gen_vertex_arrays(n).into()
1252    }
1253    pub fn gen_queries(&self, n: GLsizei) -> GLuintVec {
1254        self.get().gen_queries(n).into()
1255    }
1256    pub fn begin_query(&self, target: GLenum, id: GLuint) {
1257        self.get().begin_query(target, id)
1258    }
1259    pub fn end_query(&self, target: GLenum) {
1260        self.get().end_query(target)
1261    }
1262    pub fn query_counter(&self, id: GLuint, target: GLenum) {
1263        self.get().query_counter(id, target)
1264    }
1265    pub fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32 {
1266        self.get().get_query_object_iv(id, pname)
1267    }
1268    pub fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32 {
1269        self.get().get_query_object_uiv(id, pname)
1270    }
1271    pub fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64 {
1272        self.get().get_query_object_i64v(id, pname)
1273    }
1274    pub fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64 {
1275        self.get().get_query_object_ui64v(id, pname)
1276    }
1277    pub fn delete_queries(&self, queries: GLuintVecRef) {
1278        self.get().delete_queries(queries.as_slice())
1279    }
1280    pub fn delete_vertex_arrays(&self, vertex_arrays: GLuintVecRef) {
1281        self.get().delete_vertex_arrays(vertex_arrays.as_slice())
1282    }
1283    pub fn delete_buffers(&self, buffers: GLuintVecRef) {
1284        self.get().delete_buffers(buffers.as_slice())
1285    }
1286    pub fn delete_renderbuffers(&self, renderbuffers: GLuintVecRef) {
1287        self.get().delete_renderbuffers(renderbuffers.as_slice())
1288    }
1289    pub fn delete_framebuffers(&self, framebuffers: GLuintVecRef) {
1290        self.get().delete_framebuffers(framebuffers.as_slice())
1291    }
1292    pub fn delete_textures(&self, textures: GLuintVecRef) {
1293        self.get().delete_textures(textures.as_slice())
1294    }
1295    pub fn framebuffer_renderbuffer(
1296        &self,
1297        target: GLenum,
1298        attachment: GLenum,
1299        renderbuffertarget: GLenum,
1300        renderbuffer: GLuint,
1301    ) {
1302        self.get()
1303            .framebuffer_renderbuffer(target, attachment, renderbuffertarget, renderbuffer)
1304    }
1305    pub fn renderbuffer_storage(
1306        &self,
1307        target: GLenum,
1308        internalformat: GLenum,
1309        width: GLsizei,
1310        height: GLsizei,
1311    ) {
1312        self.get()
1313            .renderbuffer_storage(target, internalformat, width, height)
1314    }
1315    pub fn depth_func(&self, func: GLenum) {
1316        self.get().depth_func(func)
1317    }
1318    pub fn active_texture(&self, texture: GLenum) {
1319        self.get().active_texture(texture)
1320    }
1321    pub fn attach_shader(&self, program: GLuint, shader: GLuint) {
1322        self.get().attach_shader(program, shader)
1323    }
1324    pub fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) {
1325        self.get()
1326            .bind_attrib_location(program, index, name)
1327    }
1328    pub fn get_uniform_iv(&self, program: GLuint, location: GLint, mut result: GLintVecRefMut) {
1329        unsafe {
1330            self.get()
1331                .get_uniform_iv(program, location, result.as_mut_slice())
1332        }
1333    }
1334    pub fn get_uniform_fv(&self, program: GLuint, location: GLint, mut result: GLfloatVecRefMut) {
1335        unsafe {
1336            self.get()
1337                .get_uniform_fv(program, location, result.as_mut_slice())
1338        }
1339    }
1340    pub fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint {
1341        self.get().get_uniform_block_index(program, name)
1342    }
1343    pub fn get_uniform_indices(&self, program: GLuint, names: RefstrVecRef) -> GLuintVec {
1344        let names_vec = names
1345            .as_slice()
1346            .iter()
1347            .map(|n| n.as_str())
1348            .collect::<Vec<_>>();
1349        self.get().get_uniform_indices(program, &names_vec).into()
1350    }
1351    pub fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint) {
1352        self.get().bind_buffer_base(target, index, buffer)
1353    }
1354    pub fn bind_buffer_range(
1355        &self,
1356        target: GLenum,
1357        index: GLuint,
1358        buffer: GLuint,
1359        offset: GLintptr,
1360        size: GLsizeiptr,
1361    ) {
1362        self.get()
1363            .bind_buffer_range(target, index, buffer, offset, size)
1364    }
1365    pub fn uniform_block_binding(
1366        &self,
1367        program: GLuint,
1368        uniform_block_index: GLuint,
1369        uniform_block_binding: GLuint,
1370    ) {
1371        self.get()
1372            .uniform_block_binding(program, uniform_block_index, uniform_block_binding)
1373    }
1374    pub fn bind_buffer(&self, target: GLenum, buffer: GLuint) {
1375        self.get().bind_buffer(target, buffer)
1376    }
1377    pub fn bind_vertex_array(&self, vao: GLuint) {
1378        self.get().bind_vertex_array(vao)
1379    }
1380    pub fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint) {
1381        self.get().bind_renderbuffer(target, renderbuffer)
1382    }
1383    pub fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint) {
1384        self.get().bind_framebuffer(target, framebuffer)
1385    }
1386    pub fn bind_texture(&self, target: GLenum, texture: GLuint) {
1387        self.get().bind_texture(target, texture)
1388    }
1389    pub fn draw_buffers(&self, bufs: GLenumVecRef) {
1390        self.get().draw_buffers(bufs.as_slice())
1391    }
1392    pub fn tex_image_2d(
1393        &self,
1394        target: GLenum,
1395        level: GLint,
1396        internal_format: GLint,
1397        width: GLsizei,
1398        height: GLsizei,
1399        border: GLint,
1400        format: GLenum,
1401        ty: GLenum,
1402        opt_data: OptionU8VecRef,
1403    ) {
1404        let opt_data = opt_data.as_option();
1405        let opt_data: Option<&[u8]> = opt_data.map(|o| o.as_slice());
1406        self.get().tex_image_2d(
1407            target,
1408            level,
1409            internal_format,
1410            width,
1411            height,
1412            border,
1413            format,
1414            ty,
1415            opt_data,
1416        )
1417    }
1418    pub fn compressed_tex_image_2d(
1419        &self,
1420        target: GLenum,
1421        level: GLint,
1422        internal_format: GLenum,
1423        width: GLsizei,
1424        height: GLsizei,
1425        border: GLint,
1426        data: U8VecRef,
1427    ) {
1428        self.get().compressed_tex_image_2d(
1429            target,
1430            level,
1431            internal_format,
1432            width,
1433            height,
1434            border,
1435            data.as_slice(),
1436        )
1437    }
1438    pub fn compressed_tex_sub_image_2d(
1439        &self,
1440        target: GLenum,
1441        level: GLint,
1442        xoffset: GLint,
1443        yoffset: GLint,
1444        width: GLsizei,
1445        height: GLsizei,
1446        format: GLenum,
1447        data: U8VecRef,
1448    ) {
1449        self.get().compressed_tex_sub_image_2d(
1450            target,
1451            level,
1452            xoffset,
1453            yoffset,
1454            width,
1455            height,
1456            format,
1457            data.as_slice(),
1458        )
1459    }
1460    pub fn tex_image_3d(
1461        &self,
1462        target: GLenum,
1463        level: GLint,
1464        internal_format: GLint,
1465        width: GLsizei,
1466        height: GLsizei,
1467        depth: GLsizei,
1468        border: GLint,
1469        format: GLenum,
1470        ty: GLenum,
1471        opt_data: OptionU8VecRef,
1472    ) {
1473        let opt_data = opt_data.as_option();
1474        let opt_data: Option<&[u8]> = opt_data.map(|o| o.as_slice());
1475        self.get().tex_image_3d(
1476            target,
1477            level,
1478            internal_format,
1479            width,
1480            height,
1481            depth,
1482            border,
1483            format,
1484            ty,
1485            opt_data,
1486        )
1487    }
1488    pub fn copy_tex_image_2d(
1489        &self,
1490        target: GLenum,
1491        level: GLint,
1492        internal_format: GLenum,
1493        x: GLint,
1494        y: GLint,
1495        width: GLsizei,
1496        height: GLsizei,
1497        border: GLint,
1498    ) {
1499        self.get()
1500            .copy_tex_image_2d(target, level, internal_format, x, y, width, height, border)
1501    }
1502    pub fn copy_tex_sub_image_2d(
1503        &self,
1504        target: GLenum,
1505        level: GLint,
1506        xoffset: GLint,
1507        yoffset: GLint,
1508        x: GLint,
1509        y: GLint,
1510        width: GLsizei,
1511        height: GLsizei,
1512    ) {
1513        self.get()
1514            .copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height)
1515    }
1516    pub fn copy_tex_sub_image_3d(
1517        &self,
1518        target: GLenum,
1519        level: GLint,
1520        xoffset: GLint,
1521        yoffset: GLint,
1522        zoffset: GLint,
1523        x: GLint,
1524        y: GLint,
1525        width: GLsizei,
1526        height: GLsizei,
1527    ) {
1528        self.get().copy_tex_sub_image_3d(
1529            target, level, xoffset, yoffset, zoffset, x, y, width, height,
1530        )
1531    }
1532    pub fn tex_sub_image_2d(
1533        &self,
1534        target: GLenum,
1535        level: GLint,
1536        xoffset: GLint,
1537        yoffset: GLint,
1538        width: GLsizei,
1539        height: GLsizei,
1540        format: GLenum,
1541        ty: GLenum,
1542        data: U8VecRef,
1543    ) {
1544        self.get().tex_sub_image_2d(
1545            target,
1546            level,
1547            xoffset,
1548            yoffset,
1549            width,
1550            height,
1551            format,
1552            ty,
1553            data.as_slice(),
1554        )
1555    }
1556    pub fn tex_sub_image_2d_pbo(
1557        &self,
1558        target: GLenum,
1559        level: GLint,
1560        xoffset: GLint,
1561        yoffset: GLint,
1562        width: GLsizei,
1563        height: GLsizei,
1564        format: GLenum,
1565        ty: GLenum,
1566        offset: usize,
1567    ) {
1568        self.get().tex_sub_image_2d_pbo(
1569            target, level, xoffset, yoffset, width, height, format, ty, offset,
1570        )
1571    }
1572    pub fn tex_sub_image_3d(
1573        &self,
1574        target: GLenum,
1575        level: GLint,
1576        xoffset: GLint,
1577        yoffset: GLint,
1578        zoffset: GLint,
1579        width: GLsizei,
1580        height: GLsizei,
1581        depth: GLsizei,
1582        format: GLenum,
1583        ty: GLenum,
1584        data: U8VecRef,
1585    ) {
1586        self.get().tex_sub_image_3d(
1587            target,
1588            level,
1589            xoffset,
1590            yoffset,
1591            zoffset,
1592            width,
1593            height,
1594            depth,
1595            format,
1596            ty,
1597            data.as_slice(),
1598        )
1599    }
1600    pub fn tex_sub_image_3d_pbo(
1601        &self,
1602        target: GLenum,
1603        level: GLint,
1604        xoffset: GLint,
1605        yoffset: GLint,
1606        zoffset: GLint,
1607        width: GLsizei,
1608        height: GLsizei,
1609        depth: GLsizei,
1610        format: GLenum,
1611        ty: GLenum,
1612        offset: usize,
1613    ) {
1614        self.get().tex_sub_image_3d_pbo(
1615            target, level, xoffset, yoffset, zoffset, width, height, depth, format, ty, offset,
1616        )
1617    }
1618    pub fn tex_storage_2d(
1619        &self,
1620        target: GLenum,
1621        levels: GLint,
1622        internal_format: GLenum,
1623        width: GLsizei,
1624        height: GLsizei,
1625    ) {
1626        self.get()
1627            .tex_storage_2d(target, levels, internal_format, width, height)
1628    }
1629    pub fn tex_storage_3d(
1630        &self,
1631        target: GLenum,
1632        levels: GLint,
1633        internal_format: GLenum,
1634        width: GLsizei,
1635        height: GLsizei,
1636        depth: GLsizei,
1637    ) {
1638        self.get()
1639            .tex_storage_3d(target, levels, internal_format, width, height, depth)
1640    }
1641    pub fn get_tex_image_into_buffer(
1642        &self,
1643        target: GLenum,
1644        level: GLint,
1645        format: GLenum,
1646        ty: GLenum,
1647        mut output: U8VecRefMut,
1648    ) {
1649        self.get()
1650            .get_tex_image_into_buffer(target, level, format, ty, output.as_mut_slice())
1651    }
1652    pub fn copy_image_sub_data(
1653        &self,
1654        src_name: GLuint,
1655        src_target: GLenum,
1656        src_level: GLint,
1657        src_x: GLint,
1658        src_y: GLint,
1659        src_z: GLint,
1660        dst_name: GLuint,
1661        dst_target: GLenum,
1662        dst_level: GLint,
1663        dst_x: GLint,
1664        dst_y: GLint,
1665        dst_z: GLint,
1666        src_width: GLsizei,
1667        src_height: GLsizei,
1668        src_depth: GLsizei,
1669    ) {
1670        unsafe {
1671            self.get().copy_image_sub_data(
1672                src_name, src_target, src_level, src_x, src_y, src_z, dst_name, dst_target,
1673                dst_level, dst_x, dst_y, dst_z, src_width, src_height, src_depth,
1674            )
1675        }
1676    }
1677    pub fn invalidate_framebuffer(&self, target: GLenum, attachments: GLenumVecRef) {
1678        self.get()
1679            .invalidate_framebuffer(target, attachments.as_slice())
1680    }
1681    pub fn invalidate_sub_framebuffer(
1682        &self,
1683        target: GLenum,
1684        attachments: GLenumVecRef,
1685        xoffset: GLint,
1686        yoffset: GLint,
1687        width: GLsizei,
1688        height: GLsizei,
1689    ) {
1690        self.get().invalidate_sub_framebuffer(
1691            target,
1692            attachments.as_slice(),
1693            xoffset,
1694            yoffset,
1695            width,
1696            height,
1697        )
1698    }
1699    pub fn get_integer_v(&self, name: GLenum, mut result: GLintVecRefMut) {
1700        unsafe { self.get().get_integer_v(name, result.as_mut_slice()) }
1701    }
1702    pub fn get_integer_64v(&self, name: GLenum, mut result: GLint64VecRefMut) {
1703        unsafe { self.get().get_integer_64v(name, result.as_mut_slice()) }
1704    }
1705    pub fn get_integer_iv(&self, name: GLenum, index: GLuint, mut result: GLintVecRefMut) {
1706        unsafe {
1707            self.get()
1708                .get_integer_iv(name, index, result.as_mut_slice())
1709        }
1710    }
1711    pub fn get_integer_64iv(&self, name: GLenum, index: GLuint, mut result: GLint64VecRefMut) {
1712        unsafe {
1713            self.get()
1714                .get_integer_64iv(name, index, result.as_mut_slice())
1715        }
1716    }
1717    pub fn get_boolean_v(&self, name: GLenum, mut result: GLbooleanVecRefMut) {
1718        unsafe { self.get().get_boolean_v(name, result.as_mut_slice()) }
1719    }
1720    pub fn get_float_v(&self, name: GLenum, mut result: GLfloatVecRefMut) {
1721        unsafe { self.get().get_float_v(name, result.as_mut_slice()) }
1722    }
1723    pub fn get_framebuffer_attachment_parameter_iv(
1724        &self,
1725        target: GLenum,
1726        attachment: GLenum,
1727        pname: GLenum,
1728    ) -> GLint {
1729        self.get()
1730            .get_framebuffer_attachment_parameter_iv(target, attachment, pname)
1731    }
1732    pub fn get_renderbuffer_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint {
1733        self.get().get_renderbuffer_parameter_iv(target, pname)
1734    }
1735    pub fn get_tex_parameter_iv(&self, target: GLenum, name: GLenum) -> GLint {
1736        self.get().get_tex_parameter_iv(target, name)
1737    }
1738    pub fn get_tex_parameter_fv(&self, target: GLenum, name: GLenum) -> GLfloat {
1739        self.get().get_tex_parameter_fv(target, name)
1740    }
1741    pub fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) {
1742        self.get().tex_parameter_i(target, pname, param)
1743    }
1744    pub fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) {
1745        self.get().tex_parameter_f(target, pname, param)
1746    }
1747    pub fn framebuffer_texture_2d(
1748        &self,
1749        target: GLenum,
1750        attachment: GLenum,
1751        textarget: GLenum,
1752        texture: GLuint,
1753        level: GLint,
1754    ) {
1755        self.get()
1756            .framebuffer_texture_2d(target, attachment, textarget, texture, level)
1757    }
1758    pub fn framebuffer_texture_layer(
1759        &self,
1760        target: GLenum,
1761        attachment: GLenum,
1762        texture: GLuint,
1763        level: GLint,
1764        layer: GLint,
1765    ) {
1766        self.get()
1767            .framebuffer_texture_layer(target, attachment, texture, level, layer)
1768    }
1769    pub fn blit_framebuffer(
1770        &self,
1771        src_x0: GLint,
1772        src_y0: GLint,
1773        src_x1: GLint,
1774        src_y1: GLint,
1775        dst_x0: GLint,
1776        dst_y0: GLint,
1777        dst_x1: GLint,
1778        dst_y1: GLint,
1779        mask: GLbitfield,
1780        filter: GLenum,
1781    ) {
1782        self.get().blit_framebuffer(
1783            src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
1784        )
1785    }
1786    pub fn vertex_attrib_4f(&self, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
1787        self.get().vertex_attrib_4f(index, x, y, z, w)
1788    }
1789    pub fn vertex_attrib_pointer_f32(
1790        &self,
1791        index: GLuint,
1792        size: GLint,
1793        normalized: bool,
1794        stride: GLsizei,
1795        offset: GLuint,
1796    ) {
1797        self.get()
1798            .vertex_attrib_pointer_f32(index, size, normalized, stride, offset)
1799    }
1800    pub fn vertex_attrib_pointer(
1801        &self,
1802        index: GLuint,
1803        size: GLint,
1804        type_: GLenum,
1805        normalized: bool,
1806        stride: GLsizei,
1807        offset: GLuint,
1808    ) {
1809        self.get()
1810            .vertex_attrib_pointer(index, size, type_, normalized, stride, offset)
1811    }
1812    pub fn vertex_attrib_i_pointer(
1813        &self,
1814        index: GLuint,
1815        size: GLint,
1816        type_: GLenum,
1817        stride: GLsizei,
1818        offset: GLuint,
1819    ) {
1820        self.get()
1821            .vertex_attrib_i_pointer(index, size, type_, stride, offset)
1822    }
1823    pub fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint) {
1824        self.get().vertex_attrib_divisor(index, divisor)
1825    }
1826    pub fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
1827        self.get().viewport(x, y, width, height)
1828    }
1829    pub fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
1830        self.get().scissor(x, y, width, height)
1831    }
1832    pub fn line_width(&self, width: GLfloat) {
1833        self.get().line_width(width)
1834    }
1835    pub fn use_program(&self, program: GLuint) {
1836        self.get().use_program(program)
1837    }
1838    pub fn validate_program(&self, program: GLuint) {
1839        self.get().validate_program(program)
1840    }
1841    pub fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) {
1842        self.get().draw_arrays(mode, first, count)
1843    }
1844    pub fn draw_arrays_instanced(
1845        &self,
1846        mode: GLenum,
1847        first: GLint,
1848        count: GLsizei,
1849        primcount: GLsizei,
1850    ) {
1851        self.get()
1852            .draw_arrays_instanced(mode, first, count, primcount)
1853    }
1854    pub fn draw_elements(
1855        &self,
1856        mode: GLenum,
1857        count: GLsizei,
1858        element_type: GLenum,
1859        indices_offset: GLuint,
1860    ) {
1861        self.get()
1862            .draw_elements(mode, count, element_type, indices_offset)
1863    }
1864    pub fn draw_elements_instanced(
1865        &self,
1866        mode: GLenum,
1867        count: GLsizei,
1868        element_type: GLenum,
1869        indices_offset: GLuint,
1870        primcount: GLsizei,
1871    ) {
1872        self.get()
1873            .draw_elements_instanced(mode, count, element_type, indices_offset, primcount)
1874    }
1875    pub fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) {
1876        self.get().blend_color(r, g, b, a)
1877    }
1878    pub fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) {
1879        self.get().blend_func(sfactor, dfactor)
1880    }
1881    pub fn blend_func_separate(
1882        &self,
1883        src_rgb: GLenum,
1884        dest_rgb: GLenum,
1885        src_alpha: GLenum,
1886        dest_alpha: GLenum,
1887    ) {
1888        self.get()
1889            .blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha)
1890    }
1891    pub fn blend_equation(&self, mode: GLenum) {
1892        self.get().blend_equation(mode)
1893    }
1894    pub fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum) {
1895        self.get().blend_equation_separate(mode_rgb, mode_alpha)
1896    }
1897    pub fn color_mask(&self, r: bool, g: bool, b: bool, a: bool) {
1898        self.get().color_mask(r, g, b, a)
1899    }
1900    pub fn cull_face(&self, mode: GLenum) {
1901        self.get().cull_face(mode)
1902    }
1903    pub fn front_face(&self, mode: GLenum) {
1904        self.get().front_face(mode)
1905    }
1906    pub fn enable(&self, cap: GLenum) {
1907        self.get().enable(cap)
1908    }
1909    pub fn disable(&self, cap: GLenum) {
1910        self.get().disable(cap)
1911    }
1912    pub fn hint(&self, param_name: GLenum, param_val: GLenum) {
1913        self.get().hint(param_name, param_val)
1914    }
1915    pub fn is_enabled(&self, cap: GLenum) -> GLboolean {
1916        self.get().is_enabled(cap)
1917    }
1918    pub fn is_shader(&self, shader: GLuint) -> GLboolean {
1919        self.get().is_shader(shader)
1920    }
1921    pub fn is_texture(&self, texture: GLenum) -> GLboolean {
1922        self.get().is_texture(texture)
1923    }
1924    pub fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean {
1925        self.get().is_framebuffer(framebuffer)
1926    }
1927    pub fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean {
1928        self.get().is_renderbuffer(renderbuffer)
1929    }
1930    pub fn check_frame_buffer_status(&self, target: GLenum) -> GLenum {
1931        self.get().check_frame_buffer_status(target)
1932    }
1933    pub fn enable_vertex_attrib_array(&self, index: GLuint) {
1934        self.get().enable_vertex_attrib_array(index)
1935    }
1936    pub fn disable_vertex_attrib_array(&self, index: GLuint) {
1937        self.get().disable_vertex_attrib_array(index)
1938    }
1939    pub fn uniform_1f(&self, location: GLint, v0: GLfloat) {
1940        self.get().uniform_1f(location, v0)
1941    }
1942    pub fn uniform_1fv(&self, location: GLint, values: F32VecRef) {
1943        self.get().uniform_1fv(location, values.as_slice())
1944    }
1945    pub fn uniform_1i(&self, location: GLint, v0: GLint) {
1946        self.get().uniform_1i(location, v0)
1947    }
1948    pub fn uniform_1iv(&self, location: GLint, values: I32VecRef) {
1949        self.get().uniform_1iv(location, values.as_slice())
1950    }
1951    pub fn uniform_1ui(&self, location: GLint, v0: GLuint) {
1952        self.get().uniform_1ui(location, v0)
1953    }
1954    pub fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat) {
1955        self.get().uniform_2f(location, v0, v1)
1956    }
1957    pub fn uniform_2fv(&self, location: GLint, values: F32VecRef) {
1958        self.get().uniform_2fv(location, values.as_slice())
1959    }
1960    pub fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint) {
1961        self.get().uniform_2i(location, v0, v1)
1962    }
1963    pub fn uniform_2iv(&self, location: GLint, values: I32VecRef) {
1964        self.get().uniform_2iv(location, values.as_slice())
1965    }
1966    pub fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint) {
1967        self.get().uniform_2ui(location, v0, v1)
1968    }
1969    pub fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {
1970        self.get().uniform_3f(location, v0, v1, v2)
1971    }
1972    pub fn uniform_3fv(&self, location: GLint, values: F32VecRef) {
1973        self.get().uniform_3fv(location, values.as_slice())
1974    }
1975    pub fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint) {
1976        self.get().uniform_3i(location, v0, v1, v2)
1977    }
1978    pub fn uniform_3iv(&self, location: GLint, values: I32VecRef) {
1979        self.get().uniform_3iv(location, values.as_slice())
1980    }
1981    pub fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {
1982        self.get().uniform_3ui(location, v0, v1, v2)
1983    }
1984    pub fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
1985        self.get().uniform_4f(location, x, y, z, w)
1986    }
1987    pub fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) {
1988        self.get().uniform_4i(location, x, y, z, w)
1989    }
1990    pub fn uniform_4iv(&self, location: GLint, values: I32VecRef) {
1991        self.get().uniform_4iv(location, values.as_slice())
1992    }
1993    pub fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {
1994        self.get().uniform_4ui(location, x, y, z, w)
1995    }
1996    pub fn uniform_4fv(&self, location: GLint, values: F32VecRef) {
1997        self.get().uniform_4fv(location, values.as_slice())
1998    }
1999    pub fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: F32VecRef) {
2000        self.get()
2001            .uniform_matrix_2fv(location, transpose, value.as_slice())
2002    }
2003    pub fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: F32VecRef) {
2004        self.get()
2005            .uniform_matrix_3fv(location, transpose, value.as_slice())
2006    }
2007    pub fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: F32VecRef) {
2008        self.get()
2009            .uniform_matrix_4fv(location, transpose, value.as_slice())
2010    }
2011    pub fn depth_mask(&self, flag: bool) {
2012        self.get().depth_mask(flag)
2013    }
2014    pub fn depth_range(&self, near: f64, far: f64) {
2015        self.get().depth_range(near, far)
2016    }
2017    pub fn get_active_attrib(&self, program: GLuint, index: GLuint) -> GetActiveAttribReturn {
2018        let r = self.get().get_active_attrib(program, index);
2019        GetActiveAttribReturn {
2020            _0: r.0,
2021            _1: r.1,
2022            _2: r.2.into(),
2023        }
2024    }
2025    pub fn get_active_uniform(&self, program: GLuint, index: GLuint) -> GetActiveUniformReturn {
2026        let r = self.get().get_active_uniform(program, index);
2027        GetActiveUniformReturn {
2028            _0: r.0,
2029            _1: r.1,
2030            _2: r.2.into(),
2031        }
2032    }
2033    pub fn get_active_uniforms_iv(
2034        &self,
2035        program: GLuint,
2036        indices: GLuintVec,
2037        pname: GLenum,
2038    ) -> GLintVec {
2039        self.get()
2040            .get_active_uniforms_iv(program, indices.into_library_owned_vec(), pname)
2041            .into()
2042    }
2043    pub fn get_active_uniform_block_i(
2044        &self,
2045        program: GLuint,
2046        index: GLuint,
2047        pname: GLenum,
2048    ) -> GLint {
2049        self.get().get_active_uniform_block_i(program, index, pname)
2050    }
2051    pub fn get_active_uniform_block_iv(
2052        &self,
2053        program: GLuint,
2054        index: GLuint,
2055        pname: GLenum,
2056    ) -> GLintVec {
2057        self.get()
2058            .get_active_uniform_block_iv(program, index, pname)
2059            .into()
2060    }
2061    pub fn get_active_uniform_block_name(&self, program: GLuint, index: GLuint) -> AzString {
2062        self.get()
2063            .get_active_uniform_block_name(program, index)
2064            .into()
2065    }
2066    pub fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int {
2067        self.get().get_attrib_location(program, name)
2068    }
2069    pub fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int {
2070        self.get().get_frag_data_location(program, name)
2071    }
2072    pub fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int {
2073        self.get().get_uniform_location(program, name)
2074    }
2075    pub fn get_program_info_log(&self, program: GLuint) -> AzString {
2076        self.get().get_program_info_log(program).into()
2077    }
2078    pub fn get_program_iv(&self, program: GLuint, pname: GLenum, mut result: GLintVecRefMut) {
2079        unsafe {
2080            self.get()
2081                .get_program_iv(program, pname, result.as_mut_slice())
2082        }
2083    }
2084    pub fn get_program_binary(&self, program: GLuint) -> GetProgramBinaryReturn {
2085        let r = self.get().get_program_binary(program);
2086        GetProgramBinaryReturn {
2087            _0: r.0.into(),
2088            _1: r.1,
2089        }
2090    }
2091    pub fn program_binary(&self, program: GLuint, format: GLenum, binary: U8VecRef) {
2092        self.get()
2093            .program_binary(program, format, binary.as_slice())
2094    }
2095    pub fn program_parameter_i(&self, program: GLuint, pname: GLenum, value: GLint) {
2096        self.get().program_parameter_i(program, pname, value)
2097    }
2098    pub fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum, mut result: GLintVecRefMut) {
2099        unsafe {
2100            self.get()
2101                .get_vertex_attrib_iv(index, pname, result.as_mut_slice())
2102        }
2103    }
2104    pub fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum, mut result: GLfloatVecRefMut) {
2105        unsafe {
2106            self.get()
2107                .get_vertex_attrib_fv(index, pname, result.as_mut_slice())
2108        }
2109    }
2110    pub fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr {
2111        self.get().get_vertex_attrib_pointer_v(index, pname)
2112    }
2113    pub fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint {
2114        self.get().get_buffer_parameter_iv(target, pname)
2115    }
2116    pub fn get_shader_info_log(&self, shader: GLuint) -> AzString {
2117        self.get().get_shader_info_log(shader).into()
2118    }
2119    pub fn get_string(&self, which: GLenum) -> AzString {
2120        self.get().get_string(which).into()
2121    }
2122    pub fn get_string_i(&self, which: GLenum, index: GLuint) -> AzString {
2123        self.get().get_string_i(which, index).into()
2124    }
2125    pub fn get_shader_iv(&self, shader: GLuint, pname: GLenum, mut result: GLintVecRefMut) {
2126        unsafe {
2127            self.get()
2128                .get_shader_iv(shader, pname, result.as_mut_slice())
2129        }
2130    }
2131    pub fn get_shader_precision_format(
2132        &self,
2133        shader_type: GLuint,
2134        precision_type: GLuint,
2135    ) -> GlShaderPrecisionFormatReturn {
2136        let r = self
2137            .get()
2138            .get_shader_precision_format(shader_type, precision_type);
2139        GlShaderPrecisionFormatReturn {
2140            _0: r.0,
2141            _1: r.1,
2142            _2: r.2,
2143        }
2144    }
2145    pub fn compile_shader(&self, shader: GLuint) {
2146        self.get().compile_shader(shader)
2147    }
2148    pub fn create_program(&self) -> GLuint {
2149        self.get().create_program()
2150    }
2151    pub fn delete_program(&self, program: GLuint) {
2152        self.get().delete_program(program)
2153    }
2154    pub fn create_shader(&self, shader_type: GLenum) -> GLuint {
2155        self.get().create_shader(shader_type)
2156    }
2157    pub fn delete_shader(&self, shader: GLuint) {
2158        self.get().delete_shader(shader)
2159    }
2160    pub fn detach_shader(&self, program: GLuint, shader: GLuint) {
2161        self.get().detach_shader(program, shader)
2162    }
2163    pub fn link_program(&self, program: GLuint) {
2164        self.get().link_program(program)
2165    }
2166    pub fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
2167        self.get().clear_color(r, g, b, a)
2168    }
2169    pub fn clear(&self, buffer_mask: GLbitfield) {
2170        self.get().clear(buffer_mask)
2171    }
2172    pub fn clear_depth(&self, depth: f64) {
2173        self.get().clear_depth(depth)
2174    }
2175    pub fn clear_stencil(&self, s: GLint) {
2176        self.get().clear_stencil(s)
2177    }
2178    pub fn flush(&self) {
2179        self.get().flush()
2180    }
2181    pub fn finish(&self) {
2182        self.get().finish()
2183    }
2184    pub fn get_error(&self) -> GLenum {
2185        self.get().get_error()
2186    }
2187    pub fn stencil_mask(&self, mask: GLuint) {
2188        self.get().stencil_mask(mask)
2189    }
2190    pub fn stencil_mask_separate(&self, face: GLenum, mask: GLuint) {
2191        self.get().stencil_mask_separate(face, mask)
2192    }
2193    pub fn stencil_func(&self, func: GLenum, ref_: GLint, mask: GLuint) {
2194        self.get().stencil_func(func, ref_, mask)
2195    }
2196    pub fn stencil_func_separate(&self, face: GLenum, func: GLenum, ref_: GLint, mask: GLuint) {
2197        self.get().stencil_func_separate(face, func, ref_, mask)
2198    }
2199    pub fn stencil_op(&self, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
2200        self.get().stencil_op(sfail, dpfail, dppass)
2201    }
2202    pub fn stencil_op_separate(&self, face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
2203        self.get().stencil_op_separate(face, sfail, dpfail, dppass)
2204    }
2205    pub fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GlVoidPtrConst) {
2206        self.get()
2207            .egl_image_target_texture2d_oes(target, image.ptr as *const gl_context_loader::c_void)
2208    }
2209    pub fn generate_mipmap(&self, target: GLenum) {
2210        self.get().generate_mipmap(target)
2211    }
2212    pub fn insert_event_marker_ext(&self, message: &str) {
2213        self.get().insert_event_marker_ext(message)
2214    }
2215    pub fn push_group_marker_ext(&self, message: &str) {
2216        self.get().push_group_marker_ext(message)
2217    }
2218    pub fn pop_group_marker_ext(&self) {
2219        self.get().pop_group_marker_ext()
2220    }
2221    pub fn debug_message_insert_khr(
2222        &self,
2223        source: GLenum,
2224        type_: GLenum,
2225        id: GLuint,
2226        severity: GLenum,
2227        message: &str,
2228    ) {
2229        self.get()
2230            .debug_message_insert_khr(source, type_, id, severity, message)
2231    }
2232    pub fn push_debug_group_khr(&self, source: GLenum, id: GLuint, message: &str) {
2233        self.get()
2234            .push_debug_group_khr(source, id, message)
2235    }
2236    pub fn pop_debug_group_khr(&self) {
2237        self.get().pop_debug_group_khr()
2238    }
2239    pub fn fence_sync(&self, condition: GLenum, flags: GLbitfield) -> GLsyncPtr {
2240        GLsyncPtr::new(self.get().fence_sync(condition, flags))
2241    }
2242    pub fn client_wait_sync(&self, sync: GLsyncPtr, flags: GLbitfield, timeout: GLuint64) -> u32 {
2243        self.get().client_wait_sync(sync.get(), flags, timeout)
2244    }
2245    pub fn wait_sync(&self, sync: GLsyncPtr, flags: GLbitfield, timeout: GLuint64) {
2246        self.get().wait_sync(sync.get(), flags, timeout)
2247    }
2248    pub fn delete_sync(&self, sync: GLsyncPtr) {
2249        self.get().delete_sync(sync.get())
2250    }
2251    pub fn texture_range_apple(&self, target: GLenum, data: U8VecRef) {
2252        self.get().texture_range_apple(target, data.as_slice())
2253    }
2254    pub fn gen_fences_apple(&self, n: GLsizei) -> GLuintVec {
2255        self.get().gen_fences_apple(n).into()
2256    }
2257    pub fn delete_fences_apple(&self, fences: GLuintVecRef) {
2258        self.get().delete_fences_apple(fences.as_slice())
2259    }
2260    pub fn set_fence_apple(&self, fence: GLuint) {
2261        self.get().set_fence_apple(fence)
2262    }
2263    pub fn finish_fence_apple(&self, fence: GLuint) {
2264        self.get().finish_fence_apple(fence)
2265    }
2266    pub fn test_fence_apple(&self, fence: GLuint) {
2267        self.get().test_fence_apple(fence)
2268    }
2269    pub fn test_object_apple(&self, object: GLenum, name: GLuint) -> GLboolean {
2270        self.get().test_object_apple(object, name)
2271    }
2272    pub fn finish_object_apple(&self, object: GLenum, name: GLuint) {
2273        self.get().finish_object_apple(object, name)
2274    }
2275    pub fn get_frag_data_index(&self, program: GLuint, name: &str) -> GLint {
2276        self.get().get_frag_data_index(program, name)
2277    }
2278    pub fn blend_barrier_khr(&self) {
2279        self.get().blend_barrier_khr()
2280    }
2281    pub fn bind_frag_data_location_indexed(
2282        &self,
2283        program: GLuint,
2284        color_number: GLuint,
2285        index: GLuint,
2286        name: &str,
2287    ) {
2288        self.get()
2289            .bind_frag_data_location_indexed(program, color_number, index, name)
2290    }
2291    pub fn get_debug_messages(&self) -> DebugMessageVec {
2292        let dmv: Vec<DebugMessage> = self
2293            .get()
2294            .get_debug_messages()
2295            .into_iter()
2296            .map(|d| DebugMessage {
2297                message: d.message.into(),
2298                source: d.source,
2299                ty: d.ty,
2300                id: d.id,
2301                severity: d.severity,
2302            })
2303            .collect();
2304        dmv.into()
2305    }
2306    pub fn provoking_vertex_angle(&self, mode: GLenum) {
2307        self.get().provoking_vertex_angle(mode)
2308    }
2309    pub fn gen_vertex_arrays_apple(&self, n: GLsizei) -> GLuintVec {
2310        self.get().gen_vertex_arrays_apple(n).into()
2311    }
2312    pub fn bind_vertex_array_apple(&self, vao: GLuint) {
2313        self.get().bind_vertex_array_apple(vao)
2314    }
2315    pub fn delete_vertex_arrays_apple(&self, vertex_arrays: GLuintVecRef) {
2316        self.get()
2317            .delete_vertex_arrays_apple(vertex_arrays.as_slice())
2318    }
2319    pub fn copy_texture_chromium(
2320        &self,
2321        source_id: GLuint,
2322        source_level: GLint,
2323        dest_target: GLenum,
2324        dest_id: GLuint,
2325        dest_level: GLint,
2326        internal_format: GLint,
2327        dest_type: GLenum,
2328        unpack_flip_y: GLboolean,
2329        unpack_premultiply_alpha: GLboolean,
2330        unpack_unmultiply_alpha: GLboolean,
2331    ) {
2332        self.get().copy_texture_chromium(
2333            source_id,
2334            source_level,
2335            dest_target,
2336            dest_id,
2337            dest_level,
2338            internal_format,
2339            dest_type,
2340            unpack_flip_y,
2341            unpack_premultiply_alpha,
2342            unpack_unmultiply_alpha,
2343        )
2344    }
2345    pub fn copy_sub_texture_chromium(
2346        &self,
2347        source_id: GLuint,
2348        source_level: GLint,
2349        dest_target: GLenum,
2350        dest_id: GLuint,
2351        dest_level: GLint,
2352        x_offset: GLint,
2353        y_offset: GLint,
2354        x: GLint,
2355        y: GLint,
2356        width: GLsizei,
2357        height: GLsizei,
2358        unpack_flip_y: GLboolean,
2359        unpack_premultiply_alpha: GLboolean,
2360        unpack_unmultiply_alpha: GLboolean,
2361    ) {
2362        self.get().copy_sub_texture_chromium(
2363            source_id,
2364            source_level,
2365            dest_target,
2366            dest_id,
2367            dest_level,
2368            x_offset,
2369            y_offset,
2370            x,
2371            y,
2372            width,
2373            height,
2374            unpack_flip_y,
2375            unpack_premultiply_alpha,
2376            unpack_unmultiply_alpha,
2377        )
2378    }
2379    pub fn egl_image_target_renderbuffer_storage_oes(&self, target: u32, image: GlVoidPtrConst) {
2380        self.get().egl_image_target_renderbuffer_storage_oes(
2381            target,
2382            image.ptr as *const gl_context_loader::c_void,
2383        )
2384    }
2385    pub fn copy_texture_3d_angle(
2386        &self,
2387        source_id: GLuint,
2388        source_level: GLint,
2389        dest_target: GLenum,
2390        dest_id: GLuint,
2391        dest_level: GLint,
2392        internal_format: GLint,
2393        dest_type: GLenum,
2394        unpack_flip_y: GLboolean,
2395        unpack_premultiply_alpha: GLboolean,
2396        unpack_unmultiply_alpha: GLboolean,
2397    ) {
2398        self.get().copy_texture_3d_angle(
2399            source_id,
2400            source_level,
2401            dest_target,
2402            dest_id,
2403            dest_level,
2404            internal_format,
2405            dest_type,
2406            unpack_flip_y,
2407            unpack_premultiply_alpha,
2408            unpack_unmultiply_alpha,
2409        )
2410    }
2411    pub fn copy_sub_texture_3d_angle(
2412        &self,
2413        source_id: GLuint,
2414        source_level: GLint,
2415        dest_target: GLenum,
2416        dest_id: GLuint,
2417        dest_level: GLint,
2418        x_offset: GLint,
2419        y_offset: GLint,
2420        z_offset: GLint,
2421        x: GLint,
2422        y: GLint,
2423        z: GLint,
2424        width: GLsizei,
2425        height: GLsizei,
2426        depth: GLsizei,
2427        unpack_flip_y: GLboolean,
2428        unpack_premultiply_alpha: GLboolean,
2429        unpack_unmultiply_alpha: GLboolean,
2430    ) {
2431        self.get().copy_sub_texture_3d_angle(
2432            source_id,
2433            source_level,
2434            dest_target,
2435            dest_id,
2436            dest_level,
2437            x_offset,
2438            y_offset,
2439            z_offset,
2440            x,
2441            y,
2442            z,
2443            width,
2444            height,
2445            depth,
2446            unpack_flip_y,
2447            unpack_premultiply_alpha,
2448            unpack_unmultiply_alpha,
2449        )
2450    }
2451    pub fn buffer_storage(
2452        &self,
2453        target: GLenum,
2454        size: GLsizeiptr,
2455        data: GlVoidPtrConst,
2456        flags: GLbitfield,
2457    ) {
2458        self.get().buffer_storage(target, size, data.ptr, flags)
2459    }
2460    pub fn flush_mapped_buffer_range(&self, target: GLenum, offset: GLintptr, length: GLsizeiptr) {
2461        self.get().flush_mapped_buffer_range(target, offset, length)
2462    }
2463}
2464
2465impl PartialEq for GlContextPtr {
2466    fn eq(&self, rhs: &Self) -> bool {
2467        self.as_usize().eq(&rhs.as_usize())
2468    }
2469}
2470
2471impl Eq for GlContextPtr {}
2472
2473impl PartialOrd for GlContextPtr {
2474    fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
2475        self.as_usize().partial_cmp(&rhs.as_usize())
2476    }
2477}
2478
2479impl Ord for GlContextPtr {
2480    fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
2481        self.as_usize().cmp(&rhs.as_usize())
2482    }
2483}
2484
2485/// Saved OpenGL state for save/restore around framebuffer operations.
2486/// Used by `Texture::clear()` and `GlShader::draw()` to avoid corrupting
2487/// the caller's GL state.
2488struct GlStateSave {
2489    current_multisample: [u8; 1],
2490    current_index_buffer: [i32; 1],
2491    current_vertex_buffer: [i32; 1],
2492    current_vertex_array_object: [i32; 1],
2493    current_program: [i32; 1],
2494    current_framebuffers: [i32; 1],
2495    current_renderbuffers: [i32; 1],
2496    current_texture_2d: [i32; 1],
2497}
2498
2499impl GlStateSave {
2500    fn save(gl_context: &GlContextPtr) -> Self {
2501        let mut s = GlStateSave {
2502            current_multisample: [0],
2503            current_index_buffer: [0],
2504            current_vertex_buffer: [0],
2505            current_vertex_array_object: [0],
2506            current_program: [0],
2507            current_framebuffers: [0],
2508            current_renderbuffers: [0],
2509            current_texture_2d: [0],
2510        };
2511
2512        gl_context.get_boolean_v(gl::MULTISAMPLE, (&mut s.current_multisample[..]).into());
2513        gl_context.get_integer_v(gl::ARRAY_BUFFER_BINDING, (&mut s.current_vertex_buffer[..]).into());
2514        gl_context.get_integer_v(gl::ELEMENT_ARRAY_BUFFER_BINDING, (&mut s.current_index_buffer[..]).into());
2515        gl_context.get_integer_v(gl::CURRENT_PROGRAM, (&mut s.current_program[..]).into());
2516        gl_context.get_integer_v(gl::VERTEX_ARRAY_BINDING, (&mut s.current_vertex_array_object[..]).into());
2517        gl_context.get_integer_v(gl::RENDERBUFFER, (&mut s.current_renderbuffers[..]).into());
2518        gl_context.get_integer_v(gl::FRAMEBUFFER, (&mut s.current_framebuffers[..]).into());
2519        gl_context.get_integer_v(gl::TEXTURE_2D, (&mut s.current_texture_2d[..]).into());
2520
2521        s
2522    }
2523
2524    fn restore(&self, gl_context: &GlContextPtr) {
2525        if u32::from(self.current_multisample[0]) == gl::TRUE {
2526            gl_context.enable(gl::MULTISAMPLE);
2527        }
2528        gl_context.bind_framebuffer(gl::FRAMEBUFFER, self.current_framebuffers[0] as u32);
2529        gl_context.bind_texture(gl::TEXTURE_2D, self.current_texture_2d[0] as u32);
2530        gl_context.bind_buffer(gl::RENDERBUFFER, self.current_renderbuffers[0] as u32);
2531        gl_context.bind_vertex_array(self.current_vertex_array_object[0] as u32);
2532        gl_context.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.current_index_buffer[0] as u32);
2533        gl_context.bind_buffer(gl::ARRAY_BUFFER, self.current_vertex_buffer[0] as u32);
2534        gl_context.use_program(self.current_program[0] as u32);
2535    }
2536}
2537
2538/// OpenGL texture, use `ReadOnlyWindow::create_texture` to create a texture
2539#[repr(C)]
2540pub struct Texture {
2541    /// A reference-counted pointer to the OpenGL context (so that the texture can be deleted in
2542    /// the destructor)
2543    pub gl_context: GlContextPtr,
2544    /// Raw OpenGL texture ID
2545    pub texture_id: GLuint,
2546    /// Reference count, shared across
2547    pub refcount: *const AtomicUsize,
2548    /// Size of this texture (in pixels)
2549    pub size: PhysicalSizeU32,
2550    /// Format of the texture (rgba8, brga8, etc.)
2551    pub format: RawImageFormat,
2552    /// Background color of this texture
2553    pub background_color: ColorU,
2554    /// Hints and flags for optimization purposes
2555    pub flags: TextureFlags,
2556    pub run_destructor: bool,
2557}
2558
2559impl Clone for Texture {
2560    fn clone(&self) -> Self {
2561        unsafe {
2562            (*self.refcount).fetch_add(1, AtomicOrdering::SeqCst);
2563        }
2564        Self {
2565            gl_context: self.gl_context.clone(),
2566            texture_id: self.texture_id.clone(),
2567            refcount: self.refcount,
2568            size: self.size.clone(),
2569            format: self.format.clone(),
2570            background_color: self.background_color.clone(),
2571            flags: self.flags.clone(),
2572            run_destructor: true,
2573        }
2574    }
2575}
2576
2577impl_option!(
2578    Texture,
2579    OptionTexture,
2580    copy = false,
2581    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
2582);
2583
2584impl Texture {
2585    pub fn create(
2586        texture_id: GLuint,
2587        flags: TextureFlags,
2588        size: PhysicalSizeU32,
2589        background_color: ColorU,
2590        gl_context: GlContextPtr,
2591        format: RawImageFormat,
2592    ) -> Self {
2593        Self {
2594            texture_id,
2595            flags,
2596            size,
2597            background_color,
2598            gl_context,
2599            format,
2600            refcount: Box::into_raw(Box::new(AtomicUsize::new(1))),
2601            run_destructor: true,
2602        }
2603    }
2604
2605    pub fn allocate_rgba8(
2606        gl_context: GlContextPtr,
2607        size: PhysicalSizeU32,
2608        background: ColorU,
2609    ) -> Self {
2610        let textures = gl_context.gen_textures(1);
2611        let texture_id = textures.as_ref()[0];
2612
2613        let mut current_texture_2d = [0_i32];
2614        gl_context.get_integer_v(gl::TEXTURE_2D, (&mut current_texture_2d[..]).into());
2615
2616        gl_context.bind_texture(gl::TEXTURE_2D, texture_id);
2617        gl_context.tex_image_2d(
2618            gl::TEXTURE_2D,
2619            0,
2620            gl::RGBA as i32,
2621            size.width as i32,
2622            size.height as i32,
2623            0,
2624            gl::RGBA,
2625            gl::UNSIGNED_BYTE,
2626            None.into(),
2627        );
2628        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
2629        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
2630        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
2631        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
2632        gl_context.bind_texture(gl::TEXTURE_2D, current_texture_2d[0] as u32);
2633
2634        Self::create(
2635            texture_id,
2636            TextureFlags {
2637                is_opaque: false,
2638                is_video_texture: false,
2639            },
2640            size,
2641            background,
2642            gl_context,
2643            // Format is BGRA8 for WebRender integration, despite the GL upload using RGBA
2644            RawImageFormat::BGRA8,
2645        )
2646    }
2647
2648    pub fn clear(&mut self) {
2649        let saved = GlStateSave::save(&self.gl_context);
2650
2651        let framebuffers = self.gl_context.gen_framebuffers(1);
2652        let framebuffer_id = framebuffers.get(0).unwrap();
2653        self.gl_context
2654            .bind_framebuffer(gl::FRAMEBUFFER, *framebuffer_id);
2655
2656        let depthbuffers = self.gl_context.gen_renderbuffers(1);
2657        let depthbuffer_id = depthbuffers.get(0).unwrap();
2658
2659        self.gl_context
2660            .bind_texture(gl::TEXTURE_2D, self.texture_id);
2661        self.gl_context.tex_image_2d(
2662            gl::TEXTURE_2D,
2663            0,
2664            gl::RGBA as i32, // NOT RGBA8 - will generate INVALID_ENUM!
2665            self.size.width as i32,
2666            self.size.height as i32,
2667            0,
2668            gl::RGBA, // gl::BGRA?
2669            gl::UNSIGNED_BYTE,
2670            None.into(),
2671        );
2672        self.gl_context
2673            .tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
2674        self.gl_context
2675            .tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
2676        self.gl_context.tex_parameter_i(
2677            gl::TEXTURE_2D,
2678            gl::TEXTURE_WRAP_S,
2679            gl::CLAMP_TO_EDGE as i32,
2680        );
2681        self.gl_context.tex_parameter_i(
2682            gl::TEXTURE_2D,
2683            gl::TEXTURE_WRAP_T,
2684            gl::CLAMP_TO_EDGE as i32,
2685        );
2686
2687        self.gl_context
2688            .bind_renderbuffer(gl::RENDERBUFFER, *depthbuffer_id);
2689        self.gl_context.renderbuffer_storage(
2690            gl::RENDERBUFFER,
2691            gl::DEPTH_COMPONENT,
2692            self.size.width as i32,
2693            self.size.height as i32,
2694        );
2695        self.gl_context.framebuffer_renderbuffer(
2696            gl::FRAMEBUFFER,
2697            gl::DEPTH_ATTACHMENT,
2698            gl::RENDERBUFFER,
2699            *depthbuffer_id,
2700        );
2701
2702        self.gl_context.framebuffer_texture_2d(
2703            gl::FRAMEBUFFER,
2704            gl::COLOR_ATTACHMENT0,
2705            gl::TEXTURE_2D,
2706            self.texture_id,
2707            0,
2708        );
2709        self.gl_context
2710            .draw_buffers([gl::COLOR_ATTACHMENT0][..].into());
2711
2712        let clear_color: ColorF = self.background_color.into();
2713        self.gl_context
2714            .clear_color(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
2715        self.gl_context.clear_depth(0.0);
2716        self.gl_context
2717            .clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
2718
2719        self.gl_context
2720            .delete_framebuffers((&[*framebuffer_id])[..].into());
2721        self.gl_context
2722            .delete_renderbuffers((&[*depthbuffer_id])[..].into());
2723
2724        saved.restore(&self.gl_context);
2725    }
2726
2727    pub fn get_descriptor(&self) -> ImageDescriptor {
2728        ImageDescriptor {
2729            format: self.format,
2730            width: self.size.width as usize,
2731            height: self.size.height as usize,
2732            stride: None.into(),
2733            offset: 0,
2734            flags: ImageDescriptorFlags {
2735                is_opaque: self.flags.is_opaque,
2736                // The texture gets mapped 1:1 onto the display, so there is no need for mipmaps
2737                allow_mipmaps: false,
2738            },
2739        }
2740    }
2741
2742    /// Draws a `TessellatedGPUSvgNode` with the given color to the texture
2743    pub fn draw_tesselated_svg_gpu_node(
2744        &mut self,
2745        node: &TessellatedGPUSvgNode,
2746        size: PhysicalSizeU32,
2747        color: ColorU,
2748        transforms: StyleTransformVec,
2749    ) -> bool {
2750        node.draw(self, size, color, transforms)
2751    }
2752
2753    /// Draws a `TessellatedColoredGPUSvgNode` to the texture
2754    pub fn draw_tesselated_colored_svg_gpu_node(
2755        &mut self,
2756        node: &crate::svg::TessellatedColoredGPUSvgNode,
2757        size: PhysicalSizeU32,
2758        transforms: StyleTransformVec,
2759    ) -> bool {
2760        node.draw(self, size, transforms)
2761    }
2762}
2763
2764#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
2765#[repr(C)]
2766pub struct TextureFlags {
2767    /// Whether this texture contains an alpha component
2768    pub is_opaque: bool,
2769    /// Optimization: use the compositor instead of OpenGL for energy optimization
2770    pub is_video_texture: bool,
2771}
2772
2773impl ::core::fmt::Display for Texture {
2774    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
2775        write!(
2776            f,
2777            "Texture {{ id: {}, {}x{} }}",
2778            self.texture_id, self.size.width, self.size.height
2779        )
2780    }
2781}
2782
2783macro_rules! impl_traits_for_gl_object {
2784    ($struct_name:ident, $gl_id_field:ident) => {
2785        impl ::core::fmt::Debug for $struct_name {
2786            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
2787                write!(f, "{}", self)
2788            }
2789        }
2790
2791        impl Hash for $struct_name {
2792            fn hash<H: Hasher>(&self, state: &mut H) {
2793                self.$gl_id_field.hash(state);
2794            }
2795        }
2796
2797        impl PartialEq for $struct_name {
2798            fn eq(&self, other: &$struct_name) -> bool {
2799                self.$gl_id_field == other.$gl_id_field
2800            }
2801        }
2802
2803        impl Eq for $struct_name {}
2804
2805        impl PartialOrd for $struct_name {
2806            fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
2807                Some((self.$gl_id_field).cmp(&(other.$gl_id_field)))
2808            }
2809        }
2810
2811        impl Ord for $struct_name {
2812            fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
2813                (self.$gl_id_field).cmp(&(other.$gl_id_field))
2814            }
2815        }
2816    };
2817    ($struct_name:ident < $lt:lifetime > , $gl_id_field:ident) => {
2818        impl<$lt> ::core::fmt::Debug for $struct_name<$lt> {
2819            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
2820                write!(f, "{}", self)
2821            }
2822        }
2823
2824        impl<$lt> Hash for $struct_name<$lt> {
2825            fn hash<H: Hasher>(&self, state: &mut H) {
2826                self.$gl_id_field.hash(state);
2827            }
2828        }
2829
2830        impl<$lt> PartialEq for $struct_name<$lt> {
2831            fn eq(&self, other: &$struct_name) -> bool {
2832                self.$gl_id_field == other.$gl_id_field
2833            }
2834        }
2835
2836        impl<$lt> Eq for $struct_name<$lt> {}
2837
2838        impl<$lt> PartialOrd for $struct_name<$lt> {
2839            fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
2840                Some((self.$gl_id_field).cmp(&(other.$gl_id_field)))
2841            }
2842        }
2843
2844        impl<$lt> Ord for $struct_name<$lt> {
2845            fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
2846                (self.$gl_id_field).cmp(&(other.$gl_id_field))
2847            }
2848        }
2849    };
2850    ($struct_name:ident < $t:ident : $constraint:ident > , $gl_id_field:ident) => {
2851        impl<$t: $constraint> ::core::fmt::Debug for $struct_name<$t> {
2852            fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
2853                write!(f, "{}", self)
2854            }
2855        }
2856
2857        impl<$t: $constraint> Hash for $struct_name<$t> {
2858            fn hash<H: Hasher>(&self, state: &mut H) {
2859                self.$gl_id_field.hash(state);
2860            }
2861        }
2862
2863        impl<$t: $constraint> PartialEq for $struct_name<$t> {
2864            fn eq(&self, other: &$struct_name<$t>) -> bool {
2865                self.$gl_id_field == other.$gl_id_field
2866            }
2867        }
2868
2869        impl<$t: $constraint> Eq for $struct_name<$t> {}
2870
2871        impl<$t: $constraint> PartialOrd for $struct_name<$t> {
2872            fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
2873                Some((self.$gl_id_field).cmp(&(other.$gl_id_field)))
2874            }
2875        }
2876
2877        impl<$t: $constraint> Ord for $struct_name<$t> {
2878            fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
2879                (self.$gl_id_field).cmp(&(other.$gl_id_field))
2880            }
2881        }
2882    };
2883}
2884
2885impl_traits_for_gl_object!(Texture, texture_id);
2886
2887impl Drop for Texture {
2888    fn drop(&mut self) {
2889        self.run_destructor = false;
2890        let copies = unsafe { (*self.refcount).fetch_sub(1, AtomicOrdering::SeqCst) };
2891        if copies == 1 {
2892            let _ = unsafe { Box::from_raw(self.refcount as *mut AtomicUsize) };
2893            self.gl_context
2894                .delete_textures((&[self.texture_id])[..].into());
2895        }
2896    }
2897}
2898
2899/// Describes the vertex layout and offsets
2900#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2901#[repr(C)]
2902pub struct VertexLayout {
2903    pub fields: VertexAttributeVec,
2904}
2905
2906impl_vec!(VertexAttribute, VertexAttributeVec, VertexAttributeVecDestructor, VertexAttributeVecDestructorType, VertexAttributeVecSlice, OptionVertexAttribute);
2907impl_vec_debug!(VertexAttribute, VertexAttributeVec);
2908impl_vec_partialord!(VertexAttribute, VertexAttributeVec);
2909impl_vec_ord!(VertexAttribute, VertexAttributeVec);
2910impl_vec_clone!(
2911    VertexAttribute,
2912    VertexAttributeVec,
2913    VertexAttributeVecDestructor
2914);
2915impl_vec_partialeq!(VertexAttribute, VertexAttributeVec);
2916impl_vec_eq!(VertexAttribute, VertexAttributeVec);
2917impl_vec_hash!(VertexAttribute, VertexAttributeVec);
2918
2919impl VertexLayout {
2920    /// Submits the vertex buffer description to OpenGL
2921    pub fn bind(&self, gl_context: &Rc<GenericGlContext>, program_id: GLuint) {
2922        const VERTICES_ARE_NORMALIZED: bool = false;
2923
2924        let mut offset = 0;
2925
2926        let stride_between_vertices: usize =
2927            self.fields.iter().map(VertexAttribute::get_stride).sum();
2928
2929        for vertex_attribute in self.fields.iter() {
2930            let attribute_location = vertex_attribute
2931                .layout_location
2932                .as_option()
2933                .map(|ll| *ll as i32)
2934                .unwrap_or_else(|| {
2935                    gl_context
2936                        .get_attrib_location(program_id, vertex_attribute.va_name.as_str().into())
2937                });
2938
2939            gl_context.vertex_attrib_pointer(
2940                attribute_location as u32,
2941                vertex_attribute.item_count as i32,
2942                vertex_attribute.attribute_type.get_gl_id(),
2943                VERTICES_ARE_NORMALIZED,
2944                stride_between_vertices as i32,
2945                offset as u32,
2946            );
2947            gl_context.enable_vertex_attrib_array(attribute_location as u32);
2948            offset += vertex_attribute.get_stride();
2949        }
2950    }
2951
2952    /// Unsets the vertex buffer description
2953    pub fn unbind(&self, gl_context: &Rc<GenericGlContext>, program_id: GLuint) {
2954        for vertex_attribute in self.fields.iter() {
2955            let attribute_location = vertex_attribute
2956                .layout_location
2957                .as_option()
2958                .map(|ll| *ll as i32)
2959                .unwrap_or_else(|| {
2960                    gl_context
2961                        .get_attrib_location(program_id, vertex_attribute.va_name.as_str().into())
2962                });
2963            gl_context.disable_vertex_attrib_array(attribute_location as u32);
2964        }
2965    }
2966}
2967
2968#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2969#[repr(C)]
2970pub struct VertexAttribute {
2971    /// Attribute name of the vertex attribute in the vertex shader, i.e. `"vAttrXY"`
2972    pub va_name: AzString,
2973    /// If the vertex shader has a specific location, (like `layout(location = 2) vAttrXY`),
2974    /// use this instead of the name to look up the uniform location.
2975    pub layout_location: OptionUsize,
2976    /// Type of items of this attribute (i.e. for a `FloatVec2`, would be
2977    /// `VertexAttributeType::Float`)
2978    pub attribute_type: VertexAttributeType,
2979    /// Number of items of this attribute (i.e. for a `FloatVec2`, would be `2` (= 2 consecutive
2980    /// f32 values))
2981    pub item_count: usize,
2982}
2983
2984impl_option!(
2985    VertexAttribute,
2986    OptionVertexAttribute,
2987    copy = false,
2988    [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
2989);
2990
2991impl VertexAttribute {
2992    pub fn get_stride(&self) -> usize {
2993        self.attribute_type.get_mem_size() * self.item_count
2994    }
2995}
2996
2997#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
2998#[repr(C)]
2999pub enum VertexAttributeType {
3000    /// Vertex attribute has type `f32`
3001    Float,
3002    /// Vertex attribute has type `f64`
3003    Double,
3004    /// Vertex attribute has type `u8`
3005    UnsignedByte,
3006    /// Vertex attribute has type `u16`
3007    UnsignedShort,
3008    /// Vertex attribute has type `u32`
3009    UnsignedInt,
3010}
3011
3012impl VertexAttributeType {
3013    /// Returns the OpenGL id for the vertex attribute type, ex. `gl::UNSIGNED_BYTE` for
3014    /// `VertexAttributeType::UnsignedByte`.
3015    pub fn get_gl_id(&self) -> GLuint {
3016        use self::VertexAttributeType::*;
3017        match self {
3018            Float => gl::FLOAT,
3019            Double => gl::DOUBLE,
3020            UnsignedByte => gl::UNSIGNED_BYTE,
3021            UnsignedShort => gl::UNSIGNED_SHORT,
3022            UnsignedInt => gl::UNSIGNED_INT,
3023        }
3024    }
3025
3026    pub fn get_mem_size(&self) -> usize {
3027        use core::mem;
3028
3029        use self::VertexAttributeType::*;
3030        match self {
3031            Float => mem::size_of::<f32>(),
3032            Double => mem::size_of::<f64>(),
3033            UnsignedByte => mem::size_of::<u8>(),
3034            UnsignedShort => mem::size_of::<u16>(),
3035            UnsignedInt => mem::size_of::<u32>(),
3036        }
3037    }
3038}
3039
3040pub trait VertexLayoutDescription {
3041    fn get_description() -> VertexLayout;
3042}
3043
3044#[derive(Debug, PartialEq, PartialOrd)]
3045#[repr(C)]
3046pub struct VertexArrayObject {
3047    pub vertex_layout: VertexLayout,
3048    pub vao_id: GLuint,
3049    pub gl_context: GlContextPtr,
3050    pub refcount: *const AtomicUsize,
3051    pub run_destructor: bool,
3052}
3053
3054impl VertexArrayObject {
3055    pub fn new(vertex_layout: VertexLayout, vao_id: GLuint, gl_context: GlContextPtr) -> Self {
3056        Self {
3057            vertex_layout,
3058            vao_id,
3059            gl_context,
3060            refcount: Box::into_raw(Box::new(AtomicUsize::new(1))),
3061            run_destructor: true,
3062        }
3063    }
3064}
3065
3066impl Clone for VertexArrayObject {
3067    fn clone(&self) -> Self {
3068        unsafe { (*self.refcount).fetch_add(1, AtomicOrdering::SeqCst) };
3069        Self {
3070            vertex_layout: self.vertex_layout.clone(),
3071            vao_id: self.vao_id,
3072            gl_context: self.gl_context.clone(),
3073            refcount: self.refcount,
3074            run_destructor: true,
3075        }
3076    }
3077}
3078
3079impl Drop for VertexArrayObject {
3080    fn drop(&mut self) {
3081        self.run_destructor = false;
3082        let copies = unsafe { (*self.refcount).fetch_sub(1, AtomicOrdering::SeqCst) };
3083        if copies == 1 {
3084            let _ = unsafe { Box::from_raw(self.refcount as *mut AtomicUsize) };
3085            self.gl_context
3086                .delete_vertex_arrays((&[self.vao_id])[..].into());
3087        }
3088    }
3089}
3090
3091#[repr(C)]
3092pub struct VertexBuffer {
3093    pub vao: VertexArrayObject,
3094    pub vertex_buffer_id: GLuint,
3095    pub vertex_buffer_len: usize,
3096    pub index_buffer_id: GLuint,
3097    pub index_buffer_len: usize,
3098    pub refcount: *const AtomicUsize,
3099    pub index_buffer_format: IndexBufferFormat,
3100    pub run_destructor: bool,
3101}
3102
3103impl core::fmt::Display for VertexBuffer {
3104    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
3105        write!(
3106            f,
3107            "VertexBuffer {{ buffer: {} (length: {}) }})",
3108            self.vertex_buffer_id, self.vertex_buffer_len
3109        )
3110    }
3111}
3112
3113impl_traits_for_gl_object!(VertexBuffer, vertex_buffer_id);
3114
3115impl Clone for VertexBuffer {
3116    fn clone(&self) -> Self {
3117        unsafe { (*self.refcount).fetch_add(1, AtomicOrdering::SeqCst) };
3118        Self {
3119            vao: self.vao.clone(),
3120            vertex_buffer_id: self.vertex_buffer_id.clone(),
3121            vertex_buffer_len: self.vertex_buffer_len.clone(),
3122            index_buffer_id: self.index_buffer_id.clone(),
3123            index_buffer_len: self.index_buffer_len.clone(),
3124            refcount: self.refcount,
3125            index_buffer_format: self.index_buffer_format.clone(),
3126            run_destructor: true,
3127        }
3128    }
3129}
3130
3131impl Drop for VertexBuffer {
3132    fn drop(&mut self) {
3133        self.run_destructor = false;
3134        let copies = unsafe { (*self.refcount).fetch_sub(1, AtomicOrdering::SeqCst) };
3135        if copies == 1 {
3136            self.vao.vertex_layout = VertexLayout {
3137                fields: VertexAttributeVec::from_const_slice(&[]),
3138            };
3139            let _ = unsafe { Box::from_raw(self.refcount as *mut AtomicUsize) };
3140            self.vao
3141                .gl_context
3142                .delete_buffers((&[self.vertex_buffer_id, self.index_buffer_id])[..].into());
3143        }
3144    }
3145}
3146
3147impl VertexBuffer {
3148    pub fn new<T: VertexLayoutDescription>(
3149        gl_context: GlContextPtr,
3150        shader_program_id: GLuint,
3151        vertices: &[T],
3152        indices: &[u32],
3153        index_buffer_format: IndexBufferFormat,
3154    ) -> Self {
3155        use core::mem;
3156
3157        // Save the OpenGL state
3158        let mut current_vertex_array = [0_i32];
3159
3160        gl_context.get_integer_v(gl::VERTEX_ARRAY, (&mut current_vertex_array[..]).into());
3161
3162        let vertex_array_object = gl_context.gen_vertex_arrays(1);
3163        let vertex_array_object = vertex_array_object.get(0).unwrap();
3164
3165        let vertex_buffer_id = gl_context.gen_buffers(1);
3166        let vertex_buffer_id = vertex_buffer_id.get(0).unwrap();
3167
3168        let index_buffer_id = gl_context.gen_buffers(1);
3169        let index_buffer_id = index_buffer_id.get(0).unwrap();
3170
3171        gl_context.bind_vertex_array(*vertex_array_object);
3172
3173        // Upload vertex data to GPU
3174        gl_context.bind_buffer(gl::ARRAY_BUFFER, *vertex_buffer_id);
3175        gl_context.buffer_data_untyped(
3176            gl::ARRAY_BUFFER,
3177            (mem::size_of::<T>() * vertices.len()) as isize,
3178            GlVoidPtrConst {
3179                ptr: vertices.as_ptr() as *const core::ffi::c_void,
3180                run_destructor: true,
3181            },
3182            gl::STATIC_DRAW,
3183        );
3184
3185        // Generate the index buffer + upload data
3186        gl_context.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, *index_buffer_id);
3187        gl_context.buffer_data_untyped(
3188            gl::ELEMENT_ARRAY_BUFFER,
3189            (mem::size_of::<u32>() * indices.len()) as isize,
3190            GlVoidPtrConst {
3191                ptr: indices.as_ptr() as *const core::ffi::c_void,
3192                run_destructor: true,
3193            },
3194            gl::STATIC_DRAW,
3195        );
3196
3197        let vertex_description = T::get_description();
3198        vertex_description.bind(&gl_context.ptr.ptr, shader_program_id);
3199
3200        // Reset the OpenGL state
3201        gl_context.bind_vertex_array(current_vertex_array[0] as u32);
3202
3203        Self::new_raw(
3204            *vertex_buffer_id,
3205            vertices.len(),
3206            VertexArrayObject::new(vertex_description, *vertex_array_object, gl_context),
3207            *index_buffer_id,
3208            indices.len(),
3209            index_buffer_format,
3210        )
3211    }
3212
3213    pub fn new_raw(
3214        vertex_buffer_id: GLuint,
3215        vertex_buffer_len: usize,
3216        vao: VertexArrayObject,
3217        index_buffer_id: GLuint,
3218        index_buffer_len: usize,
3219        index_buffer_format: IndexBufferFormat,
3220    ) -> Self {
3221        Self {
3222            vertex_buffer_id,
3223            vertex_buffer_len,
3224            vao,
3225            index_buffer_id,
3226            index_buffer_len,
3227            index_buffer_format,
3228            refcount: Box::into_raw(Box::new(AtomicUsize::new(1))),
3229            run_destructor: true,
3230        }
3231    }
3232}
3233
3234#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3235pub enum GlApiVersion {
3236    Gl { major: usize, minor: usize },
3237    GlEs { major: usize, minor: usize },
3238}
3239
3240impl GlApiVersion {
3241    /// Returns the OpenGL version of the context
3242    pub fn get(gl_context: &GlContextPtr) -> Self {
3243        let mut major = [0];
3244        gl_context.get_integer_v(gl::MAJOR_VERSION, (&mut major[..]).into());
3245        let mut minor = [0];
3246        gl_context.get_integer_v(gl::MINOR_VERSION, (&mut minor[..]).into());
3247
3248        let major = major[0] as usize;
3249        let minor = minor[0] as usize;
3250
3251        match gl_context.get_type() {
3252            GlType::Gl => GlApiVersion::Gl { major, minor },
3253            GlType::Gles => GlApiVersion::GlEs { major, minor },
3254        }
3255    }
3256}
3257
3258#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3259#[repr(C)]
3260pub enum IndexBufferFormat {
3261    Points,
3262    Lines,
3263    LineStrip,
3264    Triangles,
3265    TriangleStrip,
3266    TriangleFan,
3267}
3268
3269impl IndexBufferFormat {
3270    /// Returns the `gl::TRIANGLE_STRIP` / `gl::POINTS`, etc.
3271    pub fn get_gl_id(&self) -> GLuint {
3272        use self::IndexBufferFormat::*;
3273        match self {
3274            Points => gl::POINTS,
3275            Lines => gl::LINES,
3276            LineStrip => gl::LINE_STRIP,
3277            Triangles => gl::TRIANGLES,
3278            TriangleStrip => gl::TRIANGLE_STRIP,
3279            TriangleFan => gl::TRIANGLE_FAN,
3280        }
3281    }
3282}
3283
3284#[derive(Debug, Clone, PartialEq, PartialOrd)]
3285#[repr(C)]
3286pub struct Uniform {
3287    pub uniform_name: AzString,
3288    pub uniform_type: UniformType,
3289}
3290
3291impl Uniform {
3292    pub fn create<S: Into<AzString>>(name: S, uniform_type: UniformType) -> Self {
3293        Self {
3294            uniform_name: name.into(),
3295            uniform_type,
3296        }
3297    }
3298}
3299
3300#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
3301#[repr(C, u8)]
3302pub enum UniformType {
3303    Float(f32),
3304    FloatVec2([f32; 2]),
3305    FloatVec3([f32; 3]),
3306    FloatVec4([f32; 4]),
3307    Int(i32),
3308    IntVec2([i32; 2]),
3309    IntVec3([i32; 3]),
3310    IntVec4([i32; 4]),
3311    UnsignedInt(u32),
3312    UnsignedIntVec2([u32; 2]),
3313    UnsignedIntVec3([u32; 3]),
3314    UnsignedIntVec4([u32; 4]),
3315    Matrix2 {
3316        transpose: bool,
3317        matrix: [f32; 2 * 2],
3318    },
3319    Matrix3 {
3320        transpose: bool,
3321        matrix: [f32; 3 * 3],
3322    },
3323    Matrix4 {
3324        transpose: bool,
3325        matrix: [f32; 4 * 4],
3326    },
3327}
3328
3329impl UniformType {
3330    /// Set a specific uniform
3331    pub fn set(self, gl_context: &Rc<GenericGlContext>, location: GLint) {
3332        use self::UniformType::*;
3333        match self {
3334            Float(r) => gl_context.uniform_1f(location, r),
3335            FloatVec2([r, g]) => gl_context.uniform_2f(location, r, g),
3336            FloatVec3([r, g, b]) => gl_context.uniform_3f(location, r, g, b),
3337            FloatVec4([r, g, b, a]) => gl_context.uniform_4f(location, r, g, b, a),
3338            Int(r) => gl_context.uniform_1i(location, r),
3339            IntVec2([r, g]) => gl_context.uniform_2i(location, r, g),
3340            IntVec3([r, g, b]) => gl_context.uniform_3i(location, r, g, b),
3341            IntVec4([r, g, b, a]) => gl_context.uniform_4i(location, r, g, b, a),
3342            UnsignedInt(r) => gl_context.uniform_1ui(location, r),
3343            UnsignedIntVec2([r, g]) => gl_context.uniform_2ui(location, r, g),
3344            UnsignedIntVec3([r, g, b]) => gl_context.uniform_3ui(location, r, g, b),
3345            UnsignedIntVec4([r, g, b, a]) => gl_context.uniform_4ui(location, r, g, b, a),
3346            Matrix2 { transpose, matrix } => {
3347                gl_context.uniform_matrix_2fv(location, transpose, &matrix[..])
3348            }
3349            Matrix3 { transpose, matrix } => {
3350                gl_context.uniform_matrix_3fv(location, transpose, &matrix[..])
3351            }
3352            Matrix4 { transpose, matrix } => {
3353                gl_context.uniform_matrix_4fv(location, transpose, &matrix[..])
3354            }
3355        }
3356    }
3357}
3358
3359#[repr(C)]
3360pub struct GlShader {
3361    pub program_id: GLuint,
3362    pub gl_context: GlContextPtr,
3363}
3364
3365impl ::core::fmt::Display for GlShader {
3366    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
3367        write!(f, "GlShader {{ program_id: {} }}", self.program_id)
3368    }
3369}
3370
3371impl_traits_for_gl_object!(GlShader, program_id);
3372
3373impl Drop for GlShader {
3374    fn drop(&mut self) {
3375        self.gl_context.delete_program(self.program_id);
3376    }
3377}
3378
3379#[repr(C)]
3380#[derive(Clone)]
3381pub struct VertexShaderCompileError {
3382    pub error_id: i32,
3383    pub info_log: AzString,
3384}
3385
3386impl_traits_for_gl_object!(VertexShaderCompileError, error_id);
3387
3388impl ::core::fmt::Display for VertexShaderCompileError {
3389    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
3390        write!(f, "E{}: {}", self.error_id, self.info_log)
3391    }
3392}
3393
3394#[repr(C)]
3395#[derive(Clone)]
3396pub struct FragmentShaderCompileError {
3397    pub error_id: i32,
3398    pub info_log: AzString,
3399}
3400
3401impl_traits_for_gl_object!(FragmentShaderCompileError, error_id);
3402
3403impl ::core::fmt::Display for FragmentShaderCompileError {
3404    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
3405        write!(f, "E{}: {}", self.error_id, self.info_log)
3406    }
3407}
3408
3409#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
3410pub enum GlShaderCompileError {
3411    Vertex(VertexShaderCompileError),
3412    Fragment(FragmentShaderCompileError),
3413}
3414
3415impl ::core::fmt::Display for GlShaderCompileError {
3416    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
3417        use self::GlShaderCompileError::*;
3418        match self {
3419            Vertex(vert_err) => write!(f, "Failed to compile vertex shader: {}", vert_err),
3420            Fragment(frag_err) => write!(f, "Failed to compile fragment shader: {}", frag_err),
3421        }
3422    }
3423}
3424
3425impl ::core::fmt::Debug for GlShaderCompileError {
3426    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
3427        write!(f, "{}", self)
3428    }
3429}
3430
3431#[repr(C)]
3432#[derive(Clone)]
3433pub struct GlShaderLinkError {
3434    pub error_id: i32,
3435    pub info_log: AzString,
3436}
3437
3438impl_traits_for_gl_object!(GlShaderLinkError, error_id);
3439
3440impl ::core::fmt::Display for GlShaderLinkError {
3441    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
3442        write!(f, "E{}: {}", self.error_id, self.info_log)
3443    }
3444}
3445
3446#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
3447pub enum GlShaderCreateError {
3448    Compile(GlShaderCompileError),
3449    Link(GlShaderLinkError),
3450    NoShaderCompiler,
3451}
3452
3453impl ::core::fmt::Display for GlShaderCreateError {
3454    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
3455        use self::GlShaderCreateError::*;
3456        match self {
3457            Compile(compile_err) => write!(f, "Shader compile error: {}", compile_err),
3458            Link(link_err) => write!(f, "Shader linking error: {}", link_err),
3459            NoShaderCompiler => {
3460                write!(f, "OpenGL implementation doesn't include a shader compiler")
3461            }
3462        }
3463    }
3464}
3465
3466impl ::core::fmt::Debug for GlShaderCreateError {
3467    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
3468        write!(f, "{}", self)
3469    }
3470}
3471
3472impl GlShader {
3473    /// Compiles and creates a new OpenGL shader, created from a vertex and a fragment shader
3474    /// string.
3475    ///
3476    /// If the shader fails to compile, the shader object gets automatically deleted, no cleanup
3477    /// necessary.
3478    pub fn new(
3479        gl_context: &GlContextPtr,
3480        vertex_shader: &str,
3481        fragment_shader: &str,
3482    ) -> Result<Self, GlShaderCreateError> {
3483        // Check whether the OpenGL implementation supports a shader compiler...
3484        let mut shader_compiler_supported = [gl::FALSE as u8];
3485        gl_context.get_boolean_v(
3486            gl::SHADER_COMPILER,
3487            (&mut shader_compiler_supported[..]).into(),
3488        );
3489        if u32::from(shader_compiler_supported[0]) == gl::FALSE {
3490            // Implementation only supports binary shaders
3491            return Err(GlShaderCreateError::NoShaderCompiler);
3492        }
3493
3494        // Compile vertex shader
3495
3496        let vertex_shader_object = gl_context.create_shader(gl::VERTEX_SHADER);
3497        gl_context.shader_source(
3498            vertex_shader_object,
3499            vec![AzString::from(vertex_shader.to_string())].into(),
3500        );
3501        gl_context.compile_shader(vertex_shader_object);
3502
3503        if let Some(error_id) = get_gl_shader_error(&gl_context, vertex_shader_object) {
3504            let info_log = gl_context.get_shader_info_log(vertex_shader_object);
3505            gl_context.delete_shader(vertex_shader_object);
3506            return Err(GlShaderCreateError::Compile(GlShaderCompileError::Vertex(
3507                VertexShaderCompileError {
3508                    error_id,
3509                    info_log: info_log.into(),
3510                },
3511            )));
3512        }
3513
3514        // Compile fragment shader
3515
3516        let fragment_shader_object = gl_context.create_shader(gl::FRAGMENT_SHADER);
3517        gl_context.shader_source(
3518            fragment_shader_object,
3519            vec![AzString::from(fragment_shader.to_string())].into(),
3520        );
3521        gl_context.compile_shader(fragment_shader_object);
3522
3523        if let Some(error_id) = get_gl_shader_error(&gl_context, fragment_shader_object) {
3524            let info_log = gl_context.get_shader_info_log(fragment_shader_object);
3525            gl_context.delete_shader(vertex_shader_object);
3526            gl_context.delete_shader(fragment_shader_object);
3527            return Err(GlShaderCreateError::Compile(
3528                GlShaderCompileError::Fragment(FragmentShaderCompileError {
3529                    error_id,
3530                    info_log: info_log.into(),
3531                }),
3532            ));
3533        }
3534
3535        // Link program
3536
3537        let program_id = gl_context.create_program();
3538        gl_context.attach_shader(program_id, vertex_shader_object);
3539        gl_context.attach_shader(program_id, fragment_shader_object);
3540        gl_context.link_program(program_id);
3541
3542        if let Some(error_id) = get_gl_program_error(&gl_context, program_id) {
3543            let info_log = gl_context.get_program_info_log(program_id);
3544            gl_context.delete_shader(vertex_shader_object);
3545            gl_context.delete_shader(fragment_shader_object);
3546            gl_context.delete_program(program_id);
3547            return Err(GlShaderCreateError::Link(GlShaderLinkError {
3548                error_id,
3549                info_log: info_log.into(),
3550            }));
3551        }
3552
3553        gl_context.delete_shader(vertex_shader_object);
3554        gl_context.delete_shader(fragment_shader_object);
3555
3556        Ok(GlShader {
3557            program_id,
3558            gl_context: gl_context.clone(),
3559        })
3560    }
3561
3562    /// Draws vertex buffers, index buffers + uniforms to the texture
3563    pub fn draw(
3564        // shader to use for drawing
3565        shader_program_id: GLuint,
3566        // note: texture is &mut so the texture is reusable -
3567        texture: &mut Texture,
3568        // buffers + uniforms to draw
3569        buffers: &[(&VertexBuffer, &[Uniform])],
3570    ) {
3571        use alloc::collections::btree_map::BTreeMap;
3572
3573        const INDEX_TYPE: GLuint = gl::UNSIGNED_INT;
3574
3575        let texture_size = texture.size;
3576
3577        let gl_context = &texture.gl_context;
3578
3579        let saved = GlStateSave::save(gl_context);
3580
3581        // save draw()-specific state not covered by GlStateSave
3582        let mut current_blend_enabled = [0_u8];
3583        let mut current_primitive_restart_enabled = [0_u8];
3584        gl_context.get_boolean_v(gl::BLEND, (&mut current_blend_enabled[..]).into());
3585        gl_context.get_boolean_v(
3586            gl::PRIMITIVE_RESTART,
3587            (&mut current_primitive_restart_enabled[..]).into(),
3588        );
3589
3590        // 1. Create the framebuffer
3591        let framebuffers = gl_context.gen_framebuffers(1);
3592        let framebuffer_id = framebuffers.get(0).unwrap();
3593        gl_context.bind_framebuffer(gl::FRAMEBUFFER, *framebuffer_id);
3594
3595        let depthbuffers = gl_context.gen_renderbuffers(1);
3596        let depthbuffer_id = depthbuffers.get(0).unwrap();
3597
3598        gl_context.bind_texture(gl::TEXTURE_2D, texture.texture_id);
3599        gl_context.tex_image_2d(
3600            gl::TEXTURE_2D,
3601            0,
3602            gl::RGBA as i32, // NOT RGBA8 - will generate INVALID_ENUM!
3603            texture_size.width as i32,
3604            texture_size.height as i32,
3605            0,
3606            gl::RGBA, // gl::BGRA?
3607            gl::UNSIGNED_BYTE,
3608            None.into(),
3609        );
3610        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
3611        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
3612        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
3613        gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
3614
3615        gl_context.bind_renderbuffer(gl::RENDERBUFFER, *depthbuffer_id);
3616        gl_context.renderbuffer_storage(
3617            gl::RENDERBUFFER,
3618            gl::DEPTH_COMPONENT,
3619            texture_size.width as i32,
3620            texture_size.height as i32,
3621        );
3622        gl_context.framebuffer_renderbuffer(
3623            gl::FRAMEBUFFER,
3624            gl::DEPTH_ATTACHMENT,
3625            gl::RENDERBUFFER,
3626            *depthbuffer_id,
3627        );
3628
3629        gl_context.framebuffer_texture_2d(
3630            gl::FRAMEBUFFER,
3631            gl::COLOR_ATTACHMENT0,
3632            gl::TEXTURE_2D,
3633            texture.texture_id,
3634            0,
3635        );
3636        gl_context.draw_buffers([gl::COLOR_ATTACHMENT0][..].into());
3637
3638        #[cfg(feature = "std")]
3639        {
3640            let fb_check = gl_context.check_frame_buffer_status(gl::FRAMEBUFFER);
3641            match fb_check {
3642                gl::FRAMEBUFFER_COMPLETE => {}
3643                gl::FRAMEBUFFER_UNDEFINED => {
3644                    println!("GL_FRAMEBUFFER_UNDEFINED");
3645                }
3646                gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => {
3647                    println!("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
3648                }
3649                gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
3650                    println!("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
3651                }
3652                gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => {
3653                    println!("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
3654                }
3655                gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => {
3656                    println!("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
3657                }
3658                gl::FRAMEBUFFER_UNSUPPORTED => {
3659                    println!("GL_FRAMEBUFFER_UNSUPPORTED");
3660                }
3661                gl::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => {
3662                    println!("GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE");
3663                }
3664                gl::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS => {
3665                    println!("GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS");
3666                }
3667                o => {
3668                    println!("glFramebufferStatus returned unknown return code: {}", o);
3669                }
3670            }
3671        }
3672
3673        gl_context.viewport(0, 0, texture_size.width as i32, texture_size.height as i32);
3674        gl_context.enable(gl::BLEND);
3675        // Use GL_PRIMITIVE_RESTART (OpenGL 3.1+) instead of
3676        // GL_PRIMITIVE_RESTART_FIXED_INDEX (4.3+) for macOS compatibility.
3677        gl_context.enable(gl::PRIMITIVE_RESTART);
3678        unsafe {
3679            let gl = gl_context.get();
3680            if gl.glPrimitiveRestartIndex != core::ptr::null_mut() {
3681                let func: extern "system" fn(u32) =
3682                    core::mem::transmute(gl.glPrimitiveRestartIndex);
3683                func(GL_RESTART_INDEX); // u32::MAX
3684            }
3685        }
3686        gl_context.disable(gl::MULTISAMPLE);
3687        gl_context.blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); // TODO: enable / disable
3688        gl_context.use_program(shader_program_id);
3689
3690        // Avoid multiple calls to get_uniform_location by caching the uniform locations
3691        let mut uniform_locations: BTreeMap<AzString, i32> = BTreeMap::new();
3692        let mut max_uniform_len = 0;
3693        for (_, uniforms) in buffers {
3694            for uniform in uniforms.iter() {
3695                if !uniform_locations.contains_key(&uniform.uniform_name) {
3696                    uniform_locations.insert(
3697                        uniform.uniform_name.clone(),
3698                        gl_context.get_uniform_location(
3699                            shader_program_id,
3700                            uniform.uniform_name.as_str().into(),
3701                        ),
3702                    );
3703                }
3704            }
3705            max_uniform_len = max_uniform_len.max(uniforms.len());
3706        }
3707        let mut current_uniforms = vec![None; max_uniform_len];
3708
3709        // Since the description of the vertex buffers is always the same,
3710        // only the first layer needs to bind its VAO
3711
3712        // Draw the actual layers
3713        for (vertex_index_buffer, uniforms) in buffers {
3714            gl_context.bind_vertex_array(vertex_index_buffer.vao.vao_id);
3715            gl_context.bind_buffer(gl::ARRAY_BUFFER, vertex_index_buffer.vertex_buffer_id);
3716            gl_context.bind_buffer(
3717                gl::ELEMENT_ARRAY_BUFFER,
3718                vertex_index_buffer.index_buffer_id,
3719            );
3720
3721            // Only set the uniform if the value has changed
3722            for (uniform_index, uniform) in uniforms.iter().enumerate() {
3723                if current_uniforms[uniform_index] != Some(uniform.uniform_type) {
3724                    let uniform_location = uniform_locations[&uniform.uniform_name];
3725                    uniform.uniform_type.set(gl_context.get(), uniform_location);
3726                    current_uniforms[uniform_index] = Some(uniform.uniform_type);
3727                }
3728            }
3729
3730            gl_context.draw_elements(
3731                vertex_index_buffer.index_buffer_format.get_gl_id(),
3732                vertex_index_buffer.index_buffer_len as i32,
3733                INDEX_TYPE,
3734                0,
3735            );
3736        }
3737
3738        // Reset draw()-specific state
3739        if u32::from(current_blend_enabled[0]) == gl::FALSE {
3740            gl_context.disable(gl::BLEND);
3741        }
3742        if u32::from(current_primitive_restart_enabled[0]) == gl::FALSE {
3743            gl_context.disable(gl::PRIMITIVE_RESTART);
3744        }
3745
3746        gl_context.delete_framebuffers((&[*framebuffer_id])[..].into());
3747        gl_context.delete_renderbuffers((&[*depthbuffer_id])[..].into());
3748
3749        // Reset common GL state
3750        saved.restore(gl_context);
3751
3752        texture.format = RawImageFormat::RGBA8;
3753        texture.flags = TextureFlags {
3754            is_opaque: false,
3755            is_video_texture: false,
3756        };
3757    }
3758}
3759
3760fn get_gl_shader_error(context: &GlContextPtr, shader_object: GLuint) -> Option<i32> {
3761    let mut err = [0];
3762    context.get_shader_iv(shader_object, gl::COMPILE_STATUS, (&mut err[..]).into());
3763    let err_code = err[0];
3764    if err_code == gl::TRUE as i32 {
3765        None
3766    } else {
3767        Some(err_code)
3768    }
3769}
3770
3771fn get_gl_program_error(context: &GlContextPtr, shader_object: GLuint) -> Option<i32> {
3772    let mut err = [0];
3773    context.get_program_iv(shader_object, gl::LINK_STATUS, (&mut err[..]).into());
3774    let err_code = err[0];
3775    if err_code == gl::TRUE as i32 {
3776        None
3777    } else {
3778        Some(err_code)
3779    }
3780}