1#![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 mem::ManuallyDrop,
15 sync::atomic::{AtomicUsize, Ordering as AtomicOrdering},
16};
17
18use azul_css::{
19 props::{
20 basic::{ColorF, ColorU},
21 style::StyleTransformVec,
22 },
23 AzString, OptionI32, OptionU32, OptionUsize, StringVec, U8Vec,
24};
25pub use gl_context_loader::{
26 ctypes::*, gl, GLeglImageOES, GLsync, GLvoid, GenericGlContext, GlType as GlContextGlType,
27};
28
29pub use crate::glconst::*;
30use crate::{
31 geom::PhysicalSizeU32,
32 hit_test::DocumentId,
33 resources::{
34 Brush, Epoch, ExternalImageId, ImageDescriptor, ImageDescriptorFlags, RawImage,
35 RawImageData, RawImageFormat,
36 },
37 svg::{TessellatedGPUSvgNode, TessellatedSvgNode},
38 window::RendererType,
39 OrderedMap,
40};
41
42pub type GLuint = u32;
43pub type GLint = i32;
44pub type GLint64 = i64;
45pub type GLuint64 = u64;
46pub type GLenum = u32;
47pub type GLintptr = isize;
48pub type GLboolean = u8;
49pub type GLsizeiptr = isize;
50pub type GLbitfield = u32;
51pub type GLsizei = i32;
52pub type GLclampf = f32;
53pub type GLfloat = f32;
54
55pub const GL_RESTART_INDEX: u32 = core::u32::MAX;
56
57#[repr(C)]
60#[derive(Debug)]
61pub struct GlVoidPtrConst {
62 pub ptr: *const GLvoid,
63 pub run_destructor: bool,
64}
65
66impl Clone for GlVoidPtrConst {
67 fn clone(&self) -> Self {
68 Self {
69 ptr: self.ptr,
70 run_destructor: true,
71 }
72 }
73}
74
75impl Drop for GlVoidPtrConst {
76 fn drop(&mut self) {
77 self.run_destructor = false;
78 }
79}
80
81#[repr(C)]
86#[derive(Debug)]
87pub struct GlVoidPtrMut {
88 pub ptr: *mut GLvoid,
89}
90
91impl Clone for GlVoidPtrMut {
92 fn clone(&self) -> Self {
93 Self { ptr: self.ptr }
94 }
95}
96
97#[repr(C)]
99pub struct Refstr {
100 pub ptr: *const u8,
101 pub len: usize,
102}
103
104impl Clone for Refstr {
105 fn clone(&self) -> Self {
106 Self {
107 ptr: self.ptr,
108 len: self.len,
109 }
110 }
111}
112
113impl fmt::Debug for Refstr {
114 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115 self.as_str().fmt(f)
116 }
117}
118
119impl Refstr {
120 #[must_use] pub const fn as_str(&self) -> &str {
121 if self.ptr.is_null() || self.len == 0 {
125 return "";
126 }
127 unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(self.ptr, self.len)) }
128 }
129}
130
131impl From<&str> for Refstr {
132 fn from(s: &str) -> Self {
133 Self {
134 ptr: s.as_ptr(),
135 len: s.len(),
136 }
137 }
138}
139
140#[repr(C)]
142pub struct RefstrVecRef {
143 pub ptr: *const Refstr,
144 pub len: usize,
145}
146
147impl Clone for RefstrVecRef {
148 fn clone(&self) -> Self {
149 Self {
150 ptr: self.ptr,
151 len: self.len,
152 }
153 }
154}
155
156impl fmt::Debug for RefstrVecRef {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 self.as_slice().fmt(f)
159 }
160}
161
162impl RefstrVecRef {
163 #[must_use] pub const fn as_slice(&self) -> &[Refstr] {
164 if self.ptr.is_null() || self.len == 0 {
166 return &[];
167 }
168 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
169 }
170}
171
172impl From<&[Refstr]> for RefstrVecRef {
173 fn from(s: &[Refstr]) -> Self {
174 Self {
175 ptr: s.as_ptr(),
176 len: s.len(),
177 }
178 }
179}
180
181#[repr(C)]
183pub struct GLint64VecRefMut {
184 pub ptr: *mut i64,
185 pub len: usize,
186}
187
188impl Clone for GLint64VecRefMut {
189 fn clone(&self) -> Self {
190 Self {
191 ptr: self.ptr,
192 len: self.len,
193 }
194 }
195}
196
197impl fmt::Debug for GLint64VecRefMut {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 self.as_slice().fmt(f)
200 }
201}
202
203impl From<&mut [GLint64]> for GLint64VecRefMut {
204 fn from(s: &mut [GLint64]) -> Self {
205 Self {
206 ptr: s.as_mut_ptr(),
207 len: s.len(),
208 }
209 }
210}
211
212impl GLint64VecRefMut {
213 #[must_use] pub const fn as_slice(&self) -> &[GLint64] {
214 if self.ptr.is_null() || self.len == 0 {
216 return &[];
217 }
218 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
219 }
220 const fn as_mut_slice(&mut self) -> &mut [GLint64] {
221 if self.ptr.is_null() || self.len == 0 {
223 return &mut [];
224 }
225 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
226 }
227}
228
229#[repr(C)]
231pub struct GLfloatVecRefMut {
232 pub ptr: *mut f32,
233 pub len: usize,
234}
235
236impl Clone for GLfloatVecRefMut {
237 fn clone(&self) -> Self {
238 Self {
239 ptr: self.ptr,
240 len: self.len,
241 }
242 }
243}
244
245impl fmt::Debug for GLfloatVecRefMut {
246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247 self.as_slice().fmt(f)
248 }
249}
250
251impl From<&mut [GLfloat]> for GLfloatVecRefMut {
252 fn from(s: &mut [GLfloat]) -> Self {
253 Self {
254 ptr: s.as_mut_ptr(),
255 len: s.len(),
256 }
257 }
258}
259
260impl GLfloatVecRefMut {
261 #[must_use] pub const fn as_slice(&self) -> &[GLfloat] {
262 if self.ptr.is_null() || self.len == 0 {
264 return &[];
265 }
266 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
267 }
268 const fn as_mut_slice(&mut self) -> &mut [GLfloat] {
269 if self.ptr.is_null() || self.len == 0 {
271 return &mut [];
272 }
273 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
274 }
275}
276
277#[repr(C)]
279pub struct GLintVecRefMut {
280 pub ptr: *mut i32,
281 pub len: usize,
282}
283
284impl Clone for GLintVecRefMut {
285 fn clone(&self) -> Self {
286 Self {
287 ptr: self.ptr,
288 len: self.len,
289 }
290 }
291}
292
293impl fmt::Debug for GLintVecRefMut {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 self.as_slice().fmt(f)
296 }
297}
298
299impl From<&mut [GLint]> for GLintVecRefMut {
300 fn from(s: &mut [GLint]) -> Self {
301 Self {
302 ptr: s.as_mut_ptr(),
303 len: s.len(),
304 }
305 }
306}
307
308impl GLintVecRefMut {
309 #[must_use] pub const fn as_slice(&self) -> &[GLint] {
310 if self.ptr.is_null() || self.len == 0 {
312 return &[];
313 }
314 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
315 }
316 const fn as_mut_slice(&mut self) -> &mut [GLint] {
317 if self.ptr.is_null() || self.len == 0 {
319 return &mut [];
320 }
321 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
322 }
323}
324
325#[repr(C)]
327pub struct GLuintVecRef {
328 pub ptr: *const u32,
329 pub len: usize,
330}
331
332impl Clone for GLuintVecRef {
333 fn clone(&self) -> Self {
334 Self {
335 ptr: self.ptr,
336 len: self.len,
337 }
338 }
339}
340
341impl fmt::Debug for GLuintVecRef {
342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
343 self.as_slice().fmt(f)
344 }
345}
346
347impl From<&[GLuint]> for GLuintVecRef {
348 fn from(s: &[GLuint]) -> Self {
349 Self {
350 ptr: s.as_ptr(),
351 len: s.len(),
352 }
353 }
354}
355
356impl GLuintVecRef {
357 #[must_use] pub const fn as_slice(&self) -> &[GLuint] {
358 if self.ptr.is_null() || self.len == 0 {
360 return &[];
361 }
362 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
363 }
364}
365
366#[repr(C)]
368pub struct GLenumVecRef {
369 pub ptr: *const u32,
370 pub len: usize,
371}
372
373impl Clone for GLenumVecRef {
374 fn clone(&self) -> Self {
375 Self {
376 ptr: self.ptr,
377 len: self.len,
378 }
379 }
380}
381
382impl fmt::Debug for GLenumVecRef {
383 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384 self.as_slice().fmt(f)
385 }
386}
387
388impl From<&[GLenum]> for GLenumVecRef {
389 fn from(s: &[GLenum]) -> Self {
390 Self {
391 ptr: s.as_ptr(),
392 len: s.len(),
393 }
394 }
395}
396
397impl GLenumVecRef {
398 #[must_use] pub const fn as_slice(&self) -> &[GLenum] {
399 if self.ptr.is_null() || self.len == 0 {
401 return &[];
402 }
403 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
404 }
405}
406
407#[repr(C)]
409pub struct U8VecRef {
410 pub ptr: *const u8,
411 pub len: usize,
412}
413
414impl Clone for U8VecRef {
415 fn clone(&self) -> Self {
416 Self {
417 ptr: self.ptr,
418 len: self.len,
419 }
420 }
421}
422
423impl From<&[u8]> for U8VecRef {
424 fn from(s: &[u8]) -> Self {
425 Self {
426 ptr: s.as_ptr(),
427 len: s.len(),
428 }
429 }
430}
431
432impl U8VecRef {
433 #[must_use] pub const fn as_slice(&self) -> &[u8] {
434 if self.ptr.is_null() || self.len == 0 {
436 return &[];
437 }
438 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
439 }
440}
441
442impl fmt::Debug for U8VecRef {
443 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444 self.as_slice().fmt(f)
445 }
446}
447
448impl PartialOrd for U8VecRef {
449 fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
450 self.as_slice().partial_cmp(rhs.as_slice())
451 }
452}
453
454impl Ord for U8VecRef {
455 fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
456 self.as_slice().cmp(rhs.as_slice())
457 }
458}
459
460impl PartialEq for U8VecRef {
461 fn eq(&self, rhs: &Self) -> bool {
462 self.as_slice().eq(rhs.as_slice())
463 }
464}
465
466impl Eq for U8VecRef {}
467
468impl Hash for U8VecRef {
469 fn hash<H>(&self, state: &mut H)
470 where
471 H: Hasher,
472 {
473 self.as_slice().hash(state);
474 }
475}
476
477#[repr(C)]
479pub struct F32VecRef {
480 pub ptr: *const f32,
481 pub len: usize,
482}
483
484impl Clone for F32VecRef {
485 fn clone(&self) -> Self {
486 Self {
487 ptr: self.ptr,
488 len: self.len,
489 }
490 }
491}
492
493impl fmt::Debug for F32VecRef {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 self.as_slice().fmt(f)
496 }
497}
498
499impl From<&[f32]> for F32VecRef {
500 fn from(s: &[f32]) -> Self {
501 Self {
502 ptr: s.as_ptr(),
503 len: s.len(),
504 }
505 }
506}
507
508impl F32VecRef {
509 #[must_use] pub const fn as_slice(&self) -> &[f32] {
510 if self.ptr.is_null() || self.len == 0 {
512 return &[];
513 }
514 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
515 }
516}
517
518#[repr(C)]
520pub struct I32VecRef {
521 pub ptr: *const i32,
522 pub len: usize,
523}
524
525impl Clone for I32VecRef {
526 fn clone(&self) -> Self {
527 Self {
528 ptr: self.ptr,
529 len: self.len,
530 }
531 }
532}
533
534impl fmt::Debug for I32VecRef {
535 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
536 self.as_slice().fmt(f)
537 }
538}
539
540impl From<&[i32]> for I32VecRef {
541 fn from(s: &[i32]) -> Self {
542 Self {
543 ptr: s.as_ptr(),
544 len: s.len(),
545 }
546 }
547}
548
549impl I32VecRef {
550 #[must_use] pub const fn as_slice(&self) -> &[i32] {
551 if self.ptr.is_null() || self.len == 0 {
553 return &[];
554 }
555 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
556 }
557}
558
559#[repr(C)]
561pub struct GLbooleanVecRefMut {
562 pub ptr: *mut u8,
563 pub len: usize,
564}
565
566impl Clone for GLbooleanVecRefMut {
567 fn clone(&self) -> Self {
568 Self {
569 ptr: self.ptr,
570 len: self.len,
571 }
572 }
573}
574
575impl fmt::Debug for GLbooleanVecRefMut {
576 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
577 self.as_slice().fmt(f)
578 }
579}
580
581impl From<&mut [GLboolean]> for GLbooleanVecRefMut {
582 fn from(s: &mut [GLboolean]) -> Self {
583 Self {
584 ptr: s.as_mut_ptr(),
585 len: s.len(),
586 }
587 }
588}
589
590impl GLbooleanVecRefMut {
591 #[must_use] pub const fn as_slice(&self) -> &[GLboolean] {
592 if self.ptr.is_null() || self.len == 0 {
594 return &[];
595 }
596 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
597 }
598 const fn as_mut_slice(&mut self) -> &mut [GLboolean] {
599 if self.ptr.is_null() || self.len == 0 {
601 return &mut [];
602 }
603 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
604 }
605}
606
607#[repr(C)]
609pub struct U8VecRefMut {
610 pub ptr: *mut u8,
611 pub len: usize,
612}
613
614impl Clone for U8VecRefMut {
615 fn clone(&self) -> Self {
616 Self {
617 ptr: self.ptr,
618 len: self.len,
619 }
620 }
621}
622
623impl fmt::Debug for U8VecRefMut {
624 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
625 self.as_slice().fmt(f)
626 }
627}
628
629impl From<&mut [u8]> for U8VecRefMut {
630 fn from(s: &mut [u8]) -> Self {
631 Self {
632 ptr: s.as_mut_ptr(),
633 len: s.len(),
634 }
635 }
636}
637
638impl U8VecRefMut {
639 #[must_use] pub const fn as_slice(&self) -> &[u8] {
640 if self.ptr.is_null() || self.len == 0 {
642 return &[];
643 }
644 unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
645 }
646 const fn as_mut_slice(&mut self) -> &mut [u8] {
647 if self.ptr.is_null() || self.len == 0 {
649 return &mut [];
650 }
651 unsafe { core::slice::from_raw_parts_mut(self.ptr, self.len) }
652 }
653}
654
655impl_option!(
656 U8VecRef,
657 OptionU8VecRef,
658 copy = false,
659 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
660);
661
662#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
663#[repr(C)]
664pub struct DebugMessage {
665 pub message: AzString,
666 pub source: GLenum,
667 pub ty: GLenum,
668 pub id: GLenum,
669 pub severity: GLenum,
670}
671
672impl_option!(
673 DebugMessage,
674 OptionDebugMessage,
675 copy = false,
676 [Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash]
677);
678
679impl_vec!(DebugMessage, DebugMessageVec, DebugMessageVecDestructor, DebugMessageVecDestructorType, DebugMessageVecSlice, OptionDebugMessage);
680impl_vec_debug!(DebugMessage, DebugMessageVec);
681impl_vec_partialord!(DebugMessage, DebugMessageVec);
682impl_vec_ord!(DebugMessage, DebugMessageVec);
683impl_vec_clone!(DebugMessage, DebugMessageVec, DebugMessageVecDestructor);
684impl_vec_partialeq!(DebugMessage, DebugMessageVec);
685impl_vec_eq!(DebugMessage, DebugMessageVec);
686impl_vec_hash!(DebugMessage, DebugMessageVec);
687
688impl_vec!(GLint, GLintVec, GLintVecDestructor, GLintVecDestructorType, GLintVecSlice, OptionI32);
689impl_vec_debug!(GLint, GLintVec);
690impl_vec_partialord!(GLint, GLintVec);
691impl_vec_ord!(GLint, GLintVec);
692impl_vec_clone!(GLint, GLintVec, GLintVecDestructor);
693impl_vec_partialeq!(GLint, GLintVec);
694impl_vec_eq!(GLint, GLintVec);
695impl_vec_hash!(GLint, GLintVec);
696
697impl_vec!(GLuint, GLuintVec, GLuintVecDestructor, GLuintVecDestructorType, GLuintVecSlice, OptionU32);
698impl_vec_debug!(GLuint, GLuintVec);
699impl_vec_partialord!(GLuint, GLuintVec);
700impl_vec_ord!(GLuint, GLuintVec);
701impl_vec_clone!(GLuint, GLuintVec, GLuintVecDestructor);
702impl_vec_partialeq!(GLuint, GLuintVec);
703impl_vec_eq!(GLuint, GLuintVec);
704impl_vec_hash!(GLuint, GLuintVec);
705
706#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
707#[repr(C)]
708pub enum GlType {
709 Gl,
710 Gles,
711}
712
713impl From<GlContextGlType> for GlType {
714 fn from(a: GlContextGlType) -> Self {
715 match a {
716 GlContextGlType::Gl => Self::Gl,
717 GlContextGlType::GlEs => Self::Gles,
718 }
719 }
720}
721
722#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
724#[repr(C)]
725#[allow(clippy::pub_underscore_fields)]
727pub struct GetProgramBinaryReturn {
728 pub _0: U8Vec,
729 pub _1: u32,
730}
731
732#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
734#[repr(C)]
735#[allow(clippy::pub_underscore_fields)]
737pub struct GetActiveAttribReturn {
738 pub _0: i32,
739 pub _1: u32,
740 pub _2: AzString,
741}
742
743#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
745#[repr(C)]
746#[allow(clippy::pub_underscore_fields)]
748pub struct GetActiveUniformReturn {
749 pub _0: i32,
750 pub _1: u32,
751 pub _2: AzString,
752}
753
754#[repr(C)]
755pub struct GLsyncPtr {
756 pub ptr: *const c_void, pub run_destructor: bool,
758}
759
760impl Clone for GLsyncPtr {
761 fn clone(&self) -> Self {
762 Self {
763 ptr: self.ptr,
764 run_destructor: true,
765 }
766 }
767}
768
769impl fmt::Debug for GLsyncPtr {
770 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
771 write!(f, "0x{:0x}", self.ptr as usize)
772 }
773}
774
775impl GLsyncPtr {
776 #[must_use] pub const fn new(p: GLsync) -> Self {
777 Self {
778 ptr: p,
779 run_destructor: true,
780 }
781 }
782 #[must_use] pub fn get(self) -> GLsync {
783 self.ptr as GLsync
784 }
785}
786
787impl Drop for GLsyncPtr {
788 fn drop(&mut self) {
789 self.run_destructor = false;
790 }
791}
792
793pub type GlTextureStorage = OrderedMap<Epoch, OrderedMap<ExternalImageId, Texture>>;
796
797static mut ACTIVE_GL_TEXTURES: Option<OrderedMap<DocumentId, GlTextureStorage>> = None;
814
815#[inline]
826#[allow(clippy::deref_addrof)] fn active_gl_textures() -> &'static mut Option<OrderedMap<DocumentId, GlTextureStorage>> {
828 unsafe { &mut *(&raw mut ACTIVE_GL_TEXTURES) }
831}
832
833#[must_use]
842pub fn insert_into_active_gl_textures(
843 document_id: DocumentId,
844 epoch: Epoch,
845 texture: Texture,
846) -> ExternalImageId {
847 let external_image_id = ExternalImageId::new();
848
849 let active = active_gl_textures();
850 if active.is_none() {
851 *active = Some(OrderedMap::new());
852 }
853 let active_textures = active.as_mut().unwrap();
854 let active_epochs = active_textures.entry(document_id).or_default();
855 let active_textures_for_epoch = active_epochs.entry(epoch).or_default();
856 active_textures_for_epoch.insert(external_image_id, texture);
857
858 external_image_id
859}
860
861pub fn gl_textures_remove_epochs_from_pipeline(document_id: &DocumentId, epoch: Epoch) {
864 let Some(active_textures) = active_gl_textures().as_mut() else {
866 return;
867 };
868
869 let Some(active_epochs) = active_textures.get_mut(document_id) else {
870 return;
871 };
872
873 let mut epochs_to_remove = Vec::new();
876
877 for (gl_texture_epoch, _) in active_epochs.iter() {
878 if *gl_texture_epoch < epoch {
879 epochs_to_remove.push(*gl_texture_epoch);
880 }
881 }
882
883 for epoch in epochs_to_remove {
884 active_epochs.remove(&epoch);
885 }
886}
887
888#[must_use] pub fn remove_single_texture_from_active_gl_textures(
890 document_id: &DocumentId,
891 epoch: &Epoch,
892 external_image_id: &ExternalImageId,
893) -> Option<()> {
894 let active_textures = active_gl_textures().as_mut()?;
895 let epochs = active_textures.get_mut(document_id)?;
896 let images_in_epoch = epochs.get_mut(epoch)?;
897 images_in_epoch.remove(external_image_id);
898 Some(())
899}
900
901pub fn gl_textures_remove_active_pipeline(document_id: &DocumentId) {
903 let Some(active_textures) = active_gl_textures().as_mut() else {
904 return;
905 };
906 active_textures.remove(document_id);
907}
908
909#[allow(clippy::cast_precision_loss)] pub fn gl_textures_clear_opengl_cache() {
912 *active_gl_textures() = None;
913}
914
915#[allow(clippy::cast_precision_loss)] #[must_use] pub fn get_opengl_texture(image_key: &ExternalImageId) -> Option<(GLuint, (f32, f32))> {
927 let active_textures = active_gl_textures().as_ref()?;
928 active_textures
929 .values()
930 .flat_map(|active_document| active_document.values())
931 .find_map(|active_epoch| active_epoch.get(image_key))
932 .map(|tex| {
933 (
934 tex.texture_id,
935 (tex.size.width as f32, tex.size.height as f32),
936 )
937 })
938}
939
940#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd)]
942#[repr(C)]
943#[allow(clippy::pub_underscore_fields)]
945pub struct GlShaderPrecisionFormatReturn {
946 pub _0: GLint,
947 pub _1: GLint,
948 pub _2: GLint,
949}
950
951#[repr(C)]
952pub struct GlContextPtr {
953 pub ptr: ManuallyDrop<Box<Rc<GlContextPtrInner>>>,
962 pub renderer_type: RendererType,
964 pub run_destructor: bool,
965}
966
967impl Clone for GlContextPtr {
968 fn clone(&self) -> Self {
969 Self {
970 ptr: ManuallyDrop::new((*self.ptr).clone()),
971 renderer_type: self.renderer_type,
972 run_destructor: true,
973 }
974 }
975}
976
977impl Drop for GlContextPtr {
978 fn drop(&mut self) {
979 if self.run_destructor {
984 self.run_destructor = false;
985 unsafe { ManuallyDrop::drop(&mut self.ptr); }
986 }
987 }
988}
989
990impl GlContextPtr {
991 #[must_use] pub fn get_svg_shader(&self) -> GLuint {
992 self.ptr.svg_shader
993 }
994 #[must_use] pub fn is_gl_usable(&self) -> bool {
1000 self.ptr.svg_shader != 0
1001 }
1002 #[must_use] pub fn get_usable_glsl_version(&self) -> AzString {
1006 self.ptr.glsl_version.clone()
1007 }
1008 #[must_use] pub fn get_brush_shader(&self) -> GLuint {
1010 self.ptr.brush_shader
1011 }
1012 #[must_use] pub fn get_fxaa_shader(&self) -> GLuint {
1013 self.ptr.fxaa_shader
1014 }
1015}
1016
1017#[repr(C)]
1018pub struct GlContextPtrInner {
1019 pub ptr: Rc<GenericGlContext>,
1020 pub svg_shader: GLuint,
1022 pub svg_multicolor_shader: GLuint,
1024 pub fxaa_shader: GLuint,
1026 pub brush_shader: GLuint,
1028 pub glsl_version: AzString,
1031}
1032
1033impl fmt::Debug for GlContextPtrInner {
1034 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1036 f.debug_struct("GlContextPtrInner")
1037 .field("svg_shader", &self.svg_shader)
1038 .field("svg_multicolor_shader", &self.svg_multicolor_shader)
1039 .field("fxaa_shader", &self.fxaa_shader)
1040 .field("brush_shader", &self.brush_shader)
1041 .field("glsl_version", &self.glsl_version)
1042 .finish_non_exhaustive()
1043 }
1044}
1045
1046impl Drop for GlContextPtrInner {
1047 fn drop(&mut self) {
1048 self.ptr.delete_program(self.svg_shader);
1049 self.ptr.delete_program(self.svg_multicolor_shader);
1050 self.ptr.delete_program(self.fxaa_shader);
1051 if self.brush_shader != 0 {
1052 self.ptr.delete_program(self.brush_shader);
1053 }
1054 }
1055}
1056
1057impl_option!(
1058 GlContextPtr,
1059 OptionGlContextPtr,
1060 copy = false,
1061 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord]
1062);
1063
1064impl fmt::Debug for GlContextPtr {
1065 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1066 write!(f, "0x{:0x}", self.as_usize())
1067 }
1068}
1069
1070static SVG_VERTEX_SHADER: &[u8] = b"#version 150
1071
1072#if __VERSION__ != 100
1073 #define varying out
1074 #define attribute in
1075#endif
1076
1077uniform vec2 vBboxSize;
1078uniform mat4 vTransformMatrix;
1079
1080attribute vec2 vAttrXY;
1081
1082void main() {
1083 vec4 vTransposed = vec4(vAttrXY, 1.0, 1.0) * vTransformMatrix;
1084 vec2 vTransposedInScreen = vTransposed.xy / vBboxSize;
1085 vec2 vCalcFinal = (vTransposedInScreen * vec2(2.0)) - vec2(1.0);
1086 gl_Position = vec4(vCalcFinal, 1.0, 1.0);
1087}";
1088
1089static SVG_FRAGMENT_SHADER: &[u8] = b"#version 150
1090
1091precision highp float;
1092
1093uniform vec4 fDrawColor;
1094
1095#if __VERSION__ == 100
1096 #define oFragColor gl_FragColor
1097#else
1098 out vec4 oFragColor;
1099#endif
1100
1101void main() {
1102 oFragColor = fDrawColor;
1103}";
1104
1105static SVG_MULTICOLOR_VERTEX_SHADER: &[u8] = b"#version 150
1106
1107#if __VERSION__ != 100
1108 #define varying out
1109 #define attribute in
1110#endif
1111
1112uniform vec2 vBboxSize;
1113uniform mat4 vTransformMatrix;
1114
1115attribute vec3 vAttrXY;
1116attribute vec4 vColor;
1117varying vec4 fColor;
1118
1119void main() {
1120 vec4 vTransposed = vec4(vAttrXY.xy, 1.0, 1.0) * vTransformMatrix;
1121 vec2 vTransposedInScreen = vTransposed.xy / vBboxSize;
1122 vec2 vCalcFinal = (vTransposedInScreen * vec2(2.0)) - vec2(1.0);
1123 gl_Position = vec4(vCalcFinal, vAttrXY.z, 1.0);
1124 fColor = vColor;
1125}";
1126
1127static SVG_MULTICOLOR_FRAGMENT_SHADER: &[u8] = b"#version 150
1128
1129precision highp float;
1130
1131#if __VERSION__ != 100
1132 #define varying in
1133#endif
1134
1135#if __VERSION__ == 100
1136 #define oFragColor gl_FragColor
1137#else
1138 out vec4 oFragColor;
1139#endif
1140
1141varying vec4 fColor;
1142
1143void main() {
1144 oFragColor = fColor;
1145}";
1146
1147static BRUSH_VERTEX_SHADER: &[u8] = b"#version 150
1152
1153#if __VERSION__ != 100
1154 #define varying out
1155 #define attribute in
1156#endif
1157
1158attribute vec2 aPos;
1159attribute vec2 aUv;
1160varying vec2 vUv;
1161
1162void main() {
1163 vUv = aUv;
1164 gl_Position = vec4(aPos, 0.0, 1.0);
1165}";
1166
1167static BRUSH_FRAGMENT_SHADER: &[u8] = b"#version 150
1168
1169precision highp float;
1170
1171#if __VERSION__ != 100
1172 #define varying in
1173#endif
1174
1175#if __VERSION__ == 100
1176 #define oFragColor gl_FragColor
1177#else
1178 out vec4 oFragColor;
1179#endif
1180
1181uniform vec4 uColor; // rgb + alpha (alpha already folds in flow * color.a)
1182uniform float uHardness; // 0 = soft .. 1 = hard edge
1183
1184varying vec2 vUv;
1185
1186void main() {
1187 float d = length(vUv);
1188 if (d > 1.0) { discard; }
1189 float edge0 = clamp(uHardness, 0.0, 1.0);
1190 float x = clamp((d - edge0) / max(1.0 - edge0, 1.0e-4), 0.0, 1.0);
1191 float cov = 1.0 - (x * x * (3.0 - 2.0 * x));
1192 oFragColor = vec4(uColor.rgb, uColor.a * cov);
1193}";
1194
1195#[allow(dead_code)]
1199#[allow(clippy::used_underscore_binding)] #[allow(clippy::cast_possible_wrap)] fn check_shader_compile(gl_context: &GenericGlContext, shader: GLuint, _label: &str) {
1202 let mut status = [0_i32];
1203 unsafe { gl_context.get_shader_iv(shader, gl::COMPILE_STATUS, &mut status) };
1204 if status[0] != gl::TRUE as i32 {
1205 #[cfg(feature = "std")]
1206 {
1207 let log = gl_context.get_shader_info_log(shader);
1208 eprintln!("azul: {_label} shader compile error: {log}");
1209 }
1210 }
1211}
1212
1213#[allow(dead_code)]
1215#[allow(clippy::used_underscore_binding)] #[allow(clippy::cast_possible_wrap)] fn check_program_link(gl_context: &GenericGlContext, program: GLuint, _label: &str) {
1218 let mut status = [0_i32];
1219 unsafe { gl_context.get_program_iv(program, gl::LINK_STATUS, &mut status) };
1220 if status[0] != gl::TRUE as i32 {
1221 #[cfg(feature = "std")]
1222 {
1223 let log = gl_context.get_program_info_log(program);
1224 eprintln!("azul: {_label} program link error: {log}");
1225 }
1226 }
1227}
1228
1229#[cfg(feature = "std")]
1233fn shader_with_glsl_version(src: &[u8], version_line: &[u8]) -> Vec<u8> {
1234 let body_start = src.iter().position(|&b| b == b'\n').map_or(0, |i| i + 1);
1235 let mut out = Vec::with_capacity(version_line.len() + src.len() - body_start);
1236 out.extend_from_slice(version_line);
1237 out.extend_from_slice(&src[body_start..]);
1238 out
1239}
1240
1241#[cfg(feature = "std")]
1248#[allow(clippy::cast_possible_wrap)]
1250fn try_compile_program(
1251 gl_context: &GenericGlContext,
1252 vert_src: &[u8],
1253 frag_src: &[u8],
1254 version_line: &[u8],
1255 attribs: &[(u32, &str)],
1256) -> Option<GLuint> {
1257 let vs = gl_context.create_shader(gl::VERTEX_SHADER);
1258 gl_context.shader_source(vs, &[shader_with_glsl_version(vert_src, version_line).as_slice()]);
1259 gl_context.compile_shader(vs);
1260 let fs = gl_context.create_shader(gl::FRAGMENT_SHADER);
1261 gl_context.shader_source(fs, &[shader_with_glsl_version(frag_src, version_line).as_slice()]);
1262 gl_context.compile_shader(fs);
1263
1264 let mut s = [0_i32];
1265 unsafe { gl_context.get_shader_iv(vs, gl::COMPILE_STATUS, &mut s) };
1266 let vs_ok = s[0] == gl::TRUE as i32;
1267 unsafe { gl_context.get_shader_iv(fs, gl::COMPILE_STATUS, &mut s) };
1268 let fs_ok = s[0] == gl::TRUE as i32;
1269 if !vs_ok || !fs_ok {
1270 gl_context.delete_shader(vs);
1271 gl_context.delete_shader(fs);
1272 return None;
1273 }
1274
1275 let prog = gl_context.create_program();
1276 gl_context.attach_shader(prog, vs);
1277 gl_context.attach_shader(prog, fs);
1278 for (loc, name) in attribs {
1279 gl_context.bind_attrib_location(prog, *loc, name);
1280 }
1281 gl_context.link_program(prog);
1282 gl_context.delete_shader(vs);
1283 gl_context.delete_shader(fs);
1284
1285 let mut l = [0_i32];
1286 unsafe { gl_context.get_program_iv(prog, gl::LINK_STATUS, &mut l) };
1287 if l[0] == gl::TRUE as i32 {
1288 Some(prog)
1289 } else {
1290 gl_context.delete_program(prog);
1291 None
1292 }
1293}
1294
1295const fn glsl_version_candidates(gl_type: GlType) -> &'static [&'static [u8]] {
1298 match gl_type {
1299 GlType::Gl => &[b"#version 150\n", b"#version 330\n", b"#version 140\n"],
1300 GlType::Gles => &[b"#version 300 es\n", b"#version 100\n"],
1301 }
1302}
1303
1304impl GlContextPtr {
1305 #[must_use] pub fn new(renderer_type: RendererType, gl_context: Rc<GenericGlContext>) -> Self {
1306 #[cfg(feature = "std")]
1317 let (svg_program_id, svg_multicolor_program_id, fxaa_program_id, brush_program_id, glsl_version) =
1318 if matches!(renderer_type, RendererType::Hardware) {
1319 use crate::gl_fxaa::{FXAA_FRAGMENT_SHADER, FXAA_VERTEX_SHADER};
1320 let gl_type: GlType = gl_context.get_type().into();
1321 let mut svg = 0;
1323 let mut chosen: Option<&'static [u8]> = None;
1324 for ver in glsl_version_candidates(gl_type) {
1325 if let Some(p) = try_compile_program(
1326 &gl_context, SVG_VERTEX_SHADER, SVG_FRAGMENT_SHADER, ver, &[(0, "vAttrXY")],
1327 ) {
1328 svg = p;
1329 chosen = Some(ver);
1330 break;
1331 }
1332 }
1333 chosen.map_or_else(|| {
1334 eprintln!(
1335 "azul: GL context UNUSABLE -- no GLSL version ({gl_type:?}) compiled the SVG \
1336 shaders; the window should fall back to CPU rendering (is_gl_usable()=false)"
1337 );
1338 (0, 0, 0, 0, AzString::from_const_str(""))
1339 }, |ver| {
1340 let ver_str: AzString = core::str::from_utf8(ver)
1342 .unwrap_or("")
1343 .trim()
1344 .trim_start_matches("#version ")
1345 .into();
1346 eprintln!(
1347 "azul: GL usable -- shaders compiled at GLSL {} ({:?})",
1348 ver_str.as_str(),
1349 gl_type
1350 );
1351 let mc = try_compile_program(
1352 &gl_context, SVG_MULTICOLOR_VERTEX_SHADER, SVG_MULTICOLOR_FRAGMENT_SHADER,
1353 ver, &[(0, "vAttrXY"), (1, "vColor")],
1354 ).unwrap_or(0);
1355 let fxaa = try_compile_program(
1356 &gl_context, FXAA_VERTEX_SHADER, FXAA_FRAGMENT_SHADER, ver, &[(0, "vAttrXY")],
1357 ).unwrap_or(0);
1358 let brush = try_compile_program(
1359 &gl_context, BRUSH_VERTEX_SHADER, BRUSH_FRAGMENT_SHADER, ver,
1360 &[(0, "aPos"), (1, "aUv")],
1361 ).unwrap_or(0);
1362 (svg, mc, fxaa, brush, ver_str)
1363 })
1364 } else {
1365 (0, 0, 0, 0, AzString::from_const_str(""))
1366 };
1367 #[cfg(not(feature = "std"))]
1369 let (svg_program_id, svg_multicolor_program_id, fxaa_program_id, brush_program_id, glsl_version) =
1370 (0u32, 0u32, 0u32, 0u32, AzString::from_const_str(""));
1371
1372
1373 Self {
1374 ptr: ManuallyDrop::new(Box::new(Rc::new(GlContextPtrInner {
1375 svg_shader: svg_program_id,
1376 svg_multicolor_shader: svg_multicolor_program_id,
1377 fxaa_shader: fxaa_program_id,
1378 brush_shader: brush_program_id,
1379 glsl_version,
1380 ptr: gl_context,
1381 }))),
1382 renderer_type,
1383 run_destructor: true,
1384 }
1385 }
1386
1387 #[must_use] pub fn get(&self) -> &Rc<GenericGlContext> {
1388 &self.ptr.ptr
1389 }
1390 fn as_usize(&self) -> usize {
1391 (Rc::as_ptr(&self.ptr.ptr) as *const c_void) as usize
1392 }
1393}
1394
1395#[allow(clippy::needless_pass_by_value)]
1400impl GlContextPtr {
1401 #[must_use] pub fn get_type(&self) -> GlType {
1402 self.get().get_type().into()
1403 }
1404 pub fn buffer_data_untyped(
1405 &self,
1406 target: GLenum,
1407 size: GLsizeiptr,
1408 data: GlVoidPtrConst,
1409 usage: GLenum,
1410 ) {
1411 self.get()
1412 .buffer_data_untyped(target, size, data.ptr, usage);
1413 }
1414 pub fn buffer_sub_data_untyped(
1415 &self,
1416 target: GLenum,
1417 offset: isize,
1418 size: GLsizeiptr,
1419 data: GlVoidPtrConst,
1420 ) {
1421 self.get()
1422 .buffer_sub_data_untyped(target, offset, size, data.ptr);
1423 }
1424 #[must_use] pub fn map_buffer(&self, target: GLenum, access: GLbitfield) -> GlVoidPtrMut {
1425 GlVoidPtrMut {
1426 ptr: self.get().map_buffer(target, access),
1427 }
1428 }
1429 #[must_use] pub fn map_buffer_range(
1430 &self,
1431 target: GLenum,
1432 offset: GLintptr,
1433 length: GLsizeiptr,
1434 access: GLbitfield,
1435 ) -> GlVoidPtrMut {
1436 GlVoidPtrMut {
1437 ptr: self.get().map_buffer_range(target, offset, length, access),
1438 }
1439 }
1440 #[must_use] pub fn unmap_buffer(&self, target: GLenum) -> GLboolean {
1441 self.get().unmap_buffer(target)
1442 }
1443 pub fn tex_buffer(&self, target: GLenum, internal_format: GLenum, buffer: GLuint) {
1444 self.get().tex_buffer(target, internal_format, buffer);
1445 }
1446 pub fn shader_source(&self, shader: GLuint, strings: StringVec) {
1447 fn str_to_bytes(input: &str) -> Vec<u8> {
1448 let mut v: Vec<u8> = input.into();
1449 v.push(0);
1450 v
1451 }
1452 let shaders_as_bytes = strings
1453 .iter()
1454 .map(|s| str_to_bytes(s.as_str()))
1455 .collect::<Vec<_>>();
1456 let shaders_as_bytes = shaders_as_bytes
1457 .iter()
1458 .map(AsRef::as_ref)
1459 .collect::<Vec<_>>();
1460 self.get().shader_source(shader, &shaders_as_bytes);
1461 }
1462 pub fn read_buffer(&self, mode: GLenum) {
1463 self.get().read_buffer(mode);
1464 }
1465 pub fn read_pixels_into_buffer(
1466 &self,
1467 x: GLint,
1468 y: GLint,
1469 width: GLsizei,
1470 height: GLsizei,
1471 format: GLenum,
1472 pixel_type: GLenum,
1473 mut dst_buffer: U8VecRefMut,
1474 ) {
1475 self.get().read_pixels_into_buffer(
1476 x,
1477 y,
1478 width,
1479 height,
1480 format,
1481 pixel_type,
1482 dst_buffer.as_mut_slice(),
1483 );
1484 }
1485 #[must_use] pub fn read_pixels(
1486 &self,
1487 x: GLint,
1488 y: GLint,
1489 width: GLsizei,
1490 height: GLsizei,
1491 format: GLenum,
1492 pixel_type: GLenum,
1493 ) -> U8Vec {
1494 let channels: usize = match format {
1501 0x1903 | 0x1906 | 0x1909 | 0x1902 | 0x1901 | 0x8D94 => 1,
1503 0x8227 | 0x190A | 0x8228 | 0x84F9 => 2,
1505 0x1907 | 0x80E0 | 0x8D98 => 3,
1507 _ => 4,
1509 };
1510 let bytes_per_component: usize = match pixel_type {
1511 0x1400 | 0x1401 => 1, 0x1402 | 0x1403 | 0x140B => 2, _ => 4, };
1515 #[allow(clippy::cast_sign_loss)]
1517 let len = (width.max(0) as usize)
1518 .saturating_mul(height.max(0) as usize)
1519 .saturating_mul(channels)
1520 .saturating_mul(bytes_per_component);
1521 let mut buf = vec![0u8; len];
1522 self.get().read_pixels_into_buffer(
1523 x,
1524 y,
1525 width,
1526 height,
1527 format,
1528 pixel_type,
1529 buf.as_mut_slice(),
1530 );
1531 buf.into()
1532 }
1533 pub fn read_pixels_into_pbo(
1534 &self,
1535 x: GLint,
1536 y: GLint,
1537 width: GLsizei,
1538 height: GLsizei,
1539 format: GLenum,
1540 pixel_type: GLenum,
1541 ) {
1542 unsafe {
1543 self.get()
1544 .read_pixels_into_pbo(x, y, width, height, format, pixel_type);
1545 }
1546 }
1547 pub fn sample_coverage(&self, value: GLclampf, invert: bool) {
1548 self.get().sample_coverage(value, invert);
1549 }
1550 pub fn polygon_offset(&self, factor: GLfloat, units: GLfloat) {
1551 self.get().polygon_offset(factor, units);
1552 }
1553 pub fn pixel_store_i(&self, name: GLenum, param: GLint) {
1554 self.get().pixel_store_i(name, param);
1555 }
1556 #[must_use] pub fn gen_buffers(&self, n: GLsizei) -> GLuintVec {
1557 self.get().gen_buffers(n).into()
1558 }
1559 #[must_use] pub fn gen_renderbuffers(&self, n: GLsizei) -> GLuintVec {
1560 self.get().gen_renderbuffers(n).into()
1561 }
1562 #[must_use] pub fn gen_framebuffers(&self, n: GLsizei) -> GLuintVec {
1563 self.get().gen_framebuffers(n).into()
1564 }
1565 #[must_use] pub fn gen_textures(&self, n: GLsizei) -> GLuintVec {
1566 self.get().gen_textures(n).into()
1567 }
1568 #[must_use] pub fn gen_vertex_arrays(&self, n: GLsizei) -> GLuintVec {
1569 self.get().gen_vertex_arrays(n).into()
1570 }
1571 #[must_use] pub fn gen_queries(&self, n: GLsizei) -> GLuintVec {
1572 self.get().gen_queries(n).into()
1573 }
1574 pub fn begin_query(&self, target: GLenum, id: GLuint) {
1575 self.get().begin_query(target, id);
1576 }
1577 pub fn end_query(&self, target: GLenum) {
1578 self.get().end_query(target);
1579 }
1580 pub fn query_counter(&self, id: GLuint, target: GLenum) {
1581 self.get().query_counter(id, target);
1582 }
1583 #[must_use] pub fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32 {
1584 self.get().get_query_object_iv(id, pname)
1585 }
1586 #[must_use] pub fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32 {
1587 self.get().get_query_object_uiv(id, pname)
1588 }
1589 #[must_use] pub fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64 {
1590 self.get().get_query_object_i64v(id, pname)
1591 }
1592 #[must_use] pub fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64 {
1593 self.get().get_query_object_ui64v(id, pname)
1594 }
1595 pub fn delete_queries(&self, queries: GLuintVecRef) {
1596 self.get().delete_queries(queries.as_slice());
1597 }
1598 pub fn delete_vertex_arrays(&self, vertex_arrays: GLuintVecRef) {
1599 self.get().delete_vertex_arrays(vertex_arrays.as_slice());
1600 }
1601 pub fn delete_buffers(&self, buffers: GLuintVecRef) {
1602 self.get().delete_buffers(buffers.as_slice());
1603 }
1604 pub fn delete_renderbuffers(&self, renderbuffers: GLuintVecRef) {
1605 self.get().delete_renderbuffers(renderbuffers.as_slice());
1606 }
1607 pub fn delete_framebuffers(&self, framebuffers: GLuintVecRef) {
1608 self.get().delete_framebuffers(framebuffers.as_slice());
1609 }
1610 pub fn delete_textures(&self, textures: GLuintVecRef) {
1611 self.get().delete_textures(textures.as_slice());
1612 }
1613 pub fn framebuffer_renderbuffer(
1614 &self,
1615 target: GLenum,
1616 attachment: GLenum,
1617 renderbuffertarget: GLenum,
1618 renderbuffer: GLuint,
1619 ) {
1620 self.get()
1621 .framebuffer_renderbuffer(target, attachment, renderbuffertarget, renderbuffer);
1622 }
1623 pub fn renderbuffer_storage(
1624 &self,
1625 target: GLenum,
1626 internalformat: GLenum,
1627 width: GLsizei,
1628 height: GLsizei,
1629 ) {
1630 self.get()
1631 .renderbuffer_storage(target, internalformat, width, height);
1632 }
1633 pub fn depth_func(&self, func: GLenum) {
1634 self.get().depth_func(func);
1635 }
1636 pub fn active_texture(&self, texture: GLenum) {
1637 self.get().active_texture(texture);
1638 }
1639 pub fn attach_shader(&self, program: GLuint, shader: GLuint) {
1640 self.get().attach_shader(program, shader);
1641 }
1642 pub fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) {
1643 self.get()
1644 .bind_attrib_location(program, index, name);
1645 }
1646 pub fn get_uniform_iv(&self, program: GLuint, location: GLint, mut result: GLintVecRefMut) {
1647 unsafe {
1648 self.get()
1649 .get_uniform_iv(program, location, result.as_mut_slice());
1650 }
1651 }
1652 pub fn get_uniform_fv(&self, program: GLuint, location: GLint, mut result: GLfloatVecRefMut) {
1653 unsafe {
1654 self.get()
1655 .get_uniform_fv(program, location, result.as_mut_slice());
1656 }
1657 }
1658 #[must_use] pub fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint {
1659 self.get().get_uniform_block_index(program, name)
1660 }
1661 #[must_use] pub fn get_uniform_indices(&self, program: GLuint, names: RefstrVecRef) -> GLuintVec {
1662 let names_vec = names
1663 .as_slice()
1664 .iter()
1665 .map(Refstr::as_str)
1666 .collect::<Vec<_>>();
1667 self.get().get_uniform_indices(program, &names_vec).into()
1668 }
1669 pub fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint) {
1670 self.get().bind_buffer_base(target, index, buffer);
1671 }
1672 pub fn bind_buffer_range(
1673 &self,
1674 target: GLenum,
1675 index: GLuint,
1676 buffer: GLuint,
1677 offset: GLintptr,
1678 size: GLsizeiptr,
1679 ) {
1680 self.get()
1681 .bind_buffer_range(target, index, buffer, offset, size);
1682 }
1683 pub fn uniform_block_binding(
1684 &self,
1685 program: GLuint,
1686 uniform_block_index: GLuint,
1687 uniform_block_binding: GLuint,
1688 ) {
1689 self.get()
1690 .uniform_block_binding(program, uniform_block_index, uniform_block_binding);
1691 }
1692 pub fn bind_buffer(&self, target: GLenum, buffer: GLuint) {
1693 self.get().bind_buffer(target, buffer);
1694 }
1695 pub fn bind_vertex_array(&self, vao: GLuint) {
1696 self.get().bind_vertex_array(vao);
1697 }
1698 pub fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint) {
1699 self.get().bind_renderbuffer(target, renderbuffer);
1700 }
1701 pub fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint) {
1702 self.get().bind_framebuffer(target, framebuffer);
1703 }
1704 pub fn bind_texture(&self, target: GLenum, texture: GLuint) {
1705 self.get().bind_texture(target, texture);
1706 }
1707 pub fn draw_buffers(&self, bufs: GLenumVecRef) {
1708 self.get().draw_buffers(bufs.as_slice());
1709 }
1710 pub fn tex_image_2d(
1711 &self,
1712 target: GLenum,
1713 level: GLint,
1714 internal_format: GLint,
1715 width: GLsizei,
1716 height: GLsizei,
1717 border: GLint,
1718 format: GLenum,
1719 ty: GLenum,
1720 opt_data: OptionU8VecRef,
1721 ) {
1722 let opt_data = opt_data.as_option();
1723 let opt_data: Option<&[u8]> = opt_data.map(U8VecRef::as_slice);
1724 self.get().tex_image_2d(
1725 target,
1726 level,
1727 internal_format,
1728 width,
1729 height,
1730 border,
1731 format,
1732 ty,
1733 opt_data,
1734 );
1735 }
1736 pub fn compressed_tex_image_2d(
1737 &self,
1738 target: GLenum,
1739 level: GLint,
1740 internal_format: GLenum,
1741 width: GLsizei,
1742 height: GLsizei,
1743 border: GLint,
1744 data: U8VecRef,
1745 ) {
1746 self.get().compressed_tex_image_2d(
1747 target,
1748 level,
1749 internal_format,
1750 width,
1751 height,
1752 border,
1753 data.as_slice(),
1754 );
1755 }
1756 pub fn compressed_tex_sub_image_2d(
1757 &self,
1758 target: GLenum,
1759 level: GLint,
1760 xoffset: GLint,
1761 yoffset: GLint,
1762 width: GLsizei,
1763 height: GLsizei,
1764 format: GLenum,
1765 data: U8VecRef,
1766 ) {
1767 self.get().compressed_tex_sub_image_2d(
1768 target,
1769 level,
1770 xoffset,
1771 yoffset,
1772 width,
1773 height,
1774 format,
1775 data.as_slice(),
1776 );
1777 }
1778 pub fn tex_image_3d(
1779 &self,
1780 target: GLenum,
1781 level: GLint,
1782 internal_format: GLint,
1783 width: GLsizei,
1784 height: GLsizei,
1785 depth: GLsizei,
1786 border: GLint,
1787 format: GLenum,
1788 ty: GLenum,
1789 opt_data: OptionU8VecRef,
1790 ) {
1791 let opt_data = opt_data.as_option();
1792 let opt_data: Option<&[u8]> = opt_data.map(U8VecRef::as_slice);
1793 self.get().tex_image_3d(
1794 target,
1795 level,
1796 internal_format,
1797 width,
1798 height,
1799 depth,
1800 border,
1801 format,
1802 ty,
1803 opt_data,
1804 );
1805 }
1806 pub fn copy_tex_image_2d(
1807 &self,
1808 target: GLenum,
1809 level: GLint,
1810 internal_format: GLenum,
1811 x: GLint,
1812 y: GLint,
1813 width: GLsizei,
1814 height: GLsizei,
1815 border: GLint,
1816 ) {
1817 self.get()
1818 .copy_tex_image_2d(target, level, internal_format, x, y, width, height, border);
1819 }
1820 pub fn copy_tex_sub_image_2d(
1821 &self,
1822 target: GLenum,
1823 level: GLint,
1824 xoffset: GLint,
1825 yoffset: GLint,
1826 x: GLint,
1827 y: GLint,
1828 width: GLsizei,
1829 height: GLsizei,
1830 ) {
1831 self.get()
1832 .copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height);
1833 }
1834 pub fn copy_tex_sub_image_3d(
1835 &self,
1836 target: GLenum,
1837 level: GLint,
1838 xoffset: GLint,
1839 yoffset: GLint,
1840 zoffset: GLint,
1841 x: GLint,
1842 y: GLint,
1843 width: GLsizei,
1844 height: GLsizei,
1845 ) {
1846 self.get().copy_tex_sub_image_3d(
1847 target, level, xoffset, yoffset, zoffset, x, y, width, height,
1848 );
1849 }
1850 pub fn tex_sub_image_2d(
1851 &self,
1852 target: GLenum,
1853 level: GLint,
1854 xoffset: GLint,
1855 yoffset: GLint,
1856 width: GLsizei,
1857 height: GLsizei,
1858 format: GLenum,
1859 ty: GLenum,
1860 data: U8VecRef,
1861 ) {
1862 self.get().tex_sub_image_2d(
1863 target,
1864 level,
1865 xoffset,
1866 yoffset,
1867 width,
1868 height,
1869 format,
1870 ty,
1871 data.as_slice(),
1872 );
1873 }
1874 pub fn tex_sub_image_2d_pbo(
1875 &self,
1876 target: GLenum,
1877 level: GLint,
1878 xoffset: GLint,
1879 yoffset: GLint,
1880 width: GLsizei,
1881 height: GLsizei,
1882 format: GLenum,
1883 ty: GLenum,
1884 offset: usize,
1885 ) {
1886 self.get().tex_sub_image_2d_pbo(
1887 target, level, xoffset, yoffset, width, height, format, ty, offset,
1888 );
1889 }
1890 pub fn tex_sub_image_3d(
1891 &self,
1892 target: GLenum,
1893 level: GLint,
1894 xoffset: GLint,
1895 yoffset: GLint,
1896 zoffset: GLint,
1897 width: GLsizei,
1898 height: GLsizei,
1899 depth: GLsizei,
1900 format: GLenum,
1901 ty: GLenum,
1902 data: U8VecRef,
1903 ) {
1904 self.get().tex_sub_image_3d(
1905 target,
1906 level,
1907 xoffset,
1908 yoffset,
1909 zoffset,
1910 width,
1911 height,
1912 depth,
1913 format,
1914 ty,
1915 data.as_slice(),
1916 );
1917 }
1918 pub fn tex_sub_image_3d_pbo(
1919 &self,
1920 target: GLenum,
1921 level: GLint,
1922 xoffset: GLint,
1923 yoffset: GLint,
1924 zoffset: GLint,
1925 width: GLsizei,
1926 height: GLsizei,
1927 depth: GLsizei,
1928 format: GLenum,
1929 ty: GLenum,
1930 offset: usize,
1931 ) {
1932 self.get().tex_sub_image_3d_pbo(
1933 target, level, xoffset, yoffset, zoffset, width, height, depth, format, ty, offset,
1934 );
1935 }
1936 pub fn tex_storage_2d(
1937 &self,
1938 target: GLenum,
1939 levels: GLint,
1940 internal_format: GLenum,
1941 width: GLsizei,
1942 height: GLsizei,
1943 ) {
1944 self.get()
1945 .tex_storage_2d(target, levels, internal_format, width, height);
1946 }
1947 pub fn tex_storage_3d(
1948 &self,
1949 target: GLenum,
1950 levels: GLint,
1951 internal_format: GLenum,
1952 width: GLsizei,
1953 height: GLsizei,
1954 depth: GLsizei,
1955 ) {
1956 self.get()
1957 .tex_storage_3d(target, levels, internal_format, width, height, depth);
1958 }
1959 pub fn get_tex_image_into_buffer(
1960 &self,
1961 target: GLenum,
1962 level: GLint,
1963 format: GLenum,
1964 ty: GLenum,
1965 mut output: U8VecRefMut,
1966 ) {
1967 self.get()
1968 .get_tex_image_into_buffer(target, level, format, ty, output.as_mut_slice());
1969 }
1970 pub fn copy_image_sub_data(
1971 &self,
1972 src_name: GLuint,
1973 src_target: GLenum,
1974 src_level: GLint,
1975 src_x: GLint,
1976 src_y: GLint,
1977 src_z: GLint,
1978 dst_name: GLuint,
1979 dst_target: GLenum,
1980 dst_level: GLint,
1981 dst_x: GLint,
1982 dst_y: GLint,
1983 dst_z: GLint,
1984 src_width: GLsizei,
1985 src_height: GLsizei,
1986 src_depth: GLsizei,
1987 ) {
1988 unsafe {
1989 self.get().copy_image_sub_data(
1990 src_name, src_target, src_level, src_x, src_y, src_z, dst_name, dst_target,
1991 dst_level, dst_x, dst_y, dst_z, src_width, src_height, src_depth,
1992 );
1993 }
1994 }
1995 pub fn invalidate_framebuffer(&self, target: GLenum, attachments: GLenumVecRef) {
1996 self.get()
1997 .invalidate_framebuffer(target, attachments.as_slice());
1998 }
1999 pub fn invalidate_sub_framebuffer(
2000 &self,
2001 target: GLenum,
2002 attachments: GLenumVecRef,
2003 xoffset: GLint,
2004 yoffset: GLint,
2005 width: GLsizei,
2006 height: GLsizei,
2007 ) {
2008 self.get().invalidate_sub_framebuffer(
2009 target,
2010 attachments.as_slice(),
2011 xoffset,
2012 yoffset,
2013 width,
2014 height,
2015 );
2016 }
2017 pub fn get_integer_v(&self, name: GLenum, mut result: GLintVecRefMut) {
2018 unsafe { self.get().get_integer_v(name, result.as_mut_slice()) }
2019 }
2020 pub fn get_integer_64v(&self, name: GLenum, mut result: GLint64VecRefMut) {
2021 unsafe { self.get().get_integer_64v(name, result.as_mut_slice()) }
2022 }
2023 pub fn get_integer_iv(&self, name: GLenum, index: GLuint, mut result: GLintVecRefMut) {
2024 unsafe {
2025 self.get()
2026 .get_integer_iv(name, index, result.as_mut_slice());
2027 }
2028 }
2029 pub fn get_integer_64iv(&self, name: GLenum, index: GLuint, mut result: GLint64VecRefMut) {
2030 unsafe {
2031 self.get()
2032 .get_integer_64iv(name, index, result.as_mut_slice());
2033 }
2034 }
2035 pub fn get_boolean_v(&self, name: GLenum, mut result: GLbooleanVecRefMut) {
2036 unsafe { self.get().get_boolean_v(name, result.as_mut_slice()) }
2037 }
2038 pub fn get_float_v(&self, name: GLenum, mut result: GLfloatVecRefMut) {
2039 unsafe { self.get().get_float_v(name, result.as_mut_slice()) }
2040 }
2041 #[must_use] pub fn get_framebuffer_attachment_parameter_iv(
2042 &self,
2043 target: GLenum,
2044 attachment: GLenum,
2045 pname: GLenum,
2046 ) -> GLint {
2047 self.get()
2048 .get_framebuffer_attachment_parameter_iv(target, attachment, pname)
2049 }
2050 #[must_use] pub fn get_renderbuffer_parameter_iv(&self, target: GLenum, pname: GLenum) -> GLint {
2051 self.get().get_renderbuffer_parameter_iv(target, pname)
2052 }
2053 #[must_use] pub fn get_tex_parameter_iv(&self, target: GLenum, name: GLenum) -> GLint {
2054 self.get().get_tex_parameter_iv(target, name)
2055 }
2056 #[must_use] pub fn get_tex_parameter_fv(&self, target: GLenum, name: GLenum) -> GLfloat {
2057 self.get().get_tex_parameter_fv(target, name)
2058 }
2059 pub fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) {
2060 self.get().tex_parameter_i(target, pname, param);
2061 }
2062 pub fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) {
2063 self.get().tex_parameter_f(target, pname, param);
2064 }
2065 pub fn framebuffer_texture_2d(
2066 &self,
2067 target: GLenum,
2068 attachment: GLenum,
2069 textarget: GLenum,
2070 texture: GLuint,
2071 level: GLint,
2072 ) {
2073 self.get()
2074 .framebuffer_texture_2d(target, attachment, textarget, texture, level);
2075 }
2076 pub fn framebuffer_texture_layer(
2077 &self,
2078 target: GLenum,
2079 attachment: GLenum,
2080 texture: GLuint,
2081 level: GLint,
2082 layer: GLint,
2083 ) {
2084 self.get()
2085 .framebuffer_texture_layer(target, attachment, texture, level, layer);
2086 }
2087 #[allow(clippy::similar_names)] pub fn blit_framebuffer(
2089 &self,
2090 src_x0: GLint,
2091 src_y0: GLint,
2092 src_x1: GLint,
2093 src_y1: GLint,
2094 dst_x0: GLint,
2095 dst_y0: GLint,
2096 dst_x1: GLint,
2097 dst_y1: GLint,
2098 mask: GLbitfield,
2099 filter: GLenum,
2100 ) {
2101 self.get().blit_framebuffer(
2102 src_x0, src_y0, src_x1, src_y1, dst_x0, dst_y0, dst_x1, dst_y1, mask, filter,
2103 );
2104 }
2105 pub fn vertex_attrib_4f(&self, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
2106 self.get().vertex_attrib_4f(index, x, y, z, w);
2107 }
2108 pub fn vertex_attrib_pointer_f32(
2109 &self,
2110 index: GLuint,
2111 size: GLint,
2112 normalized: bool,
2113 stride: GLsizei,
2114 offset: GLuint,
2115 ) {
2116 self.get()
2117 .vertex_attrib_pointer_f32(index, size, normalized, stride, offset);
2118 }
2119 pub fn vertex_attrib_pointer(
2120 &self,
2121 index: GLuint,
2122 size: GLint,
2123 type_: GLenum,
2124 normalized: bool,
2125 stride: GLsizei,
2126 offset: GLuint,
2127 ) {
2128 self.get()
2129 .vertex_attrib_pointer(index, size, type_, normalized, stride, offset);
2130 }
2131 pub fn vertex_attrib_i_pointer(
2132 &self,
2133 index: GLuint,
2134 size: GLint,
2135 type_: GLenum,
2136 stride: GLsizei,
2137 offset: GLuint,
2138 ) {
2139 self.get()
2140 .vertex_attrib_i_pointer(index, size, type_, stride, offset);
2141 }
2142 pub fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint) {
2143 self.get().vertex_attrib_divisor(index, divisor);
2144 }
2145 pub fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
2146 self.get().viewport(x, y, width, height);
2147 }
2148 pub fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
2149 self.get().scissor(x, y, width, height);
2150 }
2151 pub fn line_width(&self, width: GLfloat) {
2152 self.get().line_width(width);
2153 }
2154 pub fn use_program(&self, program: GLuint) {
2155 self.get().use_program(program);
2156 }
2157 pub fn validate_program(&self, program: GLuint) {
2158 self.get().validate_program(program);
2159 }
2160 pub fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) {
2161 self.get().draw_arrays(mode, first, count);
2162 }
2163 pub fn draw_arrays_instanced(
2164 &self,
2165 mode: GLenum,
2166 first: GLint,
2167 count: GLsizei,
2168 primcount: GLsizei,
2169 ) {
2170 self.get()
2171 .draw_arrays_instanced(mode, first, count, primcount);
2172 }
2173 pub fn draw_elements(
2174 &self,
2175 mode: GLenum,
2176 count: GLsizei,
2177 element_type: GLenum,
2178 indices_offset: GLuint,
2179 ) {
2180 self.get()
2181 .draw_elements(mode, count, element_type, indices_offset);
2182 }
2183 pub fn draw_elements_instanced(
2184 &self,
2185 mode: GLenum,
2186 count: GLsizei,
2187 element_type: GLenum,
2188 indices_offset: GLuint,
2189 primcount: GLsizei,
2190 ) {
2191 self.get()
2192 .draw_elements_instanced(mode, count, element_type, indices_offset, primcount);
2193 }
2194 pub fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) {
2195 self.get().blend_color(r, g, b, a);
2196 }
2197 pub fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) {
2198 self.get().blend_func(sfactor, dfactor);
2199 }
2200 pub fn blend_func_separate(
2201 &self,
2202 src_rgb: GLenum,
2203 dest_rgb: GLenum,
2204 src_alpha: GLenum,
2205 dest_alpha: GLenum,
2206 ) {
2207 self.get()
2208 .blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha);
2209 }
2210 pub fn blend_equation(&self, mode: GLenum) {
2211 self.get().blend_equation(mode);
2212 }
2213 pub fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum) {
2214 self.get().blend_equation_separate(mode_rgb, mode_alpha);
2215 }
2216 #[allow(clippy::fn_params_excessive_bools)]
2219 pub fn color_mask(&self, r: bool, g: bool, b: bool, a: bool) {
2220 self.get().color_mask(r, g, b, a);
2221 }
2222 pub fn cull_face(&self, mode: GLenum) {
2223 self.get().cull_face(mode);
2224 }
2225 pub fn front_face(&self, mode: GLenum) {
2226 self.get().front_face(mode);
2227 }
2228 pub fn enable(&self, cap: GLenum) {
2229 self.get().enable(cap);
2230 }
2231 pub fn disable(&self, cap: GLenum) {
2232 self.get().disable(cap);
2233 }
2234 pub fn hint(&self, param_name: GLenum, param_val: GLenum) {
2235 self.get().hint(param_name, param_val);
2236 }
2237 #[must_use] pub fn is_enabled(&self, cap: GLenum) -> GLboolean {
2238 self.get().is_enabled(cap)
2239 }
2240 #[must_use] pub fn is_shader(&self, shader: GLuint) -> GLboolean {
2241 self.get().is_shader(shader)
2242 }
2243 #[must_use] pub fn is_texture(&self, texture: GLenum) -> GLboolean {
2244 self.get().is_texture(texture)
2245 }
2246 #[must_use] pub fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean {
2247 self.get().is_framebuffer(framebuffer)
2248 }
2249 #[must_use] pub fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean {
2250 self.get().is_renderbuffer(renderbuffer)
2251 }
2252 #[must_use] pub fn check_frame_buffer_status(&self, target: GLenum) -> GLenum {
2253 self.get().check_frame_buffer_status(target)
2254 }
2255 pub fn enable_vertex_attrib_array(&self, index: GLuint) {
2256 self.get().enable_vertex_attrib_array(index);
2257 }
2258 pub fn disable_vertex_attrib_array(&self, index: GLuint) {
2259 self.get().disable_vertex_attrib_array(index);
2260 }
2261 pub fn uniform_1f(&self, location: GLint, v0: GLfloat) {
2262 self.get().uniform_1f(location, v0);
2263 }
2264 pub fn uniform_1fv(&self, location: GLint, values: F32VecRef) {
2265 self.get().uniform_1fv(location, values.as_slice());
2266 }
2267 pub fn uniform_1i(&self, location: GLint, v0: GLint) {
2268 self.get().uniform_1i(location, v0);
2269 }
2270 pub fn uniform_1iv(&self, location: GLint, values: I32VecRef) {
2271 self.get().uniform_1iv(location, values.as_slice());
2272 }
2273 pub fn uniform_1ui(&self, location: GLint, v0: GLuint) {
2274 self.get().uniform_1ui(location, v0);
2275 }
2276 pub fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat) {
2277 self.get().uniform_2f(location, v0, v1);
2278 }
2279 pub fn uniform_2fv(&self, location: GLint, values: F32VecRef) {
2280 self.get().uniform_2fv(location, values.as_slice());
2281 }
2282 pub fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint) {
2283 self.get().uniform_2i(location, v0, v1);
2284 }
2285 pub fn uniform_2iv(&self, location: GLint, values: I32VecRef) {
2286 self.get().uniform_2iv(location, values.as_slice());
2287 }
2288 pub fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint) {
2289 self.get().uniform_2ui(location, v0, v1);
2290 }
2291 pub fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {
2292 self.get().uniform_3f(location, v0, v1, v2);
2293 }
2294 pub fn uniform_3fv(&self, location: GLint, values: F32VecRef) {
2295 self.get().uniform_3fv(location, values.as_slice());
2296 }
2297 pub fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint) {
2298 self.get().uniform_3i(location, v0, v1, v2);
2299 }
2300 pub fn uniform_3iv(&self, location: GLint, values: I32VecRef) {
2301 self.get().uniform_3iv(location, values.as_slice());
2302 }
2303 pub fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {
2304 self.get().uniform_3ui(location, v0, v1, v2);
2305 }
2306 pub fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
2307 self.get().uniform_4f(location, x, y, z, w);
2308 }
2309 pub fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) {
2310 self.get().uniform_4i(location, x, y, z, w);
2311 }
2312 pub fn uniform_4iv(&self, location: GLint, values: I32VecRef) {
2313 self.get().uniform_4iv(location, values.as_slice());
2314 }
2315 pub fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {
2316 self.get().uniform_4ui(location, x, y, z, w);
2317 }
2318 pub fn uniform_4fv(&self, location: GLint, values: F32VecRef) {
2319 self.get().uniform_4fv(location, values.as_slice());
2320 }
2321 pub fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: F32VecRef) {
2322 self.get()
2323 .uniform_matrix_2fv(location, transpose, value.as_slice());
2324 }
2325 pub fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: F32VecRef) {
2326 self.get()
2327 .uniform_matrix_3fv(location, transpose, value.as_slice());
2328 }
2329 pub fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: F32VecRef) {
2330 self.get()
2331 .uniform_matrix_4fv(location, transpose, value.as_slice());
2332 }
2333 pub fn depth_mask(&self, flag: bool) {
2334 self.get().depth_mask(flag);
2335 }
2336 pub fn depth_range(&self, near: f64, far: f64) {
2337 self.get().depth_range(near, far);
2338 }
2339 #[must_use] pub fn get_active_attrib(&self, program: GLuint, index: GLuint) -> GetActiveAttribReturn {
2340 let r = self.get().get_active_attrib(program, index);
2341 GetActiveAttribReturn {
2342 _0: r.0,
2343 _1: r.1,
2344 _2: r.2.into(),
2345 }
2346 }
2347 #[must_use] pub fn get_active_uniform(&self, program: GLuint, index: GLuint) -> GetActiveUniformReturn {
2348 let r = self.get().get_active_uniform(program, index);
2349 GetActiveUniformReturn {
2350 _0: r.0,
2351 _1: r.1,
2352 _2: r.2.into(),
2353 }
2354 }
2355 #[must_use] pub fn get_active_uniforms_iv(
2356 &self,
2357 program: GLuint,
2358 indices: GLuintVec,
2359 pname: GLenum,
2360 ) -> GLintVec {
2361 self.get()
2362 .get_active_uniforms_iv(program, indices.into_library_owned_vec(), pname)
2363 .into()
2364 }
2365 #[must_use] pub fn get_active_uniform_block_i(
2366 &self,
2367 program: GLuint,
2368 index: GLuint,
2369 pname: GLenum,
2370 ) -> GLint {
2371 self.get().get_active_uniform_block_i(program, index, pname)
2372 }
2373 #[must_use] pub fn get_active_uniform_block_iv(
2374 &self,
2375 program: GLuint,
2376 index: GLuint,
2377 pname: GLenum,
2378 ) -> GLintVec {
2379 self.get()
2380 .get_active_uniform_block_iv(program, index, pname)
2381 .into()
2382 }
2383 #[must_use] pub fn get_active_uniform_block_name(&self, program: GLuint, index: GLuint) -> AzString {
2384 self.get()
2385 .get_active_uniform_block_name(program, index)
2386 .into()
2387 }
2388 #[must_use] pub fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int {
2389 self.get().get_attrib_location(program, name)
2390 }
2391 #[must_use] pub fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int {
2392 self.get().get_frag_data_location(program, name)
2393 }
2394 #[must_use] pub fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int {
2395 self.get().get_uniform_location(program, name)
2396 }
2397 #[must_use] pub fn get_program_info_log(&self, program: GLuint) -> AzString {
2398 self.get().get_program_info_log(program).into()
2399 }
2400 pub fn get_program_iv(&self, program: GLuint, pname: GLenum, mut result: GLintVecRefMut) {
2401 unsafe {
2402 self.get()
2403 .get_program_iv(program, pname, result.as_mut_slice());
2404 }
2405 }
2406 #[must_use] pub fn get_program_binary(&self, program: GLuint) -> GetProgramBinaryReturn {
2407 let r = self.get().get_program_binary(program);
2408 GetProgramBinaryReturn {
2409 _0: r.0.into(),
2410 _1: r.1,
2411 }
2412 }
2413 pub fn program_binary(&self, program: GLuint, format: GLenum, binary: U8VecRef) {
2414 self.get()
2415 .program_binary(program, format, binary.as_slice());
2416 }
2417 pub fn program_parameter_i(&self, program: GLuint, pname: GLenum, value: GLint) {
2418 self.get().program_parameter_i(program, pname, value);
2419 }
2420 pub fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum, mut result: GLintVecRefMut) {
2421 unsafe {
2422 self.get()
2423 .get_vertex_attrib_iv(index, pname, result.as_mut_slice());
2424 }
2425 }
2426 pub fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum, mut result: GLfloatVecRefMut) {
2427 unsafe {
2428 self.get()
2429 .get_vertex_attrib_fv(index, pname, result.as_mut_slice());
2430 }
2431 }
2432 #[must_use] pub fn get_vertex_attrib_pointer_v(&self, index: GLuint, pname: GLenum) -> GLsizeiptr {
2433 self.get().get_vertex_attrib_pointer_v(index, pname)
2434 }
2435 #[must_use] pub fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint {
2436 self.get().get_buffer_parameter_iv(target, pname)
2437 }
2438 #[must_use] pub fn get_shader_info_log(&self, shader: GLuint) -> AzString {
2439 self.get().get_shader_info_log(shader).into()
2440 }
2441 #[must_use] pub fn get_string(&self, which: GLenum) -> AzString {
2442 self.get().get_string(which).into()
2443 }
2444 #[must_use] pub fn get_string_i(&self, which: GLenum, index: GLuint) -> AzString {
2445 self.get().get_string_i(which, index).into()
2446 }
2447 pub fn get_shader_iv(&self, shader: GLuint, pname: GLenum, mut result: GLintVecRefMut) {
2448 unsafe {
2449 self.get()
2450 .get_shader_iv(shader, pname, result.as_mut_slice());
2451 }
2452 }
2453 #[must_use] pub fn get_shader_precision_format(
2454 &self,
2455 shader_type: GLuint,
2456 precision_type: GLuint,
2457 ) -> GlShaderPrecisionFormatReturn {
2458 let r = self
2459 .get()
2460 .get_shader_precision_format(shader_type, precision_type);
2461 GlShaderPrecisionFormatReturn {
2462 _0: r.0,
2463 _1: r.1,
2464 _2: r.2,
2465 }
2466 }
2467 pub fn compile_shader(&self, shader: GLuint) {
2468 self.get().compile_shader(shader);
2469 }
2470 #[must_use] pub fn create_program(&self) -> GLuint {
2471 self.get().create_program()
2472 }
2473 pub fn delete_program(&self, program: GLuint) {
2474 self.get().delete_program(program);
2475 }
2476 #[must_use] pub fn create_shader(&self, shader_type: GLenum) -> GLuint {
2477 self.get().create_shader(shader_type)
2478 }
2479 pub fn delete_shader(&self, shader: GLuint) {
2480 self.get().delete_shader(shader);
2481 }
2482 pub fn detach_shader(&self, program: GLuint, shader: GLuint) {
2483 self.get().detach_shader(program, shader);
2484 }
2485 pub fn link_program(&self, program: GLuint) {
2486 self.get().link_program(program);
2487 }
2488 pub fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
2489 self.get().clear_color(r, g, b, a);
2490 }
2491 pub fn clear(&self, buffer_mask: GLbitfield) {
2492 self.get().clear(buffer_mask);
2493 }
2494 pub fn clear_depth(&self, depth: f64) {
2495 self.get().clear_depth(depth);
2496 }
2497 pub fn clear_stencil(&self, s: GLint) {
2498 self.get().clear_stencil(s);
2499 }
2500 pub fn flush(&self) {
2501 self.get().flush();
2502 }
2503 pub fn finish(&self) {
2504 self.get().finish();
2505 }
2506 #[must_use] pub fn get_error(&self) -> GLenum {
2507 self.get().get_error()
2508 }
2509 pub fn stencil_mask(&self, mask: GLuint) {
2510 self.get().stencil_mask(mask);
2511 }
2512 pub fn stencil_mask_separate(&self, face: GLenum, mask: GLuint) {
2513 self.get().stencil_mask_separate(face, mask);
2514 }
2515 pub fn stencil_func(&self, func: GLenum, ref_: GLint, mask: GLuint) {
2516 self.get().stencil_func(func, ref_, mask);
2517 }
2518 pub fn stencil_func_separate(&self, face: GLenum, func: GLenum, ref_: GLint, mask: GLuint) {
2519 self.get().stencil_func_separate(face, func, ref_, mask);
2520 }
2521 pub fn stencil_op(&self, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
2522 self.get().stencil_op(sfail, dpfail, dppass);
2523 }
2524 pub fn stencil_op_separate(&self, face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum) {
2525 self.get().stencil_op_separate(face, sfail, dpfail, dppass);
2526 }
2527 pub fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GlVoidPtrConst) {
2528 self.get()
2529 .egl_image_target_texture2d_oes(target, image.ptr as *const c_void);
2530 }
2531 pub fn generate_mipmap(&self, target: GLenum) {
2532 self.get().generate_mipmap(target);
2533 }
2534 pub fn insert_event_marker_ext(&self, message: &str) {
2535 self.get().insert_event_marker_ext(message);
2536 }
2537 pub fn push_group_marker_ext(&self, message: &str) {
2538 self.get().push_group_marker_ext(message);
2539 }
2540 pub fn pop_group_marker_ext(&self) {
2541 self.get().pop_group_marker_ext();
2542 }
2543 pub fn debug_message_insert_khr(
2544 &self,
2545 source: GLenum,
2546 type_: GLenum,
2547 id: GLuint,
2548 severity: GLenum,
2549 message: &str,
2550 ) {
2551 self.get()
2552 .debug_message_insert_khr(source, type_, id, severity, message);
2553 }
2554 pub fn push_debug_group_khr(&self, source: GLenum, id: GLuint, message: &str) {
2555 self.get()
2556 .push_debug_group_khr(source, id, message);
2557 }
2558 pub fn pop_debug_group_khr(&self) {
2559 self.get().pop_debug_group_khr();
2560 }
2561 #[must_use] pub fn fence_sync(&self, condition: GLenum, flags: GLbitfield) -> GLsyncPtr {
2562 GLsyncPtr::new(self.get().fence_sync(condition, flags))
2563 }
2564 #[must_use] pub fn client_wait_sync(&self, sync: GLsyncPtr, flags: GLbitfield, timeout: GLuint64) -> u32 {
2565 self.get().client_wait_sync(sync.get(), flags, timeout)
2566 }
2567 pub fn wait_sync(&self, sync: GLsyncPtr, flags: GLbitfield, timeout: GLuint64) {
2568 self.get().wait_sync(sync.get(), flags, timeout);
2569 }
2570 pub fn delete_sync(&self, sync: GLsyncPtr) {
2571 self.get().delete_sync(sync.get());
2572 }
2573 pub fn texture_range_apple(&self, target: GLenum, data: U8VecRef) {
2574 self.get().texture_range_apple(target, data.as_slice());
2575 }
2576 #[must_use] pub fn gen_fences_apple(&self, n: GLsizei) -> GLuintVec {
2577 self.get().gen_fences_apple(n).into()
2578 }
2579 pub fn delete_fences_apple(&self, fences: GLuintVecRef) {
2580 self.get().delete_fences_apple(fences.as_slice());
2581 }
2582 pub fn set_fence_apple(&self, fence: GLuint) {
2583 self.get().set_fence_apple(fence);
2584 }
2585 pub fn finish_fence_apple(&self, fence: GLuint) {
2586 self.get().finish_fence_apple(fence);
2587 }
2588 pub fn test_fence_apple(&self, fence: GLuint) {
2589 self.get().test_fence_apple(fence);
2590 }
2591 #[must_use] pub fn test_object_apple(&self, object: GLenum, name: GLuint) -> GLboolean {
2592 self.get().test_object_apple(object, name)
2593 }
2594 pub fn finish_object_apple(&self, object: GLenum, name: GLuint) {
2595 self.get().finish_object_apple(object, name);
2596 }
2597 #[must_use] pub fn get_frag_data_index(&self, program: GLuint, name: &str) -> GLint {
2598 self.get().get_frag_data_index(program, name)
2599 }
2600 pub fn blend_barrier_khr(&self) {
2601 self.get().blend_barrier_khr();
2602 }
2603 pub fn bind_frag_data_location_indexed(
2604 &self,
2605 program: GLuint,
2606 color_number: GLuint,
2607 index: GLuint,
2608 name: &str,
2609 ) {
2610 self.get()
2611 .bind_frag_data_location_indexed(program, color_number, index, name);
2612 }
2613 #[must_use] pub fn get_debug_messages(&self) -> DebugMessageVec {
2614 let dmv: Vec<DebugMessage> = self
2615 .get()
2616 .get_debug_messages()
2617 .into_iter()
2618 .map(|d| DebugMessage {
2619 message: d.message.into(),
2620 source: d.source,
2621 ty: d.ty,
2622 id: d.id,
2623 severity: d.severity,
2624 })
2625 .collect();
2626 dmv.into()
2627 }
2628 pub fn provoking_vertex_angle(&self, mode: GLenum) {
2629 self.get().provoking_vertex_angle(mode);
2630 }
2631 #[must_use] pub fn gen_vertex_arrays_apple(&self, n: GLsizei) -> GLuintVec {
2632 self.get().gen_vertex_arrays_apple(n).into()
2633 }
2634 pub fn bind_vertex_array_apple(&self, vao: GLuint) {
2635 self.get().bind_vertex_array_apple(vao);
2636 }
2637 pub fn delete_vertex_arrays_apple(&self, vertex_arrays: GLuintVecRef) {
2638 self.get()
2639 .delete_vertex_arrays_apple(vertex_arrays.as_slice());
2640 }
2641 pub fn copy_texture_chromium(
2642 &self,
2643 source_id: GLuint,
2644 source_level: GLint,
2645 dest_target: GLenum,
2646 dest_id: GLuint,
2647 dest_level: GLint,
2648 internal_format: GLint,
2649 dest_type: GLenum,
2650 unpack_flip_y: GLboolean,
2651 unpack_premultiply_alpha: GLboolean,
2652 unpack_unmultiply_alpha: GLboolean,
2653 ) {
2654 self.get().copy_texture_chromium(
2655 source_id,
2656 source_level,
2657 dest_target,
2658 dest_id,
2659 dest_level,
2660 internal_format,
2661 dest_type,
2662 unpack_flip_y,
2663 unpack_premultiply_alpha,
2664 unpack_unmultiply_alpha,
2665 );
2666 }
2667 pub fn copy_sub_texture_chromium(
2668 &self,
2669 source_id: GLuint,
2670 source_level: GLint,
2671 dest_target: GLenum,
2672 dest_id: GLuint,
2673 dest_level: GLint,
2674 x_offset: GLint,
2675 y_offset: GLint,
2676 x: GLint,
2677 y: GLint,
2678 width: GLsizei,
2679 height: GLsizei,
2680 unpack_flip_y: GLboolean,
2681 unpack_premultiply_alpha: GLboolean,
2682 unpack_unmultiply_alpha: GLboolean,
2683 ) {
2684 self.get().copy_sub_texture_chromium(
2685 source_id,
2686 source_level,
2687 dest_target,
2688 dest_id,
2689 dest_level,
2690 x_offset,
2691 y_offset,
2692 x,
2693 y,
2694 width,
2695 height,
2696 unpack_flip_y,
2697 unpack_premultiply_alpha,
2698 unpack_unmultiply_alpha,
2699 );
2700 }
2701 pub fn egl_image_target_renderbuffer_storage_oes(&self, target: u32, image: GlVoidPtrConst) {
2702 self.get().egl_image_target_renderbuffer_storage_oes(
2703 target,
2704 image.ptr as *const c_void,
2705 );
2706 }
2707 pub fn copy_texture_3d_angle(
2708 &self,
2709 source_id: GLuint,
2710 source_level: GLint,
2711 dest_target: GLenum,
2712 dest_id: GLuint,
2713 dest_level: GLint,
2714 internal_format: GLint,
2715 dest_type: GLenum,
2716 unpack_flip_y: GLboolean,
2717 unpack_premultiply_alpha: GLboolean,
2718 unpack_unmultiply_alpha: GLboolean,
2719 ) {
2720 self.get().copy_texture_3d_angle(
2721 source_id,
2722 source_level,
2723 dest_target,
2724 dest_id,
2725 dest_level,
2726 internal_format,
2727 dest_type,
2728 unpack_flip_y,
2729 unpack_premultiply_alpha,
2730 unpack_unmultiply_alpha,
2731 );
2732 }
2733 pub fn copy_sub_texture_3d_angle(
2734 &self,
2735 source_id: GLuint,
2736 source_level: GLint,
2737 dest_target: GLenum,
2738 dest_id: GLuint,
2739 dest_level: GLint,
2740 x_offset: GLint,
2741 y_offset: GLint,
2742 z_offset: GLint,
2743 x: GLint,
2744 y: GLint,
2745 z: GLint,
2746 width: GLsizei,
2747 height: GLsizei,
2748 depth: GLsizei,
2749 unpack_flip_y: GLboolean,
2750 unpack_premultiply_alpha: GLboolean,
2751 unpack_unmultiply_alpha: GLboolean,
2752 ) {
2753 self.get().copy_sub_texture_3d_angle(
2754 source_id,
2755 source_level,
2756 dest_target,
2757 dest_id,
2758 dest_level,
2759 x_offset,
2760 y_offset,
2761 z_offset,
2762 x,
2763 y,
2764 z,
2765 width,
2766 height,
2767 depth,
2768 unpack_flip_y,
2769 unpack_premultiply_alpha,
2770 unpack_unmultiply_alpha,
2771 );
2772 }
2773 pub fn buffer_storage(
2774 &self,
2775 target: GLenum,
2776 size: GLsizeiptr,
2777 data: GlVoidPtrConst,
2778 flags: GLbitfield,
2779 ) {
2780 self.get().buffer_storage(target, size, data.ptr, flags);
2781 }
2782 pub fn flush_mapped_buffer_range(&self, target: GLenum, offset: GLintptr, length: GLsizeiptr) {
2783 self.get().flush_mapped_buffer_range(target, offset, length);
2784 }
2785}
2786
2787impl PartialEq for GlContextPtr {
2788 fn eq(&self, rhs: &Self) -> bool {
2789 self.as_usize().eq(&rhs.as_usize())
2790 }
2791}
2792
2793impl Eq for GlContextPtr {}
2794
2795impl PartialOrd for GlContextPtr {
2796 fn partial_cmp(&self, rhs: &Self) -> Option<core::cmp::Ordering> {
2797 self.as_usize().partial_cmp(&rhs.as_usize())
2798 }
2799}
2800
2801impl Ord for GlContextPtr {
2802 fn cmp(&self, rhs: &Self) -> core::cmp::Ordering {
2803 self.as_usize().cmp(&rhs.as_usize())
2804 }
2805}
2806
2807#[allow(clippy::struct_field_names)]
2813struct GlStateSave {
2814 current_multisample: [u8; 1],
2815 current_index_buffer: [i32; 1],
2816 current_vertex_buffer: [i32; 1],
2817 current_vertex_array_object: [i32; 1],
2818 current_program: [i32; 1],
2819 current_framebuffers: [i32; 1],
2820 current_renderbuffers: [i32; 1],
2821 current_texture_2d: [i32; 1],
2822}
2823
2824impl GlStateSave {
2825 fn save(gl_context: &GlContextPtr) -> Self {
2826 let mut s = Self {
2827 current_multisample: [0],
2828 current_index_buffer: [0],
2829 current_vertex_buffer: [0],
2830 current_vertex_array_object: [0],
2831 current_program: [0],
2832 current_framebuffers: [0],
2833 current_renderbuffers: [0],
2834 current_texture_2d: [0],
2835 };
2836
2837 gl_context.get_boolean_v(gl::MULTISAMPLE, (&mut s.current_multisample[..]).into());
2838 gl_context.get_integer_v(gl::ARRAY_BUFFER_BINDING, (&mut s.current_vertex_buffer[..]).into());
2839 gl_context.get_integer_v(gl::ELEMENT_ARRAY_BUFFER_BINDING, (&mut s.current_index_buffer[..]).into());
2840 gl_context.get_integer_v(gl::CURRENT_PROGRAM, (&mut s.current_program[..]).into());
2841 gl_context.get_integer_v(gl::VERTEX_ARRAY_BINDING, (&mut s.current_vertex_array_object[..]).into());
2842 gl_context.get_integer_v(gl::RENDERBUFFER, (&mut s.current_renderbuffers[..]).into());
2843 gl_context.get_integer_v(gl::FRAMEBUFFER, (&mut s.current_framebuffers[..]).into());
2844 gl_context.get_integer_v(gl::TEXTURE_2D, (&mut s.current_texture_2d[..]).into());
2845
2846 s
2847 }
2848
2849 #[allow(clippy::cast_sign_loss)]
2851 fn restore(&self, gl_context: &GlContextPtr) {
2852 if u32::from(self.current_multisample[0]) == gl::TRUE {
2853 gl_context.enable(gl::MULTISAMPLE);
2854 }
2855 gl_context.bind_framebuffer(gl::FRAMEBUFFER, self.current_framebuffers[0] as u32);
2856 gl_context.bind_texture(gl::TEXTURE_2D, self.current_texture_2d[0] as u32);
2857 gl_context.bind_buffer(gl::RENDERBUFFER, self.current_renderbuffers[0] as u32);
2858 gl_context.bind_vertex_array(self.current_vertex_array_object[0] as u32);
2859 gl_context.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.current_index_buffer[0] as u32);
2860 gl_context.bind_buffer(gl::ARRAY_BUFFER, self.current_vertex_buffer[0] as u32);
2861 gl_context.use_program(self.current_program[0] as u32);
2862 }
2863}
2864
2865struct FboRboGuard<'a> {
2871 gl_context: &'a GlContextPtr,
2872 framebuffer_id: GLuint,
2873 renderbuffer_id: GLuint,
2874}
2875
2876impl Drop for FboRboGuard<'_> {
2877 fn drop(&mut self) {
2878 if self.framebuffer_id != 0 {
2879 self.gl_context
2880 .delete_framebuffers((&[self.framebuffer_id])[..].into());
2881 }
2882 if self.renderbuffer_id != 0 {
2883 self.gl_context
2884 .delete_renderbuffers((&[self.renderbuffer_id])[..].into());
2885 }
2886 }
2887}
2888
2889#[repr(C)]
2891pub struct Texture {
2892 pub gl_context: GlContextPtr,
2895 pub texture_id: GLuint,
2897 pub refcount: *const AtomicUsize,
2899 pub size: PhysicalSizeU32,
2901 pub format: RawImageFormat,
2903 pub background_color: ColorU,
2905 pub flags: TextureFlags,
2907 pub run_destructor: bool,
2908}
2909
2910impl Clone for Texture {
2911 #[allow(clippy::cast_sign_loss)] fn clone(&self) -> Self {
2913 unsafe {
2914 (*self.refcount).fetch_add(1, AtomicOrdering::SeqCst);
2915 }
2916 Self {
2917 gl_context: self.gl_context.clone(),
2918 texture_id: self.texture_id,
2919 refcount: self.refcount,
2920 size: self.size,
2921 format: self.format,
2922 background_color: self.background_color,
2923 flags: self.flags,
2924 run_destructor: true,
2925 }
2926 }
2927}
2928
2929impl_option!(
2930 Texture,
2931 OptionTexture,
2932 copy = false,
2933 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
2934);
2935
2936impl Texture {
2937 #[must_use] pub fn create(
2938 texture_id: GLuint,
2939 flags: TextureFlags,
2940 size: PhysicalSizeU32,
2941 background_color: ColorU,
2942 gl_context: GlContextPtr,
2943 format: RawImageFormat,
2944 ) -> Self {
2945 Self {
2946 texture_id,
2947 flags,
2948 size,
2949 background_color,
2950 gl_context,
2951 format,
2952 refcount: Box::into_raw(Box::new(AtomicUsize::new(1))),
2953 run_destructor: true,
2954 }
2955 }
2956
2957 #[allow(clippy::cast_possible_wrap)]
2961 #[allow(clippy::cast_sign_loss)] #[must_use] pub fn allocate_rgba8(
2963 gl_context: GlContextPtr,
2964 size: PhysicalSizeU32,
2965 background: ColorU,
2966 ) -> Self {
2967 let textures = gl_context.gen_textures(1);
2968 let texture_id = textures.as_ref()[0];
2969
2970 let mut current_texture_2d = [0_i32];
2971 gl_context.get_integer_v(gl::TEXTURE_2D, (&mut current_texture_2d[..]).into());
2972
2973 gl_context.bind_texture(gl::TEXTURE_2D, texture_id);
2974 gl_context.tex_image_2d(
2975 gl::TEXTURE_2D,
2976 0,
2977 gl::RGBA as i32,
2978 size.width as i32,
2979 size.height as i32,
2980 0,
2981 gl::RGBA,
2982 gl::UNSIGNED_BYTE,
2983 None.into(),
2984 );
2985 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
2986 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
2987 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
2988 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
2989 gl_context.bind_texture(gl::TEXTURE_2D, current_texture_2d[0] as u32);
2990
2991 Self::create(
2992 texture_id,
2993 TextureFlags {
2994 is_opaque: false,
2995 is_video_texture: false,
2996 },
2997 size,
2998 background,
2999 gl_context,
3000 RawImageFormat::BGRA8,
3002 )
3003 }
3004
3005 #[allow(clippy::cast_possible_wrap)]
3011 pub fn clear(&mut self) {
3012 let saved = GlStateSave::save(&self.gl_context);
3013
3014 let framebuffers = self.gl_context.gen_framebuffers(1);
3015 let framebuffer_id = *framebuffers.get(0).unwrap();
3016 let mut fbo_rbo_guard = FboRboGuard {
3019 gl_context: &self.gl_context,
3020 framebuffer_id,
3021 renderbuffer_id: 0,
3022 };
3023 self.gl_context
3024 .bind_framebuffer(gl::FRAMEBUFFER, framebuffer_id);
3025
3026 let depthbuffers = self.gl_context.gen_renderbuffers(1);
3027 let depthbuffer_id = *depthbuffers.get(0).unwrap();
3028 fbo_rbo_guard.renderbuffer_id = depthbuffer_id;
3029
3030 self.gl_context
3031 .bind_texture(gl::TEXTURE_2D, self.texture_id);
3032 self.gl_context.tex_image_2d(
3033 gl::TEXTURE_2D,
3034 0,
3035 gl::RGBA as i32, self.size.width as i32,
3037 self.size.height as i32,
3038 0,
3039 gl::RGBA, gl::UNSIGNED_BYTE,
3041 None.into(),
3042 );
3043 self.gl_context
3044 .tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
3045 self.gl_context
3046 .tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
3047 self.gl_context.tex_parameter_i(
3048 gl::TEXTURE_2D,
3049 gl::TEXTURE_WRAP_S,
3050 gl::CLAMP_TO_EDGE as i32,
3051 );
3052 self.gl_context.tex_parameter_i(
3053 gl::TEXTURE_2D,
3054 gl::TEXTURE_WRAP_T,
3055 gl::CLAMP_TO_EDGE as i32,
3056 );
3057
3058 self.gl_context
3059 .bind_renderbuffer(gl::RENDERBUFFER, depthbuffer_id);
3060 self.gl_context.renderbuffer_storage(
3061 gl::RENDERBUFFER,
3062 gl::DEPTH_COMPONENT,
3063 self.size.width as i32,
3064 self.size.height as i32,
3065 );
3066 self.gl_context.framebuffer_renderbuffer(
3067 gl::FRAMEBUFFER,
3068 gl::DEPTH_ATTACHMENT,
3069 gl::RENDERBUFFER,
3070 depthbuffer_id,
3071 );
3072
3073 self.gl_context.framebuffer_texture_2d(
3074 gl::FRAMEBUFFER,
3075 gl::COLOR_ATTACHMENT0,
3076 gl::TEXTURE_2D,
3077 self.texture_id,
3078 0,
3079 );
3080 self.gl_context
3081 .draw_buffers([gl::COLOR_ATTACHMENT0][..].into());
3082
3083 let clear_color: ColorF = self.background_color.into();
3084 self.gl_context
3085 .clear_color(clear_color.r, clear_color.g, clear_color.b, clear_color.a);
3086 self.gl_context.clear_depth(0.0);
3087 self.gl_context
3088 .clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
3089
3090 saved.restore(&self.gl_context);
3094 drop(fbo_rbo_guard);
3095 }
3096
3097 #[must_use] pub fn get_descriptor(&self) -> ImageDescriptor {
3098 ImageDescriptor {
3099 format: self.format,
3100 width: self.size.width as usize,
3101 height: self.size.height as usize,
3102 stride: None.into(),
3103 offset: 0,
3104 flags: ImageDescriptorFlags {
3105 is_opaque: self.flags.is_opaque,
3106 allow_mipmaps: false,
3108 },
3109 }
3110 }
3111
3112 pub fn draw_tesselated_svg_gpu_node(
3114 &mut self,
3115 node: &TessellatedGPUSvgNode,
3116 size: PhysicalSizeU32,
3117 color: ColorU,
3118 transforms: StyleTransformVec,
3119 ) -> bool {
3120 node.draw(self, size, color, transforms)
3121 }
3122
3123 pub fn draw_tesselated_colored_svg_gpu_node(
3125 &mut self,
3126 node: &crate::svg::TessellatedColoredGPUSvgNode,
3127 size: PhysicalSizeU32,
3128 transforms: StyleTransformVec,
3129 ) -> bool {
3130 node.draw(self, size, transforms)
3131 }
3132}
3133
3134#[derive(Debug, Default, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
3135#[repr(C)]
3136pub struct TextureFlags {
3137 pub is_opaque: bool,
3139 pub is_video_texture: bool,
3141}
3142
3143impl ::core::fmt::Display for Texture {
3144 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3145 write!(
3146 f,
3147 "Texture {{ id: {}, {}x{} }}",
3148 self.texture_id, self.size.width, self.size.height
3149 )
3150 }
3151}
3152
3153macro_rules! impl_traits_for_gl_object {
3154 ($struct_name:ident, $gl_id_field:ident) => {
3155 impl ::core::fmt::Debug for $struct_name {
3156 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3157 write!(f, "{}", self)
3158 }
3159 }
3160
3161 impl Hash for $struct_name {
3162 fn hash<H: Hasher>(&self, state: &mut H) {
3163 self.$gl_id_field.hash(state);
3164 }
3165 }
3166
3167 impl PartialEq for $struct_name {
3168 fn eq(&self, other: &$struct_name) -> bool {
3169 self.$gl_id_field == other.$gl_id_field
3170 }
3171 }
3172
3173 impl Eq for $struct_name {}
3174
3175 impl PartialOrd for $struct_name {
3176 fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
3177 Some((self.$gl_id_field).cmp(&(other.$gl_id_field)))
3178 }
3179 }
3180
3181 impl Ord for $struct_name {
3182 fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
3183 (self.$gl_id_field).cmp(&(other.$gl_id_field))
3184 }
3185 }
3186 };
3187}
3188
3189impl Texture {
3190 pub fn paint_dot(&mut self, cx: f32, cy: f32, brush: Brush) {
3195 self.paint_stroke(cx, cy, cx, cy, brush);
3196 }
3197
3198 #[allow(clippy::suboptimal_flops)] #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_precision_loss, clippy::cast_sign_loss)] #[allow(clippy::many_single_char_names)] pub fn paint_stroke(&mut self, x0: f32, y0: f32, x1: f32, y1: f32, brush: Brush) {
3205 let gl = self.gl_context.clone();
3206 let prog = gl.get_brush_shader();
3207 let (tw, th) = (self.size.width as f32, self.size.height as f32);
3208 #[allow(clippy::neg_cmp_op_on_partial_ord)]
3210 if prog == 0 || self.texture_id == 0 || !(brush.radius > 0.0) || tw <= 0.0 || th <= 0.0 {
3211 return;
3212 }
3213
3214 let fbo = gl.gen_framebuffers(1).get(0).copied().unwrap_or(0);
3215 let vbo = gl.gen_buffers(1).get(0).copied().unwrap_or(0);
3216 if fbo == 0 || vbo == 0 {
3217 if fbo != 0 {
3218 gl.delete_framebuffers((&[fbo][..]).into());
3219 }
3220 if vbo != 0 {
3221 gl.delete_buffers((&[vbo][..]).into());
3222 }
3223 return;
3224 }
3225
3226 gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
3227 gl.framebuffer_texture_2d(
3228 gl::FRAMEBUFFER,
3229 gl::COLOR_ATTACHMENT0,
3230 gl::TEXTURE_2D,
3231 self.texture_id,
3232 0,
3233 );
3234 gl.viewport(0, 0, self.size.width as i32, self.size.height as i32);
3235 gl.enable(gl::BLEND);
3236 gl.blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
3237 gl.use_program(prog);
3238
3239 let a = (f32::from(brush.color.a) / 255.0) * brush.flow.clamp(0.0, 1.0);
3240 gl.uniform_4f(
3241 gl.get_uniform_location(prog, "uColor"),
3242 f32::from(brush.color.r) / 255.0,
3243 f32::from(brush.color.g) / 255.0,
3244 f32::from(brush.color.b) / 255.0,
3245 a,
3246 );
3247 gl.uniform_1f(gl.get_uniform_location(prog, "uHardness"), brush.hardness);
3248
3249 gl.bind_buffer(gl::ARRAY_BUFFER, vbo);
3250 gl.enable_vertex_attrib_array(0);
3251 gl.enable_vertex_attrib_array(1);
3252 gl.vertex_attrib_pointer_f32(0, 2, false, 16, 0);
3253 gl.vertex_attrib_pointer_f32(1, 2, false, 16, 8);
3254
3255 let dx = x1 - x0;
3256 let dy = y1 - y0;
3257 let len = dx.hypot(dy);
3258 let step = (brush.radius * brush.spacing.max(0.01)).max(0.5);
3259 let n = ((len / step).floor() as i32).max(0);
3260 let r = brush.radius;
3261 for i in 0..=n {
3262 let t = if n == 0 { 1.0 } else { i as f32 / n as f32 };
3263 let px = x0 + dx * t;
3264 let py = y0 + dy * t;
3265 let nx = |x: f32| (x / tw) * 2.0 - 1.0;
3267 let ny = |y: f32| 1.0 - (y / th) * 2.0;
3268 let (l, rr, tp, bt) = (nx(px - r), nx(px + r), ny(py - r), ny(py + r));
3269 let verts: [f32; 16] = [
3271 l, tp, -1.0, -1.0, l, bt, -1.0, 1.0, rr, tp, 1.0, -1.0, rr, bt, 1.0, 1.0,
3272 ];
3273 gl.buffer_data_untyped(
3274 gl::ARRAY_BUFFER,
3275 (verts.len() * size_of::<f32>()) as isize,
3276 GlVoidPtrConst {
3277 ptr: verts.as_ptr() as *const GLvoid,
3278 run_destructor: false,
3279 },
3280 gl::STREAM_DRAW,
3281 );
3282 gl.draw_arrays(gl::TRIANGLE_STRIP, 0, 4);
3283 }
3284
3285 gl.disable_vertex_attrib_array(0);
3286 gl.disable_vertex_attrib_array(1);
3287 gl.bind_buffer(gl::ARRAY_BUFFER, 0);
3288 gl.disable(gl::BLEND);
3289 gl.bind_framebuffer(gl::FRAMEBUFFER, 0);
3290 gl.delete_buffers((&[vbo][..]).into());
3291 gl.delete_framebuffers((&[fbo][..]).into());
3292 }
3293
3294 #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)] #[must_use] pub fn copy_to_raw_image(&self) -> RawImage {
3298 let gl = self.gl_context.clone();
3299 let (w, h) = (self.size.width as i32, self.size.height as i32);
3300 if self.texture_id == 0 || w <= 0 || h <= 0 {
3301 return RawImage::null_image();
3302 }
3303 let fbo = gl.gen_framebuffers(1).get(0).copied().unwrap_or(0);
3304 if fbo == 0 {
3305 return RawImage::null_image();
3306 }
3307 gl.bind_framebuffer(gl::FRAMEBUFFER, fbo);
3308 gl.framebuffer_texture_2d(
3309 gl::FRAMEBUFFER,
3310 gl::COLOR_ATTACHMENT0,
3311 gl::TEXTURE_2D,
3312 self.texture_id,
3313 0,
3314 );
3315 let pixels = gl.read_pixels(0, 0, w, h, gl::RGBA, gl::UNSIGNED_BYTE);
3316 gl.bind_framebuffer(gl::FRAMEBUFFER, 0);
3317 gl.delete_framebuffers((&[fbo][..]).into());
3318
3319 let mut bytes = pixels.into_library_owned_vec();
3321 let row = (w as usize) * 4;
3322 let hh = h as usize;
3323 if row > 0 && bytes.len() >= row * hh {
3324 for y in 0..hh / 2 {
3325 let yi = y * row;
3326 let yo = (hh - 1 - y) * row;
3327 for k in 0..row {
3328 bytes.swap(yi + k, yo + k);
3329 }
3330 }
3331 }
3332 RawImage {
3333 pixels: RawImageData::U8(bytes.into()),
3334 width: w as usize,
3335 height: h as usize,
3336 premultiplied_alpha: true,
3337 data_format: RawImageFormat::RGBA8,
3338 tag: Vec::new().into(),
3339 }
3340 }
3341}
3342
3343impl_traits_for_gl_object!(Texture, texture_id);
3344
3345impl Drop for Texture {
3346 fn drop(&mut self) {
3347 if !self.run_destructor {
3353 return;
3354 }
3355 self.run_destructor = false;
3356 let copies = unsafe { (*self.refcount).fetch_sub(1, AtomicOrdering::SeqCst) };
3357 if copies == 1 {
3358 drop(unsafe { Box::from_raw(self.refcount.cast_mut()) });
3359 self.gl_context
3360 .delete_textures((&[self.texture_id])[..].into());
3361 }
3362 }
3363}
3364
3365#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3367#[repr(C)]
3368pub struct VertexLayout {
3369 pub fields: VertexAttributeVec,
3370}
3371
3372impl_vec!(VertexAttribute, VertexAttributeVec, VertexAttributeVecDestructor, VertexAttributeVecDestructorType, VertexAttributeVecSlice, OptionVertexAttribute);
3373impl_vec_debug!(VertexAttribute, VertexAttributeVec);
3374impl_vec_partialord!(VertexAttribute, VertexAttributeVec);
3375impl_vec_ord!(VertexAttribute, VertexAttributeVec);
3376impl_vec_clone!(
3377 VertexAttribute,
3378 VertexAttributeVec,
3379 VertexAttributeVecDestructor
3380);
3381impl_vec_partialeq!(VertexAttribute, VertexAttributeVec);
3382impl_vec_eq!(VertexAttribute, VertexAttributeVec);
3383impl_vec_hash!(VertexAttribute, VertexAttributeVec);
3384
3385impl VertexLayout {
3386 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
3390 #[allow(clippy::cast_possible_wrap)] pub fn bind(&self, gl_context: &Rc<GenericGlContext>, program_id: GLuint) {
3392 const VERTICES_ARE_NORMALIZED: bool = false;
3393
3394 let mut offset = 0;
3395
3396 let stride_between_vertices: usize =
3397 self.fields.iter().map(VertexAttribute::get_stride).sum();
3398
3399 for vertex_attribute in &self.fields {
3400 let attribute_location = vertex_attribute.layout_location.as_option().map_or_else(
3401 || gl_context.get_attrib_location(program_id, vertex_attribute.va_name.as_str()),
3402 |ll| *ll as i32,
3403 );
3404
3405 gl_context.vertex_attrib_pointer(
3406 attribute_location as u32,
3407 vertex_attribute.item_count as i32,
3408 vertex_attribute.attribute_type.get_gl_id(),
3409 VERTICES_ARE_NORMALIZED,
3410 stride_between_vertices as i32,
3411 offset as u32,
3412 );
3413 gl_context.enable_vertex_attrib_array(attribute_location as u32);
3414 offset += vertex_attribute.get_stride();
3415 }
3416 }
3417
3418 #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] #[allow(clippy::cast_possible_wrap)] pub fn unbind(&self, gl_context: &Rc<GenericGlContext>, program_id: GLuint) {
3422 for vertex_attribute in &self.fields {
3423 let attribute_location = vertex_attribute.layout_location.as_option().map_or_else(
3424 || gl_context.get_attrib_location(program_id, vertex_attribute.va_name.as_str()),
3425 |ll| *ll as i32,
3426 );
3427 gl_context.disable_vertex_attrib_array(attribute_location as u32);
3428 }
3429 }
3430}
3431
3432#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3433#[repr(C)]
3434pub struct VertexAttribute {
3435 pub va_name: AzString,
3437 pub layout_location: OptionUsize,
3440 pub attribute_type: VertexAttributeType,
3443 pub item_count: usize,
3446}
3447
3448impl_option!(
3449 VertexAttribute,
3450 OptionVertexAttribute,
3451 copy = false,
3452 [Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash]
3453);
3454
3455impl VertexAttribute {
3456 #[must_use] pub const fn get_stride(&self) -> usize {
3457 self.attribute_type.get_mem_size() * self.item_count
3458 }
3459}
3460
3461#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3462#[repr(C)]
3463pub enum VertexAttributeType {
3464 Float,
3466 Double,
3468 UnsignedByte,
3470 UnsignedShort,
3472 UnsignedInt,
3474}
3475
3476impl VertexAttributeType {
3477 #[must_use] pub const fn get_gl_id(&self) -> GLuint {
3480 use self::VertexAttributeType::{Float, Double, UnsignedByte, UnsignedShort, UnsignedInt};
3481 match self {
3482 Float => gl::FLOAT,
3483 Double => gl::DOUBLE,
3484 UnsignedByte => gl::UNSIGNED_BYTE,
3485 UnsignedShort => gl::UNSIGNED_SHORT,
3486 UnsignedInt => gl::UNSIGNED_INT,
3487 }
3488 }
3489
3490 #[must_use] pub const fn get_mem_size(&self) -> usize {
3491 use core::mem;
3492
3493 use self::VertexAttributeType::{Float, Double, UnsignedByte, UnsignedShort, UnsignedInt};
3494 match self {
3495 Float => size_of::<f32>(),
3496 Double => size_of::<f64>(),
3497 UnsignedByte => size_of::<u8>(),
3498 UnsignedShort => size_of::<u16>(),
3499 UnsignedInt => size_of::<u32>(),
3500 }
3501 }
3502}
3503
3504pub trait VertexLayoutDescription {
3505 fn get_description() -> VertexLayout;
3506}
3507
3508#[derive(Debug, PartialEq, Eq, PartialOrd)]
3509#[repr(C)]
3510pub struct VertexArrayObject {
3511 pub vertex_layout: VertexLayout,
3512 pub vao_id: GLuint,
3513 pub gl_context: GlContextPtr,
3514 pub refcount: *const AtomicUsize,
3515 pub run_destructor: bool,
3516}
3517
3518impl VertexArrayObject {
3519 #[must_use] pub fn new(vertex_layout: VertexLayout, vao_id: GLuint, gl_context: GlContextPtr) -> Self {
3520 Self {
3521 vertex_layout,
3522 vao_id,
3523 gl_context,
3524 refcount: Box::into_raw(Box::new(AtomicUsize::new(1))),
3525 run_destructor: true,
3526 }
3527 }
3528}
3529
3530impl Clone for VertexArrayObject {
3531 fn clone(&self) -> Self {
3532 unsafe { (*self.refcount).fetch_add(1, AtomicOrdering::SeqCst) };
3533 Self {
3534 vertex_layout: self.vertex_layout.clone(),
3535 vao_id: self.vao_id,
3536 gl_context: self.gl_context.clone(),
3537 refcount: self.refcount,
3538 run_destructor: true,
3539 }
3540 }
3541}
3542
3543impl Drop for VertexArrayObject {
3544 fn drop(&mut self) {
3545 if !self.run_destructor {
3548 return;
3549 }
3550 self.run_destructor = false;
3551 let copies = unsafe { (*self.refcount).fetch_sub(1, AtomicOrdering::SeqCst) };
3552 if copies == 1 {
3553 drop(unsafe { Box::from_raw(self.refcount.cast_mut()) });
3554 self.gl_context
3555 .delete_vertex_arrays((&[self.vao_id])[..].into());
3556 }
3557 }
3558}
3559
3560#[repr(C)]
3561pub struct VertexBuffer {
3562 pub vao: VertexArrayObject,
3563 pub vertex_buffer_id: GLuint,
3564 pub vertex_buffer_len: usize,
3565 pub index_buffer_id: GLuint,
3566 pub index_buffer_len: usize,
3567 pub refcount: *const AtomicUsize,
3568 pub index_buffer_format: IndexBufferFormat,
3569 pub run_destructor: bool,
3570}
3571
3572impl fmt::Display for VertexBuffer {
3573 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3574 write!(
3575 f,
3576 "VertexBuffer {{ buffer: {} (length: {}) }}",
3577 self.vertex_buffer_id, self.vertex_buffer_len
3578 )
3579 }
3580}
3581
3582impl_traits_for_gl_object!(VertexBuffer, vertex_buffer_id);
3583
3584impl Clone for VertexBuffer {
3585 fn clone(&self) -> Self {
3586 unsafe { (*self.refcount).fetch_add(1, AtomicOrdering::SeqCst) };
3587 Self {
3588 vao: self.vao.clone(),
3589 vertex_buffer_id: self.vertex_buffer_id,
3590 vertex_buffer_len: self.vertex_buffer_len,
3591 index_buffer_id: self.index_buffer_id,
3592 index_buffer_len: self.index_buffer_len,
3593 refcount: self.refcount,
3594 index_buffer_format: self.index_buffer_format,
3595 run_destructor: true,
3596 }
3597 }
3598}
3599
3600impl Drop for VertexBuffer {
3601 fn drop(&mut self) {
3602 if !self.run_destructor {
3605 return;
3606 }
3607 self.run_destructor = false;
3608 let copies = unsafe { (*self.refcount).fetch_sub(1, AtomicOrdering::SeqCst) };
3609 if copies == 1 {
3610 self.vao.vertex_layout = VertexLayout {
3611 fields: VertexAttributeVec::from_const_slice(&[]),
3612 };
3613 drop(unsafe { Box::from_raw(self.refcount.cast_mut()) });
3614 self.vao
3615 .gl_context
3616 .delete_buffers((&[self.vertex_buffer_id, self.index_buffer_id])[..].into());
3617 }
3618 }
3619}
3620
3621impl VertexBuffer {
3622 #[allow(clippy::cast_possible_wrap, clippy::cast_sign_loss)]
3629 #[allow(clippy::cast_possible_truncation)] pub fn new<T: VertexLayoutDescription>(
3631 gl_context: GlContextPtr,
3632 shader_program_id: GLuint,
3633 vertices: &[T],
3634 indices: &[u32],
3635 index_buffer_format: IndexBufferFormat,
3636 ) -> Self {
3637 use core::mem;
3638
3639 let mut current_vertex_array = [0_i32];
3641
3642 gl_context.get_integer_v(gl::VERTEX_ARRAY, (&mut current_vertex_array[..]).into());
3643
3644 let vertex_array_object = gl_context.gen_vertex_arrays(1);
3645 let vertex_array_object = vertex_array_object.get(0).unwrap();
3646
3647 let vertex_buffer_id = gl_context.gen_buffers(1);
3648 let vertex_buffer_id = vertex_buffer_id.get(0).unwrap();
3649
3650 let index_buffer_id = gl_context.gen_buffers(1);
3651 let index_buffer_id = index_buffer_id.get(0).unwrap();
3652
3653 gl_context.bind_vertex_array(*vertex_array_object);
3654
3655 gl_context.bind_buffer(gl::ARRAY_BUFFER, *vertex_buffer_id);
3657 gl_context.buffer_data_untyped(
3658 gl::ARRAY_BUFFER,
3659 size_of_val(vertices) as isize,
3660 GlVoidPtrConst {
3661 ptr: vertices.as_ptr() as *const core::ffi::c_void,
3662 run_destructor: true,
3663 },
3664 gl::STATIC_DRAW,
3665 );
3666
3667 gl_context.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, *index_buffer_id);
3669 gl_context.buffer_data_untyped(
3670 gl::ELEMENT_ARRAY_BUFFER,
3671 size_of_val(indices) as isize,
3672 GlVoidPtrConst {
3673 ptr: indices.as_ptr() as *const core::ffi::c_void,
3674 run_destructor: true,
3675 },
3676 gl::STATIC_DRAW,
3677 );
3678
3679 let vertex_description = T::get_description();
3680 vertex_description.bind(&gl_context.ptr.ptr, shader_program_id);
3681
3682 gl_context.bind_vertex_array(current_vertex_array[0] as u32);
3684
3685 Self::new_raw(
3686 *vertex_buffer_id,
3687 vertices.len(),
3688 VertexArrayObject::new(vertex_description, *vertex_array_object, gl_context),
3689 *index_buffer_id,
3690 indices.len(),
3691 index_buffer_format,
3692 )
3693 }
3694
3695 #[must_use] pub fn new_raw(
3696 vertex_buffer_id: GLuint,
3697 vertex_buffer_len: usize,
3698 vao: VertexArrayObject,
3699 index_buffer_id: GLuint,
3700 index_buffer_len: usize,
3701 index_buffer_format: IndexBufferFormat,
3702 ) -> Self {
3703 Self {
3704 vertex_buffer_id,
3705 vertex_buffer_len,
3706 vao,
3707 index_buffer_id,
3708 index_buffer_len,
3709 index_buffer_format,
3710 refcount: Box::into_raw(Box::new(AtomicUsize::new(1))),
3711 run_destructor: true,
3712 }
3713 }
3714}
3715
3716#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3717pub enum GlApiVersion {
3718 Gl { major: usize, minor: usize },
3719 GlEs { major: usize, minor: usize },
3720}
3721
3722impl GlApiVersion {
3723 #[allow(clippy::cast_sign_loss)] #[must_use] pub fn get(gl_context: &GlContextPtr) -> Self {
3726 let mut major = [0];
3727 gl_context.get_integer_v(gl::MAJOR_VERSION, (&mut major[..]).into());
3728 let mut minor = [0];
3729 gl_context.get_integer_v(gl::MINOR_VERSION, (&mut minor[..]).into());
3730
3731 let major = major[0] as usize;
3732 let minor = minor[0] as usize;
3733
3734 match gl_context.get_type() {
3735 GlType::Gl => Self::Gl { major, minor },
3736 GlType::Gles => Self::GlEs { major, minor },
3737 }
3738 }
3739}
3740
3741#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
3742#[repr(C)]
3743pub enum IndexBufferFormat {
3744 Points,
3745 Lines,
3746 LineStrip,
3747 Triangles,
3748 TriangleStrip,
3749 TriangleFan,
3750}
3751
3752impl IndexBufferFormat {
3753 #[must_use] pub const fn get_gl_id(&self) -> GLuint {
3755 use self::IndexBufferFormat::{Points, Lines, LineStrip, Triangles, TriangleStrip, TriangleFan};
3756 match self {
3757 Points => gl::POINTS,
3758 Lines => gl::LINES,
3759 LineStrip => gl::LINE_STRIP,
3760 Triangles => gl::TRIANGLES,
3761 TriangleStrip => gl::TRIANGLE_STRIP,
3762 TriangleFan => gl::TRIANGLE_FAN,
3763 }
3764 }
3765}
3766
3767#[derive(Debug, Clone, PartialEq, PartialOrd)]
3768#[repr(C)]
3769pub struct Uniform {
3770 pub uniform_name: AzString,
3771 pub uniform_type: UniformType,
3772}
3773
3774impl Uniform {
3775 pub fn create<S: Into<AzString>>(name: S, uniform_type: UniformType) -> Self {
3776 Self {
3777 uniform_name: name.into(),
3778 uniform_type,
3779 }
3780 }
3781}
3782
3783#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
3784#[repr(C, u8)]
3785pub enum UniformType {
3786 Float(f32),
3787 FloatVec2([f32; 2]),
3788 FloatVec3([f32; 3]),
3789 FloatVec4([f32; 4]),
3790 Int(i32),
3791 IntVec2([i32; 2]),
3792 IntVec3([i32; 3]),
3793 IntVec4([i32; 4]),
3794 UnsignedInt(u32),
3795 UnsignedIntVec2([u32; 2]),
3796 UnsignedIntVec3([u32; 3]),
3797 UnsignedIntVec4([u32; 4]),
3798 Matrix2 {
3799 transpose: bool,
3800 matrix: [f32; 2 * 2],
3801 },
3802 Matrix3 {
3803 transpose: bool,
3804 matrix: [f32; 3 * 3],
3805 },
3806 Matrix4 {
3807 transpose: bool,
3808 matrix: [f32; 4 * 4],
3809 },
3810}
3811
3812impl UniformType {
3813 pub fn set(self, gl_context: &Rc<GenericGlContext>, location: GLint) {
3815 use self::UniformType::{Float, FloatVec2, FloatVec3, FloatVec4, Int, IntVec2, IntVec3, IntVec4, UnsignedInt, UnsignedIntVec2, UnsignedIntVec3, UnsignedIntVec4, Matrix2, Matrix3, Matrix4};
3816 match self {
3817 Float(r) => gl_context.uniform_1f(location, r),
3818 FloatVec2([r, g]) => gl_context.uniform_2f(location, r, g),
3819 FloatVec3([r, g, b]) => gl_context.uniform_3f(location, r, g, b),
3820 FloatVec4([r, g, b, a]) => gl_context.uniform_4f(location, r, g, b, a),
3821 Int(r) => gl_context.uniform_1i(location, r),
3822 IntVec2([r, g]) => gl_context.uniform_2i(location, r, g),
3823 IntVec3([r, g, b]) => gl_context.uniform_3i(location, r, g, b),
3824 IntVec4([r, g, b, a]) => gl_context.uniform_4i(location, r, g, b, a),
3825 UnsignedInt(r) => gl_context.uniform_1ui(location, r),
3826 UnsignedIntVec2([r, g]) => gl_context.uniform_2ui(location, r, g),
3827 UnsignedIntVec3([r, g, b]) => gl_context.uniform_3ui(location, r, g, b),
3828 UnsignedIntVec4([r, g, b, a]) => gl_context.uniform_4ui(location, r, g, b, a),
3829 Matrix2 { transpose, matrix } => {
3830 gl_context.uniform_matrix_2fv(location, transpose, &matrix[..]);
3831 }
3832 Matrix3 { transpose, matrix } => {
3833 gl_context.uniform_matrix_3fv(location, transpose, &matrix[..]);
3834 }
3835 Matrix4 { transpose, matrix } => {
3836 gl_context.uniform_matrix_4fv(location, transpose, &matrix[..]);
3837 }
3838 }
3839 }
3840}
3841
3842#[repr(C)]
3843pub struct GlShader {
3844 pub program_id: GLuint,
3845 pub gl_context: GlContextPtr,
3846 pub run_destructor: bool,
3850}
3851
3852impl ::core::fmt::Display for GlShader {
3853 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3854 write!(f, "GlShader {{ program_id: {} }}", self.program_id)
3855 }
3856}
3857
3858impl_traits_for_gl_object!(GlShader, program_id);
3859
3860impl Drop for GlShader {
3861 fn drop(&mut self) {
3862 if !self.run_destructor {
3865 return;
3866 }
3867 self.run_destructor = false;
3868 self.gl_context.delete_program(self.program_id);
3869 }
3870}
3871
3872#[repr(C)]
3873#[derive(Clone)]
3874pub struct VertexShaderCompileError {
3875 pub error_id: i32,
3876 pub info_log: AzString,
3877}
3878
3879impl_traits_for_gl_object!(VertexShaderCompileError, error_id);
3880
3881impl ::core::fmt::Display for VertexShaderCompileError {
3882 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3883 write!(f, "E{}: {}", self.error_id, self.info_log)
3884 }
3885}
3886
3887#[repr(C)]
3888#[derive(Clone)]
3889pub struct FragmentShaderCompileError {
3890 pub error_id: i32,
3891 pub info_log: AzString,
3892}
3893
3894impl_traits_for_gl_object!(FragmentShaderCompileError, error_id);
3895
3896impl ::core::fmt::Display for FragmentShaderCompileError {
3897 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3898 write!(f, "E{}: {}", self.error_id, self.info_log)
3899 }
3900}
3901
3902#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
3903pub enum GlShaderCompileError {
3904 Vertex(VertexShaderCompileError),
3905 Fragment(FragmentShaderCompileError),
3906}
3907
3908impl ::core::fmt::Display for GlShaderCompileError {
3909 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3910 use self::GlShaderCompileError::{Vertex, Fragment};
3911 match self {
3912 Vertex(vert_err) => write!(f, "Failed to compile vertex shader: {vert_err}"),
3913 Fragment(frag_err) => write!(f, "Failed to compile fragment shader: {frag_err}"),
3914 }
3915 }
3916}
3917
3918impl ::core::fmt::Debug for GlShaderCompileError {
3919 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3920 write!(f, "{self}")
3921 }
3922}
3923
3924#[repr(C)]
3925#[derive(Clone)]
3926pub struct GlShaderLinkError {
3927 pub error_id: i32,
3928 pub info_log: AzString,
3929}
3930
3931impl_traits_for_gl_object!(GlShaderLinkError, error_id);
3932
3933impl ::core::fmt::Display for GlShaderLinkError {
3934 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3935 write!(f, "E{}: {}", self.error_id, self.info_log)
3936 }
3937}
3938
3939#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
3940pub enum GlShaderCreateError {
3941 Compile(GlShaderCompileError),
3942 Link(GlShaderLinkError),
3943 NoShaderCompiler,
3944}
3945
3946impl ::core::fmt::Display for GlShaderCreateError {
3947 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3948 use self::GlShaderCreateError::{Compile, Link, NoShaderCompiler};
3949 match self {
3950 Compile(compile_err) => write!(f, "Shader compile error: {compile_err}"),
3951 Link(link_err) => write!(f, "Shader linking error: {link_err}"),
3952 NoShaderCompiler => {
3953 write!(f, "OpenGL implementation doesn't include a shader compiler")
3954 }
3955 }
3956 }
3957}
3958
3959impl ::core::fmt::Debug for GlShaderCreateError {
3960 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3961 write!(f, "{self}")
3962 }
3963}
3964
3965impl GlShader {
3966 #[allow(clippy::cast_possible_truncation)] pub fn new(
3976 gl_context: &GlContextPtr,
3977 vertex_shader: &str,
3978 fragment_shader: &str,
3979 ) -> Result<Self, GlShaderCreateError> {
3980 let mut shader_compiler_supported = [gl::FALSE as u8];
3982 gl_context.get_boolean_v(
3983 gl::SHADER_COMPILER,
3984 (&mut shader_compiler_supported[..]).into(),
3985 );
3986 if u32::from(shader_compiler_supported[0]) == gl::FALSE {
3987 return Err(GlShaderCreateError::NoShaderCompiler);
3989 }
3990
3991 let vertex_shader_object = gl_context.create_shader(gl::VERTEX_SHADER);
3994 gl_context.shader_source(
3995 vertex_shader_object,
3996 vec![AzString::from(vertex_shader.to_string())].into(),
3997 );
3998 gl_context.compile_shader(vertex_shader_object);
3999
4000 if let Some(error_id) = get_gl_shader_error(gl_context, vertex_shader_object) {
4001 let info_log = gl_context.get_shader_info_log(vertex_shader_object);
4002 gl_context.delete_shader(vertex_shader_object);
4003 return Err(GlShaderCreateError::Compile(GlShaderCompileError::Vertex(
4004 VertexShaderCompileError {
4005 error_id,
4006 info_log,
4007 },
4008 )));
4009 }
4010
4011 let fragment_shader_object = gl_context.create_shader(gl::FRAGMENT_SHADER);
4014 gl_context.shader_source(
4015 fragment_shader_object,
4016 vec![AzString::from(fragment_shader.to_string())].into(),
4017 );
4018 gl_context.compile_shader(fragment_shader_object);
4019
4020 if let Some(error_id) = get_gl_shader_error(gl_context, fragment_shader_object) {
4021 let info_log = gl_context.get_shader_info_log(fragment_shader_object);
4022 gl_context.delete_shader(vertex_shader_object);
4023 gl_context.delete_shader(fragment_shader_object);
4024 return Err(GlShaderCreateError::Compile(
4025 GlShaderCompileError::Fragment(FragmentShaderCompileError {
4026 error_id,
4027 info_log,
4028 }),
4029 ));
4030 }
4031
4032 let program_id = gl_context.create_program();
4035 gl_context.attach_shader(program_id, vertex_shader_object);
4036 gl_context.attach_shader(program_id, fragment_shader_object);
4037 gl_context.link_program(program_id);
4038
4039 if let Some(error_id) = get_gl_program_error(gl_context, program_id) {
4040 let info_log = gl_context.get_program_info_log(program_id);
4041 gl_context.delete_shader(vertex_shader_object);
4042 gl_context.delete_shader(fragment_shader_object);
4043 gl_context.delete_program(program_id);
4044 return Err(GlShaderCreateError::Link(GlShaderLinkError {
4045 error_id,
4046 info_log,
4047 }));
4048 }
4049
4050 gl_context.delete_shader(vertex_shader_object);
4051 gl_context.delete_shader(fragment_shader_object);
4052
4053 Ok(Self {
4054 program_id,
4055 gl_context: gl_context.clone(),
4056 run_destructor: true,
4057 })
4058 }
4059
4060 #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] #[allow(clippy::too_many_lines)] pub fn draw(
4068 shader_program_id: GLuint,
4070 texture: &mut Texture,
4072 buffers: &[(&VertexBuffer, &[Uniform])],
4074 ) {
4075 use alloc::collections::btree_map::BTreeMap;
4076
4077 const INDEX_TYPE: GLuint = gl::UNSIGNED_INT;
4078
4079 let texture_size = texture.size;
4080
4081 let gl_context = &texture.gl_context;
4082
4083 let saved = GlStateSave::save(gl_context);
4084
4085 let mut current_blend_enabled = [0_u8];
4087 let mut current_primitive_restart_enabled = [0_u8];
4088 gl_context.get_boolean_v(gl::BLEND, (&mut current_blend_enabled[..]).into());
4089 gl_context.get_boolean_v(
4090 gl::PRIMITIVE_RESTART,
4091 (&mut current_primitive_restart_enabled[..]).into(),
4092 );
4093
4094 let framebuffers = gl_context.gen_framebuffers(1);
4096 let framebuffer_id = *framebuffers.get(0).unwrap();
4097 let mut fbo_rbo_guard = FboRboGuard {
4101 gl_context,
4102 framebuffer_id,
4103 renderbuffer_id: 0,
4104 };
4105 gl_context.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_id);
4106
4107 let depthbuffers = gl_context.gen_renderbuffers(1);
4108 let depthbuffer_id = *depthbuffers.get(0).unwrap();
4109 fbo_rbo_guard.renderbuffer_id = depthbuffer_id;
4110
4111 gl_context.bind_texture(gl::TEXTURE_2D, texture.texture_id);
4112 gl_context.tex_image_2d(
4113 gl::TEXTURE_2D,
4114 0,
4115 gl::RGBA as i32, texture_size.width as i32,
4117 texture_size.height as i32,
4118 0,
4119 gl::RGBA, gl::UNSIGNED_BYTE,
4121 None.into(),
4122 );
4123 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as i32);
4124 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as i32);
4125 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as i32);
4126 gl_context.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as i32);
4127
4128 gl_context.bind_renderbuffer(gl::RENDERBUFFER, depthbuffer_id);
4129 gl_context.renderbuffer_storage(
4130 gl::RENDERBUFFER,
4131 gl::DEPTH_COMPONENT,
4132 texture_size.width as i32,
4133 texture_size.height as i32,
4134 );
4135 gl_context.framebuffer_renderbuffer(
4136 gl::FRAMEBUFFER,
4137 gl::DEPTH_ATTACHMENT,
4138 gl::RENDERBUFFER,
4139 depthbuffer_id,
4140 );
4141
4142 gl_context.framebuffer_texture_2d(
4143 gl::FRAMEBUFFER,
4144 gl::COLOR_ATTACHMENT0,
4145 gl::TEXTURE_2D,
4146 texture.texture_id,
4147 0,
4148 );
4149 gl_context.draw_buffers([gl::COLOR_ATTACHMENT0][..].into());
4150
4151 #[cfg(feature = "std")]
4152 {
4153 let fb_check = gl_context.check_frame_buffer_status(gl::FRAMEBUFFER);
4154 match fb_check {
4155 gl::FRAMEBUFFER_COMPLETE => {}
4156 gl::FRAMEBUFFER_UNDEFINED => {
4157 println!("GL_FRAMEBUFFER_UNDEFINED");
4158 }
4159 gl::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => {
4160 println!("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
4161 }
4162 gl::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => {
4163 println!("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
4164 }
4165 gl::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => {
4166 println!("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER");
4167 }
4168 gl::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => {
4169 println!("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER");
4170 }
4171 gl::FRAMEBUFFER_UNSUPPORTED => {
4172 println!("GL_FRAMEBUFFER_UNSUPPORTED");
4173 }
4174 gl::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => {
4175 println!("GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE");
4176 }
4177 gl::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS => {
4178 println!("GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS");
4179 }
4180 o => {
4181 println!("glFramebufferStatus returned unknown return code: {o}");
4182 }
4183 }
4184 }
4185
4186 gl_context.viewport(0, 0, texture_size.width as i32, texture_size.height as i32);
4187 gl_context.enable(gl::BLEND);
4188 gl_context.enable(gl::PRIMITIVE_RESTART);
4191 unsafe {
4192 let gl = gl_context.get();
4193 if !gl.glPrimitiveRestartIndex.is_null() {
4194 let func: extern "system" fn(u32) =
4195 core::mem::transmute(gl.glPrimitiveRestartIndex);
4196 func(GL_RESTART_INDEX); }
4198 }
4199 gl_context.disable(gl::MULTISAMPLE);
4200 gl_context.blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA); gl_context.use_program(shader_program_id);
4202
4203 let mut uniform_locations: BTreeMap<AzString, i32> = BTreeMap::new();
4205 let mut max_uniform_len = 0;
4206 for (_, uniforms) in buffers {
4207 for uniform in *uniforms {
4208 if !uniform_locations.contains_key(&uniform.uniform_name) {
4209 uniform_locations.insert(
4210 uniform.uniform_name.clone(),
4211 gl_context.get_uniform_location(
4212 shader_program_id,
4213 uniform.uniform_name.as_str(),
4214 ),
4215 );
4216 }
4217 }
4218 max_uniform_len = max_uniform_len.max(uniforms.len());
4219 }
4220 let mut current_uniforms = vec![None; max_uniform_len];
4221
4222 for (vertex_index_buffer, uniforms) in buffers {
4227 gl_context.bind_vertex_array(vertex_index_buffer.vao.vao_id);
4228 gl_context.bind_buffer(gl::ARRAY_BUFFER, vertex_index_buffer.vertex_buffer_id);
4229 gl_context.bind_buffer(
4230 gl::ELEMENT_ARRAY_BUFFER,
4231 vertex_index_buffer.index_buffer_id,
4232 );
4233
4234 for (uniform_index, uniform) in uniforms.iter().enumerate() {
4236 if current_uniforms[uniform_index] != Some(uniform.uniform_type) {
4237 let uniform_location = uniform_locations[&uniform.uniform_name];
4238 uniform.uniform_type.set(gl_context.get(), uniform_location);
4239 current_uniforms[uniform_index] = Some(uniform.uniform_type);
4240 }
4241 }
4242
4243 gl_context.draw_elements(
4244 vertex_index_buffer.index_buffer_format.get_gl_id(),
4245 vertex_index_buffer.index_buffer_len as i32,
4246 INDEX_TYPE,
4247 0,
4248 );
4249 }
4250
4251 if u32::from(current_blend_enabled[0]) == gl::FALSE {
4253 gl_context.disable(gl::BLEND);
4254 }
4255 if u32::from(current_primitive_restart_enabled[0]) == gl::FALSE {
4256 gl_context.disable(gl::PRIMITIVE_RESTART);
4257 }
4258
4259 saved.restore(gl_context);
4265 drop(fbo_rbo_guard);
4266
4267 texture.format = RawImageFormat::RGBA8;
4268 texture.flags = TextureFlags {
4269 is_opaque: false,
4270 is_video_texture: false,
4271 };
4272 }
4273}
4274
4275#[allow(clippy::cast_possible_wrap)] fn get_gl_shader_error(context: &GlContextPtr, shader_object: GLuint) -> Option<i32> {
4277 let mut err = [0];
4278 context.get_shader_iv(shader_object, gl::COMPILE_STATUS, (&mut err[..]).into());
4279 let err_code = err[0];
4280 if err_code == gl::TRUE as i32 {
4281 None
4282 } else {
4283 Some(err_code)
4284 }
4285}
4286
4287#[allow(clippy::cast_possible_wrap)] fn get_gl_program_error(context: &GlContextPtr, shader_object: GLuint) -> Option<i32> {
4289 let mut err = [0];
4290 context.get_program_iv(shader_object, gl::LINK_STATUS, (&mut err[..]).into());
4291 let err_code = err[0];
4292 if err_code == gl::TRUE as i32 {
4293 None
4294 } else {
4295 Some(err_code)
4296 }
4297}
4298
4299#[cfg(test)]
4300mod audit_tests {
4301 use super::*;
4302
4303 #[test]
4307 fn refstr_null_and_empty_is_empty_str() {
4308 let null = Refstr {
4309 ptr: core::ptr::null(),
4310 len: 0,
4311 };
4312 assert_eq!(null.as_str(), "");
4313
4314 let null_lenful = Refstr {
4316 ptr: core::ptr::null(),
4317 len: 5,
4318 };
4319 assert_eq!(null_lenful.as_str(), "");
4320
4321 let s = "hello";
4322 let good: Refstr = s.into();
4323 assert_eq!(good.as_str(), "hello");
4324 }
4325
4326 #[test]
4327 fn refstr_vec_ref_null_is_empty_slice() {
4328 let null = RefstrVecRef {
4329 ptr: core::ptr::null(),
4330 len: 3,
4331 };
4332 assert!(null.as_slice().is_empty());
4333 }
4334
4335 #[test]
4336 fn u8_vec_ref_null_is_empty_slice() {
4337 let null = U8VecRef {
4338 ptr: core::ptr::null(),
4339 len: 8,
4340 };
4341 assert!(null.as_slice().is_empty());
4342
4343 let data = [1u8, 2, 3];
4344 let good: U8VecRef = (&data[..]).into();
4345 assert_eq!(good.as_slice(), &[1, 2, 3]);
4346 }
4347}
4348
4349#[cfg(test)]
4350#[allow(clippy::float_cmp)] mod autotest_generated {
4352 use super::*;
4353
4354 fn null_gl() -> Rc<GenericGlContext> {
4366 Rc::new(unsafe { core::mem::zeroed::<GenericGlContext>() })
4369 }
4370
4371 fn null_ctx() -> GlContextPtr {
4372 GlContextPtr::new(RendererType::Software, null_gl())
4373 }
4374
4375 fn test_texture(texture_id: GLuint, width: u32, height: u32) -> Texture {
4376 Texture::create(
4377 texture_id,
4378 TextureFlags {
4379 is_opaque: false,
4380 is_video_texture: false,
4381 },
4382 PhysicalSizeU32 { width, height },
4383 ColorU {
4384 r: 1,
4385 g: 2,
4386 b: 3,
4387 a: 4,
4388 },
4389 null_ctx(),
4390 RawImageFormat::RGBA8,
4391 )
4392 }
4393
4394 const ALL_ATTRIB_TYPES: [VertexAttributeType; 5] = [
4395 VertexAttributeType::Float,
4396 VertexAttributeType::Double,
4397 VertexAttributeType::UnsignedByte,
4398 VertexAttributeType::UnsignedShort,
4399 VertexAttributeType::UnsignedInt,
4400 ];
4401
4402 const ALL_INDEX_FORMATS: [IndexBufferFormat; 6] = [
4403 IndexBufferFormat::Points,
4404 IndexBufferFormat::Lines,
4405 IndexBufferFormat::LineStrip,
4406 IndexBufferFormat::Triangles,
4407 IndexBufferFormat::TriangleStrip,
4408 IndexBufferFormat::TriangleFan,
4409 ];
4410
4411 #[test]
4417 fn refstr_roundtrips_unicode_multibyte_and_combining_marks() {
4418 for s in [
4421 "\u{1F600}",
4422 "日本語のテキスト",
4423 "e\u{0301}\u{0328}combining",
4424 "\u{0}nul\u{0}embedded\u{0}",
4425 "\u{FFFD}\u{200B}zero-width",
4426 ] {
4427 let r: Refstr = s.into();
4428 assert_eq!(r.as_str(), s);
4429 assert_eq!(r.as_str().len(), s.len());
4430 }
4431 }
4432
4433 #[test]
4434 fn refstr_len_zero_over_nonempty_buffer_is_empty_not_dangling() {
4435 let backing = "not empty";
4437 let r = Refstr {
4438 ptr: backing.as_ptr(),
4439 len: 0,
4440 };
4441 assert_eq!(r.as_str(), "");
4442 }
4443
4444 #[test]
4445 fn refstr_huge_input_does_not_hang() {
4446 let huge = "x".repeat(1_000_000);
4448 let r: Refstr = huge.as_str().into();
4449 assert_eq!(r.as_str().len(), 1_000_000);
4450 assert_eq!(r.as_str(), huge.as_str());
4451 }
4452
4453 #[test]
4454 fn refstr_debug_on_null_does_not_panic() {
4455 let null = Refstr {
4456 ptr: core::ptr::null(),
4457 len: usize::MAX,
4458 };
4459 assert_eq!(alloc::format!("{null:?}"), "\"\"");
4461 }
4462
4463 #[test]
4464 fn refstr_clone_preserves_ptr_and_len() {
4465 let s = "clone me";
4466 let r: Refstr = s.into();
4467 let c = r.clone();
4468 assert_eq!(c.as_str(), s);
4469 assert!(core::ptr::eq(c.ptr, r.ptr));
4470 assert_eq!(c.len, r.len);
4471 }
4472
4473 #[test]
4474 fn every_vec_ref_with_null_ptr_and_nonzero_len_is_empty() {
4475 const GARBAGE_LEN: usize = usize::MAX;
4478
4479 assert!(RefstrVecRef {
4480 ptr: core::ptr::null(),
4481 len: GARBAGE_LEN
4482 }
4483 .as_slice()
4484 .is_empty());
4485 assert!(GLuintVecRef {
4486 ptr: core::ptr::null(),
4487 len: GARBAGE_LEN
4488 }
4489 .as_slice()
4490 .is_empty());
4491 assert!(GLenumVecRef {
4492 ptr: core::ptr::null(),
4493 len: GARBAGE_LEN
4494 }
4495 .as_slice()
4496 .is_empty());
4497 assert!(U8VecRef {
4498 ptr: core::ptr::null(),
4499 len: GARBAGE_LEN
4500 }
4501 .as_slice()
4502 .is_empty());
4503 assert!(F32VecRef {
4504 ptr: core::ptr::null(),
4505 len: GARBAGE_LEN
4506 }
4507 .as_slice()
4508 .is_empty());
4509 assert!(I32VecRef {
4510 ptr: core::ptr::null(),
4511 len: GARBAGE_LEN
4512 }
4513 .as_slice()
4514 .is_empty());
4515
4516 let mut m64 = GLint64VecRefMut {
4518 ptr: core::ptr::null_mut(),
4519 len: GARBAGE_LEN,
4520 };
4521 assert!(m64.as_slice().is_empty());
4522 assert!(m64.as_mut_slice().is_empty());
4523
4524 let mut mf = GLfloatVecRefMut {
4525 ptr: core::ptr::null_mut(),
4526 len: GARBAGE_LEN,
4527 };
4528 assert!(mf.as_slice().is_empty());
4529 assert!(mf.as_mut_slice().is_empty());
4530
4531 let mut mi = GLintVecRefMut {
4532 ptr: core::ptr::null_mut(),
4533 len: GARBAGE_LEN,
4534 };
4535 assert!(mi.as_slice().is_empty());
4536 assert!(mi.as_mut_slice().is_empty());
4537
4538 let mut mb = GLbooleanVecRefMut {
4539 ptr: core::ptr::null_mut(),
4540 len: GARBAGE_LEN,
4541 };
4542 assert!(mb.as_slice().is_empty());
4543 assert!(mb.as_mut_slice().is_empty());
4544
4545 let mut mu8 = U8VecRefMut {
4546 ptr: core::ptr::null_mut(),
4547 len: GARBAGE_LEN,
4548 };
4549 assert!(mu8.as_slice().is_empty());
4550 assert!(mu8.as_mut_slice().is_empty());
4551 }
4552
4553 #[test]
4554 fn vec_refs_roundtrip_from_slice() {
4555 let u: [GLuint; 3] = [0, 1, u32::MAX];
4556 assert_eq!(GLuintVecRef::from(&u[..]).as_slice(), &u[..]);
4557
4558 let e: [GLenum; 2] = [gl::TRIANGLES, u32::MAX];
4559 assert_eq!(GLenumVecRef::from(&e[..]).as_slice(), &e[..]);
4560
4561 let b: [u8; 4] = [0, 127, 128, 255];
4562 assert_eq!(U8VecRef::from(&b[..]).as_slice(), &b[..]);
4563
4564 let i: [i32; 3] = [i32::MIN, 0, i32::MAX];
4565 assert_eq!(I32VecRef::from(&i[..]).as_slice(), &i[..]);
4566
4567 let empty: [u8; 0] = [];
4569 assert!(U8VecRef::from(&empty[..]).as_slice().is_empty());
4570 }
4571
4572 #[test]
4573 fn f32_vec_ref_preserves_nan_inf_and_subnormals_bit_exactly() {
4574 let vals: [f32; 6] = [
4577 f32::NAN,
4578 f32::INFINITY,
4579 f32::NEG_INFINITY,
4580 -0.0,
4581 f32::MIN_POSITIVE / 2.0, f32::MAX,
4583 ];
4584 let r = F32VecRef::from(&vals[..]);
4585 let got = r.as_slice();
4586 assert_eq!(got.len(), vals.len());
4587 for (g, v) in got.iter().zip(vals.iter()) {
4588 assert_eq!(g.to_bits(), v.to_bits());
4589 }
4590 assert!(got[0].is_nan());
4591 assert!(got[3].is_sign_negative());
4592 }
4593
4594 #[test]
4595 fn glint64_vec_ref_mut_handles_boundary_values() {
4596 let mut vals: [GLint64; 4] = [i64::MIN, -1, 0, i64::MAX];
4597 let mut r = GLint64VecRefMut::from(&mut vals[..]);
4598 assert_eq!(r.as_slice(), &[i64::MIN, -1, 0, i64::MAX]);
4599
4600 r.as_mut_slice()[0] = i64::MAX;
4602 r.as_mut_slice()[3] = i64::MIN;
4603 assert_eq!(vals, [i64::MAX, -1, 0, i64::MIN]);
4604 }
4605
4606 #[test]
4607 fn mut_vec_refs_write_through_to_the_caller_buffer() {
4608 let mut floats: [GLfloat; 2] = [0.0, 0.0];
4609 GLfloatVecRefMut::from(&mut floats[..]).as_mut_slice()[1] = f32::NAN;
4610 assert!(floats[1].is_nan());
4611
4612 let mut ints: [GLint; 2] = [0, 0];
4613 GLintVecRefMut::from(&mut ints[..]).as_mut_slice()[0] = i32::MIN;
4614 assert_eq!(ints[0], i32::MIN);
4615
4616 let mut bools: [GLboolean; 2] = [0, 0];
4617 GLbooleanVecRefMut::from(&mut bools[..]).as_mut_slice()[1] = 255;
4618 assert_eq!(bools[1], 255);
4619
4620 let mut bytes: [u8; 3] = [1, 2, 3];
4621 U8VecRefMut::from(&mut bytes[..]).as_mut_slice()[2] = 0;
4622 assert_eq!(bytes, [1, 2, 0]);
4623 }
4624
4625 #[test]
4626 fn u8_vec_ref_ord_eq_hash_agree_with_the_underlying_slice() {
4627 use core::hash::{BuildHasher, Hasher};
4628
4629 use alloc::collections::BTreeSet;
4630
4631 let a = [1u8, 2, 3];
4632 let b = [1u8, 2, 4];
4633 let ra = U8VecRef::from(&a[..]);
4634 let rb = U8VecRef::from(&b[..]);
4635
4636 assert_eq!(ra, U8VecRef::from(&a[..]));
4637 assert!(ra < rb);
4638 assert_eq!(ra.cmp(&rb), a[..].cmp(&b[..]));
4639
4640 let null = U8VecRef {
4642 ptr: core::ptr::null(),
4643 len: 99,
4644 };
4645 let empty: [u8; 0] = [];
4646 assert_eq!(null, U8VecRef::from(&empty[..]));
4647
4648 fn hash_of(v: &U8VecRef) -> u64 {
4650
4651
4652 core::hash::BuildHasherDefault::<TestHasher>::default().hash_one(v)
4653 }
4654 #[derive(Default)]
4655 struct TestHasher(u64);
4656 impl Hasher for TestHasher {
4657 fn finish(&self) -> u64 {
4658 self.0
4659 }
4660 fn write(&mut self, bytes: &[u8]) {
4661 for b in bytes {
4662 self.0 = self.0.wrapping_mul(31).wrapping_add(u64::from(*b));
4663 }
4664 }
4665 }
4666 assert_eq!(hash_of(&ra), hash_of(&U8VecRef::from(&a[..])));
4667 assert_eq!(hash_of(&null), hash_of(&U8VecRef::from(&empty[..])));
4668
4669 let mut set = BTreeSet::new();
4671 set.insert(ra.clone());
4672 set.insert(U8VecRef::from(&a[..]));
4673 set.insert(rb);
4674 assert_eq!(set.len(), 2);
4675 }
4676
4677 #[test]
4678 fn refstr_vec_ref_roundtrips_and_maps_back_to_strs() {
4679 let strs = ["", "a", "\u{1F600}"];
4680 let refstrs: Vec<Refstr> = strs.iter().map(|s| Refstr::from(*s)).collect();
4681 let vec_ref = RefstrVecRef::from(&refstrs[..]);
4682 let got: Vec<&str> = vec_ref.as_slice().iter().map(Refstr::as_str).collect();
4683 assert_eq!(got, strs);
4684 }
4685
4686 #[test]
4691 fn glsync_ptr_roundtrips_null_and_nonnull() {
4692 let null = GLsyncPtr::new(core::ptr::null());
4693 assert!(null.clone().get().is_null());
4694 assert_eq!(alloc::format!("{null:?}"), "0x0");
4695
4696 let sentinel = usize::MAX as *const c_void;
4698 let p = GLsyncPtr::new(sentinel);
4699 assert_eq!(p.clone().get() as usize, usize::MAX);
4700 assert!(p.run_destructor);
4701 }
4702
4703 #[cfg(feature = "std")]
4708 #[test]
4709 fn shader_with_glsl_version_replaces_only_the_first_line() {
4710 let src = b"#version 150\nbody line 1\nbody line 2";
4711 let out = shader_with_glsl_version(src, b"#version 300 es\n");
4712 assert_eq!(out, b"#version 300 es\nbody line 1\nbody line 2".to_vec());
4713 }
4714
4715 #[cfg(feature = "std")]
4716 #[test]
4717 fn shader_with_glsl_version_empty_src_yields_just_the_version_line() {
4718 assert_eq!(
4721 shader_with_glsl_version(b"", b"#version 150\n"),
4722 b"#version 150\n".to_vec()
4723 );
4724 }
4725
4726 #[cfg(feature = "std")]
4727 #[test]
4728 fn shader_with_glsl_version_src_without_newline_is_kept_whole() {
4729 let out = shader_with_glsl_version(b"void main(){}", b"#version 150\n");
4732 assert_eq!(out, b"#version 150\nvoid main(){}".to_vec());
4733 }
4734
4735 #[cfg(feature = "std")]
4736 #[test]
4737 fn shader_with_glsl_version_leading_newline_drops_only_that_newline() {
4738 let out = shader_with_glsl_version(b"\nrest", b"V\n");
4739 assert_eq!(out, b"V\nrest".to_vec());
4740 }
4741
4742 #[cfg(feature = "std")]
4743 #[test]
4744 fn shader_with_glsl_version_empty_version_line_still_strips_first_line() {
4745 let out = shader_with_glsl_version(b"#version 150\nbody", b"");
4746 assert_eq!(out, b"body".to_vec());
4747
4748 assert!(shader_with_glsl_version(b"", b"").is_empty());
4750 }
4751
4752 #[cfg(feature = "std")]
4753 #[test]
4754 fn shader_with_glsl_version_is_byte_exact_on_invalid_utf8_and_nul_bytes() {
4755 let src = b"#version 150\n\xFF\xFE\x00\x80body";
4758 let out = shader_with_glsl_version(src, b"#version 100\n");
4759 assert_eq!(out, b"#version 100\n\xFF\xFE\x00\x80body".to_vec());
4760
4761 let out2 = shader_with_glsl_version(&[0xFF, 0xFE, 0x00], b"V\n");
4763 assert_eq!(out2, vec![b'V', b'\n', 0xFF, 0xFE, 0x00]);
4764 }
4765
4766 #[cfg(feature = "std")]
4767 #[test]
4768 fn shader_with_glsl_version_handles_a_1mb_source_without_hanging() {
4769 let mut src = b"#version 150\n".to_vec();
4770 src.resize(src.len() + 1_000_000, b'x');
4771 let out = shader_with_glsl_version(&src, b"#version 300 es\n");
4772 assert_eq!(out.len(), b"#version 300 es\n".len() + 1_000_000);
4773 assert!(out.starts_with(b"#version 300 es\n"));
4774 assert!(out.ends_with(b"xxxx"));
4775 }
4776
4777 #[test]
4782 fn glsl_version_candidates_are_wellformed_and_distinct() {
4783 for gl_type in [GlType::Gl, GlType::Gles] {
4784 let candidates = glsl_version_candidates(gl_type);
4785 assert!(
4786 !candidates.is_empty(),
4787 "{gl_type:?} must have at least one candidate or the probe can never succeed"
4788 );
4789 for c in candidates {
4790 let s = core::str::from_utf8(c).expect("candidate must be valid UTF-8");
4794 assert!(s.starts_with("#version "), "{s:?}");
4795 assert!(s.ends_with('\n'), "{s:?}");
4796 let parsed = s.trim().trim_start_matches("#version ");
4797 assert!(!parsed.is_empty(), "{s:?} must parse to a nonempty version");
4798 }
4799 for (i, a) in candidates.iter().enumerate() {
4801 for b in candidates.iter().skip(i + 1) {
4802 assert_ne!(a, b, "duplicate candidate in {gl_type:?}");
4803 }
4804 }
4805 }
4806
4807 for g in glsl_version_candidates(GlType::Gl) {
4809 assert!(!glsl_version_candidates(GlType::Gles).contains(g));
4810 }
4811
4812 let first_gl = core::str::from_utf8(glsl_version_candidates(GlType::Gl)[0]).unwrap();
4814 assert_eq!(first_gl.trim().trim_start_matches("#version "), "150");
4815 let first_es = core::str::from_utf8(glsl_version_candidates(GlType::Gles)[0]).unwrap();
4816 assert_eq!(first_es.trim().trim_start_matches("#version "), "300 es");
4817 }
4818
4819 #[test]
4820 fn gl_type_from_context_gl_type_is_total() {
4821 assert_eq!(GlType::from(GlContextGlType::Gl), GlType::Gl);
4822 assert_eq!(GlType::from(GlContextGlType::GlEs), GlType::Gles);
4823 }
4824
4825 #[test]
4830 fn gl_context_ptr_software_is_never_usable_and_has_no_shaders() {
4831 let ctx = GlContextPtr::new(RendererType::Software, null_gl());
4834 assert!(!ctx.is_gl_usable());
4835 assert_eq!(ctx.get_svg_shader(), 0);
4836 assert_eq!(ctx.get_brush_shader(), 0);
4837 assert_eq!(ctx.get_fxaa_shader(), 0);
4838 assert_eq!(ctx.get_usable_glsl_version().as_str(), "");
4839 assert_eq!(ctx.renderer_type, RendererType::Software);
4840 }
4841
4842 #[test]
4843 fn gl_context_ptr_hardware_with_broken_driver_falls_back_instead_of_panicking() {
4844 let ctx = GlContextPtr::new(RendererType::Hardware, null_gl());
4850 assert!(
4851 !ctx.is_gl_usable(),
4852 "a driver that compiles nothing must report is_gl_usable() == false"
4853 );
4854 assert_eq!(ctx.get_svg_shader(), 0);
4855 assert_eq!(ctx.get_brush_shader(), 0);
4856 assert_eq!(ctx.get_fxaa_shader(), 0);
4857 assert_eq!(
4858 ctx.get_usable_glsl_version().as_str(),
4859 "",
4860 "glsl_version must be empty when the context is unusable"
4861 );
4862 }
4863
4864 #[test]
4865 fn gl_context_ptr_get_type_defaults_to_desktop_gl_on_an_empty_version_string() {
4866 assert_eq!(null_ctx().get_type(), GlType::Gl);
4869 }
4870
4871 #[test]
4872 fn gl_context_ptr_clone_is_eq_but_distinct_contexts_are_not() {
4873 let a = null_ctx();
4876 let clone = a.clone();
4877 assert_eq!(a, clone);
4878 assert_eq!(a.cmp(&clone), core::cmp::Ordering::Equal);
4879 assert_eq!(a.partial_cmp(&clone), Some(core::cmp::Ordering::Equal));
4880
4881 let b = null_ctx();
4882 assert_ne!(a, b);
4883 assert_eq!(a.cmp(&b), a.partial_cmp(&b).unwrap());
4885 assert_eq!(a.cmp(&b).reverse(), b.cmp(&a));
4886
4887 assert!(Rc::ptr_eq(a.get(), clone.get()));
4889 assert!(!Rc::ptr_eq(a.get(), b.get()));
4890 }
4891
4892 #[test]
4893 fn gl_context_ptr_gen_family_returns_empty_for_every_n_including_negatives() {
4894 let ctx = null_ctx();
4898 for n in [0, 1, -1, i32::MIN, i32::MAX] {
4899 assert!(ctx.gen_buffers(n).as_slice().is_empty(), "gen_buffers({n})");
4900 assert!(ctx.gen_textures(n).as_slice().is_empty(), "gen_textures({n})");
4901 assert!(
4902 ctx.gen_framebuffers(n).as_slice().is_empty(),
4903 "gen_framebuffers({n})"
4904 );
4905 assert!(
4906 ctx.gen_renderbuffers(n).as_slice().is_empty(),
4907 "gen_renderbuffers({n})"
4908 );
4909 assert!(
4910 ctx.gen_vertex_arrays(n).as_slice().is_empty(),
4911 "gen_vertex_arrays({n})"
4912 );
4913 assert!(ctx.gen_queries(n).as_slice().is_empty(), "gen_queries({n})");
4914 }
4915 }
4916
4917 #[test]
4918 fn gl_context_ptr_integer_extremes_do_not_panic() {
4919 let ctx = null_ctx();
4923 let data = [0u8; 4];
4924 let void_ptr = || GlVoidPtrConst {
4925 ptr: data.as_ptr().cast(),
4926 run_destructor: false,
4927 };
4928
4929 for offset in [0isize, -1, isize::MIN, isize::MAX] {
4930 for size in [0isize, -1, isize::MIN, isize::MAX] {
4931 ctx.buffer_sub_data_untyped(gl::ARRAY_BUFFER, offset, size, void_ptr());
4932 let _ = ctx.map_buffer_range(gl::ARRAY_BUFFER, offset, size, 0);
4933 }
4934 }
4935 ctx.buffer_data_untyped(gl::ARRAY_BUFFER, isize::MIN, void_ptr(), gl::STATIC_DRAW);
4936
4937 for offset in [0usize, 1, usize::MAX] {
4939 ctx.tex_sub_image_2d_pbo(
4940 gl::TEXTURE_2D,
4941 0,
4942 0,
4943 0,
4944 1,
4945 1,
4946 gl::RGBA,
4947 gl::UNSIGNED_BYTE,
4948 offset,
4949 );
4950 }
4951
4952 ctx.pixel_store_i(gl::PACK_ALIGNMENT, i32::MIN);
4953 ctx.pixel_store_i(gl::PACK_ALIGNMENT, i32::MAX);
4954 let _ = ctx.unmap_buffer(gl::ARRAY_BUFFER);
4955 }
4956
4957 #[test]
4958 fn gl_context_ptr_float_extremes_do_not_panic() {
4959 let ctx = null_ctx();
4961 for v in [
4962 0.0,
4963 1.0,
4964 -1.0,
4965 f32::NAN,
4966 f32::INFINITY,
4967 f32::NEG_INFINITY,
4968 f32::MIN,
4969 f32::MAX,
4970 ] {
4971 ctx.sample_coverage(v, false);
4972 ctx.sample_coverage(v, true);
4973 ctx.polygon_offset(v, v);
4974 }
4975 }
4976
4977 #[test]
4978 fn gl_context_ptr_shader_source_handles_empty_unicode_and_embedded_nuls() {
4979 let ctx = null_ctx();
4982 let strings: StringVec = vec![
4983 AzString::from(String::new()),
4984 AzString::from("\u{1F600} emoji".to_string()),
4985 AzString::from("has\u{0}nul".to_string()),
4986 AzString::from("x".repeat(100_000)),
4987 ]
4988 .into();
4989 ctx.shader_source(0, strings);
4990
4991 ctx.shader_source(u32::MAX, Vec::<AzString>::new().into());
4993 }
4994
4995 #[test]
4996 fn gl_context_ptr_read_pixels_sizes_the_buffer_from_the_dimensions() {
4997 let ctx = null_ctx();
5005 let px = ctx.read_pixels(0, 0, 2, 3, gl::RGBA, gl::UNSIGNED_BYTE);
5006 assert_eq!(px.len(), 2 * 3 * 4, "RGBA/UNSIGNED_BYTE = 4 bytes per pixel");
5007
5008 assert_eq!(
5010 ctx.read_pixels(0, 0, 0, 0, gl::RGBA, gl::UNSIGNED_BYTE).len(),
5011 0
5012 );
5013 }
5014
5015 #[test]
5016 fn gl_context_ptr_read_pixels_into_buffer_accepts_null_and_undersized_targets() {
5017 let ctx = null_ctx();
5020 ctx.read_pixels_into_buffer(
5021 0,
5022 0,
5023 4,
5024 4,
5025 gl::RGBA,
5026 gl::UNSIGNED_BYTE,
5027 U8VecRefMut {
5028 ptr: core::ptr::null_mut(),
5029 len: 64,
5030 },
5031 );
5032
5033 let mut small = [0u8; 1];
5034 ctx.read_pixels_into_buffer(
5035 0,
5036 0,
5037 4,
5038 4,
5039 gl::RGBA,
5040 gl::UNSIGNED_BYTE,
5041 (&mut small[..]).into(),
5042 );
5043 assert_eq!(small, [0u8; 1]);
5044 }
5045
5046 #[test]
5047 fn gl_context_ptr_uniform_getters_accept_null_result_buffers() {
5048 let ctx = null_ctx();
5049 ctx.get_uniform_iv(
5050 0,
5051 -1,
5052 GLintVecRefMut {
5053 ptr: core::ptr::null_mut(),
5054 len: 16,
5055 },
5056 );
5057 ctx.get_uniform_fv(
5058 0,
5059 i32::MIN,
5060 GLfloatVecRefMut {
5061 ptr: core::ptr::null_mut(),
5062 len: 16,
5063 },
5064 );
5065
5066 let mut ints = [0i32; 2];
5068 ctx.get_uniform_iv(u32::MAX, i32::MAX, (&mut ints[..]).into());
5069 let mut floats = [0f32; 2];
5070 ctx.get_uniform_fv(u32::MAX, i32::MAX, (&mut floats[..]).into());
5071 }
5072
5073 #[test]
5074 fn gl_context_ptr_get_uniform_indices_handles_empty_and_null_name_lists() {
5075 let ctx = null_ctx();
5076 let empty: &[Refstr] = &[];
5077 assert!(ctx
5078 .get_uniform_indices(0, empty.into())
5079 .as_slice()
5080 .is_empty());
5081 assert!(ctx
5082 .get_uniform_indices(
5083 0,
5084 RefstrVecRef {
5085 ptr: core::ptr::null(),
5086 len: 4,
5087 },
5088 )
5089 .as_slice()
5090 .is_empty());
5091 }
5092
5093 #[test]
5094 fn gl_context_ptr_delete_family_accepts_empty_and_null_id_lists() {
5095 let ctx = null_ctx();
5097 let empty: &[GLuint] = &[];
5098 ctx.delete_buffers(empty.into());
5099 ctx.delete_textures(empty.into());
5100 ctx.delete_framebuffers(empty.into());
5101 ctx.delete_renderbuffers(empty.into());
5102 ctx.delete_vertex_arrays(empty.into());
5103 ctx.delete_queries(empty.into());
5104
5105 let null = || GLuintVecRef {
5106 ptr: core::ptr::null(),
5107 len: 7,
5108 };
5109 ctx.delete_buffers(null());
5110 ctx.delete_textures(null());
5111 ctx.delete_framebuffers(null());
5112 ctx.delete_renderbuffers(null());
5113 ctx.delete_vertex_arrays(null());
5114 ctx.delete_queries(null());
5115
5116 let ids: &[GLuint] = &[0, 1, u32::MAX];
5118 ctx.delete_buffers(ids.into());
5119 ctx.delete_textures(ids.into());
5120 }
5121
5122 #[test]
5123 fn gl_context_ptr_draw_buffers_accepts_an_empty_list() {
5124 let ctx = null_ctx();
5125 let empty: &[GLenum] = &[];
5126 ctx.draw_buffers(empty.into());
5127 ctx.draw_buffers(
5128 GLenumVecRef {
5129 ptr: core::ptr::null(),
5130 len: 3,
5131 },
5132 );
5133 }
5134
5135 #[test]
5140 fn vertex_attribute_type_mem_size_matches_the_rust_type_it_names() {
5141 assert_eq!(
5142 VertexAttributeType::Float.get_mem_size(),
5143 core::mem::size_of::<f32>()
5144 );
5145 assert_eq!(
5146 VertexAttributeType::Double.get_mem_size(),
5147 core::mem::size_of::<f64>()
5148 );
5149 assert_eq!(
5150 VertexAttributeType::UnsignedByte.get_mem_size(),
5151 core::mem::size_of::<u8>()
5152 );
5153 assert_eq!(
5154 VertexAttributeType::UnsignedShort.get_mem_size(),
5155 core::mem::size_of::<u16>()
5156 );
5157 assert_eq!(
5158 VertexAttributeType::UnsignedInt.get_mem_size(),
5159 core::mem::size_of::<u32>()
5160 );
5161
5162 for t in ALL_ATTRIB_TYPES {
5165 assert!(t.get_mem_size() > 0, "{t:?}");
5166 }
5167 }
5168
5169 #[test]
5170 fn vertex_attribute_type_gl_ids_are_distinct_and_nonzero() {
5171 for (i, a) in ALL_ATTRIB_TYPES.iter().enumerate() {
5172 assert_ne!(a.get_gl_id(), 0, "{a:?} maps to the GL 'no type' id 0");
5173 for b in ALL_ATTRIB_TYPES.iter().skip(i + 1) {
5174 assert_ne!(
5175 a.get_gl_id(),
5176 b.get_gl_id(),
5177 "{a:?} and {b:?} share a GL id -- one of them would upload as the wrong type"
5178 );
5179 }
5180 }
5181 assert_eq!(VertexAttributeType::Float.get_gl_id(), gl::FLOAT);
5182 assert_eq!(
5183 VertexAttributeType::UnsignedByte.get_gl_id(),
5184 gl::UNSIGNED_BYTE
5185 );
5186 }
5187
5188 #[test]
5189 fn vertex_attribute_get_stride_at_zero_and_at_the_overflow_boundary() {
5190 let attr = |ty, item_count| VertexAttribute {
5191 va_name: AzString::from_const_str("vAttrXY"),
5192 layout_location: OptionUsize::None,
5193 attribute_type: ty,
5194 item_count,
5195 };
5196
5197 for t in ALL_ATTRIB_TYPES {
5199 assert_eq!(attr(t, 0).get_stride(), 0, "{t:?}");
5200 }
5201
5202 assert_eq!(attr(VertexAttributeType::Float, 2).get_stride(), 8);
5204 assert_eq!(attr(VertexAttributeType::Double, 4).get_stride(), 32);
5205 assert_eq!(attr(VertexAttributeType::UnsignedByte, 3).get_stride(), 3);
5206
5207 for t in ALL_ATTRIB_TYPES {
5211 let max_items = usize::MAX / t.get_mem_size();
5212 assert_eq!(
5213 attr(t, max_items).get_stride(),
5214 max_items * t.get_mem_size(),
5215 "{t:?} at the overflow boundary"
5216 );
5217 }
5218 }
5219
5220 #[test]
5221 fn vertex_layout_stride_is_the_sum_of_its_fields() {
5222 let attr = |name: &str, ty, item_count| VertexAttribute {
5223 va_name: AzString::from(name.to_string()),
5224 layout_location: OptionUsize::None,
5225 attribute_type: ty,
5226 item_count,
5227 };
5228
5229 let empty = VertexLayout {
5231 fields: VertexAttributeVec::from_const_slice(&[]),
5232 };
5233 assert_eq!(
5234 empty.fields.iter().map(VertexAttribute::get_stride).sum::<usize>(),
5235 0
5236 );
5237
5238 let layout = VertexLayout {
5240 fields: vec![
5241 attr("vAttrXY", VertexAttributeType::Float, 2),
5242 attr("vColor", VertexAttributeType::UnsignedByte, 4),
5243 ]
5244 .into(),
5245 };
5246 let total: usize = layout.fields.iter().map(VertexAttribute::get_stride).sum();
5247 assert_eq!(total, 12);
5248
5249 assert_eq!(layout, layout.clone());
5251 }
5252
5253 #[test]
5254 fn index_buffer_format_gl_ids_are_distinct() {
5255 for (i, a) in ALL_INDEX_FORMATS.iter().enumerate() {
5257 for b in ALL_INDEX_FORMATS.iter().skip(i + 1) {
5258 assert_ne!(a.get_gl_id(), b.get_gl_id(), "{a:?} vs {b:?}");
5259 }
5260 }
5261 assert_eq!(IndexBufferFormat::Points.get_gl_id(), gl::POINTS);
5262 assert_eq!(
5263 IndexBufferFormat::TriangleStrip.get_gl_id(),
5264 gl::TRIANGLE_STRIP
5265 );
5266 }
5267
5268 #[test]
5273 fn uniform_type_nan_never_equals_itself_so_draw_always_reuploads_it() {
5274 let nan = UniformType::Float(f32::NAN);
5279 assert_ne!(nan, UniformType::Float(f32::NAN));
5280 assert_ne!(Some(nan), Some(nan));
5281
5282 let nan_vec = UniformType::FloatVec4([f32::NAN, 0.0, 0.0, 0.0]);
5283 assert_ne!(nan_vec, nan_vec);
5284
5285 assert_eq!(UniformType::Float(0.0), UniformType::Float(-0.0));
5289
5290 assert_eq!(UniformType::Int(i32::MIN), UniformType::Int(i32::MIN));
5292 assert_ne!(UniformType::Int(0), UniformType::UnsignedInt(0));
5293 }
5294
5295 #[test]
5296 fn uniform_type_matrix_transpose_flag_is_part_of_its_identity() {
5297 let m = [0.0f32; 4];
5298 assert_ne!(
5299 UniformType::Matrix2 {
5300 transpose: false,
5301 matrix: m
5302 },
5303 UniformType::Matrix2 {
5304 transpose: true,
5305 matrix: m
5306 },
5307 );
5308 assert_ne!(
5310 UniformType::FloatVec2([1.0, 2.0]),
5311 UniformType::IntVec2([1, 2])
5312 );
5313 }
5314
5315 #[test]
5316 fn uniform_create_preserves_empty_unicode_and_huge_names() {
5317 let huge = "n".repeat(100_000);
5318 for name in ["", "u_color", "\u{1F600}", "e\u{0301}", huge.as_str()] {
5319 let u = Uniform::create(name.to_string(), UniformType::Int(0));
5320 assert_eq!(u.uniform_name.as_str(), name);
5321 }
5322 }
5323
5324 #[test]
5329 fn gl_shader_new_reports_no_shader_compiler_instead_of_panicking() {
5330 let ctx = null_ctx();
5334 let huge = "x".repeat(200_000);
5335 for (vert, frag) in [
5336 ("", ""),
5337 (" \t\n ", "\n\n"),
5338 ("not glsl at all ;;;{{{", "\u{1F600}"),
5339 ("void main(){}", "void main(){}"),
5340 (huge.as_str(), huge.as_str()),
5341 ] {
5342 let err = GlShader::new(&ctx, vert, frag).unwrap_err();
5343 assert_eq!(err, GlShaderCreateError::NoShaderCompiler);
5344 }
5345 }
5346
5347 #[test]
5348 fn shader_error_types_format_without_panicking_on_unicode_and_extremes() {
5349 let vert = VertexShaderCompileError {
5350 error_id: i32::MIN,
5351 info_log: AzString::from("\u{1F600} log".to_string()),
5352 };
5353 let frag = FragmentShaderCompileError {
5354 error_id: i32::MAX,
5355 info_log: AzString::from(String::new()),
5356 };
5357 let link = GlShaderLinkError {
5358 error_id: -1,
5359 info_log: AzString::from("multi\nline\0log".to_string()),
5360 };
5361
5362 assert!(alloc::format!("{vert}").contains("-2147483648"));
5363 assert!(alloc::format!("{vert}").contains("\u{1F600}"));
5364 assert!(alloc::format!("{frag}").contains("2147483647"));
5365
5366 let compile = GlShaderCompileError::Vertex(vert);
5367 assert!(alloc::format!("{compile}").contains("Failed to compile vertex shader"));
5368 assert_eq!(alloc::format!("{compile:?}"), alloc::format!("{compile}"));
5370
5371 let frag_err = GlShaderCompileError::Fragment(frag);
5372 assert!(alloc::format!("{frag_err}").contains("Failed to compile fragment shader"));
5373
5374 let create = GlShaderCreateError::Link(link);
5375 assert!(alloc::format!("{create}").contains("Shader linking error"));
5376 assert_eq!(alloc::format!("{create:?}"), alloc::format!("{create}"));
5377 assert!(alloc::format!("{}", GlShaderCreateError::NoShaderCompiler)
5378 .contains("doesn't include a shader compiler"));
5379 }
5380
5381 #[test]
5386 fn texture_descriptor_mirrors_the_texture_including_extreme_sizes() {
5387 let tex = test_texture(42, 640, 480);
5388 let d = tex.get_descriptor();
5389 assert_eq!(d.width, 640);
5390 assert_eq!(d.height, 480);
5391 assert_eq!(d.format, RawImageFormat::RGBA8);
5392 assert_eq!(d.offset, 0);
5393 assert!(!d.flags.is_opaque);
5394 assert!(!d.flags.allow_mipmaps, "textures map 1:1, never mipmapped");
5395
5396 let zero = test_texture(1, 0, 0);
5398 assert_eq!(zero.get_descriptor().width, 0);
5399 assert_eq!(zero.get_descriptor().height, 0);
5400
5401 let huge = test_texture(1, u32::MAX, u32::MAX);
5402 assert_eq!(huge.get_descriptor().width, u32::MAX as usize);
5403 assert_eq!(huge.get_descriptor().height, u32::MAX as usize);
5404
5405 let opaque = Texture::create(
5407 7,
5408 TextureFlags {
5409 is_opaque: true,
5410 is_video_texture: true,
5411 },
5412 PhysicalSizeU32 {
5413 width: 2,
5414 height: 2,
5415 },
5416 ColorU {
5417 r: 0,
5418 g: 0,
5419 b: 0,
5420 a: 0,
5421 },
5422 null_ctx(),
5423 RawImageFormat::BGRA8,
5424 );
5425 assert!(opaque.get_descriptor().flags.is_opaque);
5426 assert_eq!(opaque.get_descriptor().format, RawImageFormat::BGRA8);
5427 }
5428
5429 #[test]
5430 fn texture_clone_and_drop_share_one_refcount_without_double_freeing() {
5431 let tex = test_texture(9, 4, 4);
5434 let clones: Vec<Texture> = (0..16).map(|_| tex.clone()).collect();
5435 for c in &clones {
5436 assert_eq!(c.texture_id, 9);
5437 assert_eq!(c.size, tex.size);
5438 assert_eq!(c.format, tex.format);
5439 assert!(c.run_destructor);
5440 }
5441 assert_eq!(clones[0], tex);
5443 assert_eq!(clones[0], clones[1]);
5444 assert_ne!(tex, test_texture(10, 4, 4));
5445
5446 drop(clones); drop(tex); }
5449
5450 #[test]
5451 fn texture_display_and_debug_render_id_and_size() {
5452 let tex = test_texture(3, 16, 32);
5453 assert_eq!(alloc::format!("{tex}"), "Texture { id: 3, 16x32 }");
5454 assert_eq!(alloc::format!("{tex:?}"), alloc::format!("{tex}"));
5456 }
5457
5458 #[test]
5459 fn texture_paint_stroke_is_a_noop_when_gl_is_unusable() {
5460 let mut tex = test_texture(5, 8, 8);
5466 assert_eq!(tex.gl_context.get_brush_shader(), 0);
5467
5468 for radius in [1.0, 0.0, -1.0, f32::NAN, f32::INFINITY, f32::MAX] {
5469 let mut brush = Brush::new(
5470 ColorU {
5471 r: 255,
5472 g: 0,
5473 b: 0,
5474 a: 255,
5475 },
5476 radius,
5477 );
5478 brush.hardness = f32::NAN;
5479 brush.flow = f32::INFINITY;
5480 brush.spacing = 0.0; tex.paint_stroke(f32::NAN, f32::NEG_INFINITY, f32::MAX, -0.0, brush);
5482 tex.paint_dot(f32::NAN, f32::NAN, brush);
5483 }
5484
5485 let mut zero = test_texture(6, 0, 0);
5487 zero.paint_dot(
5488 0.0,
5489 0.0,
5490 Brush::new(
5491 ColorU {
5492 r: 1,
5493 g: 1,
5494 b: 1,
5495 a: 1,
5496 },
5497 4.0,
5498 ),
5499 );
5500 }
5501
5502 #[test]
5503 fn texture_copy_to_raw_image_returns_a_null_image_on_every_degenerate_input() {
5504 let is_null_image = |img: &RawImage| img.width == 0 && img.height == 0;
5511
5512 assert!(is_null_image(&test_texture(0, 16, 16).copy_to_raw_image()));
5514 assert!(is_null_image(&test_texture(1, 0, 0).copy_to_raw_image()));
5516 assert!(is_null_image(&test_texture(1, 16, 0).copy_to_raw_image()));
5517 assert!(is_null_image(&test_texture(1, 0, 16).copy_to_raw_image()));
5518
5519 assert!(is_null_image(
5521 &test_texture(1, u32::MAX, u32::MAX).copy_to_raw_image()
5522 ));
5523 assert!(is_null_image(
5524 &test_texture(1, 1 << 31, 1 << 31).copy_to_raw_image()
5525 ));
5526
5527 assert!(is_null_image(&test_texture(1, 4, 4).copy_to_raw_image()));
5530 }
5531
5532 #[test]
5533 #[should_panic(expected = "called `Option::unwrap()` on a `None` value")]
5534 fn texture_clear_panics_when_the_driver_allocates_no_framebuffer() {
5535 test_texture(1, 4, 4).clear();
5541 }
5542
5543 #[test]
5548 fn vertex_array_object_clone_and_drop_share_one_refcount() {
5549 let layout = VertexLayout {
5550 fields: VertexAttributeVec::from_const_slice(&[]),
5551 };
5552 let vao = VertexArrayObject::new(layout, 77, null_ctx());
5553 assert_eq!(vao.vao_id, 77);
5554 assert!(vao.run_destructor);
5555
5556 let clones: Vec<VertexArrayObject> = (0..8).map(|_| vao.clone()).collect();
5557 assert!(clones.iter().all(|c| c.vao_id == 77));
5558 assert_eq!(clones[0], vao);
5559 drop(clones);
5560 drop(vao);
5561 }
5562
5563 #[test]
5564 fn vertex_buffer_new_raw_keeps_its_fields_and_refcounts_its_clones() {
5565 let vao = VertexArrayObject::new(
5566 VertexLayout {
5567 fields: VertexAttributeVec::from_const_slice(&[]),
5568 },
5569 1,
5570 null_ctx(),
5571 );
5572 let vb = VertexBuffer::new_raw(11, 300, vao, 22, 40, IndexBufferFormat::TriangleStrip);
5573
5574 assert_eq!(vb.vertex_buffer_id, 11);
5575 assert_eq!(vb.vertex_buffer_len, 300);
5576 assert_eq!(vb.index_buffer_id, 22);
5577 assert_eq!(vb.index_buffer_len, 40);
5578 assert_eq!(vb.index_buffer_format, IndexBufferFormat::TriangleStrip);
5579 assert_eq!(
5580 alloc::format!("{vb}"),
5581 "VertexBuffer { buffer: 11 (length: 300) }"
5582 );
5583
5584 let clones: Vec<VertexBuffer> = (0..8).map(|_| vb.clone()).collect();
5586 assert_eq!(clones[0], vb);
5587 drop(clones);
5588 drop(vb);
5589
5590 let empty_vao = VertexArrayObject::new(
5592 VertexLayout {
5593 fields: VertexAttributeVec::from_const_slice(&[]),
5594 },
5595 0,
5596 null_ctx(),
5597 );
5598 let empty = VertexBuffer::new_raw(0, 0, empty_vao, 0, 0, IndexBufferFormat::Points);
5599 assert_eq!(empty.vertex_buffer_len, 0);
5600 }
5601
5602 #[allow(dead_code)] struct TestVertex {
5604 _xy: [f32; 2],
5605 }
5606
5607 impl VertexLayoutDescription for TestVertex {
5608 fn get_description() -> VertexLayout {
5609 VertexLayout {
5610 fields: vec![VertexAttribute {
5611 va_name: AzString::from_const_str("vAttrXY"),
5612 layout_location: OptionUsize::None,
5613 attribute_type: VertexAttributeType::Float,
5614 item_count: 2,
5615 }]
5616 .into(),
5617 }
5618 }
5619 }
5620
5621 #[test]
5622 #[should_panic(expected = "called `Option::unwrap()` on a `None` value")]
5623 fn vertex_buffer_new_panics_when_the_driver_allocates_no_vao() {
5624 let verts = [TestVertex { _xy: [0.0, 0.0] }];
5627 let _ = VertexBuffer::new(
5628 null_ctx(),
5629 0,
5630 &verts[..],
5631 &[0u32],
5632 IndexBufferFormat::Triangles,
5633 );
5634 }
5635
5636 #[test]
5646 fn gl_texture_cache_insert_lookup_and_eviction_lifecycle() {
5647 let doc = DocumentId {
5648 namespace_id: crate::resources::IdNamespace(7),
5649 id: 1,
5650 };
5651 let other_doc = DocumentId {
5652 namespace_id: crate::resources::IdNamespace(7),
5653 id: 2,
5654 };
5655
5656 gl_textures_clear_opengl_cache();
5658 let stale = ExternalImageId { inner: u64::MAX };
5659 assert!(get_opengl_texture(&stale).is_none());
5660 assert!(
5661 remove_single_texture_from_active_gl_textures(&doc, &Epoch::from(0), &stale).is_none()
5662 );
5663 gl_textures_remove_epochs_from_pipeline(&doc, Epoch::from(0));
5664 gl_textures_remove_active_pipeline(&doc);
5665 gl_textures_clear_opengl_cache(); let id5 = insert_into_active_gl_textures(doc, Epoch::from(5), test_texture(11, 4, 8));
5673 let id7 = insert_into_active_gl_textures(doc, Epoch::from(7), test_texture(22, 16, 32));
5674 assert_ne!(id5, id7, "each insert must mint a unique ExternalImageId");
5675
5676 assert_eq!(get_opengl_texture(&id5), Some((11, (4.0, 8.0))));
5678 assert_eq!(get_opengl_texture(&id7), Some((22, (16.0, 32.0))));
5679 assert!(get_opengl_texture(&stale).is_none());
5680
5681 let id_huge =
5684 insert_into_active_gl_textures(doc, Epoch::from(5), test_texture(33, u32::MAX, 1));
5685 assert_eq!(get_opengl_texture(&id_huge), Some((33, (4_294_967_296.0, 1.0))));
5686
5687 gl_textures_remove_epochs_from_pipeline(&doc, Epoch::from(7));
5689 assert!(get_opengl_texture(&id5).is_none(), "epoch 5 < 7 must be evicted");
5690 assert!(get_opengl_texture(&id_huge).is_none(), "epoch 5 < 7 must be evicted");
5691 assert_eq!(
5692 get_opengl_texture(&id7),
5693 Some((22, (16.0, 32.0))),
5694 "epoch 7 is NOT < 7, so it must survive"
5695 );
5696
5697 gl_textures_remove_epochs_from_pipeline(&other_doc, Epoch::from(u32::MAX));
5699 assert_eq!(get_opengl_texture(&id7), Some((22, (16.0, 32.0))));
5700
5701 assert_eq!(
5703 remove_single_texture_from_active_gl_textures(&doc, &Epoch::from(7), &id7),
5704 Some(())
5705 );
5706 assert!(get_opengl_texture(&id7).is_none());
5707 assert_eq!(
5710 remove_single_texture_from_active_gl_textures(&doc, &Epoch::from(7), &id7),
5711 Some(())
5712 );
5713 assert!(
5715 remove_single_texture_from_active_gl_textures(&other_doc, &Epoch::from(7), &id7)
5716 .is_none()
5717 );
5718 assert!(remove_single_texture_from_active_gl_textures(
5719 &doc,
5720 &Epoch::from(u32::MAX),
5721 &id7
5722 )
5723 .is_none());
5724
5725 let id_a = insert_into_active_gl_textures(doc, Epoch::from(1), test_texture(44, 2, 2));
5727 let id_b = insert_into_active_gl_textures(other_doc, Epoch::from(1), test_texture(55, 2, 2));
5728 assert!(get_opengl_texture(&id_a).is_some());
5729 gl_textures_remove_active_pipeline(&doc);
5730 assert!(get_opengl_texture(&id_a).is_none(), "doc was removed");
5731 assert!(
5732 get_opengl_texture(&id_b).is_some(),
5733 "other_doc must be untouched"
5734 );
5735
5736 gl_textures_clear_opengl_cache();
5738 assert!(get_opengl_texture(&id_b).is_none());
5739
5740 gl_textures_clear_opengl_cache();
5742 }
5743}