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