use std::error;
use std::fmt;
use std::sync::Arc;
use command_buffer::CommandAddError;
use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use device::Device;
use device::DeviceOwned;
use VulkanObject;
use VulkanPointers;
pub struct CmdDispatchRaw {
dimensions: [u32; 3],
device: Arc<Device>,
}
impl CmdDispatchRaw {
#[inline]
pub unsafe fn new(device: Arc<Device>, dimensions: [u32; 3])
-> Result<CmdDispatchRaw, CmdDispatchRawError>
{
let max_dims = device.physical_device().limits().max_compute_work_group_count();
if dimensions[0] > max_dims[0] || dimensions[1] > max_dims[1] ||
dimensions[2] > max_dims[2]
{
return Err(CmdDispatchRawError::DimensionsTooLarge);
}
Ok(CmdDispatchRaw {
dimensions: dimensions,
device: device,
})
}
#[inline]
pub unsafe fn unchecked_dimensions(device: Arc<Device>, dimensions: [u32; 3])
-> Result<CmdDispatchRaw, CmdDispatchRawError>
{
Ok(CmdDispatchRaw {
dimensions: dimensions,
device: device,
})
}
}
unsafe impl DeviceOwned for CmdDispatchRaw {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
unsafe impl<'a, P> AddCommand<&'a CmdDispatchRaw> for UnsafeCommandBufferBuilder<P>
where P: CommandPool
{
type Out = UnsafeCommandBufferBuilder<P>;
#[inline]
fn add(self, command: &'a CmdDispatchRaw) -> Result<Self::Out, CommandAddError> {
unsafe {
let vk = self.device().pointers();
let cmd = self.internal_object();
vk.CmdDispatch(cmd, command.dimensions[0], command.dimensions[1],
command.dimensions[2]);
}
Ok(self)
}
}
#[derive(Debug, Copy, Clone)]
pub enum CmdDispatchRawError {
DimensionsTooLarge,
}
impl error::Error for CmdDispatchRawError {
#[inline]
fn description(&self) -> &str {
match *self {
CmdDispatchRawError::DimensionsTooLarge => {
"the dispatch dimensions are larger than the hardware limits"
},
}
}
}
impl fmt::Display for CmdDispatchRawError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
#[cfg(test)]
mod tests {
use command_buffer::commands_raw::CmdDispatchRaw;
use command_buffer::commands_raw::CmdDispatchRawError;
#[test]
fn basic_create() {
let (device, _) = gfx_dev_and_queue!();
match unsafe { CmdDispatchRaw::new(device, [128, 128, 128]) } {
Ok(_) => (),
_ => panic!()
}
}
#[test]
fn limit_checked() {
let (device, _) = gfx_dev_and_queue!();
let limit = device.physical_device().limits().max_compute_work_group_count();
let x = match limit[0].checked_add(2) {
None => return,
Some(x) => x,
};
match unsafe { CmdDispatchRaw::new(device, [x, limit[1], limit[2]]) } {
Err(CmdDispatchRawError::DimensionsTooLarge) => (),
_ => panic!()
}
}
}