clay_core/buffer/
instance_buffer.rs

1use std::marker::PhantomData;
2use ocl::{self, builders::KernelBuilder};
3use crate::{Pack, Push, Context};
4
5
6/// Device buffer of abstract entities. Entity should implement `Pack`. 
7pub struct InstanceBuffer<T: Pack + 'static> {
8    buffer_int: ocl::Buffer<i32>,
9    buffer_float: ocl::Buffer<f32>,
10    count: usize,
11    phantom: PhantomData<T>,
12}
13
14impl<T: Pack> InstanceBuffer<T> {
15    pub fn new<'a, I: ExactSizeIterator<Item=&'a T>>(context: &Context, objects: I) -> crate::Result<Self> {
16        let mut buffer = Self::reserved(context, objects.len())?;
17        buffer.write(objects)?;
18        Ok(buffer)
19    }
20
21    pub fn reserved(context: &Context, count: usize) -> crate::Result<Self> {
22        let buffer_int = ocl::Buffer::<i32>::builder()
23        .queue(context.queue().clone())
24        .flags(ocl::flags::MEM_READ_ONLY)
25        .len((T::size_int()*count).max(1))
26        .fill_val(0 as i32)
27        .build()?;
28
29        let buffer_float = ocl::Buffer::<f32>::builder()
30        .queue(context.queue().clone())
31        .flags(ocl::flags::MEM_READ_ONLY)
32        .len((T::size_float()*count).max(1))
33        .fill_val(0 as f32)
34        .build()?;
35
36        Ok(Self {
37            buffer_int, buffer_float,
38            count, phantom: PhantomData::<T>,
39        })
40    }
41
42    pub fn write<'a, I: ExactSizeIterator<Item=&'a T>>(&mut self, objects: I) -> crate::Result<()> {
43        let len = objects.len();
44        let mut buffer_int = vec![0i32; T::size_int().max(1)*len];
45        let mut buffer_float = vec![0.0f32; T::size_float().max(1)*len];
46        // Use this `.max(1)` workaround because `chunks` panics on 0 (why there is such silly requirement?)
47        for (obj, (ibuf, fbuf)) in objects.zip(
48            buffer_int.chunks_mut(Self::size_int().max(1))
49            .zip(buffer_float.chunks_mut(Self::size_float().max(1)))
50        ) {
51            obj.pack_to(&mut ibuf[..T::size_int()], &mut fbuf[..T::size_float()]);
52        }
53        if len == 0 || T::size_int() == 0 { buffer_int = vec![0]; }
54        if len == 0 || T::size_float() == 0 { buffer_float = vec![0.0]; }
55
56        if buffer_int.len() == self.buffer_int.len() && buffer_float.len() == self.buffer_float.len() {
57            self.buffer_int.cmd()
58            .offset(0)
59            .write(&buffer_int)
60            .enq()?;
61
62            self.buffer_float.cmd()
63            .offset(0)
64            .write(&buffer_float)
65            .enq()?;
66
67            Ok(())
68        } else {
69            Err("buffers size mismatch".into())
70        }
71    }
72    
73    pub fn buffer_int(&self) -> &ocl::Buffer<i32> {
74        &self.buffer_int
75    }
76    pub fn buffer_float(&self) -> &ocl::Buffer<f32> {
77        &self.buffer_float
78    }
79
80    pub fn size_int() -> usize {
81        T::size_int()
82    }
83    pub fn size_float() -> usize {
84        T::size_float()
85    }
86    pub fn count(&self) -> usize {
87        self.count
88    }
89}
90
91impl<T: Pack> Push for InstanceBuffer<T> {
92    fn args_count() -> usize {
93        3
94    }
95    fn args_def(kb: &mut KernelBuilder) {
96        kb
97        .arg(None::<&ocl::Buffer<i32>>) // int buffer
98        .arg(None::<&ocl::Buffer<f32>>) // float buffer
99        .arg(0i32); // instance count
100    }
101    fn args_set(&mut self, i: usize, k: &mut ocl::Kernel) -> crate::Result<()> {
102        k.set_arg(i + 0, self.buffer_int())?;
103        k.set_arg(i + 1, self.buffer_float())?;
104        k.set_arg(i + 2, self.count() as i32)?;
105        Ok(())
106    }
107}