gfx_backend_gl/
device.rs

1use crate::{
2    command as cmd, conv,
3    info::LegacyFeatures,
4    native as n,
5    pool::{BufferMemory, CommandPool, OwnedBuffer},
6    state, Backend as B, FastHashMap, GlContainer, GlContext, MemoryUsage, Share, Starc,
7    MAX_TEXTURE_SLOTS,
8};
9
10use hal::{
11    buffer, device as d,
12    format::{ChannelType, Format, Swizzle},
13    image as i, memory, pass,
14    pool::CommandPoolCreateFlags,
15    pso, query, queue,
16};
17
18use glow::HasContext;
19use parking_lot::Mutex;
20
21use std::{ops::Range, slice, sync::Arc};
22
23#[cfg(feature = "cross")]
24type CrossAst = spirv_cross::spirv::Ast<spirv_cross::glsl::Target>;
25
26fn create_fbo_internal(
27    share: &Starc<Share>,
28) -> Option<<GlContext as glow::HasContext>::Framebuffer> {
29    if share.private_caps.framebuffer {
30        let gl = &share.context;
31        let name = unsafe { gl.create_framebuffer() }.unwrap();
32        log::info!("\tCreated frame buffer {:?}", name);
33        Some(name)
34    } else {
35        None
36    }
37}
38
39struct CompilationContext<'a> {
40    layout: &'a n::PipelineLayout,
41    sampler_map: &'a mut n::SamplerBindMap,
42    name_binding_map: &'a mut FastHashMap<String, (n::BindingRegister, u8)>,
43}
44
45impl<'a> CompilationContext<'a> {
46    fn reborrow(&mut self) -> CompilationContext<'_> {
47        CompilationContext {
48            layout: self.layout,
49            sampler_map: self.sampler_map,
50            name_binding_map: self.name_binding_map,
51        }
52    }
53}
54
55/// GL device.
56#[derive(Debug)]
57pub struct Device {
58    pub(crate) share: Starc<Share>,
59    features: hal::Features,
60    #[cfg(feature = "cross")]
61    spv_options: naga::back::spv::Options,
62}
63
64impl Drop for Device {
65    fn drop(&mut self) {
66        self.share.open.set(false);
67    }
68}
69
70impl Device {
71    /// Create a new `Device`.
72    pub(crate) fn new(share: Starc<Share>, features: hal::Features) -> Self {
73        Device {
74            share: share,
75            features,
76            #[cfg(feature = "cross")]
77            spv_options: {
78                use naga::back::spv;
79                let mut flags = spv::WriterFlags::empty();
80                flags.set(spv::WriterFlags::DEBUG, cfg!(debug_assertions));
81                flags.set(
82                    spv::WriterFlags::ADJUST_COORDINATE_SPACE,
83                    !features.contains(hal::Features::NDC_Y_UP),
84                );
85                spv::Options {
86                    lang_version: (1, 0),
87                    flags,
88                    // doesn't matter since we send it through SPIRV-Cross
89                    capabilities: None,
90                }
91            },
92        }
93    }
94
95    fn create_shader_module_raw(
96        gl: &GlContainer,
97        shader: &str,
98        stage: naga::ShaderStage,
99    ) -> Result<n::Shader, d::ShaderError> {
100        let target = match stage {
101            naga::ShaderStage::Vertex => glow::VERTEX_SHADER,
102            naga::ShaderStage::Fragment => glow::FRAGMENT_SHADER,
103            naga::ShaderStage::Compute => glow::COMPUTE_SHADER,
104        };
105
106        let name = unsafe { gl.create_shader(target) }.unwrap();
107        unsafe {
108            gl.shader_source(name, shader);
109            gl.compile_shader(name);
110        }
111        log::info!("\tCompiled shader {:?}", name);
112        if cfg!(debug_assertions) {
113            let err = super::Error::from_error_code(unsafe { gl.get_error() });
114            assert_eq!(err, super::Error::NoError, "Error compiling shader");
115        }
116
117        let compiled_ok = unsafe { gl.get_shader_compile_status(name) };
118        let log = unsafe { gl.get_shader_info_log(name) };
119        if compiled_ok {
120            if !log.is_empty() {
121                log::warn!("\tLog: {}", log);
122            }
123            Ok(name)
124        } else {
125            Err(d::ShaderError::CompilationFailed(log))
126        }
127    }
128
129    fn create_shader_program(
130        &self,
131        shaders: &[(naga::ShaderStage, Option<&pso::EntryPoint<B>>)],
132        layout: &n::PipelineLayout,
133    ) -> Result<(glow::Program, n::SamplerBindMap), pso::CreationError> {
134        let gl = &self.share.context;
135        let program = unsafe { gl.create_program().unwrap() };
136
137        let mut name_binding_map = FastHashMap::<String, (n::BindingRegister, u8)>::default();
138        let mut sampler_map = [None; MAX_TEXTURE_SLOTS];
139
140        let mut has_vertex_stage = false;
141        let mut has_fragment_stage = false;
142        let mut context = CompilationContext {
143            layout,
144            sampler_map: &mut sampler_map,
145            name_binding_map: &mut name_binding_map,
146        };
147
148        let mut shaders_to_delete = arrayvec::ArrayVec::<[_; 3]>::new();
149
150        for &(stage, point_maybe) in shaders {
151            if let Some(point) = point_maybe {
152                match stage {
153                    naga::ShaderStage::Vertex => has_vertex_stage = true,
154                    naga::ShaderStage::Fragment => has_fragment_stage = true,
155                    naga::ShaderStage::Compute => (),
156                }
157
158                let shader = self
159                    .compile_shader(point, stage, context.reborrow())
160                    .map_err(|err| {
161                        let error = format!("{} shader compilation failed: {:?}", err, stage);
162                        pso::CreationError::ShaderCreationError(stage.into(), error)
163                    })?;
164                unsafe {
165                    gl.attach_shader(program, shader);
166                    shaders_to_delete.push(shader);
167                }
168            }
169        }
170
171        // Create empty fragment shader if only vertex shader is present
172        if has_vertex_stage && !has_fragment_stage {
173            let sl = &self.share.info.shading_language;
174            let version = (sl.major * 100 + sl.minor * 10) as u16;
175            let shader_type = if sl.is_embedded { "es" } else { "" };
176            let shader_src = format!(
177                "#version {version} {shader_type} \n void main(void) {{}}",
178                version = version,
179                shader_type = shader_type
180            );
181            log::debug!(
182                "Only vertex shader is present. Creating empty fragment shader:\n{}",
183                shader_src
184            );
185            let shader = Self::create_shader_module_raw(
186                &self.share.context,
187                &shader_src,
188                naga::ShaderStage::Fragment,
189            )
190            .unwrap();
191            unsafe {
192                gl.attach_shader(program, shader);
193                shaders_to_delete.push(shader);
194            }
195        }
196
197        unsafe {
198            gl.link_program(program);
199        }
200
201        for shader in shaders_to_delete {
202            unsafe {
203                gl.delete_shader(shader);
204            }
205        }
206
207        log::info!("\tLinked program {:?}", program);
208        if let Err(err) = self.share.check() {
209            panic!("Error linking program: {:?}", err);
210        }
211
212        let linked_ok = unsafe { gl.get_program_link_status(program) };
213        let log = unsafe { gl.get_program_info_log(program) };
214        if !linked_ok {
215            let error = format!("Program {:?} linking error:{}", program, log);
216            return Err(pso::CreationError::ShaderCreationError(
217                pso::ShaderStageFlags::GRAPHICS,
218                error,
219            ));
220        }
221        if !log.is_empty() {
222            log::warn!("\tLog: {}", log);
223        }
224
225        if !self
226            .share
227            .legacy_features
228            .contains(LegacyFeatures::EXPLICIT_LAYOUTS_IN_SHADER)
229        {
230            unsafe {
231                gl.use_program(Some(program));
232            }
233            for (name, &(register, slot)) in name_binding_map.iter() {
234                log::trace!("Get binding {:?} from program {:?}", name, program);
235                match register {
236                    n::BindingRegister::Textures => unsafe {
237                        let loc = gl.get_uniform_location(program, name).unwrap();
238                        gl.uniform_1_i32(Some(&loc), slot as _);
239                    },
240                    n::BindingRegister::UniformBuffers => unsafe {
241                        let index = gl.get_uniform_block_index(program, name).unwrap();
242                        gl.uniform_block_binding(program, index, slot as _);
243                    },
244                    n::BindingRegister::StorageBuffers => unsafe {
245                        let index = gl.get_shader_storage_block_index(program, name).unwrap();
246                        gl.shader_storage_block_binding(program, index, slot as _);
247                    },
248                }
249            }
250        }
251
252        Ok((program, sampler_map))
253    }
254
255    fn _bind_target_compat(gl: &GlContainer, point: u32, attachment: u32, view: &n::ImageView) {
256        match *view {
257            n::ImageView::Renderbuffer { raw: rb, .. } => unsafe {
258                gl.framebuffer_renderbuffer(point, attachment, glow::RENDERBUFFER, Some(rb));
259            },
260            n::ImageView::Texture {
261                target,
262                raw,
263                ref sub,
264                is_3d: false,
265            } => unsafe {
266                gl.bind_texture(target, Some(raw));
267                gl.framebuffer_texture_2d(
268                    point,
269                    attachment,
270                    target,
271                    Some(raw),
272                    sub.level_start as _,
273                );
274            },
275            n::ImageView::Texture {
276                target,
277                raw,
278                ref sub,
279                is_3d: true,
280            } => unsafe {
281                gl.bind_texture(target, Some(raw));
282                gl.framebuffer_texture_3d(
283                    point,
284                    attachment,
285                    target,
286                    Some(raw),
287                    sub.level_start as _,
288                    sub.layer_start as _,
289                );
290            },
291        }
292    }
293
294    pub(crate) fn bind_target(gl: &GlContainer, point: u32, attachment: u32, view: &n::ImageView) {
295        match *view {
296            n::ImageView::Renderbuffer { raw: rb, .. } => unsafe {
297                gl.framebuffer_renderbuffer(point, attachment, glow::RENDERBUFFER, Some(rb));
298            },
299            n::ImageView::Texture {
300                target: _,
301                raw,
302                ref sub,
303                is_3d: false,
304            } => unsafe {
305                gl.framebuffer_texture_2d(
306                    point,
307                    attachment,
308                    glow::TEXTURE_2D,
309                    Some(raw),
310                    sub.level_start as _,
311                );
312            },
313            n::ImageView::Texture {
314                target: _,
315                raw,
316                ref sub,
317                is_3d: true,
318            } => unsafe {
319                gl.framebuffer_texture_layer(
320                    point,
321                    attachment,
322                    Some(raw),
323                    sub.level_start as _,
324                    sub.layer_start as _,
325                );
326            },
327        }
328    }
329
330    #[cfg(feature = "cross")]
331    fn parse_spirv_cross(&self, raw_data: &[u32]) -> Result<CrossAst, d::ShaderError> {
332        use spirv_cross::{spirv, ErrorCode as Ec};
333        let module = spirv::Module::from_words(raw_data);
334
335        spirv::Ast::parse(&module).map_err(|err| {
336            d::ShaderError::CompilationFailed(match err {
337                Ec::CompilationError(msg) => msg,
338                Ec::Unhandled => "Unknown parsing error".into(),
339            })
340        })
341    }
342
343    #[cfg(feature = "cross")]
344    fn set_push_const_layout(&self, _ast: &mut CrossAst) -> Result<(), d::ShaderError> {
345        Ok(())
346    }
347
348    #[cfg(feature = "cross")]
349    fn translate_spirv_cross(
350        &self,
351        ast: &mut CrossAst,
352        stage: naga::ShaderStage,
353        entry_point: &str,
354    ) -> Result<String, d::ShaderError> {
355        use spirv_cross::{glsl, ErrorCode as Ec};
356
357        let mut compile_options = glsl::CompilerOptions::default();
358        // see version table at https://en.wikipedia.org/wiki/OpenGL_Shading_Language
359        let is_embedded = self.share.info.shading_language.is_embedded;
360        let version = self.share.info.shading_language.tuple();
361        compile_options.version = if is_embedded {
362            match version {
363                (3, 2) => glsl::Version::V3_20Es,
364                (3, 1) => glsl::Version::V3_10Es,
365                (3, 0) => glsl::Version::V3_00Es,
366                (1, 0) => glsl::Version::V1_00Es,
367                other if other > (3, 2) => glsl::Version::V3_20Es,
368                other => panic!("GLSL version is not recognized: {:?}", other),
369            }
370        } else {
371            match version {
372                (4, 6) => glsl::Version::V4_60,
373                (4, 5) => glsl::Version::V4_50,
374                (4, 4) => glsl::Version::V4_40,
375                (4, 3) => glsl::Version::V4_30,
376                (4, 2) => glsl::Version::V4_20,
377                (4, 1) => glsl::Version::V4_10,
378                (4, 0) => glsl::Version::V4_00,
379                (3, 3) => glsl::Version::V3_30,
380                (1, 5) => glsl::Version::V1_50,
381                (1, 4) => glsl::Version::V1_40,
382                (1, 3) => glsl::Version::V1_30,
383                (1, 2) => glsl::Version::V1_20,
384                (1, 1) => glsl::Version::V1_10,
385                other if other > (4, 6) => glsl::Version::V4_60,
386                other => panic!("GLSL version is not recognized: {:?}", other),
387            }
388        };
389        compile_options.vertex.invert_y = !self.features.contains(hal::Features::NDC_Y_UP);
390        compile_options.force_zero_initialized_variables = true;
391        compile_options.entry_point = Some((
392            entry_point.to_string(),
393            conv::map_naga_stage_to_cross(stage),
394        ));
395        log::debug!("SPIR-V options {:?}", compile_options);
396
397        ast.set_compiler_options(&compile_options).map_err(|err| {
398            d::ShaderError::CompilationFailed(match err {
399                Ec::CompilationError(msg) => msg,
400                Ec::Unhandled => "Unexpected error".into(),
401            })
402        })?;
403        ast.compile().map_err(|err| {
404            d::ShaderError::CompilationFailed(match err {
405                Ec::CompilationError(msg) => msg,
406                Ec::Unhandled => "Unknown compile error".into(),
407            })
408        })
409    }
410
411    #[cfg(feature = "cross")]
412    fn remap_bindings(
413        &self,
414        ast: &mut CrossAst,
415        layout: &n::PipelineLayout,
416        nb_map: &mut FastHashMap<String, (n::BindingRegister, u8)>,
417    ) {
418        let res = ast.get_shader_resources().unwrap();
419        self.remap_binding(
420            ast,
421            &res.sampled_images,
422            n::BindingRegister::Textures,
423            layout,
424            nb_map,
425        );
426        self.remap_binding(
427            ast,
428            &res.uniform_buffers,
429            n::BindingRegister::UniformBuffers,
430            layout,
431            nb_map,
432        );
433        self.remap_binding(
434            ast,
435            &res.storage_buffers,
436            n::BindingRegister::StorageBuffers,
437            layout,
438            nb_map,
439        );
440    }
441
442    #[cfg(feature = "cross")]
443    fn remap_binding(
444        &self,
445        ast: &mut CrossAst,
446        all_res: &[spirv_cross::spirv::Resource],
447        register: n::BindingRegister,
448        layout: &n::PipelineLayout,
449        nb_map: &mut FastHashMap<String, (n::BindingRegister, u8)>,
450    ) {
451        use spirv_cross::spirv::Decoration;
452
453        for res in all_res {
454            let set = ast
455                .get_decoration(res.id, Decoration::DescriptorSet)
456                .unwrap();
457            let binding = ast.get_decoration(res.id, Decoration::Binding).unwrap();
458            let set_info = &layout.sets[set as usize];
459            let slot = set_info.bindings[binding as usize];
460            assert!((slot as usize) < MAX_TEXTURE_SLOTS);
461
462            if self
463                .share
464                .legacy_features
465                .contains(LegacyFeatures::EXPLICIT_LAYOUTS_IN_SHADER)
466            {
467                ast.set_decoration(res.id, Decoration::Binding, slot as u32)
468                    .unwrap()
469            } else {
470                ast.unset_decoration(res.id, Decoration::Binding).unwrap();
471                assert!(nb_map.insert(res.name.clone(), (register, slot)).is_none());
472            }
473            ast.unset_decoration(res.id, Decoration::DescriptorSet)
474                .unwrap();
475        }
476    }
477
478    #[cfg(feature = "cross")]
479    fn combine_separate_images_and_samplers(
480        &self,
481        ast: &mut CrossAst,
482        context: CompilationContext,
483    ) {
484        use spirv_cross::spirv::Decoration;
485
486        let mut id_map =
487            FastHashMap::<u32, (pso::DescriptorSetIndex, pso::DescriptorBinding)>::default();
488        let res = ast.get_shader_resources().unwrap();
489        self.populate_id_map(ast, &mut id_map, &res.separate_images);
490        self.populate_id_map(ast, &mut id_map, &res.separate_samplers);
491
492        for cis in ast.get_combined_image_samplers().unwrap() {
493            let texture_slot = {
494                let &(set, binding) = id_map.get(&cis.image_id).unwrap();
495                context.layout.sets[set as usize].bindings[binding as usize]
496            };
497            let sampler_slot = {
498                let &(set, binding) = id_map.get(&cis.sampler_id).unwrap();
499                context.layout.sets[set as usize].bindings[binding as usize]
500            };
501            context.sampler_map[texture_slot as usize] = Some(sampler_slot);
502
503            if self
504                .share
505                .legacy_features
506                .contains(LegacyFeatures::EXPLICIT_LAYOUTS_IN_SHADER)
507            {
508                // if it was previously assigned, clear the binding of the image
509                let _ = ast.unset_decoration(cis.image_id, Decoration::Binding);
510                ast.set_decoration(cis.combined_id, Decoration::Binding, texture_slot as u32)
511                    .unwrap()
512            } else {
513                let name = ast.get_name(cis.combined_id).unwrap();
514                ast.unset_decoration(cis.combined_id, Decoration::Binding)
515                    .unwrap();
516                assert_eq!(
517                    context
518                        .name_binding_map
519                        .insert(name, (n::BindingRegister::Textures, texture_slot)),
520                    None
521                );
522            }
523            ast.unset_decoration(cis.combined_id, Decoration::DescriptorSet)
524                .unwrap();
525        }
526    }
527
528    fn reflect_shader(
529        module: &naga::Module,
530        ep_info: &naga::valid::FunctionInfo,
531        reflection_info: naga::back::glsl::ReflectionInfo,
532        context: CompilationContext,
533    ) {
534        for (handle, var) in module.global_variables.iter() {
535            if ep_info[handle].is_empty() {
536                continue;
537            }
538            let register = match var.class {
539                naga::StorageClass::Uniform => n::BindingRegister::UniformBuffers,
540                naga::StorageClass::Storage => n::BindingRegister::StorageBuffers,
541                _ => continue,
542            };
543            //TODO: make Naga reflect all the names, not just textures
544            let slot = match var.binding {
545                Some(ref br) => {
546                    context.layout.sets[br.group as usize].bindings[br.binding as usize]
547                }
548                ref other => panic!("Unexpected resource binding {:?}", other),
549            };
550
551            let name = reflection_info.uniforms[&handle].clone();
552            log::debug!("Rebind buffer: {:?} -> {}", var.name.as_ref(), &name);
553            context.name_binding_map.insert(name, (register, slot));
554        }
555
556        for (name, mapping) in reflection_info.texture_mapping {
557            let texture_linear_index = match module.global_variables[mapping.texture].binding {
558                Some(ref br) => {
559                    context.layout.sets[br.group as usize].bindings[br.binding as usize]
560                }
561                ref other => panic!("Unexpected texture binding {:?}", other),
562            };
563            context
564                .name_binding_map
565                .insert(name, (n::BindingRegister::Textures, texture_linear_index));
566            if let Some(sampler_handle) = mapping.sampler {
567                let sampler_linear_index = match module.global_variables[sampler_handle].binding {
568                    Some(ref br) => {
569                        context.layout.sets[br.group as usize].bindings[br.binding as usize]
570                    }
571                    ref other => panic!("Unexpected sampler binding {:?}", other),
572                };
573                context.sampler_map[texture_linear_index as usize] = Some(sampler_linear_index);
574            }
575        }
576    }
577
578    #[cfg(feature = "cross")]
579    fn populate_id_map(
580        &self,
581        ast: &CrossAst,
582        id_map: &mut FastHashMap<u32, (pso::DescriptorSetIndex, pso::DescriptorBinding)>,
583        all_res: &[spirv_cross::spirv::Resource],
584    ) {
585        use spirv_cross::spirv::Decoration;
586        for res in all_res {
587            let set = ast
588                .get_decoration(res.id, Decoration::DescriptorSet)
589                .unwrap();
590            let binding = ast.get_decoration(res.id, Decoration::Binding).unwrap();
591            assert!(id_map.insert(res.id, (set as _, binding)).is_none())
592        }
593    }
594
595    fn compile_shader_library_naga(
596        gl: &GlContainer,
597        shader: &d::NagaShader,
598        options: &naga::back::glsl::Options,
599        context: CompilationContext,
600    ) -> Result<n::Shader, d::ShaderError> {
601        let mut output = String::new();
602        let mut writer =
603            naga::back::glsl::Writer::new(&mut output, &shader.module, &shader.info, options)
604                .map_err(|e| {
605                    log::warn!("Naga GLSL init: {}", e);
606                    d::ShaderError::CompilationFailed(format!("{:?}", e))
607                })?;
608
609        let entry_point_index = (&shader.module.entry_points)
610            .into_iter()
611            .position(|ep| ep.name == options.entry_point)
612            .ok_or(d::ShaderError::CompilationFailed(format!(
613                "Couldn't find entry point {}",
614                options.entry_point
615            )))?;
616
617        match writer.write() {
618            Ok(reflection_info) => {
619                Self::reflect_shader(
620                    &shader.module,
621                    shader.info.get_entry_point(entry_point_index),
622                    reflection_info,
623                    context,
624                );
625                log::debug!("Naga generated shader:\n{}", output);
626                Self::create_shader_module_raw(gl, &output, options.shader_stage)
627            }
628            Err(e) => {
629                log::warn!("Naga GLSL write: {}", e);
630                Err(d::ShaderError::CompilationFailed(format!("{:?}", e)))
631            }
632        }
633    }
634
635    fn compile_shader(
636        &self,
637        ep: &pso::EntryPoint<B>,
638        stage: naga::ShaderStage,
639        mut context: CompilationContext,
640    ) -> Result<n::Shader, d::ShaderError> {
641        let naga_options = naga::back::glsl::Options {
642            version: {
643                use naga::back::glsl::Version;
644                let sl = &self.share.info.shading_language;
645                let value = (sl.major * 100 + sl.minor * 10) as u16;
646                if sl.is_embedded {
647                    Version::Embedded(value)
648                } else {
649                    Version::Desktop(value)
650                }
651            },
652            shader_stage: stage,
653            entry_point: ep.entry.to_string(),
654        };
655
656        #[cfg_attr(not(feature = "cross"), allow(unused_mut))]
657        let mut result = match ep.module.naga {
658            Ok(ref shader) => Self::compile_shader_library_naga(
659                &self.share.context,
660                shader,
661                &naga_options,
662                context.reborrow(),
663            ),
664            Err(ref e) => Err(d::ShaderError::CompilationFailed(e.clone())),
665        };
666        #[cfg(feature = "cross")]
667        if result.is_err() {
668            let mut ast = self.parse_spirv_cross(&ep.module.spv).unwrap();
669            auxil::spirv_cross_specialize_ast(&mut ast, &ep.specialization).unwrap();
670            self.remap_bindings(&mut ast, context.layout, context.name_binding_map);
671            self.combine_separate_images_and_samplers(&mut ast, context.reborrow());
672            self.set_push_const_layout(&mut ast).unwrap();
673
674            let glsl = self
675                .translate_spirv_cross(&mut ast, stage, ep.entry)
676                .unwrap();
677            log::debug!("SPIRV-Cross generated shader:\n{}", glsl);
678            result = Self::create_shader_module_raw(&self.share.context, &glsl, stage);
679        }
680        result
681    }
682}
683
684pub(crate) unsafe fn set_sampler_info<SetParamFloat, SetParamFloatVec, SetParamInt>(
685    info: &i::SamplerDesc,
686    features: &hal::Features,
687    mut set_param_float: SetParamFloat,
688    mut set_param_float_vec: SetParamFloatVec,
689    mut set_param_int: SetParamInt,
690) where
691    // TODO: Move these into a trait and implement for sampler/texture objects
692    SetParamFloat: FnMut(u32, f32),
693    SetParamFloatVec: FnMut(u32, &mut [f32]),
694    SetParamInt: FnMut(u32, i32),
695{
696    let (min, mag) = conv::filter_to_gl(info.mag_filter, info.min_filter, info.mip_filter);
697    if let Some(fac) = info.anisotropy_clamp {
698        if features.contains(hal::Features::SAMPLER_ANISOTROPY) {
699            set_param_float(glow::TEXTURE_MAX_ANISOTROPY, fac as f32);
700        }
701    }
702
703    set_param_int(glow::TEXTURE_MIN_FILTER, min as i32);
704    set_param_int(glow::TEXTURE_MAG_FILTER, mag as i32);
705
706    let (s, t, r) = info.wrap_mode;
707    set_param_int(glow::TEXTURE_WRAP_S, conv::wrap_to_gl(s) as i32);
708    set_param_int(glow::TEXTURE_WRAP_T, conv::wrap_to_gl(t) as i32);
709    set_param_int(glow::TEXTURE_WRAP_R, conv::wrap_to_gl(r) as i32);
710
711    if features.contains(hal::Features::SAMPLER_MIP_LOD_BIAS) {
712        set_param_float(glow::TEXTURE_LOD_BIAS, info.lod_bias.0);
713    }
714    if features.contains(hal::Features::SAMPLER_BORDER_COLOR) {
715        let mut border: [f32; 4] = info.border.into();
716        set_param_float_vec(glow::TEXTURE_BORDER_COLOR, &mut border);
717    }
718
719    set_param_float(glow::TEXTURE_MIN_LOD, info.lod_range.start.0);
720    set_param_float(glow::TEXTURE_MAX_LOD, info.lod_range.end.0);
721
722    match info.comparison {
723        None => set_param_int(glow::TEXTURE_COMPARE_MODE, glow::NONE as i32),
724        Some(cmp) => {
725            set_param_int(
726                glow::TEXTURE_COMPARE_MODE,
727                glow::COMPARE_REF_TO_TEXTURE as i32,
728            );
729            set_param_int(
730                glow::TEXTURE_COMPARE_FUNC,
731                state::map_comparison(cmp) as i32,
732            );
733        }
734    }
735}
736
737impl d::Device<B> for Device {
738    unsafe fn allocate_memory(
739        &self,
740        mem_type: hal::MemoryTypeId,
741        size: u64,
742    ) -> Result<n::Memory, d::AllocationError> {
743        let (memory_type, memory_role) = self.share.memory_types[mem_type.0 as usize];
744
745        let is_device_local_memory = memory_type
746            .properties
747            .contains(memory::Properties::DEVICE_LOCAL);
748        let is_cpu_visible_memory = memory_type
749            .properties
750            .contains(memory::Properties::CPU_VISIBLE);
751        let is_coherent_memory = memory_type
752            .properties
753            .contains(memory::Properties::COHERENT);
754        let is_readable_memory = memory_type
755            .properties
756            .contains(memory::Properties::CPU_CACHED);
757
758        match memory_role {
759            MemoryUsage::Buffer(buffer_usage) => {
760                let gl = &self.share.context;
761                let target = if buffer_usage.contains(buffer::Usage::INDEX)
762                    && !self.share.private_caps.index_buffer_role_change
763                {
764                    glow::ELEMENT_ARRAY_BUFFER
765                } else {
766                    glow::ARRAY_BUFFER
767                };
768
769                let raw = gl.create_buffer().unwrap();
770                //TODO: use *Named calls to avoid binding
771                gl.bind_buffer(target, Some(raw));
772
773                let mut map_flags = 0;
774
775                if is_cpu_visible_memory {
776                    map_flags |= glow::MAP_WRITE_BIT | glow::MAP_FLUSH_EXPLICIT_BIT;
777                    if is_readable_memory {
778                        map_flags |= glow::MAP_READ_BIT;
779                    }
780                }
781
782                if self.share.private_caps.buffer_storage {
783                    let mut storage_flags = 0;
784
785                    if is_cpu_visible_memory {
786                        map_flags |= glow::MAP_PERSISTENT_BIT;
787                        storage_flags |= glow::MAP_WRITE_BIT
788                            | glow::MAP_PERSISTENT_BIT
789                            | glow::DYNAMIC_STORAGE_BIT;
790
791                        if is_readable_memory {
792                            storage_flags |= glow::MAP_READ_BIT;
793                        }
794
795                        if is_coherent_memory {
796                            map_flags |= glow::MAP_COHERENT_BIT;
797                            storage_flags |= glow::MAP_COHERENT_BIT;
798                        }
799                    }
800
801                    gl.buffer_storage(target, size as i32, None, storage_flags);
802                } else {
803                    assert!(!is_coherent_memory);
804                    let usage = if is_cpu_visible_memory {
805                        if is_readable_memory {
806                            glow::STREAM_READ
807                        } else {
808                            glow::DYNAMIC_DRAW
809                        }
810                    } else {
811                        glow::STATIC_DRAW
812                    };
813                    gl.buffer_data_size(target, size as i32, usage);
814                }
815
816                gl.bind_buffer(target, None);
817
818                if let Err(err) = self.share.check() {
819                    panic!("Error allocating memory buffer {:?}", err);
820                }
821
822                Ok(n::Memory {
823                    properties: memory_type.properties,
824                    buffer: Some((raw, target)),
825                    size,
826                    map_flags,
827                    emulate_map_allocation: None,
828                })
829            }
830
831            MemoryUsage::Image => {
832                assert!(is_device_local_memory);
833                Ok(n::Memory {
834                    properties: memory::Properties::DEVICE_LOCAL,
835                    buffer: None,
836                    size,
837                    map_flags: 0,
838                    emulate_map_allocation: None,
839                })
840            }
841        }
842    }
843
844    unsafe fn create_command_pool(
845        &self,
846        _family: queue::QueueFamilyId,
847        flags: CommandPoolCreateFlags,
848    ) -> Result<CommandPool, d::OutOfMemory> {
849        let fbo = create_fbo_internal(&self.share);
850        let limits = self.share.public_caps.limits.into();
851        let memory = if flags.contains(CommandPoolCreateFlags::RESET_INDIVIDUAL) {
852            BufferMemory::Individual {
853                storage: FastHashMap::default(),
854                next_buffer_id: 0,
855            }
856        } else {
857            BufferMemory::Linear(OwnedBuffer::new())
858        };
859
860        // Ignoring `TRANSIENT` hint, unsure how to make use of this.
861
862        Ok(CommandPool {
863            fbo,
864            limits,
865            memory: Arc::new(Mutex::new(memory)),
866            legacy_features: self.share.legacy_features,
867        })
868    }
869
870    unsafe fn destroy_command_pool(&self, pool: CommandPool) {
871        if let Some(fbo) = pool.fbo {
872            let gl = &self.share.context;
873            gl.delete_framebuffer(fbo);
874        }
875    }
876
877    unsafe fn create_render_pass<'a, Ia, Is, Id>(
878        &self,
879        attachments: Ia,
880        subpasses: Is,
881        _dependencies: Id,
882    ) -> Result<n::RenderPass, d::OutOfMemory>
883    where
884        Ia: Iterator<Item = pass::Attachment>,
885        Is: Iterator<Item = pass::SubpassDesc<'a>>,
886    {
887        let subpasses = subpasses
888            .map(|subpass| {
889                assert!(
890                    subpass.colors.len() <= self.share.public_caps.limits.max_color_attachments,
891                    "Color attachment limit exceeded"
892                );
893                let color_attachments = subpass.colors.iter().map(|&(index, _)| index).collect();
894
895                let depth_stencil = subpass.depth_stencil.map(|ds| ds.0);
896
897                n::SubpassDesc {
898                    color_attachments,
899                    depth_stencil,
900                }
901            })
902            .collect();
903
904        Ok(n::RenderPass {
905            attachments: attachments.collect::<Vec<_>>(),
906            subpasses,
907        })
908    }
909
910    unsafe fn create_pipeline_layout<'a, Is, Ic>(
911        &self,
912        layouts: Is,
913        _: Ic,
914    ) -> Result<n::PipelineLayout, d::OutOfMemory>
915    where
916        Is: Iterator<Item = &'a n::DescriptorSetLayout>,
917    {
918        use std::convert::TryInto;
919        let mut sets = Vec::new();
920        let mut num_samplers = 0usize;
921        let mut num_textures = 0usize;
922        let mut num_uniform_buffers = 0usize;
923        let mut num_storage_buffers = 0usize;
924
925        for layout_bindings in layouts {
926            // create a vector with the size enough to hold all the bindings, filled with `!0`
927            let mut bindings =
928                vec![!0; layout_bindings.last().map_or(0, |b| b.binding as usize + 1)];
929
930            for binding in layout_bindings.iter() {
931                assert!(!binding.immutable_samplers); //TODO
932                let counter = match binding.ty {
933                    pso::DescriptorType::Sampler => &mut num_samplers,
934                    pso::DescriptorType::InputAttachment | pso::DescriptorType::Image { .. } => {
935                        &mut num_textures
936                    }
937                    pso::DescriptorType::Buffer {
938                        ty,
939                        format: _, //TODO
940                    } => match ty {
941                        pso::BufferDescriptorType::Uniform => &mut num_uniform_buffers,
942                        pso::BufferDescriptorType::Storage { .. } => &mut num_storage_buffers,
943                    },
944                };
945
946                bindings[binding.binding as usize] = (*counter).try_into().unwrap();
947                *counter += binding.count;
948            }
949
950            sets.push(n::PipelineLayoutSet {
951                layout: Arc::clone(layout_bindings),
952                bindings,
953            });
954        }
955
956        Ok(n::PipelineLayout { sets })
957    }
958
959    unsafe fn create_pipeline_cache(&self, _data: Option<&[u8]>) -> Result<(), d::OutOfMemory> {
960        Ok(())
961    }
962
963    unsafe fn get_pipeline_cache_data(&self, _cache: &()) -> Result<Vec<u8>, d::OutOfMemory> {
964        //empty
965        Ok(Vec::new())
966    }
967
968    unsafe fn destroy_pipeline_cache(&self, _: ()) {
969        //empty
970    }
971
972    unsafe fn merge_pipeline_caches<'a, I>(&self, _: &mut (), _: I) -> Result<(), d::OutOfMemory>
973    where
974        I: Iterator<Item = &'a ()>,
975    {
976        //empty
977        Ok(())
978    }
979
980    unsafe fn create_graphics_pipeline<'a>(
981        &self,
982        desc: &pso::GraphicsPipelineDesc<'a, B>,
983        _cache: Option<&()>,
984    ) -> Result<n::GraphicsPipeline, pso::CreationError> {
985        let (vertex_buffers, desc_attributes, input_assembler, vs) = match desc.primitive_assembler
986        {
987            pso::PrimitiveAssemblerDesc::Vertex {
988                buffers,
989                attributes,
990                ref input_assembler,
991                ref vertex,
992                ref tessellation,
993                ref geometry,
994            } => {
995                if tessellation.is_some() || geometry.is_some() {
996                    return Err(pso::CreationError::UnsupportedPipeline);
997                }
998
999                let mut vertex_buffers = Vec::new();
1000                for vb in buffers {
1001                    while vertex_buffers.len() <= vb.binding as usize {
1002                        vertex_buffers.push(None);
1003                    }
1004                    vertex_buffers[vb.binding as usize] = Some(*vb);
1005                }
1006
1007                (vertex_buffers, attributes, input_assembler, vertex)
1008            }
1009            pso::PrimitiveAssemblerDesc::Mesh { .. } => {
1010                return Err(pso::CreationError::UnsupportedPipeline);
1011            }
1012        };
1013
1014        let shaders = [
1015            (naga::ShaderStage::Vertex, Some(vs)),
1016            (naga::ShaderStage::Fragment, desc.fragment.as_ref()),
1017        ];
1018        let (program, sampler_map) = self.create_shader_program(&shaders[..], &desc.layout)?;
1019
1020        let patch_size = match input_assembler.primitive {
1021            pso::Primitive::PatchList(size) => Some(size as _),
1022            _ => None,
1023        };
1024
1025        let mut uniforms = Vec::new();
1026        {
1027            let gl = &self.share.context;
1028            let count = gl.get_active_uniforms(program);
1029
1030            let mut offset = 0;
1031
1032            for uniform in 0..count {
1033                let glow::ActiveUniform { size, utype, name } =
1034                    gl.get_active_uniform(program, uniform).unwrap();
1035
1036                if let Some(location) = gl.get_uniform_location(program, &name) {
1037                    // Sampler2D won't show up in UniformLocation and the only other uniforms
1038                    // should be push constants
1039                    uniforms.push(n::UniformDesc {
1040                        location: Starc::new(location),
1041                        offset,
1042                        utype,
1043                    });
1044
1045                    offset += size as u32;
1046                }
1047            }
1048        }
1049
1050        Ok(n::GraphicsPipeline {
1051            program,
1052            primitive: conv::input_assember_to_gl_primitive(input_assembler),
1053            patch_size,
1054            blend_targets: desc.blender.targets.clone(),
1055            vertex_buffers,
1056            attributes: desc_attributes
1057                .iter()
1058                .map(|&a| {
1059                    let fd = conv::describe_format(a.element.format).unwrap();
1060                    n::AttributeDesc {
1061                        location: a.location,
1062                        offset: a.element.offset,
1063                        binding: a.binding,
1064                        size: fd.num_components as _,
1065                        format: fd.data_type,
1066                        vertex_attrib_fn: fd.va_fun,
1067                    }
1068                })
1069                .collect(),
1070            uniforms,
1071            rasterizer: desc.rasterizer,
1072            depth: desc.depth_stencil.depth,
1073            baked_states: desc.baked_states.clone(),
1074            sampler_map,
1075        })
1076    }
1077
1078    unsafe fn create_compute_pipeline<'a>(
1079        &self,
1080        desc: &pso::ComputePipelineDesc<'a, B>,
1081        _cache: Option<&()>,
1082    ) -> Result<n::ComputePipeline, pso::CreationError> {
1083        if self.share.public_caps.limits.max_compute_work_group_count[0] == 0 {
1084            return Err(pso::CreationError::UnsupportedPipeline);
1085        }
1086        let shader = (naga::ShaderStage::Compute, Some(&desc.shader));
1087        let (program, sampler_map) = self.create_shader_program(&[shader], &desc.layout)?;
1088        Ok(n::ComputePipeline {
1089            program,
1090            sampler_map,
1091        })
1092    }
1093
1094    unsafe fn create_framebuffer<I>(
1095        &self,
1096        _render_pass: &n::RenderPass,
1097        _attachments: I,
1098        _extent: i::Extent,
1099    ) -> Result<n::Framebuffer, d::OutOfMemory> {
1100        if !self.share.private_caps.framebuffer {
1101            return Err(d::OutOfMemory::Host);
1102        }
1103
1104        let gl = &self.share.context;
1105        let raw = gl.create_framebuffer().unwrap();
1106
1107        /*
1108        let attachments: Vec<_> = attachments
1109
1110            .map(|at| at.borrow().clone())
1111            .collect();
1112        log::debug!("create_framebuffer {:?}", attachments);
1113
1114        let target = glow::DRAW_FRAMEBUFFER;
1115
1116        let fbos = pass.subpasses.iter().map(|subpass| {
1117            let name = gl.create_framebuffer().unwrap();
1118            gl.bind_framebuffer(target, Some(name));
1119
1120            for (index, &color) in subpass.color_attachments.iter().enumerate() {
1121                let color_attachment = glow::COLOR_ATTACHMENT0 + index as u32;
1122                assert!(color_attachment <= glow::COLOR_ATTACHMENT31);
1123
1124                if self.share.private_caps.framebuffer_texture {
1125                    Self::bind_target(gl, target, color_attachment, &attachments[color]);
1126                } else {
1127                    Self::bind_target_compat(gl, target, color_attachment, &attachments[color]);
1128                }
1129            }
1130
1131            if let Some(depth_stencil) = subpass.depth_stencil {
1132                let aspects = match attachments[depth_stencil] {
1133                    n::ImageView::Texture { ref sub, .. } => sub.aspects,
1134                    n::ImageView::Renderbuffer { aspects, .. } => aspects,
1135                };
1136
1137                let attachment = if aspects == Aspects::DEPTH {
1138                    glow::DEPTH_ATTACHMENT
1139                } else if aspects == Aspects::STENCIL {
1140                    glow::STENCIL_ATTACHMENT
1141                } else {
1142                    glow::DEPTH_STENCIL_ATTACHMENT
1143                };
1144
1145                if self.share.private_caps.framebuffer_texture {
1146                    Self::bind_target(gl, target, attachment, &attachments[depth_stencil]);
1147                } else {
1148                    Self::bind_target_compat(gl, target, attachment, &attachments[depth_stencil]);
1149                }
1150            }
1151
1152            let status = gl.check_framebuffer_status(target);
1153            match status {
1154                glow::FRAMEBUFFER_COMPLETE => {},
1155                glow::FRAMEBUFFER_INCOMPLETE_ATTACHMENT => panic!("One of framebuffer attachmet points are incomplete"),
1156                glow::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT => panic!("Framebuffer does not have any image attached"),
1157                glow::FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER => panic!("FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"),
1158                glow::FRAMEBUFFER_INCOMPLETE_READ_BUFFER => panic!("FRAMEBUFFER_INCOMPLETE_READ_BUFFER"),
1159                glow::FRAMEBUFFER_UNSUPPORTED => panic!("FRAMEBUFFER_UNSUPPORTED"),
1160                glow::FRAMEBUFFER_INCOMPLETE_MULTISAMPLE => panic!("FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"),
1161                glow::FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS => panic!("FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS"),
1162                36057 /*glow::FRAMEBUFFER_INCOMPLETE_DIMENSIONS*/ => panic!("Framebuffer attachements have different dimensions"),
1163                code => panic!("Unexpected framebuffer status code {}", code),
1164            }
1165
1166            if let Err(err) = self.share.check() {
1167                //TODO: attachments have been consumed
1168                panic!("Error creating FBO: {:?} for {:?}", err, pass);
1169            }
1170
1171            Some(name)
1172        }).collect();
1173
1174        gl.bind_framebuffer(target, None);*/
1175
1176        Ok(n::Framebuffer { raw })
1177    }
1178
1179    unsafe fn create_shader_module(
1180        &self,
1181        raw_data: &[u32],
1182    ) -> Result<n::ShaderModule, d::ShaderError> {
1183        Ok(n::ShaderModule {
1184            #[cfg(feature = "cross")]
1185            spv: raw_data.to_vec(),
1186            naga: if cfg!(feature = "cross") {
1187                Err("Cross is enabled".into())
1188            } else {
1189                let options = naga::front::spv::Options {
1190                    adjust_coordinate_space: !self.features.contains(hal::Features::NDC_Y_UP),
1191                    strict_capabilities: true,
1192                    flow_graph_dump_prefix: None,
1193                };
1194                let parser = naga::front::spv::Parser::new(raw_data.iter().cloned(), &options);
1195                match parser.parse() {
1196                    Ok(module) => {
1197                        log::debug!("Naga module {:#?}", module);
1198                        match naga::valid::Validator::new(
1199                            naga::valid::ValidationFlags::empty(),
1200                            naga::valid::Capabilities::empty(), //TODO: PUSH_CONSTANT
1201                        )
1202                        .validate(&module)
1203                        {
1204                            Ok(info) => Ok(d::NagaShader { module, info }),
1205                            Err(e) => Err(format!("Naga validation: {}", e)),
1206                        }
1207                    }
1208                    Err(e) => Err(format!("Naga parsing: {:?}", e)),
1209                }
1210            },
1211        })
1212    }
1213
1214    unsafe fn create_shader_module_from_naga(
1215        &self,
1216        shader: d::NagaShader,
1217    ) -> Result<n::ShaderModule, (d::ShaderError, d::NagaShader)> {
1218        Ok(n::ShaderModule {
1219            #[cfg(feature = "cross")]
1220            spv: match naga::back::spv::write_vec(&shader.module, &shader.info, &self.spv_options) {
1221                Ok(spv) => spv,
1222                Err(e) => {
1223                    return Err((d::ShaderError::CompilationFailed(format!("{}", e)), shader))
1224                }
1225            },
1226            naga: Ok(shader),
1227        })
1228    }
1229
1230    unsafe fn create_sampler(
1231        &self,
1232        info: &i::SamplerDesc,
1233    ) -> Result<n::FatSampler, d::AllocationError> {
1234        assert!(info.normalized);
1235
1236        if !self
1237            .share
1238            .legacy_features
1239            .contains(LegacyFeatures::SAMPLER_OBJECTS)
1240        {
1241            return Ok(n::FatSampler::Info(info.clone()));
1242        }
1243
1244        let gl = &self.share.context;
1245
1246        let name = gl.create_sampler().unwrap();
1247        set_sampler_info(
1248            &info,
1249            &self.features,
1250            |a, b| gl.sampler_parameter_f32(name, a, b),
1251            |a, b| gl.sampler_parameter_f32_slice(name, a, b),
1252            |a, b| gl.sampler_parameter_i32(name, a, b),
1253        );
1254
1255        if let Err(_) = self.share.check() {
1256            Err(d::AllocationError::OutOfMemory(d::OutOfMemory::Host))
1257        } else {
1258            Ok(n::FatSampler::Sampler(name))
1259        }
1260    }
1261
1262    unsafe fn create_buffer(
1263        &self,
1264        size: u64,
1265        usage: buffer::Usage,
1266        _sparse: memory::SparseFlags,
1267    ) -> Result<n::Buffer, buffer::CreationError> {
1268        if !self
1269            .share
1270            .legacy_features
1271            .contains(LegacyFeatures::CONSTANT_BUFFER)
1272            && usage.contains(buffer::Usage::UNIFORM)
1273        {
1274            return Err(buffer::CreationError::UnsupportedUsage(usage));
1275        }
1276
1277        Ok(n::Buffer::Unbound { size, usage })
1278    }
1279
1280    unsafe fn get_buffer_requirements(&self, buffer: &n::Buffer) -> memory::Requirements {
1281        let (size, usage) = match *buffer {
1282            n::Buffer::Unbound { size, usage } => (size, usage),
1283            n::Buffer::Bound { .. } => panic!("Unexpected Buffer::Bound"),
1284        };
1285
1286        memory::Requirements {
1287            size: size as u64,
1288            // Alignment of 4 covers indexes of type u16 and u32 in index buffers, which is
1289            // currently the only alignment requirement.
1290            alignment: 4,
1291            type_mask: self.share.buffer_memory_type_mask(usage),
1292        }
1293    }
1294
1295    unsafe fn bind_buffer_memory(
1296        &self,
1297        memory: &n::Memory,
1298        offset: u64,
1299        buffer: &mut n::Buffer,
1300    ) -> Result<(), d::BindError> {
1301        let size = match *buffer {
1302            n::Buffer::Unbound { size, .. } => size,
1303            n::Buffer::Bound { .. } => panic!("Unexpected Buffer::Bound"),
1304        };
1305
1306        match memory.buffer {
1307            Some((raw, target)) => {
1308                *buffer = n::Buffer::Bound {
1309                    buffer: raw,
1310                    range: offset..offset + size,
1311                    target: target,
1312                };
1313            }
1314            None => {
1315                panic!("Improper memory type used for buffer memory");
1316            }
1317        }
1318
1319        Ok(())
1320    }
1321
1322    unsafe fn map_memory(
1323        &self,
1324        memory: &mut n::Memory,
1325        segment: memory::Segment,
1326    ) -> Result<*mut u8, d::MapError> {
1327        let gl = &self.share.context;
1328        let caps = &self.share.private_caps;
1329
1330        let offset = segment.offset;
1331        let size = segment.size.unwrap_or(memory.size - segment.offset);
1332
1333        let (buffer, target) = memory.buffer.expect("cannot map image memory");
1334        let ptr = if caps.emulate_map {
1335            let ptr: *mut u8 = if let Some(ptr) = memory.emulate_map_allocation {
1336                ptr
1337            } else {
1338                let ptr =
1339                    Box::into_raw(vec![0; memory.size as usize].into_boxed_slice()) as *mut u8;
1340                memory.emulate_map_allocation = Some(ptr);
1341                ptr
1342            };
1343
1344            ptr.offset(offset as isize)
1345        } else {
1346            gl.bind_buffer(target, Some(buffer));
1347            let raw = gl.map_buffer_range(target, offset as i32, size as i32, memory.map_flags);
1348            gl.bind_buffer(target, None);
1349            raw
1350        };
1351
1352        if let Err(err) = self.share.check() {
1353            panic!("Error mapping memory: {:?} for memory {:?}", err, memory);
1354        }
1355
1356        Ok(ptr)
1357    }
1358
1359    unsafe fn unmap_memory(&self, memory: &mut n::Memory) {
1360        let gl = &self.share.context;
1361        let (buffer, target) = memory.buffer.expect("cannot unmap image memory");
1362
1363        gl.bind_buffer(target, Some(buffer));
1364
1365        if self.share.private_caps.emulate_map {
1366            let ptr = memory.emulate_map_allocation.take().unwrap();
1367            let _ = Box::from_raw(slice::from_raw_parts_mut(ptr, memory.size as usize));
1368        } else {
1369            gl.unmap_buffer(target);
1370        }
1371
1372        gl.bind_buffer(target, None);
1373
1374        if let Err(err) = self.share.check() {
1375            panic!("Error unmapping memory: {:?} for memory {:?}", err, memory);
1376        }
1377    }
1378
1379    unsafe fn flush_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), d::OutOfMemory>
1380    where
1381        I: Iterator<Item = (&'a n::Memory, memory::Segment)>,
1382    {
1383        let gl = &self.share.context;
1384
1385        for (mem, segment) in ranges {
1386            let (buffer, target) = mem.buffer.expect("cannot flush image memory");
1387            gl.bind_buffer(target, Some(buffer));
1388
1389            let offset = segment.offset;
1390            let size = segment.size.unwrap_or(mem.size - segment.offset);
1391
1392            if self.share.private_caps.emulate_map {
1393                let ptr = mem.emulate_map_allocation.unwrap();
1394                let slice = slice::from_raw_parts_mut(ptr.offset(offset as isize), size as usize);
1395                gl.buffer_sub_data_u8_slice(target, offset as i32, slice);
1396            } else {
1397                gl.flush_mapped_buffer_range(target, offset as i32, size as i32);
1398            }
1399            gl.bind_buffer(target, None);
1400            if let Err(err) = self.share.check() {
1401                panic!(
1402                    "Error flushing memory range: {:?} for memory {:?}",
1403                    err, mem
1404                );
1405            }
1406        }
1407
1408        Ok(())
1409    }
1410
1411    unsafe fn invalidate_mapped_memory_ranges<'a, I>(&self, ranges: I) -> Result<(), d::OutOfMemory>
1412    where
1413        I: Iterator<Item = (&'a n::Memory, memory::Segment)>,
1414    {
1415        let gl = &self.share.context;
1416
1417        for (mem, segment) in ranges {
1418            let (buffer, target) = mem.buffer.expect("cannot invalidate image memory");
1419            gl.bind_buffer(target, Some(buffer));
1420
1421            let offset = segment.offset;
1422            let size = segment.size.unwrap_or(mem.size - segment.offset);
1423
1424            if self.share.private_caps.emulate_map {
1425                let ptr = mem.emulate_map_allocation.unwrap();
1426                let slice = slice::from_raw_parts_mut(ptr.offset(offset as isize), size as usize);
1427                gl.get_buffer_sub_data(target, offset as i32, slice);
1428            } else {
1429                gl.invalidate_buffer_sub_data(target, offset as i32, size as i32);
1430                gl.bind_buffer(target, None);
1431            }
1432
1433            if let Err(err) = self.share.check() {
1434                panic!(
1435                    "Error invalidating memory range: {:?} for memory {:?}",
1436                    err, mem
1437                );
1438            }
1439        }
1440
1441        Ok(())
1442    }
1443
1444    unsafe fn create_buffer_view(
1445        &self,
1446        _: &n::Buffer,
1447        _: Option<Format>,
1448        _: buffer::SubRange,
1449    ) -> Result<n::BufferView, buffer::ViewCreationError> {
1450        unimplemented!()
1451    }
1452
1453    unsafe fn create_image(
1454        &self,
1455        kind: i::Kind,
1456        num_levels: i::Level,
1457        format: Format,
1458        _tiling: i::Tiling,
1459        usage: i::Usage,
1460        _sparse: memory::SparseFlags,
1461        _view_caps: i::ViewCapabilities,
1462    ) -> Result<n::Image, i::CreationError> {
1463        let gl = &self.share.context;
1464
1465        let desc = conv::describe_format(format).ok_or(i::CreationError::Format(format))?;
1466        let channel = format.base_format().1;
1467
1468        let mut pixel_count: u64 = 0;
1469        let image = if num_levels > 1 || usage.intersects(i::Usage::STORAGE | i::Usage::SAMPLED) {
1470            let name = gl.create_texture().unwrap();
1471            let target = match kind {
1472                i::Kind::D2(w, h, 1, 1) => {
1473                    gl.bind_texture(glow::TEXTURE_2D, Some(name));
1474                    if self.share.private_caps.image_storage {
1475                        gl.tex_storage_2d(
1476                            glow::TEXTURE_2D,
1477                            num_levels as _,
1478                            desc.tex_internal,
1479                            w as _,
1480                            h as _,
1481                        );
1482                        pixel_count += (w * h) as u64 * num_levels as u64;
1483                    } else {
1484                        gl.tex_parameter_i32(
1485                            glow::TEXTURE_2D,
1486                            glow::TEXTURE_MAX_LEVEL,
1487                            (num_levels - 1) as _,
1488                        );
1489                        let mut w = w;
1490                        let mut h = h;
1491                        for i in 0..num_levels {
1492                            gl.tex_image_2d(
1493                                glow::TEXTURE_2D,
1494                                i as _,
1495                                desc.tex_internal as i32,
1496                                w as _,
1497                                h as _,
1498                                0,
1499                                desc.tex_external,
1500                                desc.data_type,
1501                                None,
1502                            );
1503                            pixel_count += (w * h) as u64;
1504                            w = std::cmp::max(w / 2, 1);
1505                            h = std::cmp::max(h / 2, 1);
1506                        }
1507                    }
1508                    match channel {
1509                        ChannelType::Uint | ChannelType::Sint => {
1510                            gl.tex_parameter_i32(
1511                                glow::TEXTURE_2D,
1512                                glow::TEXTURE_MIN_FILTER,
1513                                glow::NEAREST as _,
1514                            );
1515                            gl.tex_parameter_i32(
1516                                glow::TEXTURE_2D,
1517                                glow::TEXTURE_MAG_FILTER,
1518                                glow::NEAREST as _,
1519                            );
1520                        }
1521                        _ => {}
1522                    };
1523                    glow::TEXTURE_2D
1524                }
1525                i::Kind::D2(w, h, l, 1) => {
1526                    gl.bind_texture(glow::TEXTURE_2D_ARRAY, Some(name));
1527                    if self.share.private_caps.image_storage {
1528                        gl.tex_storage_3d(
1529                            glow::TEXTURE_2D_ARRAY,
1530                            num_levels as _,
1531                            desc.tex_internal,
1532                            w as _,
1533                            h as _,
1534                            l as _,
1535                        );
1536                        pixel_count += (w * h) as u64 * l as u64 * num_levels as u64;
1537                    } else {
1538                        gl.tex_parameter_i32(
1539                            glow::TEXTURE_2D_ARRAY,
1540                            glow::TEXTURE_MAX_LEVEL,
1541                            (num_levels - 1) as _,
1542                        );
1543                        let mut w = w;
1544                        let mut h = h;
1545                        for i in 0..num_levels {
1546                            gl.tex_image_3d(
1547                                glow::TEXTURE_2D_ARRAY,
1548                                i as _,
1549                                desc.tex_internal as i32,
1550                                w as _,
1551                                h as _,
1552                                l as _,
1553                                0,
1554                                desc.tex_external,
1555                                desc.data_type,
1556                                None,
1557                            );
1558                            pixel_count += (w * h) as u64 * l as u64;
1559                            w = std::cmp::max(w / 2, 1);
1560                            h = std::cmp::max(h / 2, 1);
1561                        }
1562                    }
1563                    match channel {
1564                        ChannelType::Uint | ChannelType::Sint => {
1565                            gl.tex_parameter_i32(
1566                                glow::TEXTURE_2D,
1567                                glow::TEXTURE_MIN_FILTER,
1568                                glow::NEAREST as _,
1569                            );
1570                            gl.tex_parameter_i32(
1571                                glow::TEXTURE_2D,
1572                                glow::TEXTURE_MAG_FILTER,
1573                                glow::NEAREST as _,
1574                            );
1575                        }
1576                        _ => {}
1577                    };
1578                    glow::TEXTURE_2D_ARRAY
1579                }
1580                _ => unimplemented!(),
1581            };
1582            n::ImageType::Texture {
1583                target,
1584                raw: name,
1585                format: desc.tex_external,
1586                pixel_type: desc.data_type,
1587                layer_count: kind.num_layers(),
1588                level_count: num_levels,
1589            }
1590        } else {
1591            let name = gl.create_renderbuffer().unwrap();
1592            gl.bind_renderbuffer(glow::RENDERBUFFER, Some(name));
1593            match kind {
1594                i::Kind::D2(w, h, 1, 1) => {
1595                    gl.renderbuffer_storage(glow::RENDERBUFFER, desc.tex_internal, w as _, h as _);
1596                    pixel_count += (w * h) as u64;
1597                }
1598                i::Kind::D2(w, h, 1, samples) => {
1599                    gl.renderbuffer_storage_multisample(
1600                        glow::RENDERBUFFER,
1601                        samples as _,
1602                        desc.tex_internal,
1603                        w as _,
1604                        h as _,
1605                    );
1606                    pixel_count += (w * h) as u64 * samples as u64; // Not sure though
1607                }
1608                _ => unimplemented!(),
1609            };
1610            n::ImageType::Renderbuffer {
1611                raw: name,
1612                format: desc.tex_external,
1613            }
1614        };
1615
1616        let surface_desc = format.base_format().0.desc();
1617        let bytes_per_texel = surface_desc.bits / 8;
1618        let size = pixel_count as u64 * bytes_per_texel as u64;
1619        let type_mask = self.share.image_memory_type_mask();
1620
1621        if let Err(err) = self.share.check() {
1622            panic!(
1623                "Error creating image: {:?} for kind {:?} of {:?}",
1624                err, kind, format
1625            );
1626        }
1627
1628        Ok(n::Image {
1629            object_type: image,
1630            kind,
1631            format_desc: surface_desc,
1632            channel,
1633            requirements: memory::Requirements {
1634                size,
1635                alignment: 1,
1636                type_mask,
1637            },
1638            num_levels,
1639            num_layers: kind.num_layers(),
1640        })
1641    }
1642
1643    unsafe fn get_image_requirements(&self, unbound: &n::Image) -> memory::Requirements {
1644        unbound.requirements
1645    }
1646
1647    unsafe fn get_image_subresource_footprint(
1648        &self,
1649        image: &n::Image,
1650        sub: i::Subresource,
1651    ) -> i::SubresourceFootprint {
1652        let num_layers = image.kind.num_layers() as buffer::Offset;
1653        let level_offset = (0..sub.level).fold(0, |offset, level| {
1654            let pitches = image.pitches(level);
1655            offset + num_layers * pitches[3]
1656        });
1657        let pitches = image.pitches(sub.level);
1658        let layer_offset = level_offset + sub.layer as buffer::Offset * pitches[3];
1659        i::SubresourceFootprint {
1660            slice: layer_offset..layer_offset + pitches[3],
1661            row_pitch: pitches[1] as _,
1662            depth_pitch: pitches[2] as _,
1663            array_pitch: pitches[3] as _,
1664        }
1665    }
1666
1667    unsafe fn bind_image_memory(
1668        &self,
1669        _memory: &n::Memory,
1670        _offset: u64,
1671        _image: &mut n::Image,
1672    ) -> Result<(), d::BindError> {
1673        Ok(())
1674    }
1675
1676    unsafe fn create_image_view(
1677        &self,
1678        image: &n::Image,
1679        kind: i::ViewKind,
1680        view_format: Format,
1681        swizzle: Swizzle,
1682        _usage: i::Usage,
1683        range: i::SubresourceRange,
1684    ) -> Result<n::ImageView, i::ViewCreationError> {
1685        assert_eq!(swizzle, Swizzle::NO);
1686        match image.object_type {
1687            n::ImageType::Renderbuffer { raw, .. } => {
1688                let level = range.level_start;
1689                if range.level_start == 0 && range.layer_start == 0 {
1690                    Ok(n::ImageView::Renderbuffer {
1691                        raw,
1692                        aspects: image.format_desc.aspects,
1693                    })
1694                } else if level != 0 {
1695                    Err(i::ViewCreationError::Level(level)) //TODO
1696                } else {
1697                    Err(i::ViewCreationError::Layer(i::LayerError::OutOfBounds))
1698                }
1699            }
1700            n::ImageType::Texture {
1701                target,
1702                raw,
1703                format,
1704                ..
1705            } => {
1706                let is_3d = match kind {
1707                    i::ViewKind::D1 | i::ViewKind::D2 => false,
1708                    _ => true,
1709                };
1710                match conv::describe_format(view_format) {
1711                    Some(description) => {
1712                        let raw_view_format = description.tex_external;
1713                        if format != raw_view_format {
1714                            log::warn!(
1715                                "View format {:?} is different from base {:?}",
1716                                raw_view_format,
1717                                format
1718                            );
1719                        }
1720                    }
1721                    None => {
1722                        log::warn!("View format {:?} is not supported", view_format);
1723                    }
1724                }
1725                Ok(n::ImageView::Texture {
1726                    target,
1727                    raw,
1728                    is_3d,
1729                    sub: range,
1730                })
1731            }
1732        }
1733    }
1734
1735    unsafe fn create_descriptor_pool<I>(
1736        &self,
1737        _: usize,
1738        _: I,
1739        _: pso::DescriptorPoolCreateFlags,
1740    ) -> Result<n::DescriptorPool, d::OutOfMemory>
1741    where
1742        I: Iterator<Item = pso::DescriptorRangeDesc>,
1743    {
1744        Ok(n::DescriptorPool {})
1745    }
1746
1747    unsafe fn create_descriptor_set_layout<'a, I, J>(
1748        &self,
1749        layout: I,
1750        _immutable_samplers: J,
1751    ) -> Result<n::DescriptorSetLayout, d::OutOfMemory>
1752    where
1753        I: Iterator<Item = pso::DescriptorSetLayoutBinding>,
1754        J: Iterator<Item = &'a n::FatSampler>,
1755    {
1756        let mut bindings = layout.collect::<Vec<_>>();
1757        // all operations rely on the ascending bindings order
1758        bindings.sort_by_key(|b| b.binding);
1759        Ok(Arc::new(bindings))
1760    }
1761
1762    unsafe fn write_descriptor_set<'a, I>(&self, op: pso::DescriptorSetWrite<'a, B, I>)
1763    where
1764        I: Iterator<Item = pso::Descriptor<'a, B>>,
1765    {
1766        let mut layout_index = op
1767            .set
1768            .layout
1769            .binary_search_by_key(&op.binding, |b| b.binding)
1770            .unwrap();
1771        let mut array_offset = op.array_offset;
1772
1773        for descriptor in op.descriptors {
1774            let binding_layout = &op.set.layout[layout_index];
1775            let binding = match descriptor {
1776                pso::Descriptor::Buffer(buffer, ref sub) => {
1777                    let bounded_buffer = buffer.as_bound();
1778                    let range = crate::resolve_sub_range(sub, bounded_buffer.range);
1779
1780                    let register = match binding_layout.ty {
1781                        pso::DescriptorType::Buffer { ty, .. } => match ty {
1782                            pso::BufferDescriptorType::Uniform => {
1783                                n::BindingRegister::UniformBuffers
1784                            }
1785                            pso::BufferDescriptorType::Storage { .. } => {
1786                                n::BindingRegister::StorageBuffers
1787                            }
1788                        },
1789                        other => {
1790                            panic!("Can't write buffer into descriptor of type {:?}", other)
1791                        }
1792                    };
1793
1794                    n::DescSetBindings::Buffer {
1795                        register,
1796                        buffer: bounded_buffer.raw,
1797                        offset: range.start as i32,
1798                        size: (range.end - range.start) as i32,
1799                    }
1800                }
1801                pso::Descriptor::CombinedImageSampler(view, _layout, sampler) => {
1802                    match *view {
1803                        n::ImageView::Texture { target, raw, .. } => op
1804                            .set
1805                            .bindings
1806                            .push(n::DescSetBindings::Texture(raw, target)),
1807                        n::ImageView::Renderbuffer { .. } => {
1808                            panic!("Texture doesn't support shader binding")
1809                        }
1810                    }
1811                    match *sampler {
1812                        n::FatSampler::Sampler(sampler) => n::DescSetBindings::Sampler(sampler),
1813                        n::FatSampler::Info(ref info) => {
1814                            n::DescSetBindings::SamplerDesc(info.clone())
1815                        }
1816                    }
1817                }
1818                pso::Descriptor::Image(view, _layout) => match *view {
1819                    n::ImageView::Texture { target, raw, .. } => {
1820                        n::DescSetBindings::Texture(raw, target)
1821                    }
1822                    n::ImageView::Renderbuffer { .. } => {
1823                        panic!("Texture doesn't support shader binding")
1824                    }
1825                },
1826                pso::Descriptor::Sampler(sampler) => match *sampler {
1827                    n::FatSampler::Sampler(sampler) => n::DescSetBindings::Sampler(sampler),
1828                    n::FatSampler::Info(ref info) => n::DescSetBindings::SamplerDesc(info.clone()),
1829                },
1830                pso::Descriptor::TexelBuffer(_view) => unimplemented!(),
1831            };
1832
1833            //TODO: overwrite instead of pushing on top
1834            op.set.bindings.push(binding);
1835
1836            array_offset += 1;
1837            if array_offset == binding_layout.count {
1838                array_offset = 0;
1839                layout_index += 1;
1840            }
1841        }
1842    }
1843
1844    unsafe fn copy_descriptor_set<'a>(&self, op: pso::DescriptorSetCopy<'a, B>) {
1845        if std::ptr::eq(op.src_set, &*op.dst_set) {
1846            panic!("copying within same descriptor set is not currently supported");
1847        }
1848
1849        // TODO: add support for array bindings when the OpenGL backend gets them
1850        let src_start = op.src_binding as usize;
1851        let src_end = src_start + op.count;
1852        assert!(src_end <= op.src_set.bindings.len());
1853
1854        let src_slice = &op.src_set.bindings[src_start..src_end];
1855
1856        let dst_start = op.dst_binding as usize;
1857        let dst_end = dst_start + op.count;
1858        assert!(dst_end <= op.dst_set.bindings.len());
1859
1860        op.dst_set.bindings[dst_start..dst_end].clone_from_slice(src_slice);
1861    }
1862
1863    fn create_semaphore(&self) -> Result<n::Semaphore, d::OutOfMemory> {
1864        Ok(n::Semaphore)
1865    }
1866
1867    fn create_fence(&self, signaled: bool) -> Result<n::Fence, d::OutOfMemory> {
1868        Ok(n::Fence::Idle { signaled })
1869    }
1870
1871    unsafe fn reset_fence(&self, fence: &mut n::Fence) -> Result<(), d::OutOfMemory> {
1872        *fence = n::Fence::Idle { signaled: false };
1873        Ok(())
1874    }
1875
1876    unsafe fn wait_for_fence(
1877        &self,
1878        fence: &n::Fence,
1879        timeout_ns: u64,
1880    ) -> Result<bool, d::WaitError> {
1881        // TODO:
1882        // This can be called by multiple objects wanting to ensure they have exclusive
1883        // access to a resource. How much does this call costs ? The status of the fence
1884        // could be cached to avoid calling this more than once (in core or in the backend ?).
1885        let gl = &self.share.context;
1886        match *fence {
1887            n::Fence::Idle { signaled } => {
1888                if !signaled {
1889                    log::warn!("Fence ptr {:?} is not pending, waiting not possible", fence);
1890                }
1891                Ok(signaled)
1892            }
1893            n::Fence::Pending(sync) => {
1894                // TODO: Could `wait_sync` be used here instead?
1895                match gl.client_wait_sync(sync, glow::SYNC_FLUSH_COMMANDS_BIT, timeout_ns as i32) {
1896                    glow::TIMEOUT_EXPIRED => Ok(false),
1897                    glow::WAIT_FAILED => {
1898                        if let Err(err) = self.share.check() {
1899                            log::error!("Error when waiting on fence: {:?}", err);
1900                        }
1901                        Ok(false)
1902                    }
1903                    glow::CONDITION_SATISFIED | glow::ALREADY_SIGNALED => {
1904                        //fence.0.set(n::Fence::Idle { signaled: true });
1905                        Ok(true)
1906                    }
1907                    _ => unreachable!(),
1908                }
1909            }
1910        }
1911    }
1912
1913    #[cfg(target_arch = "wasm32")]
1914    unsafe fn wait_for_fences<'a, I>(
1915        &self,
1916        fences: I,
1917        wait: d::WaitFor,
1918        timeout_ns: u64,
1919    ) -> Result<bool, d::WaitError>
1920    where
1921        I: Iterator<Item = &'a n::Fence>,
1922    {
1923        let performance = web_sys::window().unwrap().performance().unwrap();
1924        let start = performance.now();
1925        let get_elapsed = || ((performance.now() - start) * 1_000_000.0) as u64;
1926
1927        match wait {
1928            d::WaitFor::All => {
1929                for fence in fences {
1930                    if !self.wait_for_fence(fence, 0)? {
1931                        let elapsed_ns = get_elapsed();
1932                        if elapsed_ns > timeout_ns {
1933                            return Ok(false);
1934                        }
1935                        if !self.wait_for_fence(fence, timeout_ns - elapsed_ns)? {
1936                            return Ok(false);
1937                        }
1938                    }
1939                }
1940                Ok(true)
1941            }
1942            d::WaitFor::Any => {
1943                const FENCE_WAIT_NS: u64 = 100_000;
1944
1945                let fences: Vec<_> = fences.collect();
1946                loop {
1947                    for fence in &fences {
1948                        if self.wait_for_fence(fence, FENCE_WAIT_NS)? {
1949                            return Ok(true);
1950                        }
1951                    }
1952                    if get_elapsed() >= timeout_ns {
1953                        return Ok(false);
1954                    }
1955                }
1956            }
1957        }
1958    }
1959
1960    unsafe fn get_fence_status(&self, fence: &n::Fence) -> Result<bool, d::DeviceLost> {
1961        Ok(match *fence {
1962            n::Fence::Idle { signaled } => signaled,
1963            n::Fence::Pending(sync) => self.share.context.get_sync_status(sync) == glow::SIGNALED,
1964        })
1965    }
1966
1967    fn create_event(&self) -> Result<(), d::OutOfMemory> {
1968        unimplemented!()
1969    }
1970
1971    unsafe fn get_event_status(&self, _event: &()) -> Result<bool, d::WaitError> {
1972        unimplemented!()
1973    }
1974
1975    unsafe fn set_event(&self, _event: &mut ()) -> Result<(), d::OutOfMemory> {
1976        unimplemented!()
1977    }
1978
1979    unsafe fn reset_event(&self, _event: &mut ()) -> Result<(), d::OutOfMemory> {
1980        unimplemented!()
1981    }
1982
1983    unsafe fn free_memory(&self, memory: n::Memory) {
1984        if let Some((buffer, _)) = memory.buffer {
1985            self.share.context.delete_buffer(buffer);
1986        }
1987    }
1988
1989    unsafe fn create_query_pool(
1990        &self,
1991        ty: query::Type,
1992        _count: query::Id,
1993    ) -> Result<(), query::CreationError> {
1994        Err(query::CreationError::Unsupported(ty))
1995    }
1996
1997    unsafe fn destroy_query_pool(&self, _: ()) {
1998        unimplemented!()
1999    }
2000
2001    unsafe fn get_query_pool_results(
2002        &self,
2003        _pool: &(),
2004        _queries: Range<query::Id>,
2005        _data: &mut [u8],
2006        _stride: buffer::Stride,
2007        _flags: query::ResultFlags,
2008    ) -> Result<bool, d::WaitError> {
2009        unimplemented!()
2010    }
2011
2012    unsafe fn destroy_shader_module(&self, _: n::ShaderModule) {
2013        // Assumes compiled shaders are managed internally
2014    }
2015
2016    unsafe fn destroy_render_pass(&self, _: n::RenderPass) {
2017        // Nothing to do
2018    }
2019
2020    unsafe fn destroy_pipeline_layout(&self, _: n::PipelineLayout) {
2021        // Nothing to do
2022    }
2023
2024    unsafe fn destroy_graphics_pipeline(&self, pipeline: n::GraphicsPipeline) {
2025        self.share.context.delete_program(pipeline.program);
2026    }
2027
2028    unsafe fn destroy_compute_pipeline(&self, pipeline: n::ComputePipeline) {
2029        self.share.context.delete_program(pipeline.program);
2030    }
2031
2032    unsafe fn destroy_framebuffer(&self, framebuffer: n::Framebuffer) {
2033        self.share.context.delete_framebuffer(framebuffer.raw);
2034    }
2035
2036    unsafe fn destroy_buffer(&self, _buffer: n::Buffer) {
2037        // Nothing to do
2038    }
2039
2040    unsafe fn destroy_buffer_view(&self, _: n::BufferView) {
2041        // Nothing to do
2042    }
2043
2044    unsafe fn destroy_image(&self, image: n::Image) {
2045        let gl = &self.share.context;
2046        match image.object_type {
2047            n::ImageType::Renderbuffer { raw, .. } => gl.delete_renderbuffer(raw),
2048            n::ImageType::Texture { raw, .. } => gl.delete_texture(raw),
2049        }
2050    }
2051
2052    unsafe fn destroy_image_view(&self, _image_view: n::ImageView) {
2053        // Nothing to do
2054    }
2055
2056    unsafe fn destroy_sampler(&self, sampler: n::FatSampler) {
2057        let gl = &self.share.context;
2058        match sampler {
2059            n::FatSampler::Sampler(s) => gl.delete_sampler(s),
2060            _ => (),
2061        }
2062    }
2063
2064    unsafe fn destroy_descriptor_pool(&self, _: n::DescriptorPool) {
2065        // Nothing to do
2066    }
2067
2068    unsafe fn destroy_descriptor_set_layout(&self, _: n::DescriptorSetLayout) {
2069        // Nothing to do
2070    }
2071
2072    unsafe fn destroy_fence(&self, fence: n::Fence) {
2073        match fence {
2074            n::Fence::Idle { .. } => {}
2075            n::Fence::Pending(sync) => {
2076                self.share.context.delete_sync(sync);
2077            }
2078        }
2079    }
2080
2081    unsafe fn destroy_semaphore(&self, _: n::Semaphore) {
2082        // Nothing to do
2083    }
2084
2085    unsafe fn destroy_event(&self, _event: ()) {
2086        unimplemented!()
2087    }
2088
2089    fn wait_idle(&self) -> Result<(), d::OutOfMemory> {
2090        unsafe {
2091            self.share.context.finish();
2092        }
2093        Ok(())
2094    }
2095
2096    unsafe fn set_image_name(&self, _image: &mut n::Image, _name: &str) {
2097        // TODO
2098    }
2099
2100    unsafe fn set_buffer_name(&self, _buffer: &mut n::Buffer, _name: &str) {
2101        // TODO
2102    }
2103
2104    unsafe fn set_command_buffer_name(
2105        &self,
2106        _command_buffer: &mut cmd::CommandBuffer,
2107        _name: &str,
2108    ) {
2109        // TODO
2110    }
2111
2112    unsafe fn set_semaphore_name(&self, _semaphore: &mut n::Semaphore, _name: &str) {
2113        // TODO
2114    }
2115
2116    unsafe fn set_fence_name(&self, _fence: &mut n::Fence, _name: &str) {
2117        // TODO
2118    }
2119
2120    unsafe fn set_framebuffer_name(&self, _framebuffer: &mut n::Framebuffer, _name: &str) {
2121        // TODO
2122    }
2123
2124    unsafe fn set_render_pass_name(&self, _render_pass: &mut n::RenderPass, _name: &str) {
2125        // TODO
2126    }
2127
2128    unsafe fn set_descriptor_set_name(&self, _descriptor_set: &mut n::DescriptorSet, _name: &str) {
2129        // TODO
2130    }
2131
2132    unsafe fn set_descriptor_set_layout_name(
2133        &self,
2134        _descriptor_set_layout: &mut n::DescriptorSetLayout,
2135        _name: &str,
2136    ) {
2137        // TODO
2138    }
2139
2140    unsafe fn set_pipeline_layout_name(
2141        &self,
2142        _pipeline_layout: &mut n::PipelineLayout,
2143        _name: &str,
2144    ) {
2145        // TODO
2146    }
2147
2148    unsafe fn set_display_power_state(
2149        &self,
2150        _display: &hal::display::Display<B>,
2151        _power_state: &hal::display::control::PowerState,
2152    ) -> Result<(), hal::display::control::DisplayControlError> {
2153        unimplemented!()
2154    }
2155
2156    unsafe fn register_device_event(
2157        &self,
2158        _device_event: &hal::display::control::DeviceEvent,
2159        _fence: &mut <B as hal::Backend>::Fence,
2160    ) -> Result<(), hal::display::control::DisplayControlError> {
2161        unimplemented!()
2162    }
2163
2164    unsafe fn register_display_event(
2165        &self,
2166        _display: &hal::display::Display<B>,
2167        _display_event: &hal::display::control::DisplayEvent,
2168        _fence: &mut <B as hal::Backend>::Fence,
2169    ) -> Result<(), hal::display::control::DisplayControlError> {
2170        unimplemented!()
2171    }
2172
2173    unsafe fn create_allocate_external_buffer(
2174        &self,
2175        _external_memory_type: hal::external_memory::ExternalBufferMemoryType,
2176        _usage: hal::buffer::Usage,
2177        _sparse: hal::memory::SparseFlags,
2178        _type_mask: u32,
2179        _size: u64,
2180    ) -> Result<(n::Buffer, n::Memory), hal::external_memory::ExternalResourceError>
2181    {
2182        unimplemented!()
2183    }
2184
2185    unsafe fn import_external_buffer(
2186        &self,
2187        _external_memory: hal::external_memory::ExternalBufferMemory,
2188        _usage: hal::buffer::Usage,
2189        _sparse: hal::memory::SparseFlags,
2190        _type_mask: u32,
2191        _size: u64,
2192    ) -> Result<(n::Buffer, n::Memory), hal::external_memory::ExternalResourceError> {
2193        unimplemented!()
2194    }
2195
2196    unsafe fn create_allocate_external_image(
2197        &self,
2198        _external_memory_type: hal::external_memory::ExternalImageMemoryType,
2199        _kind: i::Kind,
2200        _num_levels: i::Level,
2201        _format: Format,
2202        _tiling: i::Tiling,
2203        _usage: i::Usage,
2204        _sparse: memory::SparseFlags,
2205        _view_caps: i::ViewCapabilities,
2206        _type_mask: u32,
2207    ) -> Result<(n::Image, n::Memory), hal::external_memory::ExternalResourceError> {
2208        unimplemented!()
2209    }
2210
2211    unsafe fn import_external_image(
2212        &self,
2213        _external_memory: hal::external_memory::ExternalImageMemory,
2214        _kind: i::Kind,
2215        _num_levels: i::Level,
2216        _format: Format,
2217        _tiling: i::Tiling,
2218        _usage: i::Usage,
2219        _sparse: memory::SparseFlags,
2220        _view_caps: i::ViewCapabilities,
2221        _type_mask: u32,
2222    ) -> Result<(n::Image, n::Memory), hal::external_memory::ExternalResourceError> {
2223        unimplemented!()
2224    }
2225
2226    unsafe fn export_memory(
2227        &self,
2228        _external_memory_type: hal::external_memory::ExternalMemoryType,
2229        _memory: &n::Memory,
2230    ) -> Result<hal::external_memory::PlatformMemory, hal::external_memory::ExternalMemoryExportError>
2231    {
2232        unimplemented!()
2233    }
2234
2235    unsafe fn drm_format_modifier(&self, _image: &n::Image) -> Option<hal::format::DrmModifier> {
2236        None
2237    }
2238
2239    fn start_capture(&self) {
2240        //TODO
2241    }
2242
2243    fn stop_capture(&self) {
2244        //TODO
2245    }
2246}