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                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                // Prevent blending with the background of the canvas. Otherwise the background
738                // will "leak" and interfere with the pixels produced by the engine.
739                alpha: false,
740                premultipliedAlpha: false,
741                // Try to use high performance GPU.
742                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        // Dump available GL extensions to the log, this will help debugging graphical issues.
771        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                            // Ignore any info because it tend to produce spam.
800                            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    /// A weak reference to the `Rc` where the server is stored.
874    pub fn weak(&self) -> Weak<Self> {
875        self.this.borrow().as_ref().unwrap().clone()
876    }
877
878    /// Determine if we are using the embedded version of OpenGL.
879    pub fn gl_kind(&self) -> GlKind {
880        self.state.borrow().gl_kind
881    }
882
883    /// Find the number of a texture unit where no texture is bound, if possible.
884    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    /// `glDeleteFramebuffers`
899    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    /// Choose the current frame buffer for reading or writing. See `glBindFramebuffer` from OpenGL.
906    /// * `binding_point`: Are we going to read from this buffer, write to it, or both?
907    /// * `framebuffer`: The buffer that we are going to use.
908    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    /// Choose a rectangle where rendering will happen. See `glViewport` from OpenGL.
919    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    /// Turn blending on or off, allowing rendered pixels to be influenced by the pixels that
936    /// are already in the frame buffer. See 'glEnable(GL_BLEND)` or `glDisable(GL_BLEND)` from OpenGL.
937    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    /// Turn depth testing on or off, allowing the content of the depth buffer to determine whether
955    /// a rendered pixel will be written to the frame buffer.
956    /// See `glEnable(GL_DEPTH_TEST)` or `glDisable(GL_DEPTH_TEST)` from OpenGL.
957    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    /// Turn depth writing on or off, allowing the depth buffer to be modified when rendering.
973    /// See `glDepthMask` from OpenGL.
974    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    /// Turn writing to each color channel on or off. For example, writing red values might be disabled.
986    /// See `glColorMask` from OpenGL.
987    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    /// Turn stencil testing on or off, allowing the content of the stencil buffer to determine whether
1004    /// each rendered pixel will be written.
1005    /// See `glEnable(GL_STENCIL_TEST)` or `glDisable(GL_STENCIL_TEST)` from OpenGL.
1006    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    /// See `glCullFace` from OpenGL.
1022    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    /// See `glEnable(GL_CULL_FACE)` or `glDisable(GL_CULL_FACE)` from OpenGL.
1032    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    /// Control which bits of the stencil buffer may be modified.
1048    /// Bits of `stencil_mask` that are 1 correspond to bits of the buffer that may be modified.
1049    /// If `stencil_mask` is 0 then nothing in the stencil mask can be modified.
1050    /// See `glStencilMask` from OpenGL.
1051    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    /// Set the color used when clearing a color buffer. See `glClearColor`.
1063    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    /// Set the depth used when clearing a depth buffer. See `glClearDepth`.
1076    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    /// Set the value used when clearing a stencil buffer. See `glClearStencil`.
1088    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    /// Modify how pixels are blended by changing the factors that multiply the source pixel
1100    /// (coming from the fragment shader) and the destination pixel (already in the frame buffer).
1101    /// See [`BlendFactor`] for available factors.
1102    /// See `glBlendFuncSeparate` from OpenGL.
1103    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    /// Modify how pixels are blended by changing the formula that is used to combine the source pixel
1120    /// (coming from the fragment shader) and the destination pixel (already in the frame buffer).
1121    /// See `glBlendEquationSeparate` from OpenGL.
1122    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    /// Set the function used to compare the fragment shader's z to the depth buffer
1137    /// and thereby decide whether to render the pixel. See `glDepthFunc` from OpenGL.
1138    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    /// Delete the given program. See `glDeleteProgram` from OpenGL.
1150    pub fn delete_program(&self, program: glow::Program) {
1151        self.state.borrow_mut().delete_program(program, &self.gl);
1152    }
1153
1154    /// Choose the program to use for the following rendering commands. See `glUseProgram` from OpenGL.
1155    pub(crate) fn set_program(&self, program: Option<glow::Program>) {
1156        self.state.borrow_mut().set_program(program, &self.gl)
1157    }
1158
1159    /// Delete the given texture. See `glDeleteTextures` from OpenGL.
1160    pub(crate) fn delete_texture(&self, texture: glow::Texture) {
1161        self.state.borrow_mut().delete_texture(texture, &self.gl)
1162    }
1163
1164    /// Bind the texture with the given identifier to the given target in the given unit.
1165    /// Target numbers can be found using [`ToGlConstant::into_gl`] on `GpuTextureKind` from the `fyrox-graphics` crate.
1166    /// The given unit will be activated if it is not already active.
1167    /// If a texture is already bound in the unit, it will be unbound.
1168    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    /// Modify how the stencil buffer prevents pixels from being drawn.
1175    /// See [`StencilFunc`] for the available options.
1176    /// See `glStencilFunc` from OpenGL.
1177    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    /// Modify how the stencil buffer is written to by rendering.
1193    /// See [`StencilOp`] for details of the available options.
1194    /// See `glStencilOp` and `glStencilMask` from OpenGL.
1195    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    /// `glDeleteVertexArrays`
1218    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    /// `glBindVertexArray`
1225    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    /// `glEnable(GL_SCISSOR_TEST)` or `glDisable(GL_SCISSOR_TEST)`.
1232    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    /// `glScissor`
1248    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    /// Call the necessary GL functions to set the given parameters.
1260    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}