use std::mem;
use std::ptr;
use std::sync::Arc;
use device::Device;
use OomError;
use VulkanObject;
use check_errors;
use vk;
pub struct PipelineCache {
device: Arc<Device>,
cache: vk::PipelineCache,
}
impl PipelineCache {
#[inline]
pub unsafe fn with_data(device: Arc<Device>, initial_data: &[u8])
-> Result<Arc<PipelineCache>, OomError> {
PipelineCache::new_impl(device, Some(initial_data))
}
#[inline]
pub fn empty(device: Arc<Device>) -> Result<Arc<PipelineCache>, OomError> {
unsafe { PipelineCache::new_impl(device, None) }
}
unsafe fn new_impl(device: Arc<Device>, initial_data: Option<&[u8]>)
-> Result<Arc<PipelineCache>, OomError> {
let vk = device.pointers();
let cache = {
let infos = vk::PipelineCacheCreateInfo {
sType: vk::STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO,
pNext: ptr::null(),
flags: 0, initialDataSize: initial_data.map(|d| d.len()).unwrap_or(0),
pInitialData: initial_data
.map(|d| d.as_ptr() as *const _)
.unwrap_or(ptr::null()),
};
let mut output = mem::uninitialized();
check_errors(vk.CreatePipelineCache(device.internal_object(),
&infos,
ptr::null(),
&mut output))?;
output
};
Ok(Arc::new(PipelineCache {
device: device.clone(),
cache: cache,
}))
}
pub fn merge<'a, I>(&self, pipelines: I) -> Result<(), OomError>
where I: IntoIterator<Item = &'a &'a Arc<PipelineCache>>
{
unsafe {
let vk = self.device.pointers();
let pipelines = pipelines
.into_iter()
.map(|pipeline| {
assert!(&***pipeline as *const _ != &*self as *const _);
pipeline.cache
})
.collect::<Vec<_>>();
check_errors(vk.MergePipelineCaches(self.device.internal_object(),
self.cache,
pipelines.len() as u32,
pipelines.as_ptr()))?;
Ok(())
}
}
pub fn get_data(&self) -> Result<Vec<u8>, OomError> {
unsafe {
let vk = self.device.pointers();
let mut num = 0;
check_errors(vk.GetPipelineCacheData(self.device.internal_object(),
self.cache,
&mut num,
ptr::null_mut()))?;
let mut data: Vec<u8> = Vec::with_capacity(num as usize);
check_errors(vk.GetPipelineCacheData(self.device.internal_object(),
self.cache,
&mut num,
data.as_mut_ptr() as *mut _))?;
data.set_len(num as usize);
Ok(data)
}
}
}
unsafe impl VulkanObject for PipelineCache {
type Object = vk::PipelineCache;
#[inline]
fn internal_object(&self) -> vk::PipelineCache {
self.cache
}
}
impl Drop for PipelineCache {
#[inline]
fn drop(&mut self) {
unsafe {
let vk = self.device.pointers();
vk.DestroyPipelineCache(self.device.internal_object(), self.cache, ptr::null());
}
}
}
#[cfg(test)]
mod tests {
use pipeline::cache::PipelineCache;
#[test]
fn merge_self_forbidden() {
let (device, queue) = gfx_dev_and_queue!();
let pipeline = PipelineCache::empty(device).unwrap();
assert_should_panic!({
pipeline.merge(&[&pipeline]).unwrap();
});
}
}