crystal_api/
device.rs

1use std::sync::Arc;
2
3use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
4
5use crate::{
6    GpuSamplerSet, GraphicsApiInitSettings,
7    bitflags::BufferFlags,
8    buffer::Buffer,
9    debug::{error, fmt_size, log, setup_startup_time},
10    errors::{GraphicsError, GraphicsResult},
11    layout::Layout,
12    mesh::{AttributeDescriptor, Mesh},
13    object::Object,
14    proxies::*,
15    render_target::RenderTarget,
16    texture::Texture,
17    vulkan::VulkanEntry,
18};
19
20/// ```Device``` is the main struct used for creation of graphics resources and using this wrapper
21pub struct Device {
22    inner: Box<dyn DeviceProxy>,
23}
24
25impl Device {
26    /// Initializes device with no presentation support
27    pub fn compute() -> GraphicsResult<Self> {
28        setup_startup_time();
29        log!("creating compute device");
30        Ok(Self {
31            inner: VulkanEntry::no_presentation()?,
32        })
33    }
34
35    /// Initializes device with presentation support
36    pub fn graphics<T: HasWindowHandle + HasDisplayHandle>(
37        settings: &GraphicsApiInitSettings,
38        window: &T,
39    ) -> GraphicsResult<Self> {
40        setup_startup_time();
41        log!("creating graphics device");
42        Ok(Self {
43            inner: VulkanEntry::with_presentation(settings, window)?,
44        })
45    }
46
47    /// Executes all operations permitted with objects passed in this method
48    pub fn dispatch_and_present(&self, objects: &[Arc<Object>]) -> GraphicsResult<()> {
49        self.inner.dispatch_and_present(objects)
50    }
51
52    /// Executes all compute operations permitted with objects passed in this method
53    pub fn dispatch_compute(&self, objects: &[Arc<Object>]) -> GraphicsResult<()> {
54        self.inner.dispatch_compute(objects)
55    }
56
57    /// Resizes resources
58    pub fn resize_resources(&self, width: u32, height: u32) -> GraphicsResult<()> {
59        self.inner.resize_resources(width, height)
60    }
61
62    /// Returns ```RenderTarget``` created on presentation init
63    pub fn get_presentation_render_target(&self) -> Option<RenderTarget> {
64        self.inner
65            .get_presentation_render_target()
66            .map(RenderTarget::new)
67    }
68
69    /// Creates shader layout
70    pub fn create_layout(
71        &self,
72        double_buffering: bool,
73        texture_num: usize,
74        sampler_num: usize,
75        uniform_num: usize,
76        storage_num: usize,
77    ) -> GraphicsResult<Layout> {
78        if (sampler_num == 0 && texture_num == 0) == (sampler_num > 0 && texture_num > 0) {
79            error!("textures cannot exist without samplers");
80            return Err(GraphicsError::DataError);
81        }
82
83        if !(uniform_num > 0 || storage_num > 0) {
84            error!("cannot create layout without buffers (WARN vulkan specific, todo fix)");
85            return Err(GraphicsError::DataError);
86        } // TODO it is possible! Vulkan specific
87
88        log!("creating layout [ double_buffering: {} ]", double_buffering);
89
90        Ok(Layout::new(self.inner.create_layout(
91            double_buffering,
92            texture_num,
93            sampler_num,
94            uniform_num,
95            storage_num,
96        )?))
97    }
98
99    /// Creates GPU buffer
100    pub fn create_buffer<T>(&self, len: u64, flags: BufferFlags) -> GraphicsResult<Buffer<T>> {
101        let size = len * size_of::<T>() as u64;
102
103        log!(
104            "creating buffer [ size: {} bits: {:?} ]",
105            fmt_size!(size),
106            flags
107        );
108
109        let uniform = !(flags & BufferFlags::UNIFORM).is_none();
110        let transfer = !(flags & BufferFlags::TRANSFER).is_none();
111        let enable_sync = !(flags & BufferFlags::SYNCED).is_none();
112
113        Ok(Buffer::new(self.inner.create_buffer(
114            size,
115            uniform,
116            transfer,
117            enable_sync,
118        )?))
119    }
120
121    /// Creates a set of GPU buffers used for meshes
122    pub fn create_buffer_mesh<V: AttributeDescriptor, I>(
123        &self,
124        mesh: &Mesh<V, I>,
125    ) -> GraphicsResult<crate::mesh::MeshBuffer<V, I>> {
126        log!("creating mesh [ size: {} ] ", {
127            let size = mesh.size();
128            fmt_size!(size)
129        });
130
131        let vertices = unsafe {
132            std::slice::from_raw_parts(
133                mesh.vertices.as_ptr() as *const u8,
134                mesh.vertices.len() * size_of::<V>(),
135            )
136        };
137        let indices = unsafe {
138            std::slice::from_raw_parts(
139                mesh.indices.as_ptr() as *const u8,
140                mesh.indices.len() * size_of::<I>(),
141            )
142        };
143        let buffer_mesh = self
144            .inner
145            .create_buffer_mesh(vertices, indices, size_of::<I>())?;
146
147        Ok(crate::mesh::MeshBuffer::new(buffer_mesh))
148    }
149
150    /// Creates sampler set
151    pub fn create_sampler_set(
152        &self,
153        textures: &[(u32, &Texture)],
154        layouts: &[&Layout],
155    ) -> GraphicsResult<Arc<GpuSamplerSet>> {
156        log!(
157            "creating sampler [ bindings: {:?} ]",
158            textures
159                .iter()
160                .map(|(binding, _)| *binding)
161                .collect::<Vec<_>>()
162        );
163
164        self.inner.create_sampler_set(
165            &textures
166                .iter()
167                .map(|(b, texture)| (*b, texture.inner.clone()))
168                .collect::<Vec<(u32, Arc<dyn TextureProxy>)>>(),
169            &layouts
170                .iter()
171                .map(|layout| layout.inner.clone())
172                .collect::<Vec<Arc<dyn LayoutProxy>>>(),
173        )
174    }
175
176    /// Creates texture from buffers
177    pub fn create_texture(
178        &self,
179        buffer: &Buffer<u8>,
180        extent: [u32; 2],
181        anisotropy_texels: f32,
182    ) -> GraphicsResult<Texture> {
183        let size = buffer.len();
184        log!(
185            "creating texture [ size: {} extent: {}x{} ]",
186            fmt_size!(size),
187            extent[0],
188            extent[1]
189        );
190        Ok(Texture::new(self.inner.create_texture(
191            buffer.inner.clone(),
192            extent,
193            anisotropy_texels,
194        )?))
195    }
196
197    /// Returns the duration of previous frame
198    pub fn get_delta_time(&self) -> std::time::Duration {
199        self.inner.get_delta_time()
200    }
201}