1 use crate::{
2     internal::{Channel, FastStorageMap},
3     window::SwapchainImage,
4     Backend,
5     BufferPtr,
6     ResourceIndex,
7     SamplerPtr,
8     TexturePtr,
9     MAX_COLOR_ATTACHMENTS,
10 };
11 
12 use auxil::FastHashMap;
13 use hal::{
14     buffer,
15     format::FormatDesc,
16     image,
17     pass::{Attachment, AttachmentId},
18     pso,
19     range::RangeArg,
20     MemoryTypeId,
21 };
22 use range_alloc::RangeAllocator;
23 
24 use arrayvec::ArrayVec;
25 use cocoa::foundation::NSRange;
26 use metal;
27 use parking_lot::{Mutex, RwLock};
28 use spirv_cross::{msl, spirv};
29 
30 use std::{
31     cell::RefCell,
32     fmt,
33     ops::Range,
34     os::raw::{c_long, c_void},
35     ptr,
36     sync::{atomic::AtomicBool, Arc},
37 };
38 
39 
40 pub type EntryPointMap = FastHashMap<String, spirv::EntryPoint>;
41 /// An index of a resource within descriptor pool.
42 pub type PoolResourceIndex = u32;
43 
44 /// Shader module can be compiled in advance if it's resource bindings do not
45 /// depend on pipeline layout, in which case the value would become `Compiled`.
46 pub enum ShaderModule {
47     Compiled(ModuleInfo),
48     Raw(Vec<u32>),
49 }
50 
51 impl fmt::Debug for ShaderModule {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result52     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
53         match *self {
54             ShaderModule::Compiled(_) => write!(formatter, "ShaderModule::Compiled(..)"),
55             ShaderModule::Raw(ref vec) => {
56                 write!(formatter, "ShaderModule::Raw(length = {})", vec.len())
57             }
58         }
59     }
60 }
61 
62 unsafe impl Send for ShaderModule {}
63 unsafe impl Sync for ShaderModule {}
64 
65 bitflags! {
66     /// Subpass attachment operations.
67     pub struct SubpassOps: u8 {
68         const LOAD = 0x0;
69         const STORE = 0x1;
70     }
71 }
72 
73 #[derive(Clone, Debug, Default, Eq, PartialEq)]
74 pub struct SubpassFormats {
75     pub colors: ArrayVec<[(metal::MTLPixelFormat, Channel); MAX_COLOR_ATTACHMENTS]>,
76     pub depth_stencil: Option<metal::MTLPixelFormat>,
77 }
78 
79 impl SubpassFormats {
copy_from(&mut self, other: &Self)80     pub fn copy_from(&mut self, other: &Self) {
81         self.colors.clear();
82         self.colors.extend(other.colors.iter().cloned());
83         self.depth_stencil = other.depth_stencil;
84     }
85 }
86 
87 #[derive(Debug)]
88 pub struct Subpass {
89     pub colors: ArrayVec<[(AttachmentId, SubpassOps, Option<AttachmentId>); MAX_COLOR_ATTACHMENTS]>,
90     pub depth_stencil: Option<(AttachmentId, SubpassOps)>,
91     pub inputs: Vec<AttachmentId>,
92     pub target_formats: SubpassFormats,
93 }
94 
95 #[derive(Debug)]
96 pub struct RenderPass {
97     pub(crate) attachments: Vec<Attachment>,
98     pub(crate) subpasses: Vec<Subpass>,
99     pub(crate) name: String,
100 }
101 
102 #[derive(Debug)]
103 pub struct Framebuffer {
104     pub(crate) extent: image::Extent,
105     pub(crate) attachments: Vec<metal::Texture>,
106 }
107 
108 unsafe impl Send for Framebuffer {}
109 unsafe impl Sync for Framebuffer {}
110 
111 
112 #[derive(Clone, Debug)]
113 pub struct ResourceData<T> {
114     pub buffers: T,
115     pub textures: T,
116     pub samplers: T,
117 }
118 
119 impl<T> ResourceData<T> {
map<V, F: Fn(&T) -> V>(&self, fun: F) -> ResourceData<V>120     pub fn map<V, F: Fn(&T) -> V>(&self, fun: F) -> ResourceData<V> {
121         ResourceData {
122             buffers: fun(&self.buffers),
123             textures: fun(&self.textures),
124             samplers: fun(&self.samplers),
125         }
126     }
127 }
128 
129 impl<T: Copy + Ord> ResourceData<Range<T>> {
expand(&mut self, point: ResourceData<T>)130     pub fn expand(&mut self, point: ResourceData<T>) {
131         //TODO: modify `start` as well?
132         self.buffers.end = self.buffers.end.max(point.buffers);
133         self.textures.end = self.textures.end.max(point.textures);
134         self.samplers.end = self.samplers.end.max(point.samplers);
135     }
136 }
137 
138 impl ResourceData<PoolResourceIndex> {
new() -> Self139     pub fn new() -> Self {
140         ResourceData {
141             buffers: 0,
142             textures: 0,
143             samplers: 0,
144         }
145     }
146 }
147 /*
148 impl ResourceData<ResourceIndex> {
149     pub fn new() -> Self {
150         ResourceCounters {
151             buffers: 0,
152             textures: 0,
153             samplers: 0,
154         }
155     }
156 }
157 */
158 impl ResourceData<PoolResourceIndex> {
159     #[inline]
add_many(&mut self, content: DescriptorContent, count: PoolResourceIndex)160     pub fn add_many(&mut self, content: DescriptorContent, count: PoolResourceIndex) {
161         if content.contains(DescriptorContent::BUFFER) {
162             self.buffers += count;
163         }
164         if content.contains(DescriptorContent::TEXTURE) {
165             self.textures += count;
166         }
167         if content.contains(DescriptorContent::SAMPLER) {
168             self.samplers += count;
169         }
170     }
171     #[inline]
add(&mut self, content: DescriptorContent)172     pub fn add(&mut self, content: DescriptorContent) {
173         self.add_many(content, 1)
174     }
175 }
176 
177 #[derive(Debug)]
178 pub struct MultiStageData<T> {
179     pub vs: T,
180     pub ps: T,
181     pub cs: T,
182 }
183 
184 pub type MultiStageResourceCounters = MultiStageData<ResourceData<ResourceIndex>>;
185 
186 #[derive(Debug)]
187 pub struct DescriptorSetInfo {
188     pub offsets: MultiStageResourceCounters,
189     pub dynamic_buffers: Vec<MultiStageData<PoolResourceIndex>>,
190 }
191 
192 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
193 pub struct PushConstantInfo {
194     pub count: u32,
195     pub buffer_index: ResourceIndex,
196 }
197 
198 #[derive(Debug)]
199 pub struct PipelineLayout {
200     pub(crate) shader_compiler_options: msl::CompilerOptions,
201     pub(crate) shader_compiler_options_point: msl::CompilerOptions,
202     pub(crate) infos: Vec<DescriptorSetInfo>,
203     pub(crate) total: MultiStageResourceCounters,
204     pub(crate) push_constants: MultiStageData<Option<PushConstantInfo>>,
205     pub(crate) total_push_constants: u32,
206 }
207 
208 #[derive(Clone)]
209 pub struct ModuleInfo {
210     pub library: metal::Library,
211     pub entry_point_map: EntryPointMap,
212     pub rasterization_enabled: bool,
213 }
214 
215 pub struct PipelineCache {
216     pub(crate) modules: FastStorageMap<msl::CompilerOptions, FastStorageMap<Vec<u32>, ModuleInfo>>,
217 }
218 
219 impl fmt::Debug for PipelineCache {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result220     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
221         write!(formatter, "PipelineCache")
222     }
223 }
224 
225 #[derive(Clone, Debug, PartialEq)]
226 pub struct RasterizerState {
227     //TODO: more states
228     pub front_winding: metal::MTLWinding,
229     pub fill_mode: metal::MTLTriangleFillMode,
230     pub cull_mode: metal::MTLCullMode,
231     pub depth_clip: Option<metal::MTLDepthClipMode>,
232 }
233 
234 impl Default for RasterizerState {
default() -> Self235     fn default() -> Self {
236         RasterizerState {
237             front_winding: metal::MTLWinding::Clockwise,
238             fill_mode: metal::MTLTriangleFillMode::Fill,
239             cull_mode: metal::MTLCullMode::None,
240             depth_clip: None,
241         }
242     }
243 }
244 
245 #[derive(Debug)]
246 pub struct StencilState<T: Clone> {
247     pub reference_values: pso::Sided<T>,
248     pub read_masks: pso::Sided<T>,
249     pub write_masks: pso::Sided<T>,
250 }
251 
252 pub type VertexBufferVec = Vec<(pso::VertexBufferDesc, pso::ElemOffset)>;
253 
254 #[derive(Debug)]
255 pub struct GraphicsPipeline {
256     // we hold the compiled libraries here for now
257     // TODO: move to some cache in `Device`
258     pub(crate) vs_lib: metal::Library,
259     pub(crate) fs_lib: Option<metal::Library>,
260     pub(crate) raw: metal::RenderPipelineState,
261     pub(crate) primitive_type: metal::MTLPrimitiveType,
262     pub(crate) vs_pc_info: Option<PushConstantInfo>,
263     pub(crate) ps_pc_info: Option<PushConstantInfo>,
264     pub(crate) rasterizer_state: Option<RasterizerState>,
265     pub(crate) depth_bias: pso::State<pso::DepthBias>,
266     pub(crate) depth_stencil_desc: pso::DepthStencilDesc,
267     pub(crate) baked_states: pso::BakedStates,
268     /// The mapping from Metal vertex buffers to Vulkan ones.
269     /// This is needed because Vulkan allows attribute offsets to exceed the strides,
270     /// while Metal does not. Thus, we register extra vertex buffer bindings with
271     /// adjusted offsets to cover this use case.
272     pub(crate) vertex_buffers: VertexBufferVec,
273     /// Tracked attachment formats
274     pub(crate) attachment_formats: SubpassFormats,
275 }
276 
277 unsafe impl Send for GraphicsPipeline {}
278 unsafe impl Sync for GraphicsPipeline {}
279 
280 #[derive(Debug)]
281 pub struct ComputePipeline {
282     pub(crate) cs_lib: metal::Library,
283     pub(crate) raw: metal::ComputePipelineState,
284     pub(crate) work_group_size: metal::MTLSize,
285     pub(crate) pc_info: Option<PushConstantInfo>,
286 }
287 
288 unsafe impl Send for ComputePipeline {}
289 unsafe impl Sync for ComputePipeline {}
290 
291 #[derive(Debug)]
292 pub enum ImageLike {
293     /// This image has not yet been bound to memory.
294     Unbound {
295         descriptor: metal::TextureDescriptor,
296         mip_sizes: Vec<buffer::Offset>,
297         host_visible: bool,
298         name: String,
299     },
300     /// This is a linearly tiled HOST-visible image, which is represented by a buffer.
301     Buffer(Buffer),
302     /// This is a regular image represented by a texture.
303     Texture(metal::Texture),
304 }
305 
306 impl ImageLike {
as_texture(&self) -> &metal::TextureRef307     pub fn as_texture(&self) -> &metal::TextureRef {
308         match *self {
309             ImageLike::Unbound { .. } | ImageLike::Buffer(..) => panic!("Expected bound image!"),
310             ImageLike::Texture(ref tex) => tex,
311         }
312     }
313 }
314 
315 #[derive(Debug)]
316 pub struct Image {
317     pub(crate) like: ImageLike,
318     pub(crate) kind: image::Kind,
319     pub(crate) format_desc: FormatDesc,
320     pub(crate) shader_channel: Channel,
321     pub(crate) mtl_format: metal::MTLPixelFormat,
322     pub(crate) mtl_type: metal::MTLTextureType,
323 }
324 
325 impl Image {
pitches_impl( extent: image::Extent, format_desc: FormatDesc, ) -> [buffer::Offset; 4]326     pub(crate) fn pitches_impl(
327         extent: image::Extent,
328         format_desc: FormatDesc,
329     ) -> [buffer::Offset; 4] {
330         let bytes_per_texel = format_desc.bits as image::Size >> 3;
331         let row_pitch = extent.width * bytes_per_texel;
332         let depth_pitch = extent.height * row_pitch;
333         let array_pitch = extent.depth * depth_pitch;
334         [
335             bytes_per_texel as _,
336             row_pitch as _,
337             depth_pitch as _,
338             array_pitch as _,
339         ]
340     }
pitches(&self, level: image::Level) -> [buffer::Offset; 4]341     pub(crate) fn pitches(&self, level: image::Level) -> [buffer::Offset; 4] {
342         let extent = self.kind.extent().at_level(level);
343         Self::pitches_impl(extent, self.format_desc)
344     }
byte_offset(&self, offset: image::Offset) -> buffer::Offset345     pub(crate) fn byte_offset(&self, offset: image::Offset) -> buffer::Offset {
346         let pitches = Self::pitches_impl(self.kind.extent(), self.format_desc);
347         pitches[0] * offset.x as buffer::Offset
348             + pitches[1] * offset.y as buffer::Offset
349             + pitches[2] * offset.z as buffer::Offset
350     }
byte_extent(&self, extent: image::Extent) -> buffer::Offset351     pub(crate) fn byte_extent(&self, extent: image::Extent) -> buffer::Offset {
352         let bytes_per_texel = self.format_desc.bits as image::Size >> 3;
353         (bytes_per_texel * extent.width * extent.height * extent.depth) as _
354     }
355     /// View this cube texture as a 2D array.
view_cube_as_2d(&self) -> Option<metal::Texture>356     pub(crate) fn view_cube_as_2d(&self) -> Option<metal::Texture> {
357         match self.mtl_type {
358             metal::MTLTextureType::Cube | metal::MTLTextureType::CubeArray => {
359                 let raw = self.like.as_texture();
360                 Some(raw.new_texture_view_from_slice(
361                     self.mtl_format,
362                     metal::MTLTextureType::D2Array,
363                     NSRange {
364                         location: 0,
365                         length: raw.mipmap_level_count(),
366                     },
367                     NSRange {
368                         location: 0,
369                         length: self.kind.num_layers() as _,
370                     },
371                 ))
372             }
373             _ => None,
374         }
375     }
376 }
377 
378 unsafe impl Send for Image {}
379 unsafe impl Sync for Image {}
380 
381 #[derive(Debug)]
382 pub struct BufferView {
383     pub(crate) raw: metal::Texture,
384 }
385 
386 unsafe impl Send for BufferView {}
387 unsafe impl Sync for BufferView {}
388 
389 #[derive(Debug)]
390 pub struct ImageView {
391     pub(crate) texture: metal::Texture,
392     pub(crate) mtl_format: metal::MTLPixelFormat,
393 }
394 
395 unsafe impl Send for ImageView {}
396 unsafe impl Sync for ImageView {}
397 
398 #[derive(Debug)]
399 pub struct Sampler {
400     pub(crate) raw: Option<metal::SamplerState>,
401     pub(crate) data: msl::SamplerData,
402 }
403 
404 unsafe impl Send for Sampler {}
405 unsafe impl Sync for Sampler {}
406 
407 #[derive(Clone, Debug)]
408 pub struct Semaphore {
409     pub(crate) system: Option<SystemSemaphore>,
410     pub(crate) image_ready: Arc<Mutex<Option<SwapchainImage>>>,
411 }
412 
413 #[derive(Debug)]
414 pub enum Buffer {
415     Unbound {
416         size: u64,
417         usage: buffer::Usage,
418         name: String,
419     },
420     Bound {
421         raw: metal::Buffer,
422         range: Range<u64>,
423         options: metal::MTLResourceOptions,
424     },
425 }
426 
427 unsafe impl Send for Buffer {}
428 unsafe impl Sync for Buffer {}
429 
430 impl Buffer {
431     //TODO: consider returning `AsNative`?
as_bound(&self) -> (&metal::BufferRef, &Range<u64>)432     pub fn as_bound(&self) -> (&metal::BufferRef, &Range<u64>) {
433         match *self {
434             Buffer::Unbound { .. } => panic!("Expected bound buffer!"),
435             Buffer::Bound {
436                 ref raw, ref range, ..
437             } => (raw, range),
438         }
439     }
440 }
441 
442 #[derive(Debug)]
443 pub struct DescriptorEmulatedPoolInner {
444     pub(crate) samplers: Vec<Option<SamplerPtr>>,
445     pub(crate) textures: Vec<Option<(TexturePtr, image::Layout)>>,
446     pub(crate) buffers: Vec<Option<(BufferPtr, buffer::Offset)>>,
447 }
448 
449 #[derive(Debug)]
450 pub struct DescriptorArgumentPoolInner {
451     pub(crate) resources: Vec<UsedResource>,
452 }
453 
454 #[derive(Debug)]
455 pub enum DescriptorPool {
456     Emulated {
457         inner: Arc<RwLock<DescriptorEmulatedPoolInner>>,
458         allocators: ResourceData<RangeAllocator<PoolResourceIndex>>,
459     },
460     ArgumentBuffer {
461         raw: metal::Buffer,
462         raw_allocator: RangeAllocator<buffer::Offset>,
463         alignment: buffer::Offset,
464         inner: Arc<RwLock<DescriptorArgumentPoolInner>>,
465         res_allocator: RangeAllocator<PoolResourceIndex>,
466     },
467 }
468 //TODO: re-evaluate Send/Sync here
469 unsafe impl Send for DescriptorPool {}
470 unsafe impl Sync for DescriptorPool {}
471 
472 impl DescriptorPool {
new_emulated(counters: ResourceData<PoolResourceIndex>) -> Self473     pub(crate) fn new_emulated(counters: ResourceData<PoolResourceIndex>) -> Self {
474         let inner = DescriptorEmulatedPoolInner {
475             samplers: vec![None; counters.samplers as usize],
476             textures: vec![None; counters.textures as usize],
477             buffers: vec![None; counters.buffers as usize],
478         };
479         DescriptorPool::Emulated {
480             inner: Arc::new(RwLock::new(inner)),
481             allocators: ResourceData {
482                 samplers: RangeAllocator::new(0 .. counters.samplers),
483                 textures: RangeAllocator::new(0 .. counters.textures),
484                 buffers: RangeAllocator::new(0 .. counters.buffers),
485             },
486         }
487     }
488 
new_argument( raw: metal::Buffer, total_bytes: buffer::Offset, alignment: buffer::Offset, total_resources: usize, ) -> Self489     pub(crate) fn new_argument(
490         raw: metal::Buffer,
491         total_bytes: buffer::Offset,
492         alignment: buffer::Offset,
493         total_resources: usize,
494     ) -> Self {
495         let default = UsedResource {
496             ptr: ptr::null_mut(),
497             usage: metal::MTLResourceUsage::empty(),
498         };
499         DescriptorPool::ArgumentBuffer {
500             raw,
501             raw_allocator: RangeAllocator::new(0 .. total_bytes),
502             alignment,
503             inner: Arc::new(RwLock::new(DescriptorArgumentPoolInner {
504                 resources: vec![default; total_resources],
505             })),
506             res_allocator: RangeAllocator::new(0 .. total_resources as PoolResourceIndex),
507         }
508     }
509 
report_available(&self)510     fn report_available(&self) {
511         match *self {
512             DescriptorPool::Emulated { ref allocators, .. } => {
513                 trace!(
514                     "\tavailable {} samplers, {} textures, and {} buffers",
515                     allocators.samplers.total_available(),
516                     allocators.textures.total_available(),
517                     allocators.buffers.total_available(),
518                 );
519             }
520             DescriptorPool::ArgumentBuffer {
521                 ref raw_allocator,
522                 ref res_allocator,
523                 ..
524             } => {
525                 trace!(
526                     "\tavailable {} bytes for {} resources",
527                     raw_allocator.total_available(),
528                     res_allocator.total_available(),
529                 );
530             }
531         }
532     }
533 }
534 
535 impl pso::DescriptorPool<Backend> for DescriptorPool {
allocate_set( &mut self, set_layout: &DescriptorSetLayout, ) -> Result<DescriptorSet, pso::AllocationError>536     unsafe fn allocate_set(
537         &mut self,
538         set_layout: &DescriptorSetLayout,
539     ) -> Result<DescriptorSet, pso::AllocationError> {
540         self.report_available();
541         match *self {
542             DescriptorPool::Emulated {
543                 ref inner,
544                 ref mut allocators,
545             } => {
546                 debug!("pool: allocate_set");
547                 let layouts = match *set_layout {
548                     DescriptorSetLayout::Emulated(ref layouts, _) => layouts,
549                     _ => return Err(pso::AllocationError::IncompatibleLayout),
550                 };
551 
552                 // step[1]: count the total number of descriptors needed
553                 let mut total = ResourceData::new();
554                 for layout in layouts.iter() {
555                     total.add(layout.content);
556                 }
557                 debug!("\ttotal {:?}", total);
558 
559                 // step[2]: try to allocate the ranges from the pool
560                 let sampler_range = if total.samplers != 0 {
561                     match allocators.samplers.allocate_range(total.samplers as _) {
562                         Ok(range) => range,
563                         Err(e) => {
564                             return Err(if e.fragmented_free_length >= total.samplers {
565                                 pso::AllocationError::FragmentedPool
566                             } else {
567                                 pso::AllocationError::OutOfPoolMemory
568                             });
569                         }
570                     }
571                 } else {
572                     0 .. 0
573                 };
574                 let texture_range = if total.textures != 0 {
575                     match allocators.textures.allocate_range(total.textures as _) {
576                         Ok(range) => range,
577                         Err(e) => {
578                             if sampler_range.end != 0 {
579                                 allocators.samplers.free_range(sampler_range);
580                             }
581                             return Err(if e.fragmented_free_length >= total.samplers {
582                                 pso::AllocationError::FragmentedPool
583                             } else {
584                                 pso::AllocationError::OutOfPoolMemory
585                             });
586                         }
587                     }
588                 } else {
589                     0 .. 0
590                 };
591                 let buffer_range = if total.buffers != 0 {
592                     match allocators.buffers.allocate_range(total.buffers as _) {
593                         Ok(range) => range,
594                         Err(e) => {
595                             if sampler_range.end != 0 {
596                                 allocators.samplers.free_range(sampler_range);
597                             }
598                             if texture_range.end != 0 {
599                                 allocators.textures.free_range(texture_range);
600                             }
601                             return Err(if e.fragmented_free_length >= total.samplers {
602                                 pso::AllocationError::FragmentedPool
603                             } else {
604                                 pso::AllocationError::OutOfPoolMemory
605                             });
606                         }
607                     }
608                 } else {
609                     0 .. 0
610                 };
611 
612                 let resources = ResourceData {
613                     buffers: buffer_range,
614                     textures: texture_range,
615                     samplers: sampler_range,
616                 };
617 
618                 Ok(DescriptorSet::Emulated {
619                     pool: Arc::clone(inner),
620                     layouts: Arc::clone(layouts),
621                     resources,
622                 })
623             }
624             DescriptorPool::ArgumentBuffer {
625                 ref raw,
626                 ref mut raw_allocator,
627                 alignment,
628                 ref inner,
629                 ref mut res_allocator,
630             } => {
631                 let (encoder, stage_flags, bindings, total) = match *set_layout {
632                     DescriptorSetLayout::ArgumentBuffer {
633                         ref encoder,
634                         stage_flags,
635                         ref bindings,
636                         total,
637                         ..
638                     } => (encoder, stage_flags, bindings, total),
639                     _ => return Err(pso::AllocationError::IncompatibleLayout),
640                 };
641                 let range = res_allocator
642                     .allocate_range(total as PoolResourceIndex)
643                     .map_err(|_| pso::AllocationError::OutOfPoolMemory)?;
644 
645                 let raw_range = raw_allocator
646                     .allocate_range(encoder.encoded_length() + alignment)
647                     .expect("Argument encoding length is inconsistent!");
648                 let raw_offset = (raw_range.start + alignment - 1) & !(alignment - 1);
649 
650                 let mut data = inner.write();
651                 for arg in bindings.values() {
652                     if arg.res.buffer_id != !0 || arg.res.texture_id != !0 {
653                         let pos = (range.start + arg.res_offset) as usize;
654                         for ur in data.resources[pos .. pos + arg.count].iter_mut() {
655                             ur.usage = arg.usage;
656                         }
657                     }
658                 }
659 
660                 Ok(DescriptorSet::ArgumentBuffer {
661                     raw: raw.clone(),
662                     raw_offset,
663                     pool: Arc::clone(inner),
664                     range,
665                     encoder: encoder.clone(),
666                     bindings: Arc::clone(bindings),
667                     stage_flags,
668                 })
669             }
670         }
671     }
672 
free_sets<I>(&mut self, descriptor_sets: I) where I: IntoIterator<Item = DescriptorSet>,673     unsafe fn free_sets<I>(&mut self, descriptor_sets: I)
674     where
675         I: IntoIterator<Item = DescriptorSet>,
676     {
677         match self {
678             DescriptorPool::Emulated {
679                 ref inner,
680                 ref mut allocators,
681             } => {
682                 debug!("pool: free_sets");
683                 let mut data = inner.write();
684                 for descriptor_set in descriptor_sets {
685                     match descriptor_set {
686                         DescriptorSet::Emulated { resources, .. } => {
687                             debug!("\t{:?} resources", resources);
688                             for sampler in &mut data.samplers[resources.samplers.start as usize
689                                 .. resources.samplers.end as usize]
690                             {
691                                 *sampler = None;
692                             }
693                             if resources.samplers.start != resources.samplers.end {
694                                 allocators.samplers.free_range(resources.samplers);
695                             }
696                             for image in &mut data.textures[resources.textures.start as usize
697                                 .. resources.textures.end as usize]
698                             {
699                                 *image = None;
700                             }
701                             if resources.textures.start != resources.textures.end {
702                                 allocators.textures.free_range(resources.textures);
703                             }
704                             for buffer in &mut data.buffers
705                                 [resources.buffers.start as usize .. resources.buffers.end as usize]
706                             {
707                                 *buffer = None;
708                             }
709                             if resources.buffers.start != resources.buffers.end {
710                                 allocators.buffers.free_range(resources.buffers);
711                             }
712                         }
713                         DescriptorSet::ArgumentBuffer { .. } => panic!(
714                             "Tried to free a DescriptorSet not given out by this DescriptorPool!"
715                         ),
716                     }
717                 }
718             }
719             DescriptorPool::ArgumentBuffer {
720                 ref mut raw_allocator,
721                 ref mut res_allocator,
722                 ref inner,
723                 ..
724             } => {
725                 let mut data = inner.write();
726                 for descriptor_set in descriptor_sets {
727                     match descriptor_set {
728                         DescriptorSet::Emulated { .. } => panic!(
729                             "Tried to free a DescriptorSet not given out by this DescriptorPool!"
730                         ),
731                         DescriptorSet::ArgumentBuffer {
732                             raw_offset,
733                             range,
734                             encoder,
735                             ..
736                         } => {
737                             for ur in data.resources[range.start as usize .. range.end as usize]
738                                 .iter_mut()
739                             {
740                                 ur.ptr = ptr::null_mut();
741                                 ur.usage = metal::MTLResourceUsage::empty();
742                             }
743 
744                             let handle_range = raw_offset .. raw_offset + encoder.encoded_length();
745                             raw_allocator.free_range(handle_range);
746                             res_allocator.free_range(range);
747                         }
748                     }
749                 }
750             }
751         }
752         self.report_available();
753     }
754 
reset(&mut self)755     unsafe fn reset(&mut self) {
756         match *self {
757             DescriptorPool::Emulated {
758                 ref inner,
759                 ref mut allocators,
760             } => {
761                 debug!("pool: reset");
762                 if allocators.samplers.is_empty()
763                     && allocators.textures.is_empty()
764                     && allocators.buffers.is_empty()
765                 {
766                     return; // spare the locking
767                 }
768                 let mut data = inner.write();
769 
770                 for range in allocators.samplers.allocated_ranges() {
771                     for sampler in &mut data.samplers[range.start as usize .. range.end as usize] {
772                         *sampler = None;
773                     }
774                 }
775                 for range in allocators.textures.allocated_ranges() {
776                     for texture in &mut data.textures[range.start as usize .. range.end as usize] {
777                         *texture = None;
778                     }
779                 }
780                 for range in allocators.buffers.allocated_ranges() {
781                     for buffer in &mut data.buffers[range.start as usize .. range.end as usize] {
782                         *buffer = None;
783                     }
784                 }
785 
786                 allocators.samplers.reset();
787                 allocators.textures.reset();
788                 allocators.buffers.reset();
789             }
790             DescriptorPool::ArgumentBuffer {
791                 ref mut raw_allocator,
792                 ref mut res_allocator,
793                 ..
794             } => {
795                 raw_allocator.reset();
796                 res_allocator.reset();
797             }
798         }
799     }
800 }
801 
802 bitflags! {
803     /// Descriptor content flags.
804     pub struct DescriptorContent: u8 {
805         const BUFFER = 1<<0;
806         const DYNAMIC_BUFFER = 1<<1;
807         const TEXTURE = 1<<2;
808         const SAMPLER = 1<<3;
809         const IMMUTABLE_SAMPLER = 1<<4;
810     }
811 }
812 
813 impl From<pso::DescriptorType> for DescriptorContent {
from(ty: pso::DescriptorType) -> Self814     fn from(ty: pso::DescriptorType) -> Self {
815         match ty {
816             pso::DescriptorType::Sampler => DescriptorContent::SAMPLER,
817             pso::DescriptorType::CombinedImageSampler => {
818                 DescriptorContent::TEXTURE | DescriptorContent::SAMPLER
819             }
820             pso::DescriptorType::SampledImage
821             | pso::DescriptorType::StorageImage
822             | pso::DescriptorType::UniformTexelBuffer
823             | pso::DescriptorType::StorageTexelBuffer
824             | pso::DescriptorType::InputAttachment => DescriptorContent::TEXTURE,
825             pso::DescriptorType::UniformBuffer | pso::DescriptorType::StorageBuffer => {
826                 DescriptorContent::BUFFER
827             }
828             pso::DescriptorType::UniformBufferDynamic
829             | pso::DescriptorType::StorageBufferDynamic => {
830                 DescriptorContent::BUFFER | DescriptorContent::DYNAMIC_BUFFER
831             }
832         }
833     }
834 }
835 
836 // Note: this structure is iterated often, so it makes sense to keep it dense
837 #[derive(Debug)]
838 pub struct DescriptorLayout {
839     pub content: DescriptorContent,
840     pub stages: pso::ShaderStageFlags,
841     pub binding: pso::DescriptorBinding,
842     pub array_index: pso::DescriptorArrayIndex,
843 }
844 
845 #[derive(Debug)]
846 pub struct ArgumentLayout {
847     pub(crate) res: msl::ResourceBinding,
848     pub(crate) res_offset: PoolResourceIndex,
849     pub(crate) count: pso::DescriptorArrayIndex,
850     pub(crate) usage: metal::MTLResourceUsage,
851     pub(crate) content: DescriptorContent,
852 }
853 
854 #[derive(Debug)]
855 pub enum DescriptorSetLayout {
856     Emulated(
857         Arc<Vec<DescriptorLayout>>,
858         Vec<(pso::DescriptorBinding, msl::SamplerData)>,
859     ),
860     ArgumentBuffer {
861         encoder: metal::ArgumentEncoder,
862         stage_flags: pso::ShaderStageFlags,
863         bindings: Arc<FastHashMap<pso::DescriptorBinding, ArgumentLayout>>,
864         total: PoolResourceIndex,
865     },
866 }
867 unsafe impl Send for DescriptorSetLayout {}
868 unsafe impl Sync for DescriptorSetLayout {}
869 
870 #[derive(Clone, Debug)]
871 pub struct UsedResource {
872     pub(crate) ptr: *mut metal::MTLResource,
873     pub(crate) usage: metal::MTLResourceUsage,
874 }
875 
876 #[derive(Debug)]
877 pub enum DescriptorSet {
878     Emulated {
879         pool: Arc<RwLock<DescriptorEmulatedPoolInner>>,
880         layouts: Arc<Vec<DescriptorLayout>>,
881         resources: ResourceData<Range<PoolResourceIndex>>,
882     },
883     ArgumentBuffer {
884         raw: metal::Buffer,
885         raw_offset: buffer::Offset,
886         pool: Arc<RwLock<DescriptorArgumentPoolInner>>,
887         range: Range<PoolResourceIndex>,
888         encoder: metal::ArgumentEncoder,
889         bindings: Arc<FastHashMap<pso::DescriptorBinding, ArgumentLayout>>,
890         stage_flags: pso::ShaderStageFlags,
891     },
892 }
893 unsafe impl Send for DescriptorSet {}
894 unsafe impl Sync for DescriptorSet {}
895 
896 #[derive(Debug)]
897 pub struct Memory {
898     pub(crate) heap: MemoryHeap,
899     pub(crate) size: u64,
900 }
901 
902 impl Memory {
new(heap: MemoryHeap, size: u64) -> Self903     pub(crate) fn new(heap: MemoryHeap, size: u64) -> Self {
904         Memory { heap, size }
905     }
906 
resolve<R: RangeArg<u64>>(&self, range: &R) -> Range<u64>907     pub(crate) fn resolve<R: RangeArg<u64>>(&self, range: &R) -> Range<u64> {
908         *range.start().unwrap_or(&0) .. *range.end().unwrap_or(&self.size)
909     }
910 }
911 
912 unsafe impl Send for Memory {}
913 unsafe impl Sync for Memory {}
914 
915 #[derive(Debug)]
916 pub(crate) enum MemoryHeap {
917     Private,
918     Public(MemoryTypeId, metal::Buffer),
919     Native(metal::Heap),
920 }
921 
922 #[derive(Default)]
923 pub(crate) struct ArgumentArray {
924     arguments: Vec<metal::ArgumentDescriptor>,
925     position: usize,
926 }
927 
928 impl ArgumentArray {
describe_usage(ty: pso::DescriptorType) -> metal::MTLResourceUsage929     pub fn describe_usage(ty: pso::DescriptorType) -> metal::MTLResourceUsage {
930         use hal::pso::DescriptorType as Dt;
931         use metal::MTLResourceUsage;
932 
933         match ty {
934             Dt::Sampler => MTLResourceUsage::empty(),
935             Dt::CombinedImageSampler | Dt::SampledImage | Dt::InputAttachment => {
936                 MTLResourceUsage::Sample
937             }
938             Dt::UniformTexelBuffer => MTLResourceUsage::Sample,
939             Dt::UniformBuffer | Dt::UniformBufferDynamic => MTLResourceUsage::Read,
940             Dt::StorageImage
941             | Dt::StorageBuffer
942             | Dt::StorageBufferDynamic
943             | Dt::StorageTexelBuffer => MTLResourceUsage::Write,
944         }
945     }
946 
push( &mut self, ty: metal::MTLDataType, count: usize, usage: metal::MTLResourceUsage, ) -> usize947     pub fn push(
948         &mut self,
949         ty: metal::MTLDataType,
950         count: usize,
951         usage: metal::MTLResourceUsage,
952     ) -> usize {
953         use metal::{MTLArgumentAccess, MTLResourceUsage};
954 
955         let pos = self.position;
956         self.position += count;
957         let access = if usage == MTLResourceUsage::Write {
958             MTLArgumentAccess::ReadWrite
959         } else {
960             MTLArgumentAccess::ReadOnly
961         };
962 
963         let arg = metal::ArgumentDescriptor::new();
964         arg.set_array_length(count as u64);
965         arg.set_index(pos as u64);
966         arg.set_access(access);
967         arg.set_data_type(ty);
968         self.arguments.push(arg.to_owned());
969 
970         pos
971     }
972 
build<'a>(self) -> (&'a metal::ArrayRef<metal::ArgumentDescriptor>, usize)973     pub fn build<'a>(self) -> (&'a metal::ArrayRef<metal::ArgumentDescriptor>, usize) {
974         (
975             metal::Array::from_owned_slice(&self.arguments),
976             self.position,
977         )
978     }
979 }
980 
981 #[derive(Debug)]
982 pub enum QueryPool {
983     Occlusion(Range<u32>),
984 }
985 
986 #[derive(Debug)]
987 pub enum FenceInner {
988     Idle {
989         signaled: bool,
990     },
991     PendingSubmission(metal::CommandBuffer),
992     AcquireFrame {
993         swapchain_image: SwapchainImage,
994         iteration: usize,
995     },
996 }
997 
998 #[derive(Debug)]
999 pub struct Fence(pub(crate) RefCell<FenceInner>);
1000 
1001 unsafe impl Send for Fence {}
1002 unsafe impl Sync for Fence {}
1003 
1004 //TODO: review the atomic ordering
1005 #[derive(Debug)]
1006 pub struct Event(pub(crate) Arc<AtomicBool>);
1007 
1008 extern "C" {
dispatch_semaphore_wait(semaphore: *mut c_void, timeout: u64) -> c_long1009     fn dispatch_semaphore_wait(semaphore: *mut c_void, timeout: u64) -> c_long;
dispatch_semaphore_signal(semaphore: *mut c_void) -> c_long1010     fn dispatch_semaphore_signal(semaphore: *mut c_void) -> c_long;
dispatch_semaphore_create(value: c_long) -> *mut c_void1011     fn dispatch_semaphore_create(value: c_long) -> *mut c_void;
dispatch_release(object: *mut c_void)1012     fn dispatch_release(object: *mut c_void);
1013 }
1014 
1015 #[cfg(feature = "signpost")]
1016 extern "C" {
kdebug_signpost(code: u32, arg1: usize, arg2: usize, arg3: usize, arg4: usize)1017     fn kdebug_signpost(code: u32, arg1: usize, arg2: usize, arg3: usize, arg4: usize);
kdebug_signpost_start(code: u32, arg1: usize, arg2: usize, arg3: usize, arg4: usize)1018     fn kdebug_signpost_start(code: u32, arg1: usize, arg2: usize, arg3: usize, arg4: usize);
kdebug_signpost_end(code: u32, arg1: usize, arg2: usize, arg3: usize, arg4: usize)1019     fn kdebug_signpost_end(code: u32, arg1: usize, arg2: usize, arg3: usize, arg4: usize);
1020 }
1021 
1022 #[derive(Clone, Debug)]
1023 pub struct SystemSemaphore(*mut c_void);
1024 unsafe impl Send for SystemSemaphore {}
1025 unsafe impl Sync for SystemSemaphore {}
1026 
1027 impl Drop for SystemSemaphore {
drop(&mut self)1028     fn drop(&mut self) {
1029         unsafe { dispatch_release(self.0) }
1030     }
1031 }
1032 impl SystemSemaphore {
new() -> Self1033     pub(crate) fn new() -> Self {
1034         SystemSemaphore(unsafe { dispatch_semaphore_create(1) })
1035     }
signal(&self)1036     pub(crate) fn signal(&self) {
1037         unsafe {
1038             dispatch_semaphore_signal(self.0);
1039         }
1040     }
wait(&self, timeout: u64)1041     pub(crate) fn wait(&self, timeout: u64) {
1042         unsafe {
1043             dispatch_semaphore_wait(self.0, timeout);
1044         }
1045     }
1046 }
1047 
1048 #[derive(Clone, Debug)]
1049 pub struct Signpost {
1050     code: u32,
1051     args: [usize; 4],
1052 }
1053 
1054 impl Drop for Signpost {
drop(&mut self)1055     fn drop(&mut self) {
1056         #[cfg(feature = "signpost")]
1057         unsafe {
1058             kdebug_signpost_end(
1059                 self.code,
1060                 self.args[0],
1061                 self.args[1],
1062                 self.args[2],
1063                 self.args[3],
1064             );
1065         }
1066     }
1067 }
1068 
1069 impl Signpost {
new(code: u32, args: [usize; 4]) -> Self1070     pub(crate) fn new(code: u32, args: [usize; 4]) -> Self {
1071         #[cfg(feature = "signpost")]
1072         unsafe {
1073             kdebug_signpost_start(code, args[0], args[1], args[2], args[3]);
1074         }
1075         Signpost { code, args }
1076     }
place(code: u32, args: [usize; 4])1077     pub(crate) fn place(code: u32, args: [usize; 4]) {
1078         #[cfg(feature = "signpost")]
1079         unsafe {
1080             kdebug_signpost(code, args[0], args[1], args[2], args[3]);
1081         }
1082         #[cfg(not(feature = "signpost"))]
1083         let _ = (code, args);
1084     }
1085 }
1086