1#![allow(deprecated)] use crate::{
24 buffer::GlBuffer,
25 framebuffer::GlFrameBuffer,
26 geometry_buffer::GlGeometryBuffer,
27 program::{GlProgram, GlShader},
28 query::GlQuery,
29 read_buffer::GlAsyncReadBuffer,
30 sampler::GlSampler,
31 texture::GlTexture,
32 ToGlConstant,
33};
34use fyrox_graphics::{
35 buffer::{GpuBuffer, GpuBufferDescriptor},
36 core::{color::Color, log::Log, math::Rect},
37 error::FrameworkError,
38 framebuffer::{Attachment, GpuFrameBuffer},
39 geometry_buffer::{GpuGeometryBuffer, GpuGeometryBufferDescriptor},
40 gpu_program::{GpuProgram, GpuShader, ShaderKind, ShaderResourceDefinition},
41 gpu_texture::{GpuTexture, GpuTextureDescriptor},
42 query::GpuQuery,
43 read_buffer::GpuAsyncReadBuffer,
44 sampler::{GpuSampler, GpuSamplerDescriptor},
45 server::{GraphicsServer, ServerCapabilities, ServerMemoryUsage, SharedGraphicsServer},
46 stats::PipelineStatistics,
47 BlendEquation, BlendFactor, BlendFunc, BlendMode, ColorMask, CompareFunc, CullFace,
48 DrawParameters, PolygonFace, PolygonFillMode, ScissorBox, StencilAction, StencilFunc,
49 StencilOp,
50};
51use glow::HasContext;
52#[cfg(not(target_arch = "wasm32"))]
53use glutin::{
54 config::ConfigTemplateBuilder,
55 context::{
56 ContextApi, ContextAttributesBuilder, GlProfile, NotCurrentGlContext,
57 PossiblyCurrentContext, Version,
58 },
59 display::{GetGlDisplay, GlDisplay},
60 surface::{GlSurface, Surface, SwapInterval, WindowSurface},
61};
62#[cfg(not(target_arch = "wasm32"))]
63use glutin_winit::{DisplayBuilder, GlWindow};
64#[cfg(not(target_arch = "wasm32"))]
65use raw_window_handle::HasRawWindowHandle;
66use std::cell::{Cell, RefCell};
67use std::rc::{Rc, Weak};
68#[cfg(not(target_arch = "wasm32"))]
69use std::{ffi::CString, num::NonZeroU32};
70use winit::event_loop::ActiveEventLoop;
71use winit::window::{Window, WindowAttributes};
72
73impl ToGlConstant for PolygonFace {
74 fn into_gl(self) -> u32 {
75 match self {
76 Self::Front => glow::FRONT,
77 Self::Back => glow::BACK,
78 Self::FrontAndBack => glow::FRONT_AND_BACK,
79 }
80 }
81}
82
83impl ToGlConstant for PolygonFillMode {
84 fn into_gl(self) -> u32 {
85 match self {
86 Self::Point => glow::POINT,
87 Self::Line => glow::LINE,
88 Self::Fill => glow::FILL,
89 }
90 }
91}
92
93impl ToGlConstant for StencilAction {
94 fn into_gl(self) -> u32 {
95 match self {
96 StencilAction::Keep => glow::KEEP,
97 StencilAction::Zero => glow::ZERO,
98 StencilAction::Replace => glow::REPLACE,
99 StencilAction::Incr => glow::INCR,
100 StencilAction::IncrWrap => glow::INCR_WRAP,
101 StencilAction::Decr => glow::DECR,
102 StencilAction::DecrWrap => glow::DECR_WRAP,
103 StencilAction::Invert => glow::INVERT,
104 }
105 }
106}
107
108impl ToGlConstant for BlendMode {
109 fn into_gl(self) -> u32 {
110 match self {
111 Self::Add => glow::FUNC_ADD,
112 Self::Subtract => glow::FUNC_SUBTRACT,
113 Self::ReverseSubtract => glow::FUNC_REVERSE_SUBTRACT,
114 Self::Min => glow::MIN,
115 Self::Max => glow::MAX,
116 }
117 }
118}
119
120impl ToGlConstant for BlendFactor {
121 fn into_gl(self) -> u32 {
122 match self {
123 Self::Zero => glow::ZERO,
124 Self::One => glow::ONE,
125 Self::SrcColor => glow::SRC_COLOR,
126 Self::OneMinusSrcColor => glow::ONE_MINUS_SRC_COLOR,
127 Self::DstColor => glow::DST_COLOR,
128 Self::OneMinusDstColor => glow::ONE_MINUS_DST_COLOR,
129 Self::SrcAlpha => glow::SRC_ALPHA,
130 Self::OneMinusSrcAlpha => glow::ONE_MINUS_SRC_ALPHA,
131 Self::DstAlpha => glow::DST_ALPHA,
132 Self::OneMinusDstAlpha => glow::ONE_MINUS_DST_ALPHA,
133 Self::ConstantColor => glow::CONSTANT_COLOR,
134 Self::OneMinusConstantColor => glow::ONE_MINUS_CONSTANT_COLOR,
135 Self::ConstantAlpha => glow::CONSTANT_ALPHA,
136 Self::OneMinusConstantAlpha => glow::ONE_MINUS_CONSTANT_ALPHA,
137 Self::SrcAlphaSaturate => glow::SRC_ALPHA_SATURATE,
138 Self::Src1Color => glow::SRC1_COLOR,
139 Self::OneMinusSrc1Color => glow::ONE_MINUS_SRC1_COLOR,
140 Self::Src1Alpha => glow::SRC1_ALPHA,
141 Self::OneMinusSrc1Alpha => glow::ONE_MINUS_SRC1_ALPHA,
142 }
143 }
144}
145
146impl ToGlConstant for CompareFunc {
147 fn into_gl(self) -> u32 {
148 match self {
149 Self::Never => glow::NEVER,
150 Self::Less => glow::LESS,
151 Self::Equal => glow::EQUAL,
152 Self::LessOrEqual => glow::LEQUAL,
153 Self::Greater => glow::GREATER,
154 Self::NotEqual => glow::NOTEQUAL,
155 Self::GreaterOrEqual => glow::GEQUAL,
156 Self::Always => glow::ALWAYS,
157 }
158 }
159}
160
161impl ToGlConstant for CullFace {
162 fn into_gl(self) -> u32 {
163 match self {
164 Self::Back => glow::BACK,
165 Self::Front => glow::FRONT,
166 }
167 }
168}
169
170#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
172pub enum GlKind {
173 OpenGL,
175 OpenGLES,
177}
178
179pub(crate) struct InnerState {
187 blend: bool,
190
191 depth_test: bool,
194 depth_write: bool,
197 depth_func: CompareFunc,
200
201 color_write: ColorMask,
205 stencil_test: bool,
208 cull_face: CullFace,
211 culling: bool,
214 clear_color: Color,
217 clear_stencil: i32,
220 clear_depth: f32,
223 scissor_test: bool,
228
229 front_fill_mode: PolygonFillMode,
232 back_fill_mode: PolygonFillMode,
235
236 write_framebuffer: Option<glow::Framebuffer>,
241 read_framebuffer: Option<glow::Framebuffer>,
246 viewport: Rect<i32>,
248
249 blend_func: BlendFunc,
251 blend_equation: BlendEquation,
253
254 program: Option<glow::Program>,
256 texture_units_storage: TextureUnitsStorage,
258
259 stencil_func: StencilFunc,
262 stencil_op: StencilOp,
266
267 vao: Option<glow::VertexArray>,
269
270 frame_statistics: PipelineStatistics,
272 gl_kind: GlKind,
274
275 pub(crate) queries: Vec<glow::Query>,
287
288 #[cfg(not(target_arch = "wasm32"))]
289 gl_context: PossiblyCurrentContext,
290 #[cfg(not(target_arch = "wasm32"))]
291 gl_surface: Surface<WindowSurface>,
292}
293
294impl InnerState {
295 fn new(
296 gl_kind: GlKind,
297 #[cfg(not(target_arch = "wasm32"))] gl_context: PossiblyCurrentContext,
298 #[cfg(not(target_arch = "wasm32"))] gl_surface: Surface<WindowSurface>,
299 ) -> Self {
300 Self {
301 blend: false,
302 depth_test: false,
303 depth_write: true,
304 depth_func: Default::default(),
305 color_write: Default::default(),
306 stencil_test: false,
307 cull_face: CullFace::Back,
308 culling: false,
309 clear_color: Color::from_rgba(0, 0, 0, 0),
310 clear_stencil: 0,
311 clear_depth: 1.0,
312 scissor_test: false,
313 front_fill_mode: PolygonFillMode::default(),
314 back_fill_mode: PolygonFillMode::default(),
315 read_framebuffer: None,
316 write_framebuffer: None,
317 blend_func: Default::default(),
318 viewport: Rect::new(0, 0, 1, 1),
319 program: Default::default(),
320 texture_units_storage: TextureUnitsStorage {
321 active_unit: 0,
322 units: Default::default(),
323 },
324 stencil_func: Default::default(),
325 stencil_op: Default::default(),
326 vao: Default::default(),
327 frame_statistics: Default::default(),
328 blend_equation: Default::default(),
329 gl_kind,
330 queries: Default::default(),
331 #[cfg(not(target_arch = "wasm32"))]
332 gl_context,
333 #[cfg(not(target_arch = "wasm32"))]
334 gl_surface,
335 }
336 }
337
338 pub(crate) fn delete_framebuffer(
339 &mut self,
340 framebuffer: Option<glow::Framebuffer>,
341 gl: &glow::Context,
342 ) {
343 if self.read_framebuffer == framebuffer {
344 self.set_framebuffer(FrameBufferBindingPoint::Read, None, gl);
345 }
346 if self.write_framebuffer == framebuffer {
347 self.set_framebuffer(FrameBufferBindingPoint::Write, None, gl);
348 }
349
350 if let Some(id) = framebuffer {
351 unsafe {
352 gl.delete_framebuffer(id);
353 }
354 }
355 }
356
357 pub(crate) fn set_framebuffer(
358 &mut self,
359 binding_point: FrameBufferBindingPoint,
360 framebuffer: Option<glow::Framebuffer>,
361 gl: &glow::Context,
362 ) {
363 match binding_point {
364 FrameBufferBindingPoint::Read => {
365 if self.read_framebuffer != framebuffer {
366 self.read_framebuffer = framebuffer;
367
368 self.frame_statistics.framebuffer_binding_changes += 1;
369
370 unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, self.read_framebuffer) }
371 }
372 }
373 FrameBufferBindingPoint::Write => {
374 if self.write_framebuffer != framebuffer {
375 self.write_framebuffer = framebuffer;
376
377 self.frame_statistics.framebuffer_binding_changes += 1;
378
379 unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, self.write_framebuffer) }
380 }
381 }
382 FrameBufferBindingPoint::ReadWrite => {
383 if self.write_framebuffer != framebuffer || self.read_framebuffer != framebuffer {
384 self.write_framebuffer = framebuffer;
385 self.read_framebuffer = framebuffer;
386
387 self.frame_statistics.framebuffer_binding_changes += 1;
388
389 unsafe { gl.bind_framebuffer(glow::FRAMEBUFFER, framebuffer) }
390 }
391 }
392 }
393 }
394
395 pub(crate) fn delete_texture(&mut self, texture: glow::Texture, gl: &glow::Context) {
396 unsafe {
397 for unit in self.texture_units_storage.units.iter_mut() {
398 for binding in unit.bindings.iter_mut() {
399 if binding.texture == Some(texture) {
400 binding.texture = None;
401 }
402 }
403 }
404
405 gl.delete_texture(texture);
406 }
407 }
408
409 pub(crate) fn set_texture(
414 &mut self,
415 unit_index: u32,
416 target: u32,
417 texture: Option<glow::Texture>,
418 gl: &glow::Context,
419 ) {
420 unsafe fn bind_texture(
421 gl: &glow::Context,
422 target: u32,
423 texture: Option<glow::Texture>,
424 unit_index: u32,
425 active_unit: &mut u32,
426 ) {
427 if *active_unit != unit_index {
428 *active_unit = unit_index;
429 gl.active_texture(glow::TEXTURE0 + unit_index);
430 }
431 gl.bind_texture(target, texture);
432 }
433
434 unsafe {
435 let unit = &mut self.texture_units_storage.units[unit_index as usize];
436 let active_unit = &mut self.texture_units_storage.active_unit;
437 for binding in unit.bindings.iter_mut() {
438 if binding.target == target {
439 if binding.texture != texture {
440 binding.texture = texture;
441 bind_texture(gl, binding.target, texture, unit_index, active_unit);
442 self.frame_statistics.texture_binding_changes += 1;
443 }
444 } else if binding.texture.is_some() {
445 binding.texture = None;
446 bind_texture(gl, binding.target, None, unit_index, active_unit);
447 self.frame_statistics.texture_binding_changes += 1;
448 }
449 }
450 }
451 }
452
453 pub(crate) fn delete_program(&mut self, program: glow::Program, gl: &glow::Context) {
454 if self.program == Some(program) {
455 self.program = None;
456 }
457
458 unsafe {
459 gl.delete_program(program);
460 }
461 }
462
463 pub(crate) fn set_program(&mut self, program: Option<glow::Program>, gl: &glow::Context) {
464 if self.program != program {
465 self.program = program;
466
467 self.frame_statistics.program_binding_changes += 1;
468
469 unsafe {
470 gl.use_program(program);
471 }
472 }
473 }
474
475 pub(crate) fn delete_vertex_array_object(
476 &mut self,
477 vao: glow::VertexArray,
478 gl: &glow::Context,
479 ) {
480 if self.vao == Some(vao) {
481 self.vao = None;
482 }
483
484 unsafe {
485 gl.delete_vertex_array(vao);
486 }
487 }
488
489 pub(crate) fn set_vertex_array_object(
490 &mut self,
491 vao: Option<glow::VertexArray>,
492 gl: &glow::Context,
493 ) {
494 if self.vao != vao {
495 self.vao = vao;
496
497 self.frame_statistics.vao_binding_changes += 1;
498
499 unsafe {
500 gl.bind_vertex_array(self.vao);
501 }
502 }
503 }
504}
505
506pub enum FrameBufferBindingPoint {
508 Read,
509 Write,
510 ReadWrite,
511}
512
513pub struct GlGraphicsServer {
516 pub gl: glow::Context,
520 pub named_objects: Cell<bool>,
523 pub(crate) state: RefCell<InnerState>,
527 pub(crate) memory_usage: RefCell<ServerMemoryUsage>,
529 this: RefCell<Option<Weak<GlGraphicsServer>>>,
533}
534
535#[derive(Copy, Clone)]
536struct TextureBinding {
537 target: u32,
538 texture: Option<glow::Texture>,
539}
540
541#[derive(Copy, Clone)]
547struct TextureUnit {
548 bindings: [TextureBinding; 4],
549}
550
551impl Default for TextureUnit {
552 fn default() -> Self {
556 Self {
557 bindings: [
558 TextureBinding {
559 target: glow::TEXTURE_2D,
560 texture: None,
561 },
562 TextureBinding {
563 target: glow::TEXTURE_3D,
564 texture: None,
565 },
566 TextureBinding {
567 target: glow::TEXTURE_1D,
568 texture: None,
569 },
570 TextureBinding {
571 target: glow::TEXTURE_CUBE_MAP,
572 texture: None,
573 },
574 ],
575 }
576 }
577}
578
579#[derive(Default)]
581struct TextureUnitsStorage {
582 active_unit: u32,
584 units: [TextureUnit; 32],
586}
587
588impl GlGraphicsServer {
589 #[allow(clippy::new_ret_no_self)]
590 #[allow(unused_mut)]
591 pub fn new(
592 #[allow(unused_variables)] vsync: bool,
593 #[allow(unused_variables)] msaa_sample_count: Option<u8>,
594 window_target: &ActiveEventLoop,
595 mut window_attributes: WindowAttributes,
596 named_objects: bool,
597 ) -> Result<(Window, SharedGraphicsServer), FrameworkError> {
598 #[cfg(not(target_arch = "wasm32"))]
599 let (window, gl_context, gl_surface, mut context, gl_kind) = {
600 let mut template = ConfigTemplateBuilder::new()
601 .prefer_hardware_accelerated(Some(true))
602 .with_stencil_size(8)
603 .with_depth_size(24);
604
605 if let Some(sample_count) = msaa_sample_count {
606 template = template.with_multisampling(sample_count);
607 }
608
609 let (opt_window, gl_config) = DisplayBuilder::new()
610 .with_window_attributes(Some(window_attributes))
611 .build(window_target, template, |mut configs| {
612 configs.next().unwrap()
613 })?;
614
615 let window = opt_window.unwrap();
616
617 let raw_window_handle = window.raw_window_handle().unwrap();
618
619 let gl_display = gl_config.display();
620
621 #[cfg(debug_assertions)]
622 let debug = true;
623
624 #[cfg(not(debug_assertions))]
625 let debug = true;
626
627 let gl3_3_core_context_attributes = ContextAttributesBuilder::new()
628 .with_debug(debug)
629 .with_profile(GlProfile::Core)
630 .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 3))))
631 .build(Some(raw_window_handle));
632
633 let gles3_context_attributes = ContextAttributesBuilder::new()
634 .with_debug(debug)
635 .with_profile(GlProfile::Core)
636 .with_context_api(ContextApi::Gles(Some(Version::new(3, 0))))
637 .build(Some(raw_window_handle));
638
639 unsafe {
640 let attrs = window.build_surface_attributes(Default::default()).unwrap();
641
642 let gl_surface = gl_config
643 .display()
644 .create_window_surface(&gl_config, &attrs)
645 .map_err(|err| FrameworkError::Custom(format!("{err:?}")))?;
646
647 let (non_current_gl_context, gl_kind) = if let Ok(gl3_3_core_context) =
648 gl_display.create_context(&gl_config, &gl3_3_core_context_attributes)
649 {
650 (gl3_3_core_context, GlKind::OpenGL)
651 } else {
652 (
653 gl_display
654 .create_context(&gl_config, &gles3_context_attributes)
655 .map_err(|err| FrameworkError::Custom(format!("{err:?}")))?,
656 GlKind::OpenGLES,
657 )
658 };
659
660 let gl_context = non_current_gl_context
661 .make_current(&gl_surface)
662 .map_err(|err| FrameworkError::Custom(format!("{err:?}")))?;
663
664 if vsync {
665 Log::verify(gl_surface.set_swap_interval(
666 &gl_context,
667 SwapInterval::Wait(NonZeroU32::new(1).unwrap()),
668 ));
669 }
670
671 (
672 window,
673 gl_context,
674 gl_surface,
675 glow::Context::from_loader_function(|s| {
676 gl_display.get_proc_address(&CString::new(s).unwrap())
677 }),
678 gl_kind,
679 )
680 }
681 };
682
683 #[cfg(target_arch = "wasm32")]
684 let (window, mut context, gl_kind) = {
685 use fyrox_core::wasm_bindgen::JsCast;
686 use serde::{Deserialize, Serialize};
687 use winit::{
688 dpi::{LogicalSize, PhysicalSize},
689 platform::web::WindowExtWebSys,
690 };
691
692 let inner_size = window_attributes.inner_size;
693 let window = window_target.create_window(window_attributes).unwrap();
694
695 let web_window = fyrox_core::web_sys::window().unwrap();
696 let scale_factor = web_window.device_pixel_ratio();
697
698 let canvas = window.canvas().unwrap();
699
700 if let Some(inner_size) = inner_size {
704 fn value_to_err(value: fyrox_core::wasm_bindgen::JsValue) -> String {
705 format!("{:?}", value)
706 }
707
708 let physical_inner_size: PhysicalSize<u32> = inner_size.to_physical(scale_factor);
709
710 canvas.set_width(physical_inner_size.width);
711 canvas.set_height(physical_inner_size.height);
712
713 let logical_inner_size: LogicalSize<f64> = inner_size.to_logical(scale_factor);
714 Log::verify(
715 canvas
716 .style()
717 .set_property("width", &format!("{}px", logical_inner_size.width))
718 .map_err(value_to_err),
719 );
720 Log::verify(
721 canvas
722 .style()
723 .set_property("height", &format!("{}px", logical_inner_size.height))
724 .map_err(value_to_err),
725 );
726 }
727
728 let document = web_window.document().unwrap();
729 let body = document.body().unwrap();
730
731 body.append_child(&canvas)
732 .expect("Append canvas to HTML body");
733
734 #[derive(Serialize, Deserialize)]
735 #[allow(non_snake_case)]
736 struct ContextAttributes {
737 alpha: bool,
738 premultipliedAlpha: bool,
739 powerPreference: String,
740 }
741
742 let context_attributes = ContextAttributes {
743 alpha: false,
746 premultipliedAlpha: false,
747 powerPreference: "high-performance".to_string(),
749 };
750
751 let webgl2_context = canvas
752 .get_context_with_context_options(
753 "webgl2",
754 &serde_wasm_bindgen::to_value(&context_attributes).unwrap(),
755 )
756 .unwrap()
757 .unwrap()
758 .dyn_into::<fyrox_core::web_sys::WebGl2RenderingContext>()
759 .unwrap();
760 (
761 window,
762 glow::Context::from_webgl2_context(webgl2_context),
763 GlKind::OpenGLES,
764 )
765 };
766
767 #[cfg(not(target_arch = "wasm32"))]
768 gl_surface.resize(
769 &gl_context,
770 NonZeroU32::new(window.inner_size().width)
771 .unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
772 NonZeroU32::new(window.inner_size().height)
773 .unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
774 );
775
776 Log::info(format!(
778 "Supported GL Extensions: {:?}",
779 context.supported_extensions()
780 ));
781
782 unsafe {
783 context.depth_func(CompareFunc::default().into_gl());
784
785 if context
786 .supported_extensions()
787 .contains("GL_ARB_seamless_cubemap_per_texture")
788 {
789 context.enable(glow::TEXTURE_CUBE_MAP_SEAMLESS);
790 }
791
792 #[cfg(debug_assertions)]
793 {
794 use fyrox_core::log::{Log, MessageKind};
795
796 if context.supported_extensions().contains("GL_KHR_debug") {
797 context.debug_message_callback(|source, msg_type, id, severity, message| {
798 let message_kind = if severity == glow::DEBUG_SEVERITY_HIGH {
799 MessageKind::Error
800 } else if severity == glow::DEBUG_SEVERITY_MEDIUM
801 || severity == glow::DEBUG_SEVERITY_LOW
802 {
803 MessageKind::Warning
804 } else {
805 return;
807 };
808
809 let source = if source == glow::DEBUG_SOURCE_API {
810 "Calls to the OpenGL API"
811 } else if source == glow::DEBUG_SOURCE_WINDOW_SYSTEM {
812 "Calls to a window-system API"
813 } else if source == glow::DEBUG_SOURCE_SHADER_COMPILER {
814 "A compiler for a shading language"
815 } else if source == glow::DEBUG_SOURCE_THIRD_PARTY {
816 "An application associated with OpenGL"
817 } else if source == glow::DEBUG_SOURCE_APPLICATION {
818 "Generated by the user of this application"
819 } else {
820 "Other"
821 };
822
823 let msg_type = if msg_type == glow::DEBUG_TYPE_ERROR {
824 "An error, typically from the API"
825 } else if msg_type == glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR {
826 "Some behavior marked deprecated has been used"
827 } else if msg_type == glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR {
828 "Something has invoked undefined behavior"
829 } else if msg_type == glow::DEBUG_TYPE_PORTABILITY {
830 "Some functionality the user relies upon is not portable"
831 } else if msg_type == glow::DEBUG_TYPE_PERFORMANCE {
832 "Code has triggered possible performance issues"
833 } else if msg_type == glow::DEBUG_TYPE_MARKER {
834 "Command stream annotation"
835 } else if msg_type == glow::DEBUG_TYPE_PUSH_GROUP
836 || msg_type == glow::DEBUG_TYPE_POP_GROUP
837 {
838 "Group pushing"
839 } else {
840 "Other"
841 };
842
843 Log::writeln(
844 message_kind,
845 format!(
846 "OpenGL Message\n\
847 \tSource: {source}\n\
848 \tType: {msg_type}\n\
849 \tId: {id}\n\
850 \tMessage: {message}"
851 ),
852 );
853 })
854 }
855 }
856 }
857
858 let state = Self {
859 gl: context,
860 named_objects: Cell::new(named_objects),
861 state: RefCell::new(InnerState::new(
862 gl_kind,
863 #[cfg(not(target_arch = "wasm32"))]
864 gl_context,
865 #[cfg(not(target_arch = "wasm32"))]
866 gl_surface,
867 )),
868 memory_usage: Default::default(),
869 this: Default::default(),
870 };
871
872 let shared = Rc::new(state);
873
874 *shared.this.borrow_mut() = Some(Rc::downgrade(&shared));
875
876 Ok((window, shared))
877 }
878
879 pub fn weak(&self) -> Weak<Self> {
881 self.this.borrow().as_ref().unwrap().clone()
882 }
883
884 pub fn gl_kind(&self) -> GlKind {
886 self.state.borrow().gl_kind
887 }
888
889 pub fn free_texture_unit(&self) -> Option<u32> {
891 let state = self.state.borrow();
892 for (index, unit) in state.texture_units_storage.units.iter().enumerate() {
893 if unit
894 .bindings
895 .iter()
896 .all(|binding| binding.texture.is_none())
897 {
898 return Some(index as u32);
899 }
900 }
901 None
902 }
903
904 pub(crate) fn delete_framebuffer(&self, framebuffer: Option<glow::Framebuffer>) {
906 self.state
907 .borrow_mut()
908 .delete_framebuffer(framebuffer, &self.gl)
909 }
910
911 pub(crate) fn set_framebuffer(
915 &self,
916 binding_point: FrameBufferBindingPoint,
917 framebuffer: Option<glow::Framebuffer>,
918 ) {
919 self.state
920 .borrow_mut()
921 .set_framebuffer(binding_point, framebuffer, &self.gl)
922 }
923
924 pub(crate) fn set_viewport(&self, viewport: Rect<i32>) {
926 let mut state = self.state.borrow_mut();
927 if state.viewport != viewport {
928 state.viewport = viewport;
929
930 unsafe {
931 self.gl.viewport(
932 state.viewport.x(),
933 state.viewport.y(),
934 state.viewport.w(),
935 state.viewport.h(),
936 );
937 }
938 }
939 }
940
941 pub(crate) fn set_blend(&self, blend: bool) {
944 let mut state = self.state.borrow_mut();
945 if state.blend != blend {
946 state.blend = blend;
947
948 state.frame_statistics.blend_state_changes += 1;
949
950 unsafe {
951 if state.blend {
952 self.gl.enable(glow::BLEND);
953 } else {
954 self.gl.disable(glow::BLEND);
955 }
956 }
957 }
958 }
959
960 pub(crate) fn set_depth_test(&self, depth_test: bool) {
964 let mut state = self.state.borrow_mut();
965 if state.depth_test != depth_test {
966 state.depth_test = depth_test;
967
968 unsafe {
969 if state.depth_test {
970 self.gl.enable(glow::DEPTH_TEST);
971 } else {
972 self.gl.disable(glow::DEPTH_TEST);
973 }
974 }
975 }
976 }
977
978 pub(crate) fn set_depth_write(&self, depth_write: bool) {
981 let mut state = self.state.borrow_mut();
982 if state.depth_write != depth_write {
983 state.depth_write = depth_write;
984
985 unsafe {
986 self.gl.depth_mask(state.depth_write);
987 }
988 }
989 }
990
991 pub(crate) fn set_color_write(&self, color_write: ColorMask) {
994 let mut state = self.state.borrow_mut();
995 if state.color_write != color_write {
996 state.color_write = color_write;
997
998 unsafe {
999 self.gl.color_mask(
1000 state.color_write.red,
1001 state.color_write.green,
1002 state.color_write.blue,
1003 state.color_write.alpha,
1004 );
1005 }
1006 }
1007 }
1008
1009 pub(crate) fn set_stencil_test(&self, stencil_test: bool) {
1013 let mut state = self.state.borrow_mut();
1014 if state.stencil_test != stencil_test {
1015 state.stencil_test = stencil_test;
1016
1017 unsafe {
1018 if state.stencil_test {
1019 self.gl.enable(glow::STENCIL_TEST);
1020 } else {
1021 self.gl.disable(glow::STENCIL_TEST);
1022 }
1023 }
1024 }
1025 }
1026
1027 pub(crate) fn set_cull_face(&self, cull_face: CullFace) {
1029 let mut state = self.state.borrow_mut();
1030 if state.cull_face != cull_face {
1031 state.cull_face = cull_face;
1032
1033 unsafe { self.gl.cull_face(state.cull_face.into_gl()) }
1034 }
1035 }
1036
1037 pub(crate) fn set_culling(&self, culling: bool) {
1039 let mut state = self.state.borrow_mut();
1040 if state.culling != culling {
1041 state.culling = culling;
1042
1043 unsafe {
1044 if state.culling {
1045 self.gl.enable(glow::CULL_FACE);
1046 } else {
1047 self.gl.disable(glow::CULL_FACE);
1048 }
1049 }
1050 }
1051 }
1052
1053 pub(crate) fn set_stencil_mask(&self, stencil_mask: u32) {
1058 let mut state = self.state.borrow_mut();
1059 if state.stencil_op.write_mask != stencil_mask {
1060 state.stencil_op.write_mask = stencil_mask;
1061
1062 unsafe {
1063 self.gl.stencil_mask(stencil_mask);
1064 }
1065 }
1066 }
1067
1068 pub(crate) fn set_clear_color(&self, color: Color) {
1070 let mut state = self.state.borrow_mut();
1071 if state.clear_color != color {
1072 state.clear_color = color;
1073
1074 let rgba = color.as_frgba();
1075 unsafe {
1076 self.gl.clear_color(rgba.x, rgba.y, rgba.z, rgba.w);
1077 }
1078 }
1079 }
1080
1081 pub(crate) fn set_clear_depth(&self, depth: f32) {
1083 let mut state = self.state.borrow_mut();
1084 if (state.clear_depth - depth).abs() > f32::EPSILON {
1085 state.clear_depth = depth;
1086
1087 unsafe {
1088 self.gl.clear_depth_f32(depth);
1089 }
1090 }
1091 }
1092
1093 pub(crate) fn set_clear_stencil(&self, stencil: i32) {
1095 let mut state = self.state.borrow_mut();
1096 if state.clear_stencil != stencil {
1097 state.clear_stencil = stencil;
1098
1099 unsafe {
1100 self.gl.clear_stencil(stencil);
1101 }
1102 }
1103 }
1104
1105 pub(crate) fn set_blend_func(&self, func: BlendFunc) {
1110 let mut state = self.state.borrow_mut();
1111 if state.blend_func != func {
1112 state.blend_func = func;
1113
1114 unsafe {
1115 self.gl.blend_func_separate(
1116 state.blend_func.sfactor.into_gl(),
1117 state.blend_func.dfactor.into_gl(),
1118 state.blend_func.alpha_sfactor.into_gl(),
1119 state.blend_func.alpha_dfactor.into_gl(),
1120 );
1121 }
1122 }
1123 }
1124
1125 pub(crate) fn set_blend_equation(&self, equation: BlendEquation) {
1129 let mut state = self.state.borrow_mut();
1130 if state.blend_equation != equation {
1131 state.blend_equation = equation;
1132
1133 unsafe {
1134 self.gl.blend_equation_separate(
1135 state.blend_equation.rgb.into_gl(),
1136 state.blend_equation.alpha.into_gl(),
1137 );
1138 }
1139 }
1140 }
1141
1142 pub(crate) fn set_depth_func(&self, depth_func: CompareFunc) {
1145 let mut state = self.state.borrow_mut();
1146 if state.depth_func != depth_func {
1147 state.depth_func = depth_func;
1148
1149 unsafe {
1150 self.gl.depth_func(depth_func.into_gl());
1151 }
1152 }
1153 }
1154
1155 pub fn delete_program(&self, program: glow::Program) {
1157 self.state.borrow_mut().delete_program(program, &self.gl);
1158 }
1159
1160 pub(crate) fn set_program(&self, program: Option<glow::Program>) {
1162 self.state.borrow_mut().set_program(program, &self.gl)
1163 }
1164
1165 pub(crate) fn delete_texture(&self, texture: glow::Texture) {
1167 self.state.borrow_mut().delete_texture(texture, &self.gl)
1168 }
1169
1170 pub(crate) fn set_texture(&self, unit_index: u32, target: u32, texture: Option<glow::Texture>) {
1175 self.state
1176 .borrow_mut()
1177 .set_texture(unit_index, target, texture, &self.gl)
1178 }
1179
1180 pub(crate) fn set_stencil_func(&self, func: StencilFunc) {
1184 let mut state = self.state.borrow_mut();
1185 if state.stencil_func != func {
1186 state.stencil_func = func;
1187
1188 unsafe {
1189 self.gl.stencil_func(
1190 state.stencil_func.func.into_gl(),
1191 state.stencil_func.ref_value as i32,
1192 state.stencil_func.mask,
1193 );
1194 }
1195 }
1196 }
1197
1198 pub(crate) fn set_stencil_op(&self, op: StencilOp) {
1202 let mut state = self.state.borrow_mut();
1203 let new_mask = op.write_mask;
1204 if !state.stencil_op.eq_actions(&op) {
1205 state.stencil_op = op;
1206
1207 unsafe {
1208 self.gl.stencil_op(
1209 state.stencil_op.fail.into_gl(),
1210 state.stencil_op.zfail.into_gl(),
1211 state.stencil_op.zpass.into_gl(),
1212 );
1213 }
1214 }
1215 if state.stencil_op.write_mask != new_mask {
1216 state.stencil_op.write_mask = new_mask;
1217 unsafe {
1218 self.gl.stencil_mask(state.stencil_op.write_mask);
1219 }
1220 }
1221 }
1222
1223 pub(crate) fn delete_vertex_array_object(&self, vao: glow::VertexArray) {
1225 self.state
1226 .borrow_mut()
1227 .delete_vertex_array_object(vao, &self.gl);
1228 }
1229
1230 pub(crate) fn set_vertex_array_object(&self, vao: Option<glow::VertexArray>) {
1232 self.state
1233 .borrow_mut()
1234 .set_vertex_array_object(vao, &self.gl);
1235 }
1236
1237 pub(crate) fn set_scissor_test(&self, scissor_test: bool) {
1239 let mut state = self.state.borrow_mut();
1240 if state.scissor_test != scissor_test {
1241 state.scissor_test = scissor_test;
1242
1243 unsafe {
1244 if scissor_test {
1245 self.gl.enable(glow::SCISSOR_TEST);
1246 } else {
1247 self.gl.disable(glow::SCISSOR_TEST);
1248 }
1249 }
1250 }
1251 }
1252
1253 pub(crate) fn set_scissor_box(&self, scissor_box: &ScissorBox) {
1255 unsafe {
1256 self.gl.scissor(
1257 scissor_box.x,
1258 scissor_box.y,
1259 scissor_box.width,
1260 scissor_box.height,
1261 );
1262 }
1263 }
1264
1265 pub(crate) fn apply_draw_parameters(&self, draw_params: &DrawParameters) {
1267 let DrawParameters {
1268 cull_face,
1269 color_write,
1270 depth_write,
1271 stencil_test,
1272 depth_test,
1273 blend,
1274 stencil_op,
1275 scissor_box,
1276 } = draw_params;
1277
1278 if let Some(ref blend_params) = blend {
1279 self.set_blend_func(blend_params.func);
1280 self.set_blend_equation(blend_params.equation);
1281 self.set_blend(true);
1282 } else {
1283 self.set_blend(false);
1284 }
1285
1286 if let Some(depth_func) = depth_test {
1287 self.set_depth_func(*depth_func);
1288 self.set_depth_test(true);
1289 } else {
1290 self.set_depth_test(false);
1291 }
1292 self.set_depth_write(*depth_write);
1293
1294 self.set_color_write(*color_write);
1295
1296 if let Some(stencil_func) = stencil_test {
1297 self.set_stencil_test(true);
1298 self.set_stencil_func(*stencil_func);
1299 } else {
1300 self.set_stencil_test(false);
1301 }
1302
1303 self.set_stencil_op(*stencil_op);
1304
1305 if let Some(cull_face) = cull_face {
1306 self.set_cull_face(*cull_face);
1307 self.set_culling(true);
1308 } else {
1309 self.set_culling(false);
1310 }
1311
1312 if let Some(scissor_box) = scissor_box {
1313 self.set_scissor_test(true);
1314 self.set_scissor_box(scissor_box);
1315 } else {
1316 self.set_scissor_test(false);
1317 }
1318 }
1319}
1320
1321impl GraphicsServer for GlGraphicsServer {
1322 fn create_buffer(&self, desc: GpuBufferDescriptor) -> Result<GpuBuffer, FrameworkError> {
1323 Ok(GpuBuffer(Rc::new(GlBuffer::new(self, desc)?)))
1324 }
1325
1326 fn create_texture(&self, desc: GpuTextureDescriptor) -> Result<GpuTexture, FrameworkError> {
1327 Ok(GpuTexture(Rc::new(GlTexture::new(self, desc)?)))
1328 }
1329
1330 fn create_sampler(&self, desc: GpuSamplerDescriptor) -> Result<GpuSampler, FrameworkError> {
1331 Ok(GpuSampler(Rc::new(GlSampler::new(self, desc)?)))
1332 }
1333
1334 fn create_frame_buffer(
1335 &self,
1336 depth_attachment: Option<Attachment>,
1337 color_attachments: Vec<Attachment>,
1338 ) -> Result<GpuFrameBuffer, FrameworkError> {
1339 Ok(GpuFrameBuffer(Rc::new(GlFrameBuffer::new(
1340 self,
1341 depth_attachment,
1342 color_attachments,
1343 )?)))
1344 }
1345
1346 fn back_buffer(&self) -> GpuFrameBuffer {
1347 GpuFrameBuffer(Rc::new(GlFrameBuffer::backbuffer(self)))
1348 }
1349
1350 fn create_query(&self) -> Result<GpuQuery, FrameworkError> {
1351 Ok(GpuQuery(Rc::new(GlQuery::new(self)?)))
1352 }
1353
1354 fn create_shader(
1355 &self,
1356 name: String,
1357 kind: ShaderKind,
1358 source: String,
1359 resources: &[ShaderResourceDefinition],
1360 line_offset: isize,
1361 ) -> Result<GpuShader, FrameworkError> {
1362 Ok(GpuShader(Rc::new(GlShader::new(
1363 self,
1364 name,
1365 kind,
1366 source,
1367 resources,
1368 line_offset,
1369 )?)))
1370 }
1371
1372 fn create_program(
1373 &self,
1374 name: &str,
1375 vertex_source: String,
1376 vertex_source_line_offset: isize,
1377 fragment_source: String,
1378 fragment_source_line_offset: isize,
1379 resources: &[ShaderResourceDefinition],
1380 ) -> Result<GpuProgram, FrameworkError> {
1381 Ok(GpuProgram(Rc::new(GlProgram::from_source_and_resources(
1382 self,
1383 name,
1384 vertex_source,
1385 vertex_source_line_offset,
1386 fragment_source,
1387 fragment_source_line_offset,
1388 resources,
1389 )?)))
1390 }
1391
1392 fn create_program_from_shaders(
1393 &self,
1394 name: &str,
1395 vertex_shader: &GpuShader,
1396 fragment_shader: &GpuShader,
1397 resources: &[ShaderResourceDefinition],
1398 ) -> Result<GpuProgram, FrameworkError> {
1399 Ok(GpuProgram(Rc::new(GlProgram::from_shaders_and_resources(
1400 self,
1401 name,
1402 vertex_shader,
1403 fragment_shader,
1404 resources,
1405 )?)))
1406 }
1407
1408 fn create_async_read_buffer(
1409 &self,
1410 name: &str,
1411 pixel_size: usize,
1412 pixel_count: usize,
1413 ) -> Result<GpuAsyncReadBuffer, FrameworkError> {
1414 Ok(GpuAsyncReadBuffer(Rc::new(GlAsyncReadBuffer::new(
1415 self,
1416 name,
1417 pixel_size,
1418 pixel_count,
1419 )?)))
1420 }
1421
1422 fn create_geometry_buffer(
1423 &self,
1424 desc: GpuGeometryBufferDescriptor,
1425 ) -> Result<GpuGeometryBuffer, FrameworkError> {
1426 Ok(GpuGeometryBuffer(Rc::new(GlGeometryBuffer::new(
1427 self, desc,
1428 )?)))
1429 }
1430
1431 fn weak(&self) -> Weak<dyn GraphicsServer> {
1432 self.this.borrow().as_ref().unwrap().clone()
1433 }
1434
1435 fn flush(&self) {
1436 unsafe {
1437 self.gl.flush();
1438 }
1439 }
1440
1441 fn finish(&self) {
1442 unsafe {
1443 self.gl.finish();
1444 }
1445 }
1446
1447 fn invalidate_resource_bindings_cache(&self) {
1448 let mut state = self.state.borrow_mut();
1449 state.frame_statistics = Default::default();
1450 }
1451
1452 fn pipeline_statistics(&self) -> PipelineStatistics {
1453 self.state.borrow().frame_statistics
1454 }
1455
1456 fn swap_buffers(&self) -> Result<(), FrameworkError> {
1457 #[cfg(not(target_arch = "wasm32"))]
1458 {
1459 let state = self.state.borrow();
1460 state
1461 .gl_surface
1462 .swap_buffers(&state.gl_context)
1463 .map_err(|err| FrameworkError::Custom(format!("{err:?}")))
1464 }
1465
1466 #[cfg(target_arch = "wasm32")]
1467 {
1468 Ok(())
1469 }
1470 }
1471
1472 fn set_frame_size(&self, #[allow(unused_variables)] new_size: (u32, u32)) {
1473 #[cfg(not(target_arch = "wasm32"))]
1474 {
1475 use std::num::NonZeroU32;
1476 let state = self.state.borrow();
1477 state.gl_surface.resize(
1478 &state.gl_context,
1479 NonZeroU32::new(new_size.0).unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
1480 NonZeroU32::new(new_size.1).unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
1481 );
1482 }
1483 }
1484
1485 fn generate_mipmap(&self, texture: &GpuTexture) {
1486 texture
1487 .as_any()
1488 .downcast_ref::<GlTexture>()
1489 .unwrap()
1490 .generate_mipmap();
1491 }
1492
1493 fn capabilities(&self) -> ServerCapabilities {
1494 let gl = &self.gl;
1495 unsafe {
1496 ServerCapabilities {
1497 max_uniform_block_size: gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE) as usize,
1498 uniform_buffer_offset_alignment: gl
1499 .get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT)
1500 as usize,
1501 max_lod_bias: gl.get_parameter_f32(glow::MAX_TEXTURE_LOD_BIAS),
1502 }
1503 }
1504 }
1505
1506 fn set_polygon_fill_mode(&self, polygon_face: PolygonFace, polygon_fill_mode: PolygonFillMode) {
1507 let (set_front, set_back) = match polygon_face {
1508 PolygonFace::Front => (true, false),
1509 PolygonFace::Back => (false, true),
1510 PolygonFace::FrontAndBack => (true, true),
1511 };
1512 let mut state = self.state.borrow_mut();
1513 if (set_front && state.front_fill_mode != polygon_fill_mode)
1514 || (set_back && state.back_fill_mode != polygon_fill_mode)
1515 {
1516 if set_front {
1517 state.front_fill_mode = polygon_fill_mode;
1518 }
1519 if set_back {
1520 state.back_fill_mode = polygon_fill_mode;
1521 }
1522
1523 unsafe {
1524 self.gl
1525 .polygon_mode(polygon_face.into_gl(), polygon_fill_mode.into_gl())
1526 }
1527 }
1528 }
1529
1530 fn memory_usage(&self) -> ServerMemoryUsage {
1531 self.memory_usage.borrow().clone()
1532 }
1533
1534 fn push_debug_group(&self, name: &str) {
1535 if self.gl.supports_debug() && self.named_objects.get() {
1536 unsafe {
1537 self.gl
1538 .push_debug_group(glow::DEBUG_SOURCE_APPLICATION, 0, name)
1539 }
1540 }
1541 }
1542
1543 fn pop_debug_group(&self) {
1544 if self.gl.supports_debug() && self.named_objects.get() {
1545 unsafe { self.gl.pop_debug_group() }
1546 }
1547 }
1548}