1 use std::{fmt, sync::Arc}; 2 3 use winapi::shared::winerror::SUCCEEDED; 4 5 use crate::{command::CommandBuffer, Backend, Shared}; 6 use hal::{command, pool}; 7 8 #[derive(Debug)] 9 pub enum CommandPoolAllocator { 10 Shared(native::CommandAllocator), 11 Individual(Vec<native::CommandAllocator>), 12 } 13 14 pub struct CommandPool { 15 pub(crate) allocator: CommandPoolAllocator, 16 pub(crate) device: native::Device, 17 pub(crate) list_type: native::CmdListType, 18 pub(crate) shared: Arc<Shared>, 19 pub(crate) create_flags: pool::CommandPoolCreateFlags, 20 } 21 22 impl fmt::Debug for CommandPool { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result23 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 24 fmt.write_str("CommandPool") 25 } 26 } 27 28 impl CommandPool { create_command_list(&mut self) -> (native::GraphicsCommandList, native::CommandAllocator)29 fn create_command_list(&mut self) -> (native::GraphicsCommandList, native::CommandAllocator) { 30 let command_allocator = match self.allocator { 31 CommandPoolAllocator::Shared(ref allocator) => allocator.clone(), 32 CommandPoolAllocator::Individual(ref mut allocators) => { 33 let (command_allocator, hr) = self.device.create_command_allocator(self.list_type); 34 35 // TODO: error handling 36 if !SUCCEEDED(hr) { 37 error!("error on command allocator creation: {:x}", hr); 38 } 39 40 allocators.push(command_allocator); 41 command_allocator 42 } 43 }; 44 45 // allocate command lists 46 let (command_list, hr) = self.device.create_graphics_command_list( 47 self.list_type, 48 command_allocator, 49 native::PipelineState::null(), 50 0, 51 ); 52 53 if !SUCCEEDED(hr) { 54 error!("error on command list creation: {:x}", hr); 55 } 56 57 // Close command list as they are initiated as recording. 58 // But only one command list can be recording for each allocator 59 let _hr = command_list.close(); 60 61 (command_list, command_allocator) 62 } 63 destroy(self)64 pub(crate) fn destroy(self) { 65 match self.allocator { 66 CommandPoolAllocator::Shared(ref allocator) => unsafe { 67 allocator.destroy(); 68 }, 69 CommandPoolAllocator::Individual(ref allocators) => { 70 for allocator in allocators.iter() { 71 unsafe { 72 allocator.destroy(); 73 } 74 } 75 } 76 } 77 } 78 } 79 80 unsafe impl Send for CommandPool {} 81 unsafe impl Sync for CommandPool {} 82 83 impl pool::CommandPool<Backend> for CommandPool { reset(&mut self, _release_resources: bool)84 unsafe fn reset(&mut self, _release_resources: bool) { 85 match self.allocator { 86 CommandPoolAllocator::Shared(ref allocator) => { 87 allocator.Reset(); 88 } 89 CommandPoolAllocator::Individual(ref mut allocators) => { 90 for allocator in allocators.iter_mut() { 91 allocator.Reset(); 92 } 93 } 94 } 95 } 96 allocate_one(&mut self, level: command::Level) -> CommandBuffer97 unsafe fn allocate_one(&mut self, level: command::Level) -> CommandBuffer { 98 // TODO: Implement secondary buffers 99 assert_eq!(level, command::Level::Primary); 100 let (command_list, command_allocator) = self.create_command_list(); 101 CommandBuffer::new( 102 command_list, 103 command_allocator, 104 self.shared.clone(), 105 self.create_flags, 106 ) 107 } 108 free<I>(&mut self, cbufs: I) where I: IntoIterator<Item = CommandBuffer>,109 unsafe fn free<I>(&mut self, cbufs: I) 110 where 111 I: IntoIterator<Item = CommandBuffer>, 112 { 113 for mut cbuf in cbufs { 114 cbuf.destroy(); 115 } 116 } 117 } 118