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