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#[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 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 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 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 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 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 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 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 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 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 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); 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: _, } => 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 Ok(Vec::new())
966 }
967
968 unsafe fn destroy_pipeline_cache(&self, _: ()) {
969 }
971
972 unsafe fn merge_pipeline_caches<'a, I>(&self, _: &mut (), _: I) -> Result<(), d::OutOfMemory>
973 where
974 I: Iterator<Item = &'a ()>,
975 {
976 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 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 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(), )
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: 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; }
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)) } 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 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 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 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 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 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 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 }
2015
2016 unsafe fn destroy_render_pass(&self, _: n::RenderPass) {
2017 }
2019
2020 unsafe fn destroy_pipeline_layout(&self, _: n::PipelineLayout) {
2021 }
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 }
2039
2040 unsafe fn destroy_buffer_view(&self, _: n::BufferView) {
2041 }
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 }
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 }
2067
2068 unsafe fn destroy_descriptor_set_layout(&self, _: n::DescriptorSetLayout) {
2069 }
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 }
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 }
2099
2100 unsafe fn set_buffer_name(&self, _buffer: &mut n::Buffer, _name: &str) {
2101 }
2103
2104 unsafe fn set_command_buffer_name(
2105 &self,
2106 _command_buffer: &mut cmd::CommandBuffer,
2107 _name: &str,
2108 ) {
2109 }
2111
2112 unsafe fn set_semaphore_name(&self, _semaphore: &mut n::Semaphore, _name: &str) {
2113 }
2115
2116 unsafe fn set_fence_name(&self, _fence: &mut n::Fence, _name: &str) {
2117 }
2119
2120 unsafe fn set_framebuffer_name(&self, _framebuffer: &mut n::Framebuffer, _name: &str) {
2121 }
2123
2124 unsafe fn set_render_pass_name(&self, _render_pass: &mut n::RenderPass, _name: &str) {
2125 }
2127
2128 unsafe fn set_descriptor_set_name(&self, _descriptor_set: &mut n::DescriptorSet, _name: &str) {
2129 }
2131
2132 unsafe fn set_descriptor_set_layout_name(
2133 &self,
2134 _descriptor_set_layout: &mut n::DescriptorSetLayout,
2135 _name: &str,
2136 ) {
2137 }
2139
2140 unsafe fn set_pipeline_layout_name(
2141 &self,
2142 _pipeline_layout: &mut n::PipelineLayout,
2143 _name: &str,
2144 ) {
2145 }
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 }
2242
2243 fn stop_capture(&self) {
2244 }
2246}