1use crate::gpu_texture::GpuTextureDescriptor;
22use crate::{
23 buffer::{Buffer, BufferKind, BufferUsage},
24 core::{color::Color, log::Log, math::Rect},
25 error::FrameworkError,
26 framebuffer::{Attachment, FrameBuffer},
27 geometry_buffer::{GeometryBuffer, GeometryBufferDescriptor},
28 gl::{
29 self, framebuffer::GlFrameBuffer, geometry_buffer::GlGeometryBuffer, program::GlProgram,
30 query::GlQuery, read_buffer::GlAsyncReadBuffer, texture::GlTexture, ToGlConstant,
31 },
32 gpu_program::{GpuProgram, ShaderResourceDefinition},
33 gpu_texture::GpuTexture,
34 query::Query,
35 read_buffer::AsyncReadBuffer,
36 server::{GraphicsServer, ServerCapabilities, SharedGraphicsServer},
37 stats::PipelineStatistics,
38 BlendEquation, BlendFactor, BlendFunc, BlendMode, ColorMask, CompareFunc, CullFace,
39 DrawParameters, PolygonFace, PolygonFillMode, ScissorBox, StencilAction, StencilFunc,
40 StencilOp,
41};
42use glow::HasContext;
43#[cfg(not(target_arch = "wasm32"))]
44use glutin::{
45 config::ConfigTemplateBuilder,
46 context::{
47 ContextApi, ContextAttributesBuilder, GlProfile, NotCurrentGlContext,
48 PossiblyCurrentContext, Version,
49 },
50 display::{GetGlDisplay, GlDisplay},
51 surface::{GlSurface, Surface, SwapInterval, WindowSurface},
52};
53#[cfg(not(target_arch = "wasm32"))]
54use glutin_winit::{DisplayBuilder, GlWindow};
55#[cfg(not(target_arch = "wasm32"))]
56use raw_window_handle::HasRawWindowHandle;
57use std::cell::RefCell;
58use std::ops::DerefMut;
59use std::rc::{Rc, Weak};
60#[cfg(not(target_arch = "wasm32"))]
61use std::{ffi::CString, num::NonZeroU32};
62use winit::{
63 event_loop::EventLoopWindowTarget,
64 window::{Window, WindowBuilder},
65};
66
67impl ToGlConstant for PolygonFace {
68 fn into_gl(self) -> u32 {
69 match self {
70 Self::Front => glow::FRONT,
71 Self::Back => glow::BACK,
72 Self::FrontAndBack => glow::FRONT_AND_BACK,
73 }
74 }
75}
76
77impl ToGlConstant for PolygonFillMode {
78 fn into_gl(self) -> u32 {
79 match self {
80 Self::Point => glow::POINT,
81 Self::Line => glow::LINE,
82 Self::Fill => glow::FILL,
83 }
84 }
85}
86
87impl ToGlConstant for StencilAction {
88 fn into_gl(self) -> u32 {
89 match self {
90 StencilAction::Keep => glow::KEEP,
91 StencilAction::Zero => glow::ZERO,
92 StencilAction::Replace => glow::REPLACE,
93 StencilAction::Incr => glow::INCR,
94 StencilAction::IncrWrap => glow::INCR_WRAP,
95 StencilAction::Decr => glow::DECR,
96 StencilAction::DecrWrap => glow::DECR_WRAP,
97 StencilAction::Invert => glow::INVERT,
98 }
99 }
100}
101
102impl ToGlConstant for BlendMode {
103 fn into_gl(self) -> u32 {
104 match self {
105 Self::Add => glow::FUNC_ADD,
106 Self::Subtract => glow::FUNC_SUBTRACT,
107 Self::ReverseSubtract => glow::FUNC_REVERSE_SUBTRACT,
108 Self::Min => glow::MIN,
109 Self::Max => glow::MAX,
110 }
111 }
112}
113
114impl ToGlConstant for BlendFactor {
115 fn into_gl(self) -> u32 {
116 match self {
117 Self::Zero => glow::ZERO,
118 Self::One => glow::ONE,
119 Self::SrcColor => glow::SRC_COLOR,
120 Self::OneMinusSrcColor => glow::ONE_MINUS_SRC_COLOR,
121 Self::DstColor => glow::DST_COLOR,
122 Self::OneMinusDstColor => glow::ONE_MINUS_DST_COLOR,
123 Self::SrcAlpha => glow::SRC_ALPHA,
124 Self::OneMinusSrcAlpha => glow::ONE_MINUS_SRC_ALPHA,
125 Self::DstAlpha => glow::DST_ALPHA,
126 Self::OneMinusDstAlpha => glow::ONE_MINUS_DST_ALPHA,
127 Self::ConstantColor => glow::CONSTANT_COLOR,
128 Self::OneMinusConstantColor => glow::ONE_MINUS_CONSTANT_COLOR,
129 Self::ConstantAlpha => glow::CONSTANT_ALPHA,
130 Self::OneMinusConstantAlpha => glow::ONE_MINUS_CONSTANT_ALPHA,
131 Self::SrcAlphaSaturate => glow::SRC_ALPHA_SATURATE,
132 Self::Src1Color => glow::SRC1_COLOR,
133 Self::OneMinusSrc1Color => glow::ONE_MINUS_SRC1_COLOR,
134 Self::Src1Alpha => glow::SRC1_ALPHA,
135 Self::OneMinusSrc1Alpha => glow::ONE_MINUS_SRC1_ALPHA,
136 }
137 }
138}
139
140impl ToGlConstant for CompareFunc {
141 fn into_gl(self) -> u32 {
142 match self {
143 Self::Never => glow::NEVER,
144 Self::Less => glow::LESS,
145 Self::Equal => glow::EQUAL,
146 Self::LessOrEqual => glow::LEQUAL,
147 Self::Greater => glow::GREATER,
148 Self::NotEqual => glow::NOTEQUAL,
149 Self::GreaterOrEqual => glow::GEQUAL,
150 Self::Always => glow::ALWAYS,
151 }
152 }
153}
154
155impl ToGlConstant for CullFace {
156 fn into_gl(self) -> u32 {
157 match self {
158 Self::Back => glow::BACK,
159 Self::Front => glow::FRONT,
160 }
161 }
162}
163
164#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
165pub enum GlKind {
166 OpenGL,
167 OpenGLES,
168}
169
170pub(crate) struct InnerState {
171 blend: bool,
172
173 depth_test: bool,
174 depth_write: bool,
175 depth_func: CompareFunc,
176
177 color_write: ColorMask,
178 stencil_test: bool,
179 cull_face: CullFace,
180 culling: bool,
181 stencil_mask: u32,
182 clear_color: Color,
183 clear_stencil: i32,
184 clear_depth: f32,
185 scissor_test: bool,
186
187 polygon_face: PolygonFace,
188 polygon_fill_mode: PolygonFillMode,
189
190 framebuffer: Option<glow::Framebuffer>,
191 viewport: Rect<i32>,
192
193 blend_func: BlendFunc,
194 blend_equation: BlendEquation,
195
196 program: Option<glow::Program>,
197 texture_units_storage: TextureUnitsStorage,
198
199 stencil_func: StencilFunc,
200 stencil_op: StencilOp,
201
202 vao: Option<glow::VertexArray>,
203
204 frame_statistics: PipelineStatistics,
205 gl_kind: GlKind,
206
207 pub(crate) queries: Vec<glow::Query>,
208
209 #[cfg(not(target_arch = "wasm32"))]
210 gl_context: PossiblyCurrentContext,
211 #[cfg(not(target_arch = "wasm32"))]
212 gl_surface: Surface<WindowSurface>,
213}
214
215impl InnerState {
216 fn new(
217 gl_kind: GlKind,
218 #[cfg(not(target_arch = "wasm32"))] gl_context: PossiblyCurrentContext,
219 #[cfg(not(target_arch = "wasm32"))] gl_surface: Surface<WindowSurface>,
220 ) -> Self {
221 Self {
222 blend: false,
223 depth_test: false,
224 depth_write: true,
225 depth_func: Default::default(),
226 color_write: Default::default(),
227 stencil_test: false,
228 cull_face: CullFace::Back,
229 culling: false,
230 stencil_mask: 0xFFFF_FFFF,
231 clear_color: Color::from_rgba(0, 0, 0, 0),
232 clear_stencil: 0,
233 clear_depth: 1.0,
234 scissor_test: false,
235 polygon_face: Default::default(),
236 polygon_fill_mode: Default::default(),
237 framebuffer: None,
238 blend_func: Default::default(),
239 viewport: Rect::new(0, 0, 1, 1),
240 program: Default::default(),
241 texture_units_storage: TextureUnitsStorage {
242 active_unit: 0,
243 units: Default::default(),
244 },
245 stencil_func: Default::default(),
246 stencil_op: Default::default(),
247 vao: Default::default(),
248 frame_statistics: Default::default(),
249 blend_equation: Default::default(),
250 gl_kind,
251 queries: Default::default(),
252 #[cfg(not(target_arch = "wasm32"))]
253 gl_context,
254 #[cfg(not(target_arch = "wasm32"))]
255 gl_surface,
256 }
257 }
258}
259
260pub struct GlGraphicsServer {
261 pub gl: glow::Context,
262 pub(crate) state: RefCell<InnerState>,
263 this: RefCell<Option<Weak<GlGraphicsServer>>>,
264}
265
266#[derive(Copy, Clone)]
267struct TextureBinding {
268 target: u32,
269 texture: Option<glow::Texture>,
270}
271
272#[derive(Copy, Clone)]
273struct TextureUnit {
274 bindings: [TextureBinding; 4],
275}
276
277impl Default for TextureUnit {
278 fn default() -> Self {
279 Self {
280 bindings: [
281 TextureBinding {
282 target: glow::TEXTURE_2D,
283 texture: None,
284 },
285 TextureBinding {
286 target: glow::TEXTURE_3D,
287 texture: None,
288 },
289 TextureBinding {
290 target: glow::TEXTURE_1D,
291 texture: None,
292 },
293 TextureBinding {
294 target: glow::TEXTURE_CUBE_MAP,
295 texture: None,
296 },
297 ],
298 }
299 }
300}
301
302#[derive(Default)]
303struct TextureUnitsStorage {
304 active_unit: u32,
305 units: [TextureUnit; 32],
306}
307
308impl GlGraphicsServer {
309 #[allow(clippy::new_ret_no_self)]
310 #[allow(unused_mut)]
311 pub fn new(
312 #[allow(unused_variables)] vsync: bool,
313 #[allow(unused_variables)] msaa_sample_count: Option<u8>,
314 window_target: &EventLoopWindowTarget<()>,
315 window_builder: WindowBuilder,
316 ) -> Result<(Window, SharedGraphicsServer), FrameworkError> {
317 #[cfg(not(target_arch = "wasm32"))]
318 let (window, gl_context, gl_surface, mut context, gl_kind) = {
319 let mut template = ConfigTemplateBuilder::new()
320 .prefer_hardware_accelerated(Some(true))
321 .with_stencil_size(8)
322 .with_depth_size(24);
323
324 if let Some(sample_count) = msaa_sample_count {
325 template = template.with_multisampling(sample_count);
326 }
327
328 let (opt_window, gl_config) = DisplayBuilder::new()
329 .with_window_builder(Some(window_builder))
330 .build(window_target, template, |mut configs| {
331 configs.next().unwrap()
332 })?;
333
334 let window = opt_window.unwrap();
335
336 let raw_window_handle = window.raw_window_handle();
337
338 let gl_display = gl_config.display();
339
340 #[cfg(debug_assertions)]
341 let debug = true;
342
343 #[cfg(not(debug_assertions))]
344 let debug = true;
345
346 let gl3_3_core_context_attributes = ContextAttributesBuilder::new()
347 .with_debug(debug)
348 .with_profile(GlProfile::Core)
349 .with_context_api(ContextApi::OpenGl(Some(Version::new(3, 3))))
350 .build(Some(raw_window_handle));
351
352 let gles3_context_attributes = ContextAttributesBuilder::new()
353 .with_debug(debug)
354 .with_profile(GlProfile::Core)
355 .with_context_api(ContextApi::Gles(Some(Version::new(3, 0))))
356 .build(Some(raw_window_handle));
357
358 unsafe {
359 let attrs = window.build_surface_attributes(Default::default());
360
361 let gl_surface = gl_config
362 .display()
363 .create_window_surface(&gl_config, &attrs)?;
364
365 let (non_current_gl_context, gl_kind) = if let Ok(gl3_3_core_context) =
366 gl_display.create_context(&gl_config, &gl3_3_core_context_attributes)
367 {
368 (gl3_3_core_context, GlKind::OpenGL)
369 } else {
370 (
371 gl_display.create_context(&gl_config, &gles3_context_attributes)?,
372 GlKind::OpenGLES,
373 )
374 };
375
376 let gl_context = non_current_gl_context.make_current(&gl_surface)?;
377
378 if vsync {
379 Log::verify(gl_surface.set_swap_interval(
380 &gl_context,
381 SwapInterval::Wait(NonZeroU32::new(1).unwrap()),
382 ));
383 }
384
385 (
386 window,
387 gl_context,
388 gl_surface,
389 glow::Context::from_loader_function(|s| {
390 gl_display.get_proc_address(&CString::new(s).unwrap())
391 }),
392 gl_kind,
393 )
394 }
395 };
396
397 #[cfg(target_arch = "wasm32")]
398 let (window, mut context, gl_kind) = {
399 use crate::core::wasm_bindgen::JsCast;
400 use serde::{Deserialize, Serialize};
401 use winit::{
402 dpi::{LogicalSize, PhysicalSize},
403 platform::web::WindowExtWebSys,
404 };
405
406 let inner_size = window_builder.window_attributes().inner_size;
407 let window = window_builder.build(window_target).unwrap();
408
409 let web_window = crate::core::web_sys::window().unwrap();
410 let scale_factor = web_window.device_pixel_ratio();
411
412 let canvas = window.canvas().unwrap();
413
414 if let Some(inner_size) = inner_size {
418 let physical_inner_size: PhysicalSize<u32> = inner_size.to_physical(scale_factor);
419
420 canvas.set_width(physical_inner_size.width);
421 canvas.set_height(physical_inner_size.height);
422
423 let logical_inner_size: LogicalSize<f64> = inner_size.to_logical(scale_factor);
424 Log::verify(
425 canvas
426 .style()
427 .set_property("width", &format!("{}px", logical_inner_size.width)),
428 );
429 Log::verify(
430 canvas
431 .style()
432 .set_property("height", &format!("{}px", logical_inner_size.height)),
433 );
434 }
435
436 let document = web_window.document().unwrap();
437 let body = document.body().unwrap();
438
439 body.append_child(&canvas)
440 .expect("Append canvas to HTML body");
441
442 #[derive(Serialize, Deserialize)]
443 #[allow(non_snake_case)]
444 struct ContextAttributes {
445 alpha: bool,
446 premultipliedAlpha: bool,
447 powerPreference: String,
448 }
449
450 let context_attributes = ContextAttributes {
451 alpha: false,
454 premultipliedAlpha: false,
455 powerPreference: "high-performance".to_string(),
457 };
458
459 let webgl2_context = canvas
460 .get_context_with_context_options(
461 "webgl2",
462 &serde_wasm_bindgen::to_value(&context_attributes).unwrap(),
463 )
464 .unwrap()
465 .unwrap()
466 .dyn_into::<crate::core::web_sys::WebGl2RenderingContext>()
467 .unwrap();
468 (
469 window,
470 glow::Context::from_webgl2_context(webgl2_context),
471 GlKind::OpenGLES,
472 )
473 };
474
475 #[cfg(not(target_arch = "wasm32"))]
476 gl_surface.resize(
477 &gl_context,
478 NonZeroU32::new(window.inner_size().width)
479 .unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
480 NonZeroU32::new(window.inner_size().height)
481 .unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
482 );
483
484 Log::info(format!(
486 "Supported GL Extensions: {:?}",
487 context.supported_extensions()
488 ));
489
490 unsafe {
491 context.depth_func(CompareFunc::default().into_gl());
492
493 #[cfg(debug_assertions)]
494 {
495 use crate::core::log::{Log, MessageKind};
496
497 if context.supported_extensions().contains("GL_KHR_debug") {
498 context.debug_message_callback(|source, msg_type, id, severity, message| {
499 let message_kind = if severity == glow::DEBUG_SEVERITY_HIGH {
500 MessageKind::Error
501 } else if severity == glow::DEBUG_SEVERITY_MEDIUM
502 || severity == glow::DEBUG_SEVERITY_LOW
503 {
504 MessageKind::Warning
505 } else {
506 return;
508 };
509
510 let source = if source == glow::DEBUG_SOURCE_API {
511 "Calls to the OpenGL API"
512 } else if source == glow::DEBUG_SOURCE_WINDOW_SYSTEM {
513 "Calls to a window-system API"
514 } else if source == glow::DEBUG_SOURCE_SHADER_COMPILER {
515 "A compiler for a shading language"
516 } else if source == glow::DEBUG_SOURCE_THIRD_PARTY {
517 "An application associated with OpenGL"
518 } else if source == glow::DEBUG_SOURCE_APPLICATION {
519 "Generated by the user of this application"
520 } else {
521 "Other"
522 };
523
524 let msg_type = if msg_type == glow::DEBUG_TYPE_ERROR {
525 "An error, typically from the API"
526 } else if msg_type == glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR {
527 "Some behavior marked deprecated has been used"
528 } else if msg_type == glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR {
529 "Something has invoked undefined behavior"
530 } else if msg_type == glow::DEBUG_TYPE_PORTABILITY {
531 "Some functionality the user relies upon is not portable"
532 } else if msg_type == glow::DEBUG_TYPE_PERFORMANCE {
533 "Code has triggered possible performance issues"
534 } else if msg_type == glow::DEBUG_TYPE_MARKER {
535 "Command stream annotation"
536 } else if msg_type == glow::DEBUG_TYPE_PUSH_GROUP
537 || msg_type == glow::DEBUG_TYPE_POP_GROUP
538 {
539 "Group pushing"
540 } else {
541 "Other"
542 };
543
544 Log::writeln(
545 message_kind,
546 format!(
547 "OpenGL Message\n\
548 \tSource: {source}\n\
549 \tType: {msg_type}\n\
550 \tId: {id}\n\
551 \tMessage: {message}"
552 ),
553 );
554 })
555 }
556 }
557 }
558
559 let state = Self {
560 gl: context,
561 state: RefCell::new(InnerState::new(
562 gl_kind,
563 #[cfg(not(target_arch = "wasm32"))]
564 gl_context,
565 #[cfg(not(target_arch = "wasm32"))]
566 gl_surface,
567 )),
568 this: Default::default(),
569 };
570
571 let shared = Rc::new(state);
572
573 *shared.this.borrow_mut() = Some(Rc::downgrade(&shared));
574
575 Ok((window, shared))
576 }
577
578 pub fn weak(&self) -> Weak<Self> {
579 self.this.borrow().as_ref().unwrap().clone()
580 }
581
582 pub fn gl_kind(&self) -> GlKind {
583 self.state.borrow().gl_kind
584 }
585
586 pub fn free_texture_unit(&self) -> Option<u32> {
587 let state = self.state.borrow();
588 for (index, unit) in state.texture_units_storage.units.iter().enumerate() {
589 if unit
590 .bindings
591 .iter()
592 .all(|binding| binding.texture.is_none())
593 {
594 return Some(index as u32);
595 }
596 }
597 None
598 }
599
600 pub(crate) fn set_framebuffer(&self, framebuffer: Option<glow::Framebuffer>) {
601 let mut state = self.state.borrow_mut();
602 if state.framebuffer != framebuffer {
603 state.framebuffer = framebuffer;
604
605 state.frame_statistics.framebuffer_binding_changes += 1;
606
607 unsafe {
608 self.gl
609 .bind_framebuffer(glow::FRAMEBUFFER, state.framebuffer)
610 }
611 }
612 }
613
614 pub(crate) fn set_viewport(&self, viewport: Rect<i32>) {
615 let mut state = self.state.borrow_mut();
616 if state.viewport != viewport {
617 state.viewport = viewport;
618
619 unsafe {
620 self.gl.viewport(
621 state.viewport.x(),
622 state.viewport.y(),
623 state.viewport.w(),
624 state.viewport.h(),
625 );
626 }
627 }
628 }
629
630 pub(crate) fn set_blend(&self, blend: bool) {
631 let mut state = self.state.borrow_mut();
632 if state.blend != blend {
633 state.blend = blend;
634
635 state.frame_statistics.blend_state_changes += 1;
636
637 unsafe {
638 if state.blend {
639 self.gl.enable(glow::BLEND);
640 } else {
641 self.gl.disable(glow::BLEND);
642 }
643 }
644 }
645 }
646
647 pub(crate) fn set_depth_test(&self, depth_test: bool) {
648 let mut state = self.state.borrow_mut();
649 if state.depth_test != depth_test {
650 state.depth_test = depth_test;
651
652 unsafe {
653 if state.depth_test {
654 self.gl.enable(glow::DEPTH_TEST);
655 } else {
656 self.gl.disable(glow::DEPTH_TEST);
657 }
658 }
659 }
660 }
661
662 pub(crate) fn set_depth_write(&self, depth_write: bool) {
663 let mut state = self.state.borrow_mut();
664 if state.depth_write != depth_write {
665 state.depth_write = depth_write;
666
667 unsafe {
668 self.gl.depth_mask(state.depth_write);
669 }
670 }
671 }
672
673 pub(crate) fn set_color_write(&self, color_write: ColorMask) {
674 let mut state = self.state.borrow_mut();
675 if state.color_write != color_write {
676 state.color_write = color_write;
677
678 unsafe {
679 self.gl.color_mask(
680 state.color_write.red,
681 state.color_write.green,
682 state.color_write.blue,
683 state.color_write.alpha,
684 );
685 }
686 }
687 }
688
689 pub(crate) fn set_stencil_test(&self, stencil_test: bool) {
690 let mut state = self.state.borrow_mut();
691 if state.stencil_test != stencil_test {
692 state.stencil_test = stencil_test;
693
694 unsafe {
695 if state.stencil_test {
696 self.gl.enable(glow::STENCIL_TEST);
697 } else {
698 self.gl.disable(glow::STENCIL_TEST);
699 }
700 }
701 }
702 }
703
704 pub(crate) fn set_cull_face(&self, cull_face: CullFace) {
705 let mut state = self.state.borrow_mut();
706 if state.cull_face != cull_face {
707 state.cull_face = cull_face;
708
709 unsafe { self.gl.cull_face(state.cull_face.into_gl()) }
710 }
711 }
712
713 pub(crate) fn set_culling(&self, culling: bool) {
714 let mut state = self.state.borrow_mut();
715 if state.culling != culling {
716 state.culling = culling;
717
718 unsafe {
719 if state.culling {
720 self.gl.enable(glow::CULL_FACE);
721 } else {
722 self.gl.disable(glow::CULL_FACE);
723 }
724 }
725 }
726 }
727
728 pub(crate) fn set_stencil_mask(&self, stencil_mask: u32) {
729 let mut state = self.state.borrow_mut();
730 if state.stencil_mask != stencil_mask {
731 state.stencil_mask = stencil_mask;
732
733 unsafe {
734 self.gl.stencil_mask(stencil_mask);
735 }
736 }
737 }
738
739 pub(crate) fn set_clear_color(&self, color: Color) {
740 let mut state = self.state.borrow_mut();
741 if state.clear_color != color {
742 state.clear_color = color;
743
744 let rgba = color.as_frgba();
745 unsafe {
746 self.gl.clear_color(rgba.x, rgba.y, rgba.z, rgba.w);
747 }
748 }
749 }
750
751 pub(crate) fn set_clear_depth(&self, depth: f32) {
752 let mut state = self.state.borrow_mut();
753 if (state.clear_depth - depth).abs() > f32::EPSILON {
754 state.clear_depth = depth;
755
756 unsafe {
757 self.gl.clear_depth_f32(depth);
758 }
759 }
760 }
761
762 pub(crate) fn set_clear_stencil(&self, stencil: i32) {
763 let mut state = self.state.borrow_mut();
764 if state.clear_stencil != stencil {
765 state.clear_stencil = stencil;
766
767 unsafe {
768 self.gl.clear_stencil(stencil);
769 }
770 }
771 }
772
773 pub(crate) fn set_blend_func(&self, func: BlendFunc) {
774 let mut state = self.state.borrow_mut();
775 if state.blend_func != func {
776 state.blend_func = func;
777
778 unsafe {
779 self.gl.blend_func_separate(
780 state.blend_func.sfactor.into_gl(),
781 state.blend_func.dfactor.into_gl(),
782 state.blend_func.alpha_sfactor.into_gl(),
783 state.blend_func.alpha_dfactor.into_gl(),
784 );
785 }
786 }
787 }
788
789 pub(crate) fn set_blend_equation(&self, equation: BlendEquation) {
790 let mut state = self.state.borrow_mut();
791 if state.blend_equation != equation {
792 state.blend_equation = equation;
793
794 unsafe {
795 self.gl.blend_equation_separate(
796 state.blend_equation.rgb.into_gl(),
797 state.blend_equation.alpha.into_gl(),
798 );
799 }
800 }
801 }
802
803 pub(crate) fn set_depth_func(&self, depth_func: CompareFunc) {
804 let mut state = self.state.borrow_mut();
805 if state.depth_func != depth_func {
806 state.depth_func = depth_func;
807
808 unsafe {
809 self.gl.depth_func(depth_func.into_gl());
810 }
811 }
812 }
813
814 pub(crate) fn set_program(&self, program: Option<glow::Program>) {
815 let mut state = self.state.borrow_mut();
816 if state.program != program {
817 state.program = program;
818
819 state.frame_statistics.program_binding_changes += 1;
820
821 unsafe {
822 self.gl.use_program(state.program);
823 }
824 }
825 }
826
827 pub(crate) fn set_texture(&self, unit_index: u32, target: u32, texture: Option<glow::Texture>) {
828 unsafe fn bind_texture(
829 gl: &glow::Context,
830 target: u32,
831 texture: Option<glow::Texture>,
832 unit_index: u32,
833 active_unit: &mut u32,
834 ) {
835 if *active_unit != unit_index {
836 *active_unit = unit_index;
837 gl.active_texture(glow::TEXTURE0 + unit_index);
838 }
839 gl.bind_texture(target, texture);
840 }
841
842 unsafe {
843 let mut state_guard = self.state.borrow_mut();
844 let state = state_guard.deref_mut();
845
846 let unit = &mut state.texture_units_storage.units[unit_index as usize];
847 let active_unit = &mut state.texture_units_storage.active_unit;
848 for binding in unit.bindings.iter_mut() {
849 if binding.target == target {
850 if binding.texture != texture {
851 binding.texture = texture;
852 bind_texture(&self.gl, binding.target, texture, unit_index, active_unit);
853 state.frame_statistics.texture_binding_changes += 1;
854 }
855 } else if binding.texture.is_some() {
856 binding.texture = None;
857 bind_texture(&self.gl, binding.target, None, unit_index, active_unit);
858 state.frame_statistics.texture_binding_changes += 1;
859 }
860 }
861 }
862 }
863
864 pub(crate) fn set_stencil_func(&self, func: StencilFunc) {
865 let mut state = self.state.borrow_mut();
866 if state.stencil_func != func {
867 state.stencil_func = func;
868
869 unsafe {
870 self.gl.stencil_func(
871 state.stencil_func.func.into_gl(),
872 state.stencil_func.ref_value as i32,
873 state.stencil_func.mask,
874 );
875 }
876 }
877 }
878
879 pub(crate) fn set_stencil_op(&self, op: StencilOp) {
880 let mut state = self.state.borrow_mut();
881 if state.stencil_op != op {
882 state.stencil_op = op;
883
884 unsafe {
885 self.gl.stencil_op(
886 state.stencil_op.fail.into_gl(),
887 state.stencil_op.zfail.into_gl(),
888 state.stencil_op.zpass.into_gl(),
889 );
890
891 self.gl.stencil_mask(state.stencil_op.write_mask);
892 }
893 }
894 }
895
896 pub(crate) fn set_vertex_array_object(&self, vao: Option<glow::VertexArray>) {
897 let mut state = self.state.borrow_mut();
898 if state.vao != vao {
899 state.vao = vao;
900
901 state.frame_statistics.vao_binding_changes += 1;
902
903 unsafe {
904 self.gl.bind_vertex_array(state.vao);
905 }
906 }
907 }
908
909 pub(crate) fn set_scissor_test(&self, scissor_test: bool) {
910 let mut state = self.state.borrow_mut();
911 if state.scissor_test != scissor_test {
912 state.scissor_test = scissor_test;
913
914 unsafe {
915 if scissor_test {
916 self.gl.enable(glow::SCISSOR_TEST);
917 } else {
918 self.gl.disable(glow::SCISSOR_TEST);
919 }
920 }
921 }
922 }
923
924 pub(crate) fn set_scissor_box(&self, scissor_box: &ScissorBox) {
925 unsafe {
926 self.gl.scissor(
927 scissor_box.x,
928 scissor_box.y,
929 scissor_box.width,
930 scissor_box.height,
931 );
932 }
933 }
934
935 pub(crate) fn apply_draw_parameters(&self, draw_params: &DrawParameters) {
936 let DrawParameters {
937 cull_face,
938 color_write,
939 depth_write,
940 stencil_test,
941 depth_test,
942 blend,
943 stencil_op,
944 scissor_box,
945 } = draw_params;
946
947 if let Some(ref blend_params) = blend {
948 self.set_blend_func(blend_params.func);
949 self.set_blend_equation(blend_params.equation);
950 self.set_blend(true);
951 } else {
952 self.set_blend(false);
953 }
954
955 if let Some(depth_func) = depth_test {
956 self.set_depth_func(*depth_func);
957 self.set_depth_test(true);
958 } else {
959 self.set_depth_test(false);
960 }
961 self.set_depth_write(*depth_write);
962
963 self.set_color_write(*color_write);
964
965 if let Some(stencil_func) = stencil_test {
966 self.set_stencil_test(true);
967 self.set_stencil_func(*stencil_func);
968 } else {
969 self.set_stencil_test(false);
970 }
971
972 self.set_stencil_op(*stencil_op);
973
974 if let Some(cull_face) = cull_face {
975 self.set_cull_face(*cull_face);
976 self.set_culling(true);
977 } else {
978 self.set_culling(false);
979 }
980
981 if let Some(scissor_box) = scissor_box {
982 self.set_scissor_test(true);
983 self.set_scissor_box(scissor_box);
984 } else {
985 self.set_scissor_test(false);
986 }
987 }
988}
989
990impl GraphicsServer for GlGraphicsServer {
991 fn create_buffer(
992 &self,
993 size: usize,
994 buffer_kind: BufferKind,
995 buffer_usage: BufferUsage,
996 ) -> Result<Box<dyn Buffer>, FrameworkError> {
997 Ok(Box::new(gl::buffer::GlBuffer::new(
998 self,
999 size,
1000 buffer_kind,
1001 buffer_usage,
1002 )?))
1003 }
1004
1005 fn create_texture(
1006 &self,
1007 desc: GpuTextureDescriptor,
1008 ) -> Result<Rc<RefCell<dyn GpuTexture>>, FrameworkError> {
1009 Ok(Rc::new(RefCell::new(GlTexture::new(self, desc)?)))
1010 }
1011
1012 fn create_frame_buffer(
1013 &self,
1014 depth_attachment: Option<Attachment>,
1015 color_attachments: Vec<Attachment>,
1016 ) -> Result<Box<dyn FrameBuffer>, FrameworkError> {
1017 Ok(Box::new(GlFrameBuffer::new(
1018 self,
1019 depth_attachment,
1020 color_attachments,
1021 )?))
1022 }
1023
1024 fn back_buffer(&self) -> Box<dyn FrameBuffer> {
1025 Box::new(GlFrameBuffer::backbuffer(self))
1026 }
1027
1028 fn create_query(&self) -> Result<Box<dyn Query>, FrameworkError> {
1029 Ok(Box::new(GlQuery::new(self)?))
1030 }
1031
1032 fn create_program(
1033 &self,
1034 name: &str,
1035 vertex_source: &str,
1036 fragment_source: &str,
1037 ) -> Result<Box<dyn GpuProgram>, FrameworkError> {
1038 Ok(Box::new(GlProgram::from_source(
1039 self,
1040 name,
1041 vertex_source,
1042 fragment_source,
1043 )?))
1044 }
1045
1046 fn create_program_with_properties(
1047 &self,
1048 name: &str,
1049 vertex_source: &str,
1050 fragment_source: &str,
1051 properties: &[ShaderResourceDefinition],
1052 ) -> Result<Box<dyn GpuProgram>, FrameworkError> {
1053 Ok(Box::new(GlProgram::from_source_and_properties(
1054 self,
1055 name,
1056 vertex_source,
1057 fragment_source,
1058 properties,
1059 )?))
1060 }
1061
1062 fn create_async_read_buffer(
1063 &self,
1064 pixel_size: usize,
1065 pixel_count: usize,
1066 ) -> Result<Box<dyn AsyncReadBuffer>, FrameworkError> {
1067 Ok(Box::new(GlAsyncReadBuffer::new(
1068 self,
1069 pixel_size,
1070 pixel_count,
1071 )?))
1072 }
1073
1074 fn create_geometry_buffer(
1075 &self,
1076 desc: GeometryBufferDescriptor,
1077 ) -> Result<Box<dyn GeometryBuffer>, FrameworkError> {
1078 Ok(Box::new(GlGeometryBuffer::new(self, desc)?))
1079 }
1080
1081 fn weak(self: Rc<Self>) -> Weak<dyn GraphicsServer> {
1082 self.this.borrow().as_ref().unwrap().clone()
1083 }
1084
1085 fn flush(&self) {
1086 unsafe {
1087 self.gl.flush();
1088 }
1089 }
1090
1091 fn finish(&self) {
1092 unsafe {
1093 self.gl.finish();
1094 }
1095 }
1096
1097 fn invalidate_resource_bindings_cache(&self) {
1098 let mut state = self.state.borrow_mut();
1099
1100 unsafe {
1101 for (unit_index, unit) in state.texture_units_storage.units.iter().enumerate() {
1102 self.gl.active_texture(glow::TEXTURE0 + unit_index as u32);
1103 for binding in unit.bindings.iter() {
1104 self.gl.bind_texture(binding.target, None)
1105 }
1106 }
1107 self.gl.active_texture(glow::TEXTURE0);
1108 }
1109 state.texture_units_storage = Default::default();
1110
1111 state.program = Default::default();
1112 state.frame_statistics = Default::default();
1113 }
1114
1115 fn pipeline_statistics(&self) -> PipelineStatistics {
1116 self.state.borrow().frame_statistics
1117 }
1118
1119 fn swap_buffers(&self) -> Result<(), FrameworkError> {
1120 #[cfg(not(target_arch = "wasm32"))]
1121 {
1122 let state = self.state.borrow();
1123 Ok(state.gl_surface.swap_buffers(&state.gl_context)?)
1124 }
1125
1126 #[cfg(target_arch = "wasm32")]
1127 {
1128 Ok(())
1129 }
1130 }
1131
1132 fn set_frame_size(&self, #[allow(unused_variables)] new_size: (u32, u32)) {
1133 #[cfg(not(target_arch = "wasm32"))]
1134 {
1135 use std::num::NonZeroU32;
1136 let state = self.state.borrow();
1137 state.gl_surface.resize(
1138 &state.gl_context,
1139 NonZeroU32::new(new_size.0).unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
1140 NonZeroU32::new(new_size.1).unwrap_or_else(|| NonZeroU32::new(1).unwrap()),
1141 );
1142 }
1143 }
1144
1145 fn capabilities(&self) -> ServerCapabilities {
1146 let gl = &self.gl;
1147 unsafe {
1148 ServerCapabilities {
1149 max_uniform_block_size: gl.get_parameter_i32(glow::MAX_UNIFORM_BLOCK_SIZE) as usize,
1150 uniform_buffer_offset_alignment: gl
1151 .get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT)
1152 as usize,
1153 max_lod_bias: gl.get_parameter_f32(glow::MAX_TEXTURE_LOD_BIAS),
1154 }
1155 }
1156 }
1157
1158 fn set_polygon_fill_mode(&self, polygon_face: PolygonFace, polygon_fill_mode: PolygonFillMode) {
1159 let mut state = self.state.borrow_mut();
1160 if state.polygon_fill_mode != polygon_fill_mode || state.polygon_face != polygon_face {
1161 state.polygon_fill_mode = polygon_fill_mode;
1162 state.polygon_face = polygon_face;
1163
1164 unsafe {
1165 self.gl.polygon_mode(
1166 state.polygon_face.into_gl(),
1167 state.polygon_fill_mode.into_gl(),
1168 )
1169 }
1170 }
1171 }
1172}