1#[cfg(not(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten")))))]
61mod egl;
62#[cfg(target_os = "emscripten")]
63mod emscripten;
64#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
65mod web;
66#[cfg(windows)]
67mod wgl;
68
69mod adapter;
70mod command;
71mod conv;
72mod device;
73mod queue;
74
75use crate::{CopyExtent, TextureDescriptor};
76
77#[cfg(not(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten")))))]
78pub use self::egl::{AdapterContext, AdapterContextLock};
79#[cfg(not(any(windows, all(target_arch = "wasm32", not(target_os = "emscripten")))))]
80use self::egl::{Instance, Surface};
81
82#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
83pub use self::web::AdapterContext;
84#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
85use self::web::{Instance, Surface};
86
87#[cfg(windows)]
88use self::wgl::AdapterContext;
89#[cfg(windows)]
90use self::wgl::{Instance, Surface};
91
92use arrayvec::ArrayVec;
93
94use glow::HasContext;
95
96use naga::FastHashMap;
97use parking_lot::Mutex;
98use std::sync::atomic::AtomicU32;
99use std::{fmt, ops::Range, sync::Arc};
100
101#[derive(Clone, Debug)]
102pub struct Api;
103
104const MAX_TEXTURE_SLOTS: usize = 16;
107const MAX_SAMPLERS: usize = 16;
108const MAX_VERTEX_ATTRIBUTES: usize = 16;
109const ZERO_BUFFER_SIZE: usize = 256 << 10;
110const MAX_PUSH_CONSTANTS: usize = 64;
111
112impl crate::Api for Api {
113 type Instance = Instance;
114 type Surface = Surface;
115 type Adapter = Adapter;
116 type Device = Device;
117
118 type Queue = Queue;
119 type CommandEncoder = CommandEncoder;
120 type CommandBuffer = CommandBuffer;
121
122 type Buffer = Buffer;
123 type Texture = Texture;
124 type SurfaceTexture = Texture;
125 type TextureView = TextureView;
126 type Sampler = Sampler;
127 type QuerySet = QuerySet;
128 type Fence = Fence;
129
130 type BindGroupLayout = BindGroupLayout;
131 type BindGroup = BindGroup;
132 type PipelineLayout = PipelineLayout;
133 type ShaderModule = ShaderModule;
134 type RenderPipeline = RenderPipeline;
135 type ComputePipeline = ComputePipeline;
136}
137
138bitflags::bitflags! {
139 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
142 struct PrivateCapabilities: u32 {
143 const BUFFER_ALLOCATION = 1 << 0;
145 const SHADER_BINDING_LAYOUT = 1 << 1;
147 const SHADER_TEXTURE_SHADOW_LOD = 1 << 2;
149 const MEMORY_BARRIERS = 1 << 3;
151 const VERTEX_BUFFER_LAYOUT = 1 << 4;
153 const INDEX_BUFFER_ROLE_CHANGE = 1 << 5;
156 const GET_BUFFER_SUB_DATA = 1 << 7;
158 const COLOR_BUFFER_HALF_FLOAT = 1 << 8;
160 const COLOR_BUFFER_FLOAT = 1 << 9;
162 const TEXTURE_FLOAT_LINEAR = 1 << 10;
164 const QUERY_BUFFERS = 1 << 11;
166 }
167}
168
169bitflags::bitflags! {
170 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
172 struct Workarounds: u32 {
173 const MESA_I915_SRGB_SHADER_CLEAR = 1 << 0;
180 const EMULATE_BUFFER_MAP = 1 << 1;
182 }
183}
184
185type BindTarget = u32;
186
187#[derive(Debug, Clone, Copy)]
188enum VertexAttribKind {
189 Float, Integer, }
193
194impl Default for VertexAttribKind {
195 fn default() -> Self {
196 Self::Float
197 }
198}
199
200#[derive(Clone, Debug)]
201pub struct TextureFormatDesc {
202 pub internal: u32,
203 pub external: u32,
204 pub data_type: u32,
205}
206
207struct AdapterShared {
208 context: AdapterContext,
209 private_caps: PrivateCapabilities,
210 features: wgt::Features,
211 workarounds: Workarounds,
212 shading_language_version: naga::back::glsl::Version,
213 max_texture_size: u32,
214 next_shader_id: AtomicU32,
215 program_cache: Mutex<ProgramCache>,
216 es: bool,
217}
218
219pub struct Adapter {
220 shared: Arc<AdapterShared>,
221}
222
223pub struct Device {
224 shared: Arc<AdapterShared>,
225 main_vao: glow::VertexArray,
226 #[cfg(all(not(target_arch = "wasm32"), feature = "renderdoc"))]
227 render_doc: crate::auxil::renderdoc::RenderDoc,
228}
229
230pub struct Queue {
231 shared: Arc<AdapterShared>,
232 features: wgt::Features,
233 draw_fbo: glow::Framebuffer,
234 copy_fbo: glow::Framebuffer,
235 shader_clear_program: glow::Program,
238 shader_clear_program_color_uniform_location: glow::UniformLocation,
240 zero_buffer: glow::Buffer,
243 temp_query_results: Vec<u64>,
244 draw_buffer_count: u8,
245 current_index_buffer: Option<glow::Buffer>,
246}
247
248#[derive(Clone, Debug)]
249pub struct Buffer {
250 raw: Option<glow::Buffer>,
251 target: BindTarget,
252 size: wgt::BufferAddress,
253 map_flags: u32,
254 data: Option<Arc<std::sync::Mutex<Vec<u8>>>>,
255}
256
257#[cfg(all(
258 target_arch = "wasm32",
259 feature = "fragile-send-sync-non-atomic-wasm",
260 not(target_feature = "atomics")
261))]
262unsafe impl Sync for Buffer {}
263#[cfg(all(
264 target_arch = "wasm32",
265 feature = "fragile-send-sync-non-atomic-wasm",
266 not(target_feature = "atomics")
267))]
268unsafe impl Send for Buffer {}
269
270#[derive(Clone, Debug)]
271pub enum TextureInner {
272 Renderbuffer {
273 raw: glow::Renderbuffer,
274 },
275 DefaultRenderbuffer,
276 Texture {
277 raw: glow::Texture,
278 target: BindTarget,
279 },
280 #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
281 ExternalFramebuffer {
282 inner: web_sys::WebGlFramebuffer,
283 },
284}
285
286#[cfg(all(
287 target_arch = "wasm32",
288 feature = "fragile-send-sync-non-atomic-wasm",
289 not(target_feature = "atomics")
290))]
291unsafe impl Sync for TextureInner {}
292#[cfg(all(
293 target_arch = "wasm32",
294 feature = "fragile-send-sync-non-atomic-wasm",
295 not(target_feature = "atomics")
296))]
297unsafe impl Send for TextureInner {}
298
299impl TextureInner {
300 fn as_native(&self) -> (glow::Texture, BindTarget) {
301 match *self {
302 Self::Renderbuffer { .. } | Self::DefaultRenderbuffer => {
303 panic!("Unexpected renderbuffer");
304 }
305 Self::Texture { raw, target } => (raw, target),
306 #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
307 Self::ExternalFramebuffer { .. } => panic!("Unexpected external framebuffer"),
308 }
309 }
310}
311
312#[derive(Debug)]
313pub struct Texture {
314 pub inner: TextureInner,
315 pub drop_guard: Option<crate::DropGuard>,
316 pub mip_level_count: u32,
317 pub array_layer_count: u32,
318 pub format: wgt::TextureFormat,
319 #[allow(unused)]
320 pub format_desc: TextureFormatDesc,
321 pub copy_size: CopyExtent,
322}
323
324impl Texture {
325 pub fn default_framebuffer(format: wgt::TextureFormat) -> Self {
326 Self {
327 inner: TextureInner::DefaultRenderbuffer,
328 drop_guard: None,
329 mip_level_count: 1,
330 array_layer_count: 1,
331 format,
332 format_desc: TextureFormatDesc {
333 internal: 0,
334 external: 0,
335 data_type: 0,
336 },
337 copy_size: CopyExtent {
338 width: 0,
339 height: 0,
340 depth: 0,
341 },
342 }
343 }
344
345 fn get_info_from_desc(desc: &TextureDescriptor) -> u32 {
347 match desc.dimension {
348 wgt::TextureDimension::D1 => glow::TEXTURE_2D,
349 wgt::TextureDimension::D2 => {
350 match (desc.is_cube_compatible(), desc.size.depth_or_array_layers) {
352 (false, 1) => glow::TEXTURE_2D,
353 (false, _) => glow::TEXTURE_2D_ARRAY,
354 (true, 6) => glow::TEXTURE_CUBE_MAP,
355 (true, _) => glow::TEXTURE_CUBE_MAP_ARRAY,
356 }
357 }
358 wgt::TextureDimension::D3 => glow::TEXTURE_3D,
359 }
360 }
361}
362
363#[derive(Clone, Debug)]
364pub struct TextureView {
365 inner: TextureInner,
366 aspects: crate::FormatAspects,
367 mip_levels: Range<u32>,
368 array_layers: Range<u32>,
369 format: wgt::TextureFormat,
370}
371
372#[derive(Debug)]
373pub struct Sampler {
374 raw: glow::Sampler,
375}
376
377#[derive(Debug)]
378pub struct BindGroupLayout {
379 entries: Arc<[wgt::BindGroupLayoutEntry]>,
380}
381
382struct BindGroupLayoutInfo {
383 entries: Arc<[wgt::BindGroupLayoutEntry]>,
384 binding_to_slot: Box<[u8]>,
390}
391
392pub struct PipelineLayout {
393 group_infos: Box<[BindGroupLayoutInfo]>,
394 naga_options: naga::back::glsl::Options,
395}
396
397impl PipelineLayout {
398 fn get_slot(&self, br: &naga::ResourceBinding) -> u8 {
399 let group_info = &self.group_infos[br.group as usize];
400 group_info.binding_to_slot[br.binding as usize]
401 }
402}
403
404#[derive(Debug)]
405enum BindingRegister {
406 UniformBuffers,
407 StorageBuffers,
408 Textures,
409 Images,
410}
411
412#[derive(Debug)]
413enum RawBinding {
414 Buffer {
415 raw: glow::Buffer,
416 offset: i32,
417 size: i32,
418 },
419 Texture {
420 raw: glow::Texture,
421 target: BindTarget,
422 aspects: crate::FormatAspects,
423 },
425 Image(ImageBinding),
426 Sampler(glow::Sampler),
427}
428
429#[derive(Debug)]
430pub struct BindGroup {
431 contents: Box<[RawBinding]>,
432}
433
434type ShaderId = u32;
435
436#[derive(Debug)]
437pub struct ShaderModule {
438 naga: crate::NagaShader,
439 label: Option<String>,
440 id: ShaderId,
441}
442
443#[derive(Clone, Debug, Default)]
444struct VertexFormatDesc {
445 element_count: i32,
446 element_format: u32,
447 attrib_kind: VertexAttribKind,
448}
449
450#[derive(Clone, Debug, Default)]
451struct AttributeDesc {
452 location: u32,
453 offset: u32,
454 buffer_index: u32,
455 format_desc: VertexFormatDesc,
456}
457
458#[derive(Clone, Debug)]
459struct BufferBinding {
460 raw: glow::Buffer,
461 offset: wgt::BufferAddress,
462}
463
464#[derive(Clone, Debug)]
465struct ImageBinding {
466 raw: glow::Texture,
467 mip_level: u32,
468 array_layer: Option<u32>,
469 access: u32,
470 format: u32,
471}
472
473#[derive(Clone, Debug, Default, PartialEq)]
474struct VertexBufferDesc {
475 step: wgt::VertexStepMode,
476 stride: u32,
477}
478
479#[derive(Clone, Debug, Default)]
480struct UniformDesc {
481 location: Option<glow::UniformLocation>,
482 size: u32,
483 utype: u32,
484}
485
486#[cfg(all(
487 target_arch = "wasm32",
488 feature = "fragile-send-sync-non-atomic-wasm",
489 not(target_feature = "atomics")
490))]
491unsafe impl Sync for UniformDesc {}
492#[cfg(all(
493 target_arch = "wasm32",
494 feature = "fragile-send-sync-non-atomic-wasm",
495 not(target_feature = "atomics")
496))]
497unsafe impl Send for UniformDesc {}
498
499type SamplerBindMap = [Option<u8>; MAX_TEXTURE_SLOTS];
502
503struct PipelineInner {
504 program: glow::Program,
505 sampler_map: SamplerBindMap,
506 uniforms: [UniformDesc; MAX_PUSH_CONSTANTS],
507}
508
509#[derive(Clone, Debug)]
510struct DepthState {
511 function: u32,
512 mask: bool,
513}
514
515#[derive(Clone, Debug, PartialEq)]
516struct BlendComponent {
517 src: u32,
518 dst: u32,
519 equation: u32,
520}
521
522#[derive(Clone, Debug, PartialEq)]
523struct BlendDesc {
524 alpha: BlendComponent,
525 color: BlendComponent,
526}
527
528#[derive(Clone, Debug, Default, PartialEq)]
529struct ColorTargetDesc {
530 mask: wgt::ColorWrites,
531 blend: Option<BlendDesc>,
532}
533
534#[derive(PartialEq, Eq, Hash)]
535struct ProgramStage {
536 naga_stage: naga::ShaderStage,
537 shader_id: ShaderId,
538 entry_point: String,
539}
540
541#[derive(PartialEq, Eq, Hash)]
542struct ProgramCacheKey {
543 stages: ArrayVec<ProgramStage, 3>,
544 group_to_binding_to_slot: Box<[Box<[u8]>]>,
545}
546
547type ProgramCache = FastHashMap<ProgramCacheKey, Result<Arc<PipelineInner>, crate::PipelineError>>;
548
549pub struct RenderPipeline {
550 inner: Arc<PipelineInner>,
551 primitive: wgt::PrimitiveState,
552 vertex_buffers: Box<[VertexBufferDesc]>,
553 vertex_attributes: Box<[AttributeDesc]>,
554 color_targets: Box<[ColorTargetDesc]>,
555 depth: Option<DepthState>,
556 depth_bias: wgt::DepthBiasState,
557 stencil: Option<StencilState>,
558 alpha_to_coverage_enabled: bool,
559}
560
561#[cfg(all(
562 target_arch = "wasm32",
563 feature = "fragile-send-sync-non-atomic-wasm",
564 not(target_feature = "atomics")
565))]
566unsafe impl Sync for RenderPipeline {}
567#[cfg(all(
568 target_arch = "wasm32",
569 feature = "fragile-send-sync-non-atomic-wasm",
570 not(target_feature = "atomics")
571))]
572unsafe impl Send for RenderPipeline {}
573
574pub struct ComputePipeline {
575 inner: Arc<PipelineInner>,
576}
577
578#[cfg(all(
579 target_arch = "wasm32",
580 feature = "fragile-send-sync-non-atomic-wasm",
581 not(target_feature = "atomics")
582))]
583unsafe impl Sync for ComputePipeline {}
584#[cfg(all(
585 target_arch = "wasm32",
586 feature = "fragile-send-sync-non-atomic-wasm",
587 not(target_feature = "atomics")
588))]
589unsafe impl Send for ComputePipeline {}
590
591#[derive(Debug)]
592pub struct QuerySet {
593 queries: Box<[glow::Query]>,
594 target: BindTarget,
595}
596
597#[derive(Debug)]
598pub struct Fence {
599 last_completed: crate::FenceValue,
600 pending: Vec<(crate::FenceValue, glow::Fence)>,
601}
602
603#[cfg(any(
604 not(target_arch = "wasm32"),
605 all(
606 feature = "fragile-send-sync-non-atomic-wasm",
607 not(target_feature = "atomics")
608 )
609))]
610unsafe impl Send for Fence {}
611#[cfg(any(
612 not(target_arch = "wasm32"),
613 all(
614 feature = "fragile-send-sync-non-atomic-wasm",
615 not(target_feature = "atomics")
616 )
617))]
618unsafe impl Sync for Fence {}
619
620impl Fence {
621 fn get_latest(&self, gl: &glow::Context) -> crate::FenceValue {
622 let mut max_value = self.last_completed;
623 for &(value, sync) in self.pending.iter() {
624 let status = unsafe { gl.get_sync_status(sync) };
625 if status == glow::SIGNALED {
626 max_value = value;
627 }
628 }
629 max_value
630 }
631
632 fn maintain(&mut self, gl: &glow::Context) {
633 let latest = self.get_latest(gl);
634 for &(value, sync) in self.pending.iter() {
635 if value <= latest {
636 unsafe {
637 gl.delete_sync(sync);
638 }
639 }
640 }
641 self.pending.retain(|&(value, _)| value > latest);
642 self.last_completed = latest;
643 }
644}
645
646#[derive(Clone, Debug, PartialEq)]
647struct StencilOps {
648 pass: u32,
649 fail: u32,
650 depth_fail: u32,
651}
652
653impl Default for StencilOps {
654 fn default() -> Self {
655 Self {
656 pass: glow::KEEP,
657 fail: glow::KEEP,
658 depth_fail: glow::KEEP,
659 }
660 }
661}
662
663#[derive(Clone, Debug, PartialEq)]
664struct StencilSide {
665 function: u32,
666 mask_read: u32,
667 mask_write: u32,
668 reference: u32,
669 ops: StencilOps,
670}
671
672impl Default for StencilSide {
673 fn default() -> Self {
674 Self {
675 function: glow::ALWAYS,
676 mask_read: 0xFF,
677 mask_write: 0xFF,
678 reference: 0,
679 ops: StencilOps::default(),
680 }
681 }
682}
683
684#[derive(Clone, Default)]
685struct StencilState {
686 front: StencilSide,
687 back: StencilSide,
688}
689
690#[derive(Clone, Debug, Default, PartialEq)]
691struct PrimitiveState {
692 front_face: u32,
693 cull_face: u32,
694 unclipped_depth: bool,
695}
696
697type InvalidatedAttachments = ArrayVec<u32, { crate::MAX_COLOR_ATTACHMENTS + 2 }>;
698
699#[derive(Debug)]
700enum Command {
701 Draw {
702 topology: u32,
703 start_vertex: u32,
704 vertex_count: u32,
705 instance_count: u32,
706 },
707 DrawIndexed {
708 topology: u32,
709 index_type: u32,
710 index_count: u32,
711 index_offset: wgt::BufferAddress,
712 base_vertex: i32,
713 instance_count: u32,
714 },
715 DrawIndirect {
716 topology: u32,
717 indirect_buf: glow::Buffer,
718 indirect_offset: wgt::BufferAddress,
719 },
720 DrawIndexedIndirect {
721 topology: u32,
722 index_type: u32,
723 indirect_buf: glow::Buffer,
724 indirect_offset: wgt::BufferAddress,
725 },
726 Dispatch([u32; 3]),
727 DispatchIndirect {
728 indirect_buf: glow::Buffer,
729 indirect_offset: wgt::BufferAddress,
730 },
731 ClearBuffer {
732 dst: Buffer,
733 dst_target: BindTarget,
734 range: crate::MemoryRange,
735 },
736 CopyBufferToBuffer {
737 src: Buffer,
738 src_target: BindTarget,
739 dst: Buffer,
740 dst_target: BindTarget,
741 copy: crate::BufferCopy,
742 },
743 #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
744 CopyExternalImageToTexture {
745 src: wgt::ImageCopyExternalImage,
746 dst: glow::Texture,
747 dst_target: BindTarget,
748 dst_format: wgt::TextureFormat,
749 dst_premultiplication: bool,
750 copy: crate::TextureCopy,
751 },
752 CopyTextureToTexture {
753 src: glow::Texture,
754 src_target: BindTarget,
755 dst: glow::Texture,
756 dst_target: BindTarget,
757 copy: crate::TextureCopy,
758 },
759 CopyBufferToTexture {
760 src: Buffer,
761 #[allow(unused)]
762 src_target: BindTarget,
763 dst: glow::Texture,
764 dst_target: BindTarget,
765 dst_format: wgt::TextureFormat,
766 copy: crate::BufferTextureCopy,
767 },
768 CopyTextureToBuffer {
769 src: glow::Texture,
770 src_target: BindTarget,
771 src_format: wgt::TextureFormat,
772 dst: Buffer,
773 #[allow(unused)]
774 dst_target: BindTarget,
775 copy: crate::BufferTextureCopy,
776 },
777 SetIndexBuffer(glow::Buffer),
778 BeginQuery(glow::Query, BindTarget),
779 EndQuery(BindTarget),
780 TimestampQuery(glow::Query),
781 CopyQueryResults {
782 query_range: Range<u32>,
783 dst: Buffer,
784 dst_target: BindTarget,
785 dst_offset: wgt::BufferAddress,
786 },
787 ResetFramebuffer {
788 is_default: bool,
789 },
790 BindAttachment {
791 attachment: u32,
792 view: TextureView,
793 },
794 ResolveAttachment {
795 attachment: u32,
796 dst: TextureView,
797 size: wgt::Extent3d,
798 },
799 InvalidateAttachments(InvalidatedAttachments),
800 SetDrawColorBuffers(u8),
801 ClearColorF {
802 draw_buffer: u32,
803 color: [f32; 4],
804 is_srgb: bool,
805 },
806 ClearColorU(u32, [u32; 4]),
807 ClearColorI(u32, [i32; 4]),
808 ClearDepth(f32),
809 ClearStencil(u32),
810 ClearDepthAndStencil(f32, u32),
815 BufferBarrier(glow::Buffer, crate::BufferUses),
816 TextureBarrier(crate::TextureUses),
817 SetViewport {
818 rect: crate::Rect<i32>,
819 depth: Range<f32>,
820 },
821 SetScissor(crate::Rect<i32>),
822 SetStencilFunc {
823 face: u32,
824 function: u32,
825 reference: u32,
826 read_mask: u32,
827 },
828 SetStencilOps {
829 face: u32,
830 write_mask: u32,
831 ops: StencilOps,
832 },
833 SetDepth(DepthState),
834 SetDepthBias(wgt::DepthBiasState),
835 ConfigureDepthStencil(crate::FormatAspects),
836 SetAlphaToCoverage(bool),
837 SetVertexAttribute {
838 buffer: Option<glow::Buffer>,
839 buffer_desc: VertexBufferDesc,
840 attribute_desc: AttributeDesc,
841 },
842 UnsetVertexAttribute(u32),
843 SetVertexBuffer {
844 index: u32,
845 buffer: BufferBinding,
846 buffer_desc: VertexBufferDesc,
847 },
848 SetProgram(glow::Program),
849 SetPrimitive(PrimitiveState),
850 SetBlendConstant([f32; 4]),
851 SetColorTarget {
852 draw_buffer_index: Option<u32>,
853 desc: ColorTargetDesc,
854 },
855 BindBuffer {
856 target: BindTarget,
857 slot: u32,
858 buffer: glow::Buffer,
859 offset: i32,
860 size: i32,
861 },
862 BindSampler(u32, Option<glow::Sampler>),
863 BindTexture {
864 slot: u32,
865 texture: glow::Texture,
866 target: BindTarget,
867 aspects: crate::FormatAspects,
868 },
869 BindImage {
870 slot: u32,
871 binding: ImageBinding,
872 },
873 InsertDebugMarker(Range<u32>),
874 PushDebugGroup(Range<u32>),
875 PopDebugGroup,
876 SetPushConstants {
877 uniform: UniformDesc,
878 offset: u32,
880 },
881}
882
883#[derive(Default)]
884pub struct CommandBuffer {
885 label: Option<String>,
886 commands: Vec<Command>,
887 data_bytes: Vec<u8>,
888 queries: Vec<glow::Query>,
889}
890
891impl fmt::Debug for CommandBuffer {
892 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
893 let mut builder = f.debug_struct("CommandBuffer");
894 if let Some(ref label) = self.label {
895 builder.field("label", label);
896 }
897 builder.finish()
898 }
899}
900
901pub struct CommandEncoder {
906 cmd_buffer: CommandBuffer,
907 state: command::State,
908 private_caps: PrivateCapabilities,
909}
910
911impl fmt::Debug for CommandEncoder {
912 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
913 f.debug_struct("CommandEncoder")
914 .field("cmd_buffer", &self.cmd_buffer)
915 .finish()
916 }
917}
918
919#[cfg(not(all(target_arch = "wasm32", not(target_os = "emscripten"))))]
920fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, message: &str) {
921 let source_str = match source {
922 glow::DEBUG_SOURCE_API => "API",
923 glow::DEBUG_SOURCE_WINDOW_SYSTEM => "Window System",
924 glow::DEBUG_SOURCE_SHADER_COMPILER => "ShaderCompiler",
925 glow::DEBUG_SOURCE_THIRD_PARTY => "Third Party",
926 glow::DEBUG_SOURCE_APPLICATION => "Application",
927 glow::DEBUG_SOURCE_OTHER => "Other",
928 _ => unreachable!(),
929 };
930
931 let log_severity = match severity {
932 glow::DEBUG_SEVERITY_HIGH => log::Level::Error,
933 glow::DEBUG_SEVERITY_MEDIUM => log::Level::Warn,
934 glow::DEBUG_SEVERITY_LOW => log::Level::Info,
935 glow::DEBUG_SEVERITY_NOTIFICATION => log::Level::Trace,
936 _ => unreachable!(),
937 };
938
939 let type_str = match gltype {
940 glow::DEBUG_TYPE_DEPRECATED_BEHAVIOR => "Deprecated Behavior",
941 glow::DEBUG_TYPE_ERROR => "Error",
942 glow::DEBUG_TYPE_MARKER => "Marker",
943 glow::DEBUG_TYPE_OTHER => "Other",
944 glow::DEBUG_TYPE_PERFORMANCE => "Performance",
945 glow::DEBUG_TYPE_POP_GROUP => "Pop Group",
946 glow::DEBUG_TYPE_PORTABILITY => "Portability",
947 glow::DEBUG_TYPE_PUSH_GROUP => "Push Group",
948 glow::DEBUG_TYPE_UNDEFINED_BEHAVIOR => "Undefined Behavior",
949 _ => unreachable!(),
950 };
951
952 let _ = std::panic::catch_unwind(|| {
953 log::log!(
954 log_severity,
955 "GLES: [{}/{}] ID {} : {}",
956 source_str,
957 type_str,
958 id,
959 message
960 );
961 });
962
963 if cfg!(debug_assertions) && log_severity == log::Level::Error {
964 crate::VALIDATION_CANARY.set();
966 }
967}