Skip to main content

fyrox_graphics_gl/
server.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21#![allow(deprecated)] // TODO
22
23use 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/// Indicator of whether we are using the embedded version of OpenGL.
171#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
172pub enum GlKind {
173    /// The full Open Graphics Library, without restrictions for embedded systems.
174    OpenGL,
175    /// OpenGL for Embedded Systems is a subset of OpenGL designed for systems such as smartphones, tablet computers, and PDAs.
176    OpenGLES,
177}
178
179/// A representation of the state of the GL context. OpenGL keeps track of various flags and values internally,
180/// and this struct remembers those settings. This makes it possible to check if a setting is actually being changed
181/// when a new value is supplied, so we can avoid calling OpenGL functions unnecessarily.
182///
183/// For example: we can call [`GlGraphicsServer::set_clear_color`] multiple times with the same color, and it will not
184/// result in repeated calls to the underlying `glClearColor` function because `GlGraphicsServer` will store the color
185/// in its `InnerState` and avoid calling `glClearColor` when it would be redundant.
186pub(crate) struct InnerState {
187    /// True if blending is currently enabled in the GL context due to a blending function being set in the [`DrawParameters`].
188    /// Protects `glEnable(GL_BLEND)` and `glDisable(GL_BLEND)`.
189    blend: bool,
190
191    /// True if depth testing is currently enabled in the GL contex due to a depth test function being set in [`DrawParameters`].
192    /// Protects `glEnable(GL_DEPTH_TEST)` and `glDisable(GL_DEPTH_TEST)`.
193    depth_test: bool,
194    /// True if depth mask is currently enabled in the GL context.
195    /// Protects `glDepthMask`.
196    depth_write: bool,
197    /// The depth test function currently set in the context, only to be used if `depth_test` is true.
198    /// Protects `glDepthFunc`.
199    depth_func: CompareFunc,
200
201    /// A mask that defines which colors will be stored in a frame buffer during rendering operation.
202    /// By default, all colors are stored (every field is set to `true`).
203    /// Protects `glColorMask`.
204    color_write: ColorMask,
205    /// True if stencil testing is currently enabled in the GL contex due to a stencil function being set in [`DrawParameters`].
206    /// Protects `glEnable(GL_STENCIL_TEST)` and `glDisable(GL_STENCIL_TEST)`.
207    stencil_test: bool,
208    /// Which side of the geometry is OpenGL set to cull?
209    /// Protects `glCullFace`.
210    cull_face: CullFace,
211    /// True if culling is enabled, with `cull_face` determining whether to cull the front or the back.
212    /// Protects `glEnable(GL_CULL_FACE)` and `glDisable(GL_CULL_FACE)`.
213    culling: bool,
214    /// The color that GL will use when clearing color buffers.
215    /// Protects `glClearColor`.
216    clear_color: Color,
217    /// The stencil value that GL will use when clearing the stencil buffer.
218    /// Protects `glClearStencil`.
219    clear_stencil: i32,
220    /// The depth value that GL will use when clearing the depth buffer.
221    /// Protects `glClearDepth`.
222    clear_depth: f32,
223    /// True if OpenGL is limiting rendering to a specific rectangle.
224    /// The size and position of the rectangle is not stored in `InnerState`, but it is changed in
225    /// OpenGL by calling [`GlGraphicsServer::set_scissor_box`].
226    /// Protects `glEnable(GL_SCISSOR_TEST)` and `glDisable(GL_SCISSOR_TEST)`.
227    scissor_test: bool,
228
229    /// The fill mode for the front of polygons.
230    /// Protects `glPolygonMode`.
231    front_fill_mode: PolygonFillMode,
232    /// The fill mode for the back of polygons.
233    /// Protects `glPolygonMode`.
234    back_fill_mode: PolygonFillMode,
235
236    /// The identifier for the currently bound frame buffer for writing. Frame buffers in OpenGL are identified by numbers.
237    /// If there is a currently bound frame buffer for writing, then this will be that frame buffer's number.
238    /// Otherwise, this will be None.
239    /// Protects `glBindFramebuffer`.
240    write_framebuffer: Option<glow::Framebuffer>,
241    /// The identifier for the currently bound frame buffer for reading. Frame buffers in OpenGL are identified by numbers.
242    /// If there is a currently bound frame buffer for reading, then this will be that frame buffer's number.
243    /// Otherwise, this will be None.
244    /// Protects `glBindFramebuffer`.
245    read_framebuffer: Option<glow::Framebuffer>,
246    /// Protects `glViewport`.
247    viewport: Rect<i32>,
248
249    /// Protects `glBlendFuncSeparate`.
250    blend_func: BlendFunc,
251    /// Protects `glBlendEquationSeparate`.
252    blend_equation: BlendEquation,
253
254    /// Protects `glUseProgram`.
255    program: Option<glow::Program>,
256    /// Protects `glBindTexture` and `glActiveTexture`.
257    texture_units_storage: TextureUnitsStorage,
258
259    /// Similar to `depth_func`, this controls how the stencil buffer will determine which fragments to draw.
260    /// Protects `glStencilFunc`.
261    stencil_func: StencilFunc,
262    /// A set of actions that will be performed with the stencil buffer during various testing stages.
263    /// `stencil_mask` can limit which bits of the stencil buffer are affected.
264    /// Protects `glStencilOp` and `glStencilMask`.
265    stencil_op: StencilOp,
266
267    /// Protects `glBindVertexArray`.
268    vao: Option<glow::VertexArray>,
269
270    /// Counts of various rendering operations.
271    frame_statistics: PipelineStatistics,
272    /// Indicator of whether we are using the embedded version of OpenGL.
273    gl_kind: GlKind,
274
275    /// A pool of available query identifiers for use by [`GlQuery`].
276    /// Each time a `GlQuery` is created, it checks this list for unused query identifies and pops off
277    /// the last one to use, or it creates a new query if the list is empty. When `GlQuery` is dropped,
278    /// it returns its query identifier to this list.
279    ///
280    /// Each query corresponds to some count that is recorded during rendering, such as the number of
281    /// sambles that pass the depth check or the number of primitives that are generated.
282    /// The only query types that are supported by Fyrox are given in `QueryKind` in the fyrox-graphics crate.
283    ///
284    /// Once the rendering commands have been sent, we may use the query identifier to wait until the
285    /// rendering is finished the desired number is available.
286    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    /// Bind the texture with the given identifier to the given target in the given unit.
410    /// Target numbers can be found using [`ToGlConstant::into_gl`] on `GpuTextureKind` from the `fyrox-graphics` crate.
411    /// The given unit will be activated if it is not already active.
412    /// If a texture is already bound in the unit, it will be unbound.
413    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
506/// A frame buffer can be bound for reading, writing, or both.
507pub enum FrameBufferBindingPoint {
508    Read,
509    Write,
510    ReadWrite,
511}
512
513/// `GlGraphicsServer` implements the [`GraphicsServer`] trait using the `glow` crate.
514/// `glow` is "GL on Whatever: a set of bindings to run GL anywhere (Open GL, OpenGL ES, and WebGL) and avoid target-specific code."
515pub struct GlGraphicsServer {
516    /// `glow::Context` provides access to the current rendering state.
517    /// It creates buffers, creates textures, compiles shaders, accepts geometry data,
518    /// and broadly provides access too all sorts of rendering services.
519    pub gl: glow::Context,
520    /// Controls whether objects the `glow::Context::object_label` method should be used
521    /// to assign labels to rendering objects. These labels can help with debugging.
522    pub named_objects: Cell<bool>,
523    /// A representation of the state of the GL context. OpenGL keeps track of various flags and values internally,
524    /// and this struct remembers those settings. This makes it possible to check if a setting is actually being changed
525    /// when a new value is supplied, so we can avoid calling OpenGL functions unnecessarily.
526    pub(crate) state: RefCell<InnerState>,
527    /// Contains information about used memory per each category of GPU resource.
528    pub(crate) memory_usage: RefCell<ServerMemoryUsage>,
529    /// A weak reference to the `Rc` that contains this server.
530    /// This is needed in order to convert a borrow of this server into an `Rc` reference of
531    /// this server, for implementing [`GlGraphicsServer::weak`] and [`GraphicsServer::weak`].
532    this: RefCell<Option<Weak<GlGraphicsServer>>>,
533}
534
535#[derive(Copy, Clone)]
536struct TextureBinding {
537    target: u32,
538    texture: Option<glow::Texture>,
539}
540
541/// A record of which texture is bound to each target.
542/// There is one binding for each of the texture targets
543/// defined by `GpuTextureKind` in the `fyrox-graphics` crate.
544/// It is forbidden to have multiple targets bound at once in any unit,
545/// and [`GlGraphicsServer::set_texture`] enforces this by automatically unbinding other targets.
546#[derive(Copy, Clone)]
547struct TextureUnit {
548    bindings: [TextureBinding; 4],
549}
550
551impl Default for TextureUnit {
552    /// Initialize the array of texture bindings with the valid target
553    /// values that can be produced by [`ToGlConstant::into_gl`] on `GpuTextureKind`
554    /// in the `fyrox-graphics` crate.
555    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/// A record of every texture binding in every unit and the currently active unit.
580#[derive(Default)]
581struct TextureUnitsStorage {
582    /// The currently active texture unit, as set by `glActiveTexture`.
583    active_unit: u32,
584    /// The textures that are bound to each target in each texture unit.
585    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            // For some reason winit completely ignores the requested inner size. This is a quick-n-dirty fix
701            // that also handles HiDPI monitors. It has one issue - if user changes DPI, it won't be handled
702            // correctly.
703            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                // Prevent blending with the background of the canvas. Otherwise the background
744                // will "leak" and interfere with the pixels produced by the engine.
745                alpha: false,
746                premultipliedAlpha: false,
747                // Try to use high performance GPU.
748                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        // Dump available GL extensions to the log, this will help debugging graphical issues.
777        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                            // Ignore any info because it tend to produce spam.
806                            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    /// A weak reference to the `Rc` where the server is stored.
880    pub fn weak(&self) -> Weak<Self> {
881        self.this.borrow().as_ref().unwrap().clone()
882    }
883
884    /// Determine if we are using the embedded version of OpenGL.
885    pub fn gl_kind(&self) -> GlKind {
886        self.state.borrow().gl_kind
887    }
888
889    /// Find the number of a texture unit where no texture is bound, if possible.
890    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    /// `glDeleteFramebuffers`
905    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    /// Choose the current frame buffer for reading or writing. See `glBindFramebuffer` from OpenGL.
912    /// * `binding_point`: Are we going to read from this buffer, write to it, or both?
913    /// * `framebuffer`: The buffer that we are going to use.
914    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    /// Choose a rectangle where rendering will happen. See `glViewport` from OpenGL.
925    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    /// Turn blending on or off, allowing rendered pixels to be influenced by the pixels that
942    /// are already in the frame buffer. See 'glEnable(GL_BLEND)` or `glDisable(GL_BLEND)` from OpenGL.
943    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    /// Turn depth testing on or off, allowing the content of the depth buffer to determine whether
961    /// a rendered pixel will be written to the frame buffer.
962    /// See `glEnable(GL_DEPTH_TEST)` or `glDisable(GL_DEPTH_TEST)` from OpenGL.
963    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    /// Turn depth writing on or off, allowing the depth buffer to be modified when rendering.
979    /// See `glDepthMask` from OpenGL.
980    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    /// Turn writing to each color channel on or off. For example, writing red values might be disabled.
992    /// See `glColorMask` from OpenGL.
993    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    /// Turn stencil testing on or off, allowing the content of the stencil buffer to determine whether
1010    /// each rendered pixel will be written.
1011    /// See `glEnable(GL_STENCIL_TEST)` or `glDisable(GL_STENCIL_TEST)` from OpenGL.
1012    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    /// See `glCullFace` from OpenGL.
1028    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    /// See `glEnable(GL_CULL_FACE)` or `glDisable(GL_CULL_FACE)` from OpenGL.
1038    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    /// Control which bits of the stencil buffer may be modified.
1054    /// Bits of `stencil_mask` that are 1 correspond to bits of the buffer that may be modified.
1055    /// If `stencil_mask` is 0 then nothing in the stencil mask can be modified.
1056    /// See `glStencilMask` from OpenGL.
1057    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    /// Set the color used when clearing a color buffer. See `glClearColor`.
1069    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    /// Set the depth used when clearing a depth buffer. See `glClearDepth`.
1082    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    /// Set the value used when clearing a stencil buffer. See `glClearStencil`.
1094    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    /// Modify how pixels are blended by changing the factors that multiply the source pixel
1106    /// (coming from the fragment shader) and the destination pixel (already in the frame buffer).
1107    /// See [`BlendFactor`] for available factors.
1108    /// See `glBlendFuncSeparate` from OpenGL.
1109    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    /// Modify how pixels are blended by changing the formula that is used to combine the source pixel
1126    /// (coming from the fragment shader) and the destination pixel (already in the frame buffer).
1127    /// See `glBlendEquationSeparate` from OpenGL.
1128    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    /// Set the function used to compare the fragment shader's z to the depth buffer
1143    /// and thereby decide whether to render the pixel. See `glDepthFunc` from OpenGL.
1144    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    /// Delete the given program. See `glDeleteProgram` from OpenGL.
1156    pub fn delete_program(&self, program: glow::Program) {
1157        self.state.borrow_mut().delete_program(program, &self.gl);
1158    }
1159
1160    /// Choose the program to use for the following rendering commands. See `glUseProgram` from OpenGL.
1161    pub(crate) fn set_program(&self, program: Option<glow::Program>) {
1162        self.state.borrow_mut().set_program(program, &self.gl)
1163    }
1164
1165    /// Delete the given texture. See `glDeleteTextures` from OpenGL.
1166    pub(crate) fn delete_texture(&self, texture: glow::Texture) {
1167        self.state.borrow_mut().delete_texture(texture, &self.gl)
1168    }
1169
1170    /// Bind the texture with the given identifier to the given target in the given unit.
1171    /// Target numbers can be found using [`ToGlConstant::into_gl`] on `GpuTextureKind` from the `fyrox-graphics` crate.
1172    /// The given unit will be activated if it is not already active.
1173    /// If a texture is already bound in the unit, it will be unbound.
1174    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    /// Modify how the stencil buffer prevents pixels from being drawn.
1181    /// See [`StencilFunc`] for the available options.
1182    /// See `glStencilFunc` from OpenGL.
1183    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    /// Modify how the stencil buffer is written to by rendering.
1199    /// See [`StencilOp`] for details of the available options.
1200    /// See `glStencilOp` and `glStencilMask` from OpenGL.
1201    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    /// `glDeleteVertexArrays`
1224    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    /// `glBindVertexArray`
1231    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    /// `glEnable(GL_SCISSOR_TEST)` or `glDisable(GL_SCISSOR_TEST)`.
1238    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    /// `glScissor`
1254    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    /// Call the necessary GL functions to set the given parameters.
1266    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}