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 let physical_inner_size: PhysicalSize<u32> = inner_size.to_physical(scale_factor);
705
706 canvas.set_width(physical_inner_size.width);
707 canvas.set_height(physical_inner_size.height);
708
709 let logical_inner_size: LogicalSize<f64> = inner_size.to_logical(scale_factor);
710 Log::verify(
711 canvas
712 .style()
713 .set_property("width", &format!("{}px", logical_inner_size.width)),
714 );
715 Log::verify(
716 canvas
717 .style()
718 .set_property("height", &format!("{}px", logical_inner_size.height)),
719 );
720 }
721
722 let document = web_window.document().unwrap();
723 let body = document.body().unwrap();
724
725 body.append_child(&canvas)
726 .expect("Append canvas to HTML body");
727
728 #[derive(Serialize, Deserialize)]
729 #[allow(non_snake_case)]
730 struct ContextAttributes {
731 alpha: bool,
732 premultipliedAlpha: bool,
733 powerPreference: String,
734 }
735
736 let context_attributes = ContextAttributes {
737 alpha: false,
740 premultipliedAlpha: false,
741 powerPreference: "high-performance".to_string(),
743 };
744
745 let webgl2_context = canvas
746 .get_context_with_context_options(
747 "webgl2",
748 &serde_wasm_bindgen::to_value(&context_attributes).unwrap(),
749 )
750 .unwrap()
751 .unwrap()
752 .dyn_into::<fyrox_core::web_sys::WebGl2RenderingContext>()
753 .unwrap();
754 (
755 window,
756 glow::Context::from_webgl2_context(webgl2_context),
757 GlKind::OpenGLES,
758 )
759 };
760
761 #[cfg(not(target_arch = "wasm32"))]
762 gl_surface.resize(
763 &gl_context,
764 NonZeroU32::new(window.inner_size().width)
765 .unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
766 NonZeroU32::new(window.inner_size().height)
767 .unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
768 );
769
770 Log::info(format!(
772 "Supported GL Extensions: {:?}",
773 context.supported_extensions()
774 ));
775
776 unsafe {
777 context.depth_func(CompareFunc::default().into_gl());
778
779 if context
780 .supported_extensions()
781 .contains("GL_ARB_seamless_cubemap_per_texture")
782 {
783 context.enable(glow::TEXTURE_CUBE_MAP_SEAMLESS);
784 }
785
786 #[cfg(debug_assertions)]
787 {
788 use fyrox_core::log::{Log, MessageKind};
789
790 if context.supported_extensions().contains("GL_KHR_debug") {
791 context.debug_message_callback(|source, msg_type, id, severity, message| {
792 let message_kind = if severity == glow::DEBUG_SEVERITY_HIGH {
793 MessageKind::Error
794 } else if severity == glow::DEBUG_SEVERITY_MEDIUM
795 || severity == glow::DEBUG_SEVERITY_LOW
796 {
797 MessageKind::Warning
798 } else {
799 return;
801 };
802
803 let source = if source == glow::DEBUG_SOURCE_API {
804 "Calls to the OpenGL API"
805 } else if source == glow::DEBUG_SOURCE_WINDOW_SYSTEM {
806 "Calls to a window-system API"
807 } else if source == glow::DEBUG_SOURCE_SHADER_COMPILER {
808 "A compiler for a shading language"
809 } else if source == glow::DEBUG_SOURCE_THIRD_PARTY {
810 "An application associated with OpenGL"
811 } else if source == glow::DEBUG_SOURCE_APPLICATION {
812 "Generated by the user of this application"
813 } else {
814 "Other"
815 };
816
817 let msg_type = if msg_type == glow::DEBUG_TYPE_ERROR {
818 "An error, typically from the API"
819 } else if msg_type == glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR {
820 "Some behavior marked deprecated has been used"
821 } else if msg_type == glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR {
822 "Something has invoked undefined behavior"
823 } else if msg_type == glow::DEBUG_TYPE_PORTABILITY {
824 "Some functionality the user relies upon is not portable"
825 } else if msg_type == glow::DEBUG_TYPE_PERFORMANCE {
826 "Code has triggered possible performance issues"
827 } else if msg_type == glow::DEBUG_TYPE_MARKER {
828 "Command stream annotation"
829 } else if msg_type == glow::DEBUG_TYPE_PUSH_GROUP
830 || msg_type == glow::DEBUG_TYPE_POP_GROUP
831 {
832 "Group pushing"
833 } else {
834 "Other"
835 };
836
837 Log::writeln(
838 message_kind,
839 format!(
840 "OpenGL Message\n\
841 \tSource: {source}\n\
842 \tType: {msg_type}\n\
843 \tId: {id}\n\
844 \tMessage: {message}"
845 ),
846 );
847 })
848 }
849 }
850 }
851
852 let state = Self {
853 gl: context,
854 named_objects: Cell::new(named_objects),
855 state: RefCell::new(InnerState::new(
856 gl_kind,
857 #[cfg(not(target_arch = "wasm32"))]
858 gl_context,
859 #[cfg(not(target_arch = "wasm32"))]
860 gl_surface,
861 )),
862 memory_usage: Default::default(),
863 this: Default::default(),
864 };
865
866 let shared = Rc::new(state);
867
868 *shared.this.borrow_mut() = Some(Rc::downgrade(&shared));
869
870 Ok((window, shared))
871 }
872
873 pub fn weak(&self) -> Weak<Self> {
875 self.this.borrow().as_ref().unwrap().clone()
876 }
877
878 pub fn gl_kind(&self) -> GlKind {
880 self.state.borrow().gl_kind
881 }
882
883 pub fn free_texture_unit(&self) -> Option<u32> {
885 let state = self.state.borrow();
886 for (index, unit) in state.texture_units_storage.units.iter().enumerate() {
887 if unit
888 .bindings
889 .iter()
890 .all(|binding| binding.texture.is_none())
891 {
892 return Some(index as u32);
893 }
894 }
895 None
896 }
897
898 pub(crate) fn delete_framebuffer(&self, framebuffer: Option<glow::Framebuffer>) {
900 self.state
901 .borrow_mut()
902 .delete_framebuffer(framebuffer, &self.gl)
903 }
904
905 pub(crate) fn set_framebuffer(
909 &self,
910 binding_point: FrameBufferBindingPoint,
911 framebuffer: Option<glow::Framebuffer>,
912 ) {
913 self.state
914 .borrow_mut()
915 .set_framebuffer(binding_point, framebuffer, &self.gl)
916 }
917
918 pub(crate) fn set_viewport(&self, viewport: Rect<i32>) {
920 let mut state = self.state.borrow_mut();
921 if state.viewport != viewport {
922 state.viewport = viewport;
923
924 unsafe {
925 self.gl.viewport(
926 state.viewport.x(),
927 state.viewport.y(),
928 state.viewport.w(),
929 state.viewport.h(),
930 );
931 }
932 }
933 }
934
935 pub(crate) fn set_blend(&self, blend: bool) {
938 let mut state = self.state.borrow_mut();
939 if state.blend != blend {
940 state.blend = blend;
941
942 state.frame_statistics.blend_state_changes += 1;
943
944 unsafe {
945 if state.blend {
946 self.gl.enable(glow::BLEND);
947 } else {
948 self.gl.disable(glow::BLEND);
949 }
950 }
951 }
952 }
953
954 pub(crate) fn set_depth_test(&self, depth_test: bool) {
958 let mut state = self.state.borrow_mut();
959 if state.depth_test != depth_test {
960 state.depth_test = depth_test;
961
962 unsafe {
963 if state.depth_test {
964 self.gl.enable(glow::DEPTH_TEST);
965 } else {
966 self.gl.disable(glow::DEPTH_TEST);
967 }
968 }
969 }
970 }
971
972 pub(crate) fn set_depth_write(&self, depth_write: bool) {
975 let mut state = self.state.borrow_mut();
976 if state.depth_write != depth_write {
977 state.depth_write = depth_write;
978
979 unsafe {
980 self.gl.depth_mask(state.depth_write);
981 }
982 }
983 }
984
985 pub(crate) fn set_color_write(&self, color_write: ColorMask) {
988 let mut state = self.state.borrow_mut();
989 if state.color_write != color_write {
990 state.color_write = color_write;
991
992 unsafe {
993 self.gl.color_mask(
994 state.color_write.red,
995 state.color_write.green,
996 state.color_write.blue,
997 state.color_write.alpha,
998 );
999 }
1000 }
1001 }
1002
1003 pub(crate) fn set_stencil_test(&self, stencil_test: bool) {
1007 let mut state = self.state.borrow_mut();
1008 if state.stencil_test != stencil_test {
1009 state.stencil_test = stencil_test;
1010
1011 unsafe {
1012 if state.stencil_test {
1013 self.gl.enable(glow::STENCIL_TEST);
1014 } else {
1015 self.gl.disable(glow::STENCIL_TEST);
1016 }
1017 }
1018 }
1019 }
1020
1021 pub(crate) fn set_cull_face(&self, cull_face: CullFace) {
1023 let mut state = self.state.borrow_mut();
1024 if state.cull_face != cull_face {
1025 state.cull_face = cull_face;
1026
1027 unsafe { self.gl.cull_face(state.cull_face.into_gl()) }
1028 }
1029 }
1030
1031 pub(crate) fn set_culling(&self, culling: bool) {
1033 let mut state = self.state.borrow_mut();
1034 if state.culling != culling {
1035 state.culling = culling;
1036
1037 unsafe {
1038 if state.culling {
1039 self.gl.enable(glow::CULL_FACE);
1040 } else {
1041 self.gl.disable(glow::CULL_FACE);
1042 }
1043 }
1044 }
1045 }
1046
1047 pub(crate) fn set_stencil_mask(&self, stencil_mask: u32) {
1052 let mut state = self.state.borrow_mut();
1053 if state.stencil_op.write_mask != stencil_mask {
1054 state.stencil_op.write_mask = stencil_mask;
1055
1056 unsafe {
1057 self.gl.stencil_mask(stencil_mask);
1058 }
1059 }
1060 }
1061
1062 pub(crate) fn set_clear_color(&self, color: Color) {
1064 let mut state = self.state.borrow_mut();
1065 if state.clear_color != color {
1066 state.clear_color = color;
1067
1068 let rgba = color.as_frgba();
1069 unsafe {
1070 self.gl.clear_color(rgba.x, rgba.y, rgba.z, rgba.w);
1071 }
1072 }
1073 }
1074
1075 pub(crate) fn set_clear_depth(&self, depth: f32) {
1077 let mut state = self.state.borrow_mut();
1078 if (state.clear_depth - depth).abs() > f32::EPSILON {
1079 state.clear_depth = depth;
1080
1081 unsafe {
1082 self.gl.clear_depth_f32(depth);
1083 }
1084 }
1085 }
1086
1087 pub(crate) fn set_clear_stencil(&self, stencil: i32) {
1089 let mut state = self.state.borrow_mut();
1090 if state.clear_stencil != stencil {
1091 state.clear_stencil = stencil;
1092
1093 unsafe {
1094 self.gl.clear_stencil(stencil);
1095 }
1096 }
1097 }
1098
1099 pub(crate) fn set_blend_func(&self, func: BlendFunc) {
1104 let mut state = self.state.borrow_mut();
1105 if state.blend_func != func {
1106 state.blend_func = func;
1107
1108 unsafe {
1109 self.gl.blend_func_separate(
1110 state.blend_func.sfactor.into_gl(),
1111 state.blend_func.dfactor.into_gl(),
1112 state.blend_func.alpha_sfactor.into_gl(),
1113 state.blend_func.alpha_dfactor.into_gl(),
1114 );
1115 }
1116 }
1117 }
1118
1119 pub(crate) fn set_blend_equation(&self, equation: BlendEquation) {
1123 let mut state = self.state.borrow_mut();
1124 if state.blend_equation != equation {
1125 state.blend_equation = equation;
1126
1127 unsafe {
1128 self.gl.blend_equation_separate(
1129 state.blend_equation.rgb.into_gl(),
1130 state.blend_equation.alpha.into_gl(),
1131 );
1132 }
1133 }
1134 }
1135
1136 pub(crate) fn set_depth_func(&self, depth_func: CompareFunc) {
1139 let mut state = self.state.borrow_mut();
1140 if state.depth_func != depth_func {
1141 state.depth_func = depth_func;
1142
1143 unsafe {
1144 self.gl.depth_func(depth_func.into_gl());
1145 }
1146 }
1147 }
1148
1149 pub fn delete_program(&self, program: glow::Program) {
1151 self.state.borrow_mut().delete_program(program, &self.gl);
1152 }
1153
1154 pub(crate) fn set_program(&self, program: Option<glow::Program>) {
1156 self.state.borrow_mut().set_program(program, &self.gl)
1157 }
1158
1159 pub(crate) fn delete_texture(&self, texture: glow::Texture) {
1161 self.state.borrow_mut().delete_texture(texture, &self.gl)
1162 }
1163
1164 pub(crate) fn set_texture(&self, unit_index: u32, target: u32, texture: Option<glow::Texture>) {
1169 self.state
1170 .borrow_mut()
1171 .set_texture(unit_index, target, texture, &self.gl)
1172 }
1173
1174 pub(crate) fn set_stencil_func(&self, func: StencilFunc) {
1178 let mut state = self.state.borrow_mut();
1179 if state.stencil_func != func {
1180 state.stencil_func = func;
1181
1182 unsafe {
1183 self.gl.stencil_func(
1184 state.stencil_func.func.into_gl(),
1185 state.stencil_func.ref_value as i32,
1186 state.stencil_func.mask,
1187 );
1188 }
1189 }
1190 }
1191
1192 pub(crate) fn set_stencil_op(&self, op: StencilOp) {
1196 let mut state = self.state.borrow_mut();
1197 let new_mask = op.write_mask;
1198 if !state.stencil_op.eq_actions(&op) {
1199 state.stencil_op = op;
1200
1201 unsafe {
1202 self.gl.stencil_op(
1203 state.stencil_op.fail.into_gl(),
1204 state.stencil_op.zfail.into_gl(),
1205 state.stencil_op.zpass.into_gl(),
1206 );
1207 }
1208 }
1209 if state.stencil_op.write_mask != new_mask {
1210 state.stencil_op.write_mask = new_mask;
1211 unsafe {
1212 self.gl.stencil_mask(state.stencil_op.write_mask);
1213 }
1214 }
1215 }
1216
1217 pub(crate) fn delete_vertex_array_object(&self, vao: glow::VertexArray) {
1219 self.state
1220 .borrow_mut()
1221 .delete_vertex_array_object(vao, &self.gl);
1222 }
1223
1224 pub(crate) fn set_vertex_array_object(&self, vao: Option<glow::VertexArray>) {
1226 self.state
1227 .borrow_mut()
1228 .set_vertex_array_object(vao, &self.gl);
1229 }
1230
1231 pub(crate) fn set_scissor_test(&self, scissor_test: bool) {
1233 let mut state = self.state.borrow_mut();
1234 if state.scissor_test != scissor_test {
1235 state.scissor_test = scissor_test;
1236
1237 unsafe {
1238 if scissor_test {
1239 self.gl.enable(glow::SCISSOR_TEST);
1240 } else {
1241 self.gl.disable(glow::SCISSOR_TEST);
1242 }
1243 }
1244 }
1245 }
1246
1247 pub(crate) fn set_scissor_box(&self, scissor_box: &ScissorBox) {
1249 unsafe {
1250 self.gl.scissor(
1251 scissor_box.x,
1252 scissor_box.y,
1253 scissor_box.width,
1254 scissor_box.height,
1255 );
1256 }
1257 }
1258
1259 pub(crate) fn apply_draw_parameters(&self, draw_params: &DrawParameters) {
1261 let DrawParameters {
1262 cull_face,
1263 color_write,
1264 depth_write,
1265 stencil_test,
1266 depth_test,
1267 blend,
1268 stencil_op,
1269 scissor_box,
1270 } = draw_params;
1271
1272 if let Some(ref blend_params) = blend {
1273 self.set_blend_func(blend_params.func);
1274 self.set_blend_equation(blend_params.equation);
1275 self.set_blend(true);
1276 } else {
1277 self.set_blend(false);
1278 }
1279
1280 if let Some(depth_func) = depth_test {
1281 self.set_depth_func(*depth_func);
1282 self.set_depth_test(true);
1283 } else {
1284 self.set_depth_test(false);
1285 }
1286 self.set_depth_write(*depth_write);
1287
1288 self.set_color_write(*color_write);
1289
1290 if let Some(stencil_func) = stencil_test {
1291 self.set_stencil_test(true);
1292 self.set_stencil_func(*stencil_func);
1293 } else {
1294 self.set_stencil_test(false);
1295 }
1296
1297 self.set_stencil_op(*stencil_op);
1298
1299 if let Some(cull_face) = cull_face {
1300 self.set_cull_face(*cull_face);
1301 self.set_culling(true);
1302 } else {
1303 self.set_culling(false);
1304 }
1305
1306 if let Some(scissor_box) = scissor_box {
1307 self.set_scissor_test(true);
1308 self.set_scissor_box(scissor_box);
1309 } else {
1310 self.set_scissor_test(false);
1311 }
1312 }
1313}
1314
1315impl GraphicsServer for GlGraphicsServer {
1316 fn create_buffer(&self, desc: GpuBufferDescriptor) -> Result<GpuBuffer, FrameworkError> {
1317 Ok(GpuBuffer(Rc::new(GlBuffer::new(self, desc)?)))
1318 }
1319
1320 fn create_texture(&self, desc: GpuTextureDescriptor) -> Result<GpuTexture, FrameworkError> {
1321 Ok(GpuTexture(Rc::new(GlTexture::new(self, desc)?)))
1322 }
1323
1324 fn create_sampler(&self, desc: GpuSamplerDescriptor) -> Result<GpuSampler, FrameworkError> {
1325 Ok(GpuSampler(Rc::new(GlSampler::new(self, desc)?)))
1326 }
1327
1328 fn create_frame_buffer(
1329 &self,
1330 depth_attachment: Option<Attachment>,
1331 color_attachments: Vec<Attachment>,
1332 ) -> Result<GpuFrameBuffer, FrameworkError> {
1333 Ok(GpuFrameBuffer(Rc::new(GlFrameBuffer::new(
1334 self,
1335 depth_attachment,
1336 color_attachments,
1337 )?)))
1338 }
1339
1340 fn back_buffer(&self) -> GpuFrameBuffer {
1341 GpuFrameBuffer(Rc::new(GlFrameBuffer::backbuffer(self)))
1342 }
1343
1344 fn create_query(&self) -> Result<GpuQuery, FrameworkError> {
1345 Ok(GpuQuery(Rc::new(GlQuery::new(self)?)))
1346 }
1347
1348 fn create_shader(
1349 &self,
1350 name: String,
1351 kind: ShaderKind,
1352 source: String,
1353 resources: &[ShaderResourceDefinition],
1354 line_offset: isize,
1355 ) -> Result<GpuShader, FrameworkError> {
1356 Ok(GpuShader(Rc::new(GlShader::new(
1357 self,
1358 name,
1359 kind,
1360 source,
1361 resources,
1362 line_offset,
1363 )?)))
1364 }
1365
1366 fn create_program(
1367 &self,
1368 name: &str,
1369 vertex_source: String,
1370 vertex_source_line_offset: isize,
1371 fragment_source: String,
1372 fragment_source_line_offset: isize,
1373 resources: &[ShaderResourceDefinition],
1374 ) -> Result<GpuProgram, FrameworkError> {
1375 Ok(GpuProgram(Rc::new(GlProgram::from_source_and_resources(
1376 self,
1377 name,
1378 vertex_source,
1379 vertex_source_line_offset,
1380 fragment_source,
1381 fragment_source_line_offset,
1382 resources,
1383 )?)))
1384 }
1385
1386 fn create_program_from_shaders(
1387 &self,
1388 name: &str,
1389 vertex_shader: &GpuShader,
1390 fragment_shader: &GpuShader,
1391 resources: &[ShaderResourceDefinition],
1392 ) -> Result<GpuProgram, FrameworkError> {
1393 Ok(GpuProgram(Rc::new(GlProgram::from_shaders_and_resources(
1394 self,
1395 name,
1396 vertex_shader,
1397 fragment_shader,
1398 resources,
1399 )?)))
1400 }
1401
1402 fn create_async_read_buffer(
1403 &self,
1404 name: &str,
1405 pixel_size: usize,
1406 pixel_count: usize,
1407 ) -> Result<GpuAsyncReadBuffer, FrameworkError> {
1408 Ok(GpuAsyncReadBuffer(Rc::new(GlAsyncReadBuffer::new(
1409 self,
1410 name,
1411 pixel_size,
1412 pixel_count,
1413 )?)))
1414 }
1415
1416 fn create_geometry_buffer(
1417 &self,
1418 desc: GpuGeometryBufferDescriptor,
1419 ) -> Result<GpuGeometryBuffer, FrameworkError> {
1420 Ok(GpuGeometryBuffer(Rc::new(GlGeometryBuffer::new(
1421 self, desc,
1422 )?)))
1423 }
1424
1425 fn weak(self: Rc<Self>) -> Weak<dyn GraphicsServer> {
1426 self.this.borrow().as_ref().unwrap().clone()
1427 }
1428
1429 fn flush(&self) {
1430 unsafe {
1431 self.gl.flush();
1432 }
1433 }
1434
1435 fn finish(&self) {
1436 unsafe {
1437 self.gl.finish();
1438 }
1439 }
1440
1441 fn invalidate_resource_bindings_cache(&self) {
1442 let mut state = self.state.borrow_mut();
1443 state.frame_statistics = Default::default();
1444 }
1445
1446 fn pipeline_statistics(&self) -> PipelineStatistics {
1447 self.state.borrow().frame_statistics
1448 }
1449
1450 fn swap_buffers(&self) -> Result<(), FrameworkError> {
1451 #[cfg(not(target_arch = "wasm32"))]
1452 {
1453 let state = self.state.borrow();
1454 state
1455 .gl_surface
1456 .swap_buffers(&state.gl_context)
1457 .map_err(|err| FrameworkError::Custom(format!("{err:?}")))
1458 }
1459
1460 #[cfg(target_arch = "wasm32")]
1461 {
1462 Ok(())
1463 }
1464 }
1465
1466 fn set_frame_size(&self, #[allow(unused_variables)] new_size: (u32, u32)) {
1467 #[cfg(not(target_arch = "wasm32"))]
1468 {
1469 use std::num::NonZeroU32;
1470 let state = self.state.borrow();
1471 state.gl_surface.resize(
1472 &state.gl_context,
1473 NonZeroU32::new(new_size.0).unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
1474 NonZeroU32::new(new_size.1).unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
1475 );
1476 }
1477 }
1478
1479 fn generate_mipmap(&self, texture: &GpuTexture) {
1480 texture
1481 .as_any()
1482 .downcast_ref::<GlTexture>()
1483 .unwrap()
1484 .generate_mipmap();
1485 }
1486
1487 fn capabilities(&self) -> ServerCapabilities {
1488 let gl = &self.gl;
1489 unsafe {
1490 ServerCapabilities {
1491 max_uniform_block_size: gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE) as usize,
1492 uniform_buffer_offset_alignment: gl
1493 .get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT)
1494 as usize,
1495 max_lod_bias: gl.get_parameter_f32(glow::MAX_TEXTURE_LOD_BIAS),
1496 }
1497 }
1498 }
1499
1500 fn set_polygon_fill_mode(&self, polygon_face: PolygonFace, polygon_fill_mode: PolygonFillMode) {
1501 let (set_front, set_back) = match polygon_face {
1502 PolygonFace::Front => (true, false),
1503 PolygonFace::Back => (false, true),
1504 PolygonFace::FrontAndBack => (true, true),
1505 };
1506 let mut state = self.state.borrow_mut();
1507 if (set_front && state.front_fill_mode != polygon_fill_mode)
1508 || (set_back && state.back_fill_mode != polygon_fill_mode)
1509 {
1510 if set_front {
1511 state.front_fill_mode = polygon_fill_mode;
1512 }
1513 if set_back {
1514 state.back_fill_mode = polygon_fill_mode;
1515 }
1516
1517 unsafe {
1518 self.gl
1519 .polygon_mode(polygon_face.into_gl(), polygon_fill_mode.into_gl())
1520 }
1521 }
1522 }
1523
1524 fn memory_usage(&self) -> ServerMemoryUsage {
1525 self.memory_usage.borrow().clone()
1526 }
1527}