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