1use crate::gl33::{
4 depth_stencil::{
5 comparison_to_glenum, glenum_to_comparison, glenum_to_stencil_op, stencil_op_to_glenum,
6 },
7 vertex_restart::VertexRestart,
8};
9use gl::types::*;
10use luminance::{
11 blending::{Equation, Factor},
12 depth_stencil::{Comparison, StencilOperations, StencilTest, Write},
13 face_culling::{FaceCullingMode, FaceCullingOrder},
14 scissor::ScissorRegion,
15};
16use std::{cell::RefCell, error, ffi::CStr, fmt, marker::PhantomData, os::raw::c_char};
17
18thread_local!(static TLS_ACQUIRE_GFX_STATE: RefCell<Option<()>> = RefCell::new(Some(())));
22
23#[derive(Debug)]
24pub(crate) struct BindingStack {
25 pub(crate) next_texture_unit: u32,
26 pub(crate) free_texture_units: Vec<u32>,
27 pub(crate) next_shader_data: u32,
28 pub(crate) free_shader_data: Vec<u32>,
29}
30
31impl BindingStack {
32 fn new() -> Self {
34 BindingStack {
35 next_texture_unit: 0,
36 free_texture_units: Vec::new(),
37 next_shader_data: 0,
38 free_shader_data: Vec::new(),
39 }
40 }
41}
42
43#[derive(Debug)]
58struct Cached<T>(Option<T>)
59where
60 T: PartialEq;
61
62impl<T> Cached<T>
63where
64 T: PartialEq,
65{
66 fn new(initial: T) -> Self {
68 Cached(Some(initial))
69 }
70
71 fn invalidate(&mut self) {
75 self.0 = None;
76 }
77
78 fn set(&mut self, value: T) {
79 self.0 = Some(value);
80 }
81
82 fn is_invalid(&self, new_val: &T) -> bool {
87 match &self.0 {
88 Some(ref t) => t != new_val,
89 _ => true,
90 }
91 }
92}
93
94#[derive(Debug)]
101pub struct GLState {
102 _a: PhantomData<*const ()>, binding_stack: BindingStack,
106
107 viewport: Cached<[GLint; 4]>,
109
110 clear_color: Cached<[GLfloat; 4]>,
112 clear_depth: Cached<GLfloat>,
113 clear_stencil: Cached<GLint>,
114
115 blending_state: Cached<BlendingState>,
117 blending_equations: Cached<BlendingEquations>,
118 blending_funcs: Cached<BlendingFactors>,
119
120 depth_test: Cached<DepthTest>,
122 depth_test_comparison: Cached<Comparison>,
123
124 depth_write: Cached<Write>,
126
127 stencil_test_enabled: Cached<bool>,
129 stencil_test: Cached<StencilTest>,
130 stencil_operations: Cached<StencilOperations>,
131
132 face_culling_state: Cached<FaceCullingState>,
134 face_culling_order: Cached<FaceCullingOrder>,
135 face_culling_mode: Cached<FaceCullingMode>,
136
137 scissor_state: Cached<ScissorState>,
139 scissor_region: Cached<ScissorRegion>,
140
141 vertex_restart: Cached<VertexRestart>,
143
144 patch_vertex_nb: Cached<usize>,
146
147 current_texture_unit: Cached<GLenum>,
149 bound_textures: Vec<(GLenum, GLuint)>,
150
151 texture_swimming_pool: Vec<GLuint>,
158
159 bound_uniform_buffers: Vec<GLuint>,
161
162 bound_array_buffer: GLuint,
164
165 bound_element_array_buffer: GLuint,
167
168 bound_draw_framebuffer: Cached<GLuint>,
170
171 bound_vertex_array: GLuint,
173
174 current_program: GLuint,
176
177 srgb_framebuffer_enabled: Cached<bool>,
179
180 vendor_name: Option<String>,
182
183 renderer_name: Option<String>,
185
186 gl_version: Option<String>,
188
189 glsl_version: Option<String>,
191
192 max_texture_array_elements: Option<usize>,
194}
195
196impl GLState {
197 pub(crate) fn new() -> Result<Self, StateQueryError> {
203 TLS_ACQUIRE_GFX_STATE.with(|rc| {
204 let mut inner = rc.borrow_mut();
205
206 match *inner {
207 Some(_) => {
208 inner.take();
209 Self::get_from_context()
210 }
211
212 None => Err(StateQueryError::UnavailableGLState),
213 }
214 })
215 }
216
217 fn get_from_context() -> Result<Self, StateQueryError> {
219 unsafe {
220 let binding_stack = BindingStack::new();
221 let viewport = Cached::new(get_ctx_viewport()?);
222 let clear_color = Cached::new(get_ctx_clear_color()?);
223 let clear_depth = Cached::new(get_ctx_clear_depth()?);
224 let clear_stencil = Cached::new(get_ctx_clear_stencil()?);
225 let blending_state = Cached::new(get_ctx_blending_state()?);
226 let blending_equations = Cached::new(get_ctx_blending_equations()?);
227 let blending_funcs = Cached::new(get_ctx_blending_factors()?);
228 let depth_test = Cached::new(get_ctx_depth_test()?);
229 let depth_test_comparison = Cached::new(Comparison::Less);
230 let depth_write = Cached::new(get_ctx_depth_write()?);
231 let stencil_test_enabled = Cached::new(get_ctx_stencil_test_enabled()?);
232 let stencil_test = Cached::new(get_ctx_stencil_test()?);
233 let stencil_operations = Cached::new(get_ctx_stencil_operations()?);
234 let face_culling_state = Cached::new(get_ctx_face_culling_state()?);
235 let face_culling_order = Cached::new(get_ctx_face_culling_order()?);
236 let face_culling_mode = Cached::new(get_ctx_face_culling_mode()?);
237 let vertex_restart = Cached::new(get_ctx_vertex_restart()?);
238 let patch_vertex_nb = Cached::new(0);
239 let current_texture_unit = Cached::new(get_ctx_current_texture_unit()?);
240 let bound_textures = vec![(gl::TEXTURE_2D, 0); 48]; let texture_swimming_pool = Vec::new();
242 let bound_uniform_buffers = vec![0; 36]; let bound_array_buffer = 0;
244 let bound_element_array_buffer = 0;
245 let bound_draw_framebuffer = Cached::new(get_ctx_bound_draw_framebuffer()?);
246 let bound_vertex_array = get_ctx_bound_vertex_array()?;
247 let current_program = get_ctx_current_program()?;
248 let srgb_framebuffer_enabled = Cached::new(get_ctx_srgb_framebuffer_enabled()?);
249 let scissor_state = Cached::new(get_ctx_scissor_state()?);
250 let scissor_region = Cached::new(get_ctx_scissor_region()?);
251 let vendor_name = None;
252 let renderer_name = None;
253 let gl_version = None;
254 let glsl_version = None;
255 let max_texture_array_elements = None;
256
257 Ok(GLState {
258 _a: PhantomData,
259 binding_stack,
260 viewport,
261 clear_color,
262 clear_depth,
263 clear_stencil,
264 blending_state,
265 blending_equations,
266 blending_funcs,
267 depth_test,
268 depth_test_comparison,
269 depth_write,
270 stencil_test_enabled,
271 stencil_test,
272 stencil_operations,
273 face_culling_state,
274 face_culling_order,
275 face_culling_mode,
276 vertex_restart,
277 patch_vertex_nb,
278 current_texture_unit,
279 bound_textures,
280 texture_swimming_pool,
281 bound_uniform_buffers,
282 bound_array_buffer,
283 bound_element_array_buffer,
284 bound_draw_framebuffer,
285 bound_vertex_array,
286 current_program,
287 srgb_framebuffer_enabled,
288 scissor_state,
289 scissor_region,
290 vendor_name,
291 renderer_name,
292 gl_version,
293 glsl_version,
294 max_texture_array_elements,
295 })
296 }
297 }
298
299 pub fn invalidate_vertex_array(&mut self) {
301 self.bound_vertex_array = 0;
302 }
303
304 pub fn invalidate_array_buffer(&mut self) {
306 self.bound_array_buffer = 0;
307 }
308
309 pub fn invalidate_shader_program(&mut self) {
311 self.current_program = 0;
312 }
313
314 pub fn invalidate_framebuffer(&mut self) {
316 self.bound_draw_framebuffer.invalidate();
317 }
318
319 pub fn invalidate_element_array_buffer(&mut self) {
321 self.bound_element_array_buffer = 0;
322 }
323
324 pub fn invalidate_texture_unit(&mut self) {
326 self.current_texture_unit.invalidate();
327 }
328
329 pub fn invalidate_bound_textures(&mut self) {
331 for t in &mut self.bound_textures {
332 *t = (gl::TEXTURE_2D, 0);
333 }
334 }
335
336 pub fn invalidate_bound_uniform_buffers(&mut self) {
338 for b in &mut self.bound_uniform_buffers {
339 *b = 0;
340 }
341 }
342
343 pub fn invalidate_viewport(&mut self) {
345 self.viewport.invalidate()
346 }
347
348 pub fn invalidate_clear_color(&mut self) {
350 self.clear_color.invalidate()
351 }
352
353 pub fn invalidate_blending_state(&mut self) {
355 self.blending_state.invalidate()
356 }
357
358 pub fn invalidate_blending_equation(&mut self) {
360 self.blending_equations.invalidate()
361 }
362
363 pub fn invalidate_blending_func(&mut self) {
365 self.blending_funcs.invalidate()
366 }
367
368 pub fn invalidate_depth_test(&mut self) {
370 self.depth_test.invalidate()
371 }
372
373 pub fn invalidate_depth_test_comparison(&mut self) {
375 self.depth_test_comparison.invalidate()
376 }
377
378 pub fn invalidate_depth_write(&mut self) {
380 self.depth_write.invalidate()
381 }
382
383 pub fn invalidate_face_culling_state(&mut self) {
385 self.face_culling_state.invalidate()
386 }
387
388 pub fn invalidate_face_culling_order(&mut self) {
390 self.face_culling_order.invalidate()
391 }
392
393 pub fn invalidate_face_culling_mode(&mut self) {
395 self.face_culling_mode.invalidate()
396 }
397
398 pub fn invalidate_vertex_restart(&mut self) {
400 self.vertex_restart.invalidate()
401 }
402
403 pub fn invalidate_patch_vertex_nb(&mut self) {
405 self.patch_vertex_nb.invalidate()
406 }
407
408 pub fn invalidate_srgb_framebuffer_enabled(&mut self) {
410 self.srgb_framebuffer_enabled.invalidate()
411 }
412
413 fn marshal_gl_string(repr: GLenum) -> String {
417 unsafe {
418 let name_ptr = gl::GetString(repr);
419 let name = CStr::from_ptr(name_ptr as *const c_char);
420 name.to_string_lossy().into_owned()
421 }
422 }
423
424 pub fn get_vendor_name(&mut self) -> String {
428 self.vendor_name.as_ref().cloned().unwrap_or_else(|| {
429 let name = Self::marshal_gl_string(gl::VENDOR);
430 self.vendor_name = Some(name.clone());
431 name
432 })
433 }
434
435 pub fn get_renderer_name(&mut self) -> String {
439 self.renderer_name.as_ref().cloned().unwrap_or_else(|| {
440 let name = Self::marshal_gl_string(gl::RENDERER);
441 self.renderer_name = Some(name.clone());
442 name
443 })
444 }
445
446 pub fn get_gl_version(&mut self) -> String {
450 self.gl_version.as_ref().cloned().unwrap_or_else(|| {
451 let version = Self::marshal_gl_string(gl::VERSION);
452 self.gl_version = Some(version.clone());
453 version
454 })
455 }
456
457 pub fn get_glsl_version(&mut self) -> String {
461 self.glsl_version.as_ref().cloned().unwrap_or_else(|| {
462 let version = Self::marshal_gl_string(gl::SHADING_LANGUAGE_VERSION);
463 self.glsl_version = Some(version.clone());
464 version
465 })
466 }
467
468 pub fn get_max_texture_array_elements(&mut self) -> usize {
472 self.max_texture_array_elements.unwrap_or_else(|| {
473 let mut max = 0;
474 unsafe { gl::GetIntegerv(gl::MAX_ARRAY_TEXTURE_LAYERS, &mut max) };
475 let max = max as usize;
476 self.max_texture_array_elements = Some(max);
477 max
478 })
479 }
480
481 pub(crate) fn binding_stack_mut(&mut self) -> &mut BindingStack {
482 &mut self.binding_stack
483 }
484
485 pub(crate) fn create_texture(&mut self) -> GLuint {
486 self.texture_swimming_pool.pop().unwrap_or_else(|| {
487 let mut texture = 0;
488
489 unsafe { gl::GenTextures(1, &mut texture) };
490 texture
491 })
492 }
493
494 pub(crate) fn reserve_textures(&mut self, nb: usize) {
496 let available = self.texture_swimming_pool.len();
497 let needed = nb.max(available) - available;
498
499 if needed > 0 {
500 self.texture_swimming_pool.resize(available + needed, 0);
503 let textures = &mut self.texture_swimming_pool[available..];
504
505 unsafe { gl::GenTextures(needed as _, textures.as_mut_ptr()) };
506 }
507 }
508
509 pub(crate) unsafe fn set_viewport(&mut self, viewport: [GLint; 4]) {
510 if self.viewport.is_invalid(&viewport) {
511 gl::Viewport(viewport[0], viewport[1], viewport[2], viewport[3]);
512 self.viewport.set(viewport);
513 }
514 }
515
516 pub(crate) unsafe fn set_clear_color(&mut self, clear_color: [GLfloat; 4]) {
517 if self.clear_color.is_invalid(&clear_color) {
518 gl::ClearColor(
519 clear_color[0],
520 clear_color[1],
521 clear_color[2],
522 clear_color[3],
523 );
524 self.clear_color.set(clear_color);
525 }
526 }
527
528 pub(crate) unsafe fn set_clear_depth(&mut self, clear_depth: GLfloat) {
529 if self.clear_depth.is_invalid(&clear_depth) {
530 gl::ClearDepth(clear_depth as _);
531 self.clear_depth.set(clear_depth);
532 }
533 }
534
535 pub(crate) unsafe fn set_clear_stencil(&mut self, clear_stencil: GLint) {
536 if self.clear_stencil.is_invalid(&clear_stencil) {
537 gl::ClearStencil(clear_stencil);
538 self.clear_stencil.set(clear_stencil);
539 }
540 }
541
542 pub(crate) unsafe fn set_blending_state(&mut self, state: BlendingState) {
543 if self.blending_state.is_invalid(&state) {
544 match state {
545 BlendingState::On => gl::Enable(gl::BLEND),
546 BlendingState::Off => gl::Disable(gl::BLEND),
547 }
548
549 self.blending_state.set(state);
550 }
551 }
552
553 pub(crate) unsafe fn set_scissor_state(&mut self, state: ScissorState) {
554 if self.scissor_state.is_invalid(&state) {
555 match state {
556 ScissorState::On => gl::Enable(gl::SCISSOR_TEST),
557 ScissorState::Off => gl::Disable(gl::SCISSOR_TEST),
558 }
559
560 self.scissor_state.set(state);
561 }
562 }
563
564 pub(crate) unsafe fn set_scissor_region(&mut self, region: &ScissorRegion) {
565 if self.scissor_region.is_invalid(region) {
566 let ScissorRegion {
567 x,
568 y,
569 width,
570 height,
571 } = *region;
572
573 gl::Scissor(x as GLint, y as GLint, width as GLint, height as GLint);
574
575 self.scissor_region.set(*region);
576 }
577 }
578
579 pub(crate) unsafe fn set_blending_equation(&mut self, equation: Equation) {
580 let equations = BlendingEquations {
581 rgb: equation,
582 alpha: equation,
583 };
584
585 if self.blending_equations.is_invalid(&equations) {
586 gl::BlendEquation(from_blending_equation(equation));
587 self.blending_equations.set(equations);
588 }
589 }
590
591 pub(crate) unsafe fn set_blending_equation_separate(
592 &mut self,
593 equation_rgb: Equation,
594 equation_alpha: Equation,
595 ) {
596 let equations = BlendingEquations {
597 rgb: equation_rgb,
598 alpha: equation_alpha,
599 };
600
601 if self.blending_equations.is_invalid(&equations) {
602 gl::BlendEquationSeparate(
603 from_blending_equation(equation_rgb),
604 from_blending_equation(equation_alpha),
605 );
606
607 self.blending_equations.set(equations);
608 }
609 }
610
611 pub(crate) unsafe fn set_blending_func(&mut self, src: Factor, dst: Factor) {
612 let funcs = BlendingFactors {
613 src_rgb: src,
614 dst_rgb: dst,
615 src_alpha: src,
616 dst_alpha: dst,
617 };
618
619 if self.blending_funcs.is_invalid(&funcs) {
620 gl::BlendFunc(from_blending_factor(src), from_blending_factor(dst));
621 self.blending_funcs.set(funcs);
622 }
623 }
624
625 pub(crate) unsafe fn set_blending_func_separate(
626 &mut self,
627 src_rgb: Factor,
628 dst_rgb: Factor,
629 src_alpha: Factor,
630 dst_alpha: Factor,
631 ) {
632 let funcs = BlendingFactors {
633 src_rgb,
634 dst_rgb,
635 src_alpha,
636 dst_alpha,
637 };
638
639 if self.blending_funcs.is_invalid(&funcs) {
640 gl::BlendFuncSeparate(
641 from_blending_factor(src_rgb),
642 from_blending_factor(dst_rgb),
643 from_blending_factor(src_alpha),
644 from_blending_factor(dst_alpha),
645 );
646
647 self.blending_funcs.set(funcs);
648 }
649 }
650
651 pub(crate) unsafe fn set_depth_test(&mut self, depth_test: DepthTest) {
652 if self.depth_test.is_invalid(&depth_test) {
653 match depth_test {
654 DepthTest::On => gl::Enable(gl::DEPTH_TEST),
655 DepthTest::Off => gl::Disable(gl::DEPTH_TEST),
656 }
657
658 self.depth_test.set(depth_test);
659 }
660 }
661
662 pub(crate) unsafe fn set_depth_test_comparison(&mut self, depth_test_comparison: Comparison) {
663 if self
664 .depth_test_comparison
665 .is_invalid(&depth_test_comparison)
666 {
667 gl::DepthFunc(comparison_to_glenum(depth_test_comparison));
668 self.depth_test_comparison.set(depth_test_comparison);
669 }
670 }
671
672 pub(crate) unsafe fn set_depth_write(&mut self, depth_write: Write) {
673 if self.depth_write.is_invalid(&depth_write) {
674 let enabled = match depth_write {
675 Write::On => gl::TRUE,
676 Write::Off => gl::FALSE,
677 };
678
679 gl::DepthMask(enabled);
680
681 self.depth_write.set(depth_write);
682 }
683 }
684
685 pub(crate) unsafe fn enable_stencil_test(&mut self, enable: bool) {
686 if self.stencil_test_enabled.is_invalid(&enable) {
687 if enable {
688 gl::Enable(gl::STENCIL_TEST);
689 } else {
690 gl::Disable(gl::STENCIL_TEST);
691 }
692
693 self.stencil_test_enabled.set(enable);
694 }
695 }
696
697 pub(crate) unsafe fn set_stencil_test(&mut self, stencil_test: StencilTest) {
698 if self.stencil_test.is_invalid(&stencil_test) {
699 let comparison = comparison_to_glenum(stencil_test.comparison);
700 gl::StencilFunc(
701 comparison,
702 stencil_test.reference as _,
703 stencil_test.mask as _,
704 );
705
706 self.stencil_test.set(stencil_test);
707 }
708 }
709
710 pub(crate) unsafe fn set_stencil_operations(&mut self, stencil_ops: StencilOperations) {
711 if self.stencil_operations.is_invalid(&stencil_ops) {
712 gl::StencilOp(
713 stencil_op_to_glenum(stencil_ops.depth_passes_stencil_fails),
714 stencil_op_to_glenum(stencil_ops.depth_fails_stencil_passes),
715 stencil_op_to_glenum(stencil_ops.depth_stencil_pass),
716 );
717
718 self.stencil_operations.set(stencil_ops);
719 }
720 }
721
722 pub(crate) unsafe fn set_face_culling_state(&mut self, state: FaceCullingState) {
723 if self.face_culling_state.is_invalid(&state) {
724 match state {
725 FaceCullingState::On => gl::Enable(gl::CULL_FACE),
726 FaceCullingState::Off => gl::Disable(gl::CULL_FACE),
727 }
728
729 self.face_culling_state.set(state);
730 }
731 }
732
733 pub(crate) unsafe fn set_face_culling_order(&mut self, order: FaceCullingOrder) {
734 if self.face_culling_order.is_invalid(&order) {
735 match order {
736 FaceCullingOrder::CW => gl::FrontFace(gl::CW),
737 FaceCullingOrder::CCW => gl::FrontFace(gl::CCW),
738 }
739
740 self.face_culling_order.set(order);
741 }
742 }
743
744 pub(crate) unsafe fn set_face_culling_mode(&mut self, mode: FaceCullingMode) {
745 if self.face_culling_mode.is_invalid(&mode) {
746 match mode {
747 FaceCullingMode::Front => gl::CullFace(gl::FRONT),
748 FaceCullingMode::Back => gl::CullFace(gl::BACK),
749 FaceCullingMode::Both => gl::CullFace(gl::FRONT_AND_BACK),
750 }
751
752 self.face_culling_mode.set(mode);
753 }
754 }
755
756 pub(crate) unsafe fn set_vertex_restart(&mut self, state: VertexRestart) {
757 if self.vertex_restart.is_invalid(&state) {
758 match state {
759 VertexRestart::On => gl::Enable(gl::PRIMITIVE_RESTART),
760 VertexRestart::Off => gl::Disable(gl::PRIMITIVE_RESTART),
761 }
762
763 self.vertex_restart.set(state);
764 }
765 }
766
767 pub(crate) unsafe fn set_patch_vertex_nb(&mut self, nb: usize) {
768 if self.patch_vertex_nb.is_invalid(&nb) {
769 gl::PatchParameteri(gl::PATCH_VERTICES, nb as GLint);
770 self.patch_vertex_nb.set(nb);
771 }
772 }
773
774 pub(crate) unsafe fn set_texture_unit(&mut self, unit: u32) {
775 let unit = unit as GLenum;
776
777 if self.current_texture_unit.is_invalid(&unit) {
778 gl::ActiveTexture(gl::TEXTURE0 + unit);
779 self.current_texture_unit.set(unit);
780 }
781 }
782
783 pub(crate) unsafe fn bind_texture(&mut self, target: GLenum, handle: GLuint) {
785 let unit = self.current_texture_unit.0.unwrap();
788 self.bind_texture_at(target, handle, unit);
789 }
790
791 pub(crate) unsafe fn bind_texture_at(&mut self, target: GLenum, handle: GLuint, unit: u32) {
793 match self.bound_textures.get(unit as usize).cloned() {
794 Some((target_, handle_)) if target != target_ || handle != handle_ => {
796 self.set_texture_unit(unit);
797 gl::BindTexture(target, handle);
798 self.bound_textures[unit as usize] = (target, handle);
799 }
800
801 None => {
803 self.set_texture_unit(unit);
804 gl::BindTexture(target, handle);
805
806 let unit = unit as usize;
808 self.bound_textures.resize(unit + 1, (gl::TEXTURE_2D, 0));
809 self.bound_textures[unit] = (target, handle);
810 }
811
812 _ => (), }
814 }
815
816 pub(crate) unsafe fn bind_array_buffer(&mut self, handle: GLuint, bind: Bind) {
817 if bind == Bind::Forced || self.bound_array_buffer != handle {
818 gl::BindBuffer(gl::ARRAY_BUFFER, handle);
819 self.bound_array_buffer = handle;
820 }
821 }
822
823 pub(crate) unsafe fn bind_element_array_buffer(&mut self, handle: GLuint, bind: Bind) {
824 if bind == Bind::Forced || self.bound_element_array_buffer != handle {
825 gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, handle);
826 self.bound_element_array_buffer = handle;
827 }
828 }
829
830 pub(crate) unsafe fn bind_uniform_buffer(&mut self, handle: GLuint, binding: u32) {
831 let binding_ = binding as usize;
832
833 match self.bound_uniform_buffers.get(binding_) {
834 Some(&handle_) if handle != handle_ => {
835 gl::BindBufferBase(gl::UNIFORM_BUFFER, binding as GLuint, handle);
836 self.bound_uniform_buffers[binding_] = handle;
837 }
838
839 None => {
840 gl::BindBufferBase(gl::UNIFORM_BUFFER, binding as GLuint, handle);
841
842 self.bound_uniform_buffers.resize(binding_ + 1, 0);
844 self.bound_uniform_buffers[binding_] = handle;
845 }
846
847 _ => (), }
849 }
850
851 pub(crate) unsafe fn unbind_buffer(&mut self, handle: GLuint) {
852 if self.bound_array_buffer == handle {
853 self.bind_array_buffer(0, Bind::Cached);
854 } else if self.bound_element_array_buffer == handle {
855 self.bind_element_array_buffer(0, Bind::Cached);
856 } else if let Some(handle_) = self
857 .bound_uniform_buffers
858 .iter_mut()
859 .find(|h| **h == handle)
860 {
861 *handle_ = 0;
862 }
863 }
864
865 pub(crate) unsafe fn bind_draw_framebuffer(&mut self, handle: GLuint) {
866 if self.bound_draw_framebuffer.is_invalid(&handle) {
867 gl::BindFramebuffer(gl::DRAW_FRAMEBUFFER, handle);
868 self.bound_draw_framebuffer.set(handle);
869 }
870 }
871
872 pub(crate) unsafe fn bind_vertex_array(&mut self, handle: GLuint, bind: Bind) {
873 if bind == Bind::Forced || self.bound_vertex_array != handle {
874 gl::BindVertexArray(handle);
875 self.bound_vertex_array = handle;
876 }
877 }
878
879 pub(crate) unsafe fn unbind_vertex_array(&mut self) {
880 self.bind_vertex_array(0, Bind::Cached)
881 }
882
883 pub(crate) unsafe fn use_program(&mut self, handle: GLuint) {
884 if self.current_program != handle {
885 gl::UseProgram(handle);
886 self.current_program = handle;
887 }
888 }
889
890 pub(crate) unsafe fn enable_srgb_framebuffer(&mut self, srgb_framebuffer_enabled: bool) {
891 if self
892 .srgb_framebuffer_enabled
893 .is_invalid(&srgb_framebuffer_enabled)
894 {
895 if srgb_framebuffer_enabled {
896 gl::Enable(gl::FRAMEBUFFER_SRGB);
897 } else {
898 gl::Disable(gl::FRAMEBUFFER_SRGB);
899 }
900
901 self.srgb_framebuffer_enabled.set(srgb_framebuffer_enabled);
902 }
903 }
904}
905
906#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
908pub(crate) enum Bind {
909 Forced,
910 Cached,
911}
912
913#[inline]
914fn from_blending_equation(equation: Equation) -> GLenum {
915 match equation {
916 Equation::Additive => gl::FUNC_ADD,
917 Equation::Subtract => gl::FUNC_SUBTRACT,
918 Equation::ReverseSubtract => gl::FUNC_REVERSE_SUBTRACT,
919 Equation::Min => gl::MIN,
920 Equation::Max => gl::MAX,
921 }
922}
923
924#[inline]
925fn from_blending_factor(factor: Factor) -> GLenum {
926 match factor {
927 Factor::One => gl::ONE,
928 Factor::Zero => gl::ZERO,
929 Factor::SrcColor => gl::SRC_COLOR,
930 Factor::SrcColorComplement => gl::ONE_MINUS_SRC_COLOR,
931 Factor::DestColor => gl::DST_COLOR,
932 Factor::DestColorComplement => gl::ONE_MINUS_DST_COLOR,
933 Factor::SrcAlpha => gl::SRC_ALPHA,
934 Factor::SrcAlphaComplement => gl::ONE_MINUS_SRC_ALPHA,
935 Factor::DstAlpha => gl::DST_ALPHA,
936 Factor::DstAlphaComplement => gl::ONE_MINUS_DST_ALPHA,
937 Factor::SrcAlphaSaturate => gl::SRC_ALPHA_SATURATE,
938 }
939}
940
941#[non_exhaustive]
943#[derive(Debug)]
944pub enum StateQueryError {
945 UnavailableGLState,
950 UnknownBlendingState(GLboolean),
952 UnknownBlendingEquation(GLenum),
954 UnknownBlendingSrcFactor(GLenum),
956 UnknownBlendingDstFactor(GLenum),
958 UnknownDepthTestState(GLboolean),
960 UnknownStencilTestState(GLboolean),
962 UnknownStencilTestComparison(GLint),
964 UnknownStencilOp(GLint),
966 UnknownWriteState(GLboolean),
968 UnknownFaceCullingState(GLboolean),
970 UnknownFaceCullingOrder(GLenum),
972 UnknownFaceCullingMode(GLenum),
974 UnknownVertexRestartState(GLboolean),
976 UnknownSRGBFramebufferState(GLboolean),
978 UnknownScissorState(GLboolean),
980}
981
982impl fmt::Display for StateQueryError {
983 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
984 match *self {
985 StateQueryError::UnavailableGLState => write!(f, "unavailable graphics state"),
986 StateQueryError::UnknownBlendingState(ref s) => write!(f, "unknown blending state: {}", s),
987 StateQueryError::UnknownBlendingEquation(ref e) => {
988 write!(f, "unknown blending equation: {}", e)
989 }
990 StateQueryError::UnknownBlendingSrcFactor(ref k) => {
991 write!(f, "unknown blending source factor: {}", k)
992 }
993 StateQueryError::UnknownBlendingDstFactor(ref k) => {
994 write!(f, "unknown blending destination factor: {}", k)
995 }
996 StateQueryError::UnknownDepthTestState(ref s) => write!(f, "unknown depth test state: {}", s),
997 StateQueryError::UnknownWriteState(ref s) => {
998 write!(f, "unknown depth write state: {}", s)
999 }
1000 StateQueryError::UnknownStencilTestState(ref s) => {
1001 write!(f, "unknown stencil test state: {}", s)
1002 }
1003 StateQueryError::UnknownStencilTestComparison(ref k) => {
1004 write!(f, "unknown stencil test comparison: {}", k)
1005 }
1006 StateQueryError::UnknownStencilOp(ref op) => {
1007 write!(f, "unknown stencil operation: {}", op)
1008 }
1009 StateQueryError::UnknownFaceCullingState(ref s) => {
1010 write!(f, "unknown face culling state: {}", s)
1011 }
1012 StateQueryError::UnknownFaceCullingOrder(ref o) => {
1013 write!(f, "unknown face culling order: {}", o)
1014 }
1015 StateQueryError::UnknownFaceCullingMode(ref m) => {
1016 write!(f, "unknown face culling mode: {}", m)
1017 }
1018 StateQueryError::UnknownVertexRestartState(ref s) => {
1019 write!(f, "unknown vertex restart state: {}", s)
1020 }
1021 StateQueryError::UnknownSRGBFramebufferState(ref s) => {
1022 write!(f, "unknown sRGB framebuffer state: {}", s)
1023 }
1024 StateQueryError::UnknownScissorState(ref s) => write!(f, "unknown scissor state: {}", s),
1025 }
1026 }
1027}
1028
1029impl error::Error for StateQueryError {}
1030
1031unsafe fn get_ctx_viewport() -> Result<[GLint; 4], StateQueryError> {
1032 let mut data = [0; 4];
1033 gl::GetIntegerv(gl::VIEWPORT, data.as_mut_ptr());
1034 Ok(data)
1035}
1036
1037unsafe fn get_ctx_clear_color() -> Result<[GLfloat; 4], StateQueryError> {
1038 let mut data = [0.; 4];
1039 gl::GetFloatv(gl::COLOR_CLEAR_VALUE, data.as_mut_ptr());
1040 Ok(data)
1041}
1042
1043unsafe fn get_ctx_clear_depth() -> Result<GLfloat, StateQueryError> {
1044 let mut data = 0.;
1045 gl::GetFloatv(gl::DEPTH_CLEAR_VALUE, &mut data);
1046 Ok(data)
1047}
1048
1049unsafe fn get_ctx_clear_stencil() -> Result<GLint, StateQueryError> {
1050 let mut data = 0;
1051 gl::GetIntegerv(gl::STENCIL_CLEAR_VALUE, &mut data);
1052 Ok(data)
1053}
1054
1055unsafe fn get_ctx_blending_state() -> Result<BlendingState, StateQueryError> {
1056 let state = gl::IsEnabled(gl::BLEND);
1057
1058 match state {
1059 gl::TRUE => Ok(BlendingState::On),
1060 gl::FALSE => Ok(BlendingState::Off),
1061 _ => Err(StateQueryError::UnknownBlendingState(state)),
1062 }
1063}
1064
1065unsafe fn get_ctx_scissor_state() -> Result<ScissorState, StateQueryError> {
1066 let state = gl::IsEnabled(gl::SCISSOR_TEST);
1067
1068 match state {
1069 gl::TRUE => Ok(ScissorState::On),
1070 gl::FALSE => Ok(ScissorState::Off),
1071 _ => Err(StateQueryError::UnknownScissorState(state)),
1072 }
1073}
1074
1075unsafe fn get_ctx_scissor_region() -> Result<ScissorRegion, StateQueryError> {
1076 let mut data = [0; 4];
1077 gl::GetIntegerv(gl::SCISSOR_BOX, data.as_mut_ptr());
1078
1079 Ok(ScissorRegion {
1080 x: data[0] as u32,
1081 y: data[1] as u32,
1082 width: data[2] as u32,
1083 height: data[3] as u32,
1084 })
1085}
1086
1087unsafe fn get_ctx_blending_equations() -> Result<BlendingEquations, StateQueryError> {
1088 let mut rgb = gl::FUNC_ADD as GLint;
1089 let mut alpha = gl::FUNC_ADD as GLint;
1090
1091 gl::GetIntegerv(gl::BLEND_EQUATION_RGB, &mut rgb);
1092 gl::GetIntegerv(gl::BLEND_EQUATION_ALPHA, &mut alpha);
1093
1094 let rgb = map_enum_to_blending_equation(rgb as GLenum)?;
1095 let alpha = map_enum_to_blending_equation(alpha as GLenum)?;
1096
1097 Ok(BlendingEquations { rgb, alpha })
1098}
1099
1100unsafe fn get_ctx_blending_factors() -> Result<BlendingFactors, StateQueryError> {
1101 let mut src_rgb = gl::ONE as GLint;
1102 let mut dst_rgb = gl::ZERO as GLint;
1103 let mut src_alpha = gl::ONE as GLint;
1104 let mut dst_alpha = gl::ZERO as GLint;
1105
1106 gl::GetIntegerv(gl::BLEND_SRC_RGB, &mut src_rgb);
1107 gl::GetIntegerv(gl::BLEND_DST_RGB, &mut dst_rgb);
1108 gl::GetIntegerv(gl::BLEND_SRC_ALPHA, &mut src_alpha);
1109 gl::GetIntegerv(gl::BLEND_DST_ALPHA, &mut dst_alpha);
1110
1111 let src_rgb = from_gl_blending_factor(src_rgb as GLenum)
1112 .map_err(StateQueryError::UnknownBlendingSrcFactor)?;
1113 let dst_rgb = from_gl_blending_factor(dst_rgb as GLenum)
1114 .map_err(StateQueryError::UnknownBlendingDstFactor)?;
1115 let src_alpha = from_gl_blending_factor(src_alpha as GLenum)
1116 .map_err(StateQueryError::UnknownBlendingSrcFactor)?;
1117 let dst_alpha = from_gl_blending_factor(dst_alpha as GLenum)
1118 .map_err(StateQueryError::UnknownBlendingDstFactor)?;
1119
1120 Ok(BlendingFactors {
1121 src_rgb,
1122 dst_rgb,
1123 src_alpha,
1124 dst_alpha,
1125 })
1126}
1127
1128#[inline]
1129fn map_enum_to_blending_equation(data: GLenum) -> Result<Equation, StateQueryError> {
1130 match data {
1131 gl::FUNC_ADD => Ok(Equation::Additive),
1132 gl::FUNC_SUBTRACT => Ok(Equation::Subtract),
1133 gl::FUNC_REVERSE_SUBTRACT => Ok(Equation::ReverseSubtract),
1134 gl::MIN => Ok(Equation::Min),
1135 gl::MAX => Ok(Equation::Max),
1136 _ => Err(StateQueryError::UnknownBlendingEquation(data)),
1137 }
1138}
1139
1140#[inline]
1141fn from_gl_blending_factor(factor: GLenum) -> Result<Factor, GLenum> {
1142 match factor {
1143 gl::ONE => Ok(Factor::One),
1144 gl::ZERO => Ok(Factor::Zero),
1145 gl::SRC_COLOR => Ok(Factor::SrcColor),
1146 gl::ONE_MINUS_SRC_COLOR => Ok(Factor::SrcColorComplement),
1147 gl::DST_COLOR => Ok(Factor::DestColor),
1148 gl::ONE_MINUS_DST_COLOR => Ok(Factor::DestColorComplement),
1149 gl::SRC_ALPHA => Ok(Factor::SrcAlpha),
1150 gl::ONE_MINUS_SRC_ALPHA => Ok(Factor::SrcAlphaComplement),
1151 gl::DST_ALPHA => Ok(Factor::DstAlpha),
1152 gl::ONE_MINUS_DST_ALPHA => Ok(Factor::DstAlphaComplement),
1153 gl::SRC_ALPHA_SATURATE => Ok(Factor::SrcAlphaSaturate),
1154 _ => Err(factor),
1155 }
1156}
1157
1158unsafe fn get_ctx_depth_test() -> Result<DepthTest, StateQueryError> {
1159 let state = gl::IsEnabled(gl::DEPTH_TEST);
1160
1161 match state {
1162 gl::TRUE => Ok(DepthTest::On),
1163 gl::FALSE => Ok(DepthTest::Off),
1164 _ => Err(StateQueryError::UnknownDepthTestState(state)),
1165 }
1166}
1167
1168unsafe fn get_ctx_depth_write() -> Result<Write, StateQueryError> {
1169 let mut state = gl::FALSE;
1170
1171 gl::GetBooleanv(gl::DEPTH_WRITEMASK, &mut state);
1172
1173 match state {
1174 gl::TRUE => Ok(Write::On),
1175 gl::FALSE => Ok(Write::Off),
1176 _ => Err(StateQueryError::UnknownWriteState(state)),
1177 }
1178}
1179
1180unsafe fn get_ctx_stencil_test_enabled() -> Result<bool, StateQueryError> {
1181 let state = gl::IsEnabled(gl::STENCIL_TEST);
1182
1183 match state {
1184 gl::TRUE => Ok(true),
1185 gl::FALSE => Ok(false),
1186 _ => Err(StateQueryError::UnknownStencilTestState(state)),
1187 }
1188}
1189
1190unsafe fn get_ctx_stencil_test() -> Result<StencilTest, StateQueryError> {
1191 let mut data = gl::ALWAYS as GLint;
1193
1194 gl::GetIntegerv(gl::STENCIL_FUNC, &mut data);
1195 let comparison = glenum_to_comparison(data as GLenum)
1196 .ok_or_else(|| StateQueryError::UnknownStencilTestComparison(data))?;
1197
1198 gl::GetIntegerv(gl::STENCIL_REF, &mut data);
1199 let reference = data as u8;
1200
1201 gl::GetIntegerv(gl::STENCIL_VALUE_MASK, &mut data);
1202 let mask = data as u8;
1203
1204 Ok(StencilTest {
1205 comparison,
1206 reference,
1207 mask,
1208 })
1209}
1210
1211unsafe fn get_ctx_stencil_operations() -> Result<StencilOperations, StateQueryError> {
1212 let mut data = 0 as GLint;
1213
1214 gl::GetIntegerv(gl::STENCIL_FAIL, &mut data);
1215 let depth_passes_stencil_fails =
1216 glenum_to_stencil_op(data as _).ok_or_else(|| StateQueryError::UnknownStencilOp(data))?;
1217 gl::GetIntegerv(gl::STENCIL_PASS_DEPTH_FAIL, &mut data);
1218 let depth_fails_stencil_passes =
1219 glenum_to_stencil_op(data as _).ok_or_else(|| StateQueryError::UnknownStencilOp(data))?;
1220 gl::GetIntegerv(gl::STENCIL_PASS_DEPTH_PASS, &mut data);
1221 let depth_stencil_pass =
1222 glenum_to_stencil_op(data as _).ok_or_else(|| StateQueryError::UnknownStencilOp(data))?;
1223
1224 Ok(StencilOperations {
1225 depth_passes_stencil_fails,
1226 depth_fails_stencil_passes,
1227 depth_stencil_pass,
1228 })
1229}
1230
1231unsafe fn get_ctx_face_culling_state() -> Result<FaceCullingState, StateQueryError> {
1232 let state = gl::IsEnabled(gl::CULL_FACE);
1233
1234 match state {
1235 gl::TRUE => Ok(FaceCullingState::On),
1236 gl::FALSE => Ok(FaceCullingState::Off),
1237 _ => Err(StateQueryError::UnknownFaceCullingState(state)),
1238 }
1239}
1240
1241unsafe fn get_ctx_face_culling_order() -> Result<FaceCullingOrder, StateQueryError> {
1242 let mut order = gl::CCW as GLint;
1243 gl::GetIntegerv(gl::FRONT_FACE, &mut order);
1244
1245 let order = order as GLenum;
1246 match order {
1247 gl::CCW => Ok(FaceCullingOrder::CCW),
1248 gl::CW => Ok(FaceCullingOrder::CW),
1249 _ => Err(StateQueryError::UnknownFaceCullingOrder(order)),
1250 }
1251}
1252
1253unsafe fn get_ctx_face_culling_mode() -> Result<FaceCullingMode, StateQueryError> {
1254 let mut mode = gl::BACK as GLint;
1255 gl::GetIntegerv(gl::CULL_FACE_MODE, &mut mode);
1256
1257 let mode = mode as GLenum;
1258 match mode {
1259 gl::FRONT => Ok(FaceCullingMode::Front),
1260 gl::BACK => Ok(FaceCullingMode::Back),
1261 gl::FRONT_AND_BACK => Ok(FaceCullingMode::Both),
1262 _ => Err(StateQueryError::UnknownFaceCullingMode(mode)),
1263 }
1264}
1265
1266unsafe fn get_ctx_vertex_restart() -> Result<VertexRestart, StateQueryError> {
1267 let state = gl::IsEnabled(gl::PRIMITIVE_RESTART);
1268
1269 match state {
1270 gl::TRUE => Ok(VertexRestart::On),
1271 gl::FALSE => Ok(VertexRestart::Off),
1272 _ => Err(StateQueryError::UnknownVertexRestartState(state)),
1273 }
1274}
1275
1276unsafe fn get_ctx_current_texture_unit() -> Result<GLenum, StateQueryError> {
1277 let mut active_texture = gl::TEXTURE0 as GLint;
1278 gl::GetIntegerv(gl::ACTIVE_TEXTURE, &mut active_texture);
1279 Ok(active_texture as GLenum)
1280}
1281
1282unsafe fn get_ctx_bound_draw_framebuffer() -> Result<GLuint, StateQueryError> {
1283 let mut bound = 0 as GLint;
1284 gl::GetIntegerv(gl::DRAW_FRAMEBUFFER_BINDING, &mut bound);
1285 Ok(bound as GLuint)
1286}
1287
1288unsafe fn get_ctx_bound_vertex_array() -> Result<GLuint, StateQueryError> {
1289 let mut bound = 0 as GLint;
1290 gl::GetIntegerv(gl::VERTEX_ARRAY_BINDING, &mut bound);
1291 Ok(bound as GLuint)
1292}
1293
1294unsafe fn get_ctx_current_program() -> Result<GLuint, StateQueryError> {
1295 let mut used = 0 as GLint;
1296 gl::GetIntegerv(gl::CURRENT_PROGRAM, &mut used);
1297 Ok(used as GLuint)
1298}
1299
1300unsafe fn get_ctx_srgb_framebuffer_enabled() -> Result<bool, StateQueryError> {
1301 let state = gl::IsEnabled(gl::FRAMEBUFFER_SRGB);
1302
1303 match state {
1304 gl::TRUE => Ok(true),
1305 gl::FALSE => Ok(false),
1306 _ => Err(StateQueryError::UnknownSRGBFramebufferState(state)),
1307 }
1308}
1309
1310#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1312pub(crate) enum BlendingState {
1313 On,
1315 Off,
1317}
1318
1319#[derive(Debug, PartialEq, Eq)]
1320pub(crate) struct BlendingFactors {
1321 src_rgb: Factor,
1322 dst_rgb: Factor,
1323 src_alpha: Factor,
1324 dst_alpha: Factor,
1325}
1326
1327#[derive(Debug, PartialEq, Eq)]
1328pub(crate) struct BlendingEquations {
1329 rgb: Equation,
1330 alpha: Equation,
1331}
1332
1333#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1335pub(crate) enum DepthTest {
1336 On,
1338 Off,
1340}
1341
1342#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1344pub(crate) enum FaceCullingState {
1345 On,
1347 Off,
1349}
1350
1351#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1353pub(crate) enum ScissorState {
1354 On,
1356 Off,
1358}