notan_graphics/
device.rs

1use crate::buffer::*;
2use crate::commands::*;
3use crate::crevice::std140::{AsStd140, Std140};
4use crate::limits::Limits;
5use crate::pipeline::*;
6use crate::render_texture::*;
7use crate::renderer::Renderer;
8use crate::shader::*;
9use crate::texture::*;
10use parking_lot::RwLock;
11use std::sync::Arc;
12
13/// Device resource ID, used to know which resource was dropped
14#[derive(Debug)]
15pub enum ResourceId {
16    Buffer(u64),
17    Texture(u64),
18    Pipeline(u64),
19    RenderTexture(u64),
20}
21
22/// Represents what the GPU did in the last frame
23#[derive(Clone, Copy, Default, Debug)]
24pub struct GpuStats {
25    /// Number of draw calls
26    pub draw_calls: usize,
27    /// Number of read_pixels callas
28    pub read_pixels: usize,
29    /// Number of textures updated
30    pub texture_updates: usize,
31    /// Number of textures created
32    pub texture_creation: usize,
33    /// Number of buffers updated
34    pub buffer_updates: usize,
35    /// Number of buffers created
36    pub buffer_creation: usize,
37    /// Any other interaction with the GPU
38    pub misc: usize,
39}
40
41impl GpuStats {
42    pub fn total(&self) -> usize {
43        self.draw_calls + self.read_pixels + self.misc
44    }
45}
46
47/// Represents a the implementation graphics backend like glow, wgpu or another
48pub trait DeviceBackend {
49    /// Returns the name of the api used (like webgl, wgpu, etc...)
50    fn api_name(&self) -> &str;
51
52    /// Return the device limits
53    fn limits(&self) -> Limits {
54        Default::default()
55    }
56
57    /// Return the GPU stats
58    fn stats(&self) -> GpuStats;
59
60    /// Reset the GPU stats
61    fn reset_stats(&mut self);
62
63    /// Create a new pipeline and returns the id
64    fn create_pipeline(
65        &mut self,
66        vertex_source: &[u8],
67        fragment_source: &[u8],
68        vertex_attrs: &[VertexAttr],
69        texture_locations: &[(u32, String)],
70        options: PipelineOptions,
71    ) -> Result<u64, String>;
72
73    /// Create a new vertex buffer object and returns the id
74    fn create_vertex_buffer(
75        &mut self,
76        attrs: &[VertexAttr],
77        step_mode: VertexStepMode,
78    ) -> Result<u64, String>;
79
80    /// Create a new index buffer object and returns the id
81    fn create_index_buffer(&mut self, format: IndexFormat) -> Result<u64, String>;
82
83    /// Create a new uniform buffer and returns the id
84    fn create_uniform_buffer(&mut self, slot: u32, name: &str) -> Result<u64, String>;
85
86    /// Upload to the GPU the buffer data slice
87    fn set_buffer_data(&mut self, buffer: u64, data: &[u8]);
88
89    /// Create a new renderer using the size of the graphics
90    fn render(&mut self, commands: &[Commands], target: Option<u64>);
91
92    /// Clean all the dropped resources
93    fn clean(&mut self, to_clean: &[ResourceId]);
94
95    /// Sets the render size
96    fn set_size(&mut self, width: u32, height: u32);
97
98    /// Sets the screen dpi
99    fn set_dpi(&mut self, scale_factor: f64);
100
101    /// Create a new texture and returns the id
102    fn create_texture(
103        &mut self,
104        source: TextureSourceKind,
105        info: TextureInfo,
106    ) -> Result<(u64, TextureInfo), String>;
107
108    /// Create a new render target and returns the id
109    fn create_render_texture(&mut self, texture_id: u64, info: &TextureInfo)
110        -> Result<u64, String>;
111
112    /// Update texture data
113    fn update_texture(
114        &mut self,
115        texture: u64,
116        source: TextureUpdaterSourceKind,
117        opts: TextureUpdate,
118    ) -> Result<(), String>;
119
120    /// Read texture pixels
121    fn read_pixels(
122        &mut self,
123        texture: u64,
124        bytes: &mut [u8],
125        opts: &TextureRead,
126    ) -> Result<(), String>;
127
128    fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
129}
130
131/// Helper to drop resources on the backend
132/// Like pipelines, textures, buffers
133#[derive(Debug, Default)]
134pub(crate) struct DropManager {
135    dropped: RwLock<Vec<ResourceId>>,
136}
137
138impl DropManager {
139    pub fn push(&self, id: ResourceId) {
140        self.dropped.write().push(id);
141    }
142
143    pub fn clean(&self) {
144        self.dropped.write().clear();
145    }
146}
147
148pub struct Device {
149    size: (u32, u32),
150    dpi: f64,
151    backend: Box<dyn DeviceBackend>, //TODO generic?
152    drop_manager: Arc<DropManager>,
153}
154
155impl Device {
156    pub fn new(backend: Box<dyn DeviceBackend>) -> Result<Self, String> {
157        Ok(Self {
158            backend,
159            size: (1, 1),
160            dpi: 1.0,
161            drop_manager: Arc::new(Default::default()),
162        })
163    }
164
165    #[inline]
166    pub fn limits(&self) -> Limits {
167        self.backend.limits()
168    }
169
170    #[inline]
171    pub fn stats(&self) -> GpuStats {
172        self.backend.stats()
173    }
174
175    #[inline]
176    pub fn size(&self) -> (u32, u32) {
177        self.size
178    }
179
180    #[inline]
181    pub fn set_size(&mut self, width: u32, height: u32) {
182        self.size = (width, height);
183        self.backend.set_size(width, height);
184    }
185
186    #[inline]
187    pub fn dpi(&self) -> f64 {
188        self.dpi
189    }
190
191    #[inline]
192    pub fn set_dpi(&mut self, scale_factor: f64) {
193        self.dpi = scale_factor;
194        self.backend.set_dpi(scale_factor);
195    }
196
197    #[inline]
198    pub fn api_name(&self) -> &str {
199        self.backend.api_name()
200    }
201
202    #[inline]
203    pub fn create_renderer(&self) -> Renderer {
204        Renderer::new(self.size.0, self.size.1)
205    }
206
207    /// Creates a Pipeline builder
208    #[inline]
209    pub fn create_pipeline(&mut self) -> PipelineBuilder {
210        PipelineBuilder::new(self)
211    }
212
213    /// Creates a texture builder
214    #[inline]
215    pub fn create_texture(&mut self) -> TextureBuilder {
216        TextureBuilder::new(self)
217    }
218
219    /// Creates a render texture builder
220    #[inline]
221    pub fn create_render_texture(&mut self, width: u32, height: u32) -> RenderTextureBuilder {
222        RenderTextureBuilder::new(self, width, height)
223    }
224
225    /// Creates a vertex buffer builder
226    #[inline]
227    pub fn create_vertex_buffer(&mut self) -> VertexBufferBuilder {
228        VertexBufferBuilder::new(self)
229    }
230
231    /// Creates a index buffer builder
232    #[inline]
233    pub fn create_index_buffer(&mut self) -> IndexBufferBuilder {
234        IndexBufferBuilder::new(self)
235    }
236
237    /// Creates a uniform buffer builder
238    #[inline]
239    pub fn create_uniform_buffer(&mut self, slot: u32, name: &str) -> UniformBufferBuilder {
240        UniformBufferBuilder::new(self, slot, name)
241    }
242
243    /// Update the texture data
244    #[inline]
245    pub fn update_texture<'a>(&'a mut self, texture: &'a mut Texture) -> TextureUpdater<'a> {
246        TextureUpdater::new(self, texture)
247    }
248
249    /// Read pixels from a texture
250    #[inline]
251    pub fn read_pixels<'a>(&'a mut self, texture: &'a Texture) -> TextureReader<'a> {
252        TextureReader::new(self, texture)
253    }
254
255    #[inline]
256    pub(crate) fn inner_create_pipeline_from_raw(
257        &mut self,
258        vertex_source: &[u8],
259        fragment_source: &[u8],
260        vertex_attrs: &[VertexAttr],
261        texture_locations: &[(u32, String)],
262        options: PipelineOptions,
263    ) -> Result<Pipeline, String> {
264        let stride = vertex_attrs
265            .iter()
266            .fold(0, |acc, data| acc + data.format.bytes()) as usize;
267
268        let id = self.backend.create_pipeline(
269            vertex_source,
270            fragment_source,
271            vertex_attrs,
272            texture_locations,
273            options,
274        )?;
275
276        Ok(Pipeline::new(
277            id,
278            stride,
279            options,
280            self.drop_manager.clone(),
281        ))
282    }
283
284    #[inline]
285    pub(crate) fn inner_create_pipeline(
286        &mut self,
287        vertex_source: &ShaderSource,
288        fragment_source: &ShaderSource,
289        vertex_attrs: &[VertexAttr],
290        texture_locations: &[(u32, String)],
291        options: PipelineOptions,
292    ) -> Result<Pipeline, String> {
293        let api = self.backend.api_name();
294        let vertex = match vertex_source.get_source(api) {
295            Some(v) => v,
296            None => {
297                log::warn!("Vertex shader for api '{api}' not available.");
298                &[]
299            }
300        };
301        let fragment = match fragment_source.get_source(api) {
302            Some(f) => f,
303            None => {
304                log::warn!("Fragment shader for api '{api}' not available.");
305                &[]
306            }
307        };
308        self.inner_create_pipeline_from_raw(
309            vertex,
310            fragment,
311            vertex_attrs,
312            texture_locations,
313            options,
314        )
315    }
316
317    #[inline(always)]
318    pub(crate) fn inner_create_vertex_buffer(
319        &mut self,
320        data: Option<&[f32]>,
321        attrs: &[VertexAttr],
322        step_mode: VertexStepMode,
323    ) -> Result<Buffer, String> {
324        let id = self.backend.create_vertex_buffer(attrs, step_mode)?;
325
326        let buffer = Buffer::new(id, BufferUsage::Vertex, None, self.drop_manager.clone());
327
328        if let Some(d) = data {
329            self.set_buffer_data(&buffer, d);
330        }
331
332        Ok(buffer)
333    }
334
335    #[inline]
336    pub(crate) fn inner_create_index_buffer(
337        &mut self,
338        data: Option<IndexBufferWrapper>,
339        format: IndexFormat,
340    ) -> Result<Buffer, String> {
341        let id = self.backend.create_index_buffer(format)?;
342        let buffer = Buffer::new(id, BufferUsage::Index, None, self.drop_manager.clone());
343        if let Some(d) = data {
344            match d {
345                IndexBufferWrapper::Uint16(s) => self.set_buffer_data(&buffer, s),
346                IndexBufferWrapper::Uint32(s) => self.set_buffer_data(&buffer, s),
347            }
348        }
349        Ok(buffer)
350    }
351
352    #[inline]
353    pub(crate) fn inner_create_uniform_buffer(
354        &mut self,
355        slot: u32,
356        name: &str,
357        data: Option<Vec<u8>>,
358    ) -> Result<Buffer, String> {
359        //debug_assert!(current_pipeline.is_some()) //pipeline should be already binded
360        let id = self.backend.create_uniform_buffer(slot, name)?;
361        let buffer = Buffer::new(
362            id,
363            BufferUsage::Uniform(slot),
364            None,
365            self.drop_manager.clone(),
366        );
367
368        if let Some(d) = data {
369            self.set_buffer_data(&buffer, &d);
370        }
371
372        Ok(buffer)
373    }
374
375    #[inline]
376    pub(crate) fn inner_create_texture(
377        &mut self,
378        source: TextureSourceKind,
379        info: TextureInfo,
380    ) -> Result<Texture, String> {
381        let (id, info) = self.backend.create_texture(source, info)?;
382        Ok(Texture::new(id, info, self.drop_manager.clone()))
383    }
384
385    #[inline]
386    pub(crate) fn inner_create_render_texture(
387        &mut self,
388        info: TextureInfo,
389    ) -> Result<RenderTexture, String> {
390        let (tex_id, info) = self
391            .backend
392            .create_texture(TextureSourceKind::Empty, info)?;
393
394        let id = self.backend.create_render_texture(tex_id, &info)?;
395        let mut texture = Texture::new(tex_id, info, self.drop_manager.clone());
396        texture.is_render_texture = true;
397        Ok(RenderTexture::new(id, texture, self.drop_manager.clone()))
398    }
399
400    #[inline]
401    pub fn render(&mut self, commands: &[Commands]) {
402        self.backend.render(commands, None);
403    }
404
405    #[inline]
406    pub fn render_to(&mut self, target: &RenderTexture, commands: &[Commands]) {
407        self.backend.render(commands, Some(target.id()));
408    }
409
410    #[inline]
411    pub(crate) fn inner_update_texture(
412        &mut self,
413        texture: &mut Texture,
414        source: TextureUpdaterSourceKind,
415        opts: TextureUpdate,
416    ) -> Result<(), String> {
417        self.backend.update_texture(texture.id(), source, opts)
418    }
419
420    #[inline]
421    pub(crate) fn inner_read_pixels(
422        &mut self,
423        texture: &Texture,
424        bytes: &mut [u8],
425        opts: &TextureRead,
426    ) -> Result<(), String> {
427        // Check if the buffer size is enough to read the pixels
428        if cfg!(debug_assertions) {
429            let size = (opts.width * opts.height) as usize;
430            let bpp = opts.format.bytes_per_pixel() as usize;
431            let len = size * bpp;
432            debug_assert!(
433                bytes.len() >= len,
434                "The provided buffer len of {} is less than the required {} when reading pixels from texture {}",
435                bytes.len(),
436                len,
437                texture.id()
438            );
439        }
440
441        self.backend.read_pixels(texture.id(), bytes, opts)
442    }
443
444    #[inline]
445    pub fn clean(&mut self) {
446        self.backend.reset_stats();
447
448        if self.drop_manager.dropped.read().is_empty() {
449            return;
450        }
451
452        self.backend.clean(&self.drop_manager.dropped.read());
453        self.drop_manager.clean();
454    }
455
456    #[inline]
457    pub fn set_buffer_data<T: BufferData>(&mut self, buffer: &Buffer, data: T) {
458        data.upload(self, buffer.id());
459    }
460
461    pub fn downcast_backend<B: DeviceBackend + 'static>(&mut self) -> Result<&mut B, String> {
462        self.backend
463            .as_any_mut()
464            .downcast_mut()
465            .ok_or_else(|| "Invalid backend type".to_string())
466    }
467}
468
469pub trait Uniform: AsStd140 {}
470pub trait BufferData {
471    fn upload(&self, device: &mut Device, id: u64);
472    fn save_as_bytes(&self, _data: &mut Vec<u8>) {}
473}
474
475impl<T> BufferData for &[T]
476where
477    T: bytemuck::Pod,
478{
479    #[inline]
480    fn upload(&self, device: &mut Device, id: u64) {
481        device
482            .backend
483            .set_buffer_data(id, bytemuck::cast_slice(self));
484    }
485
486    fn save_as_bytes(&self, data: &mut Vec<u8>) {
487        data.extend_from_slice(bytemuck::cast_slice(self));
488    }
489}
490
491impl<const N: usize, T> BufferData for &[T; N]
492where
493    T: bytemuck::Pod,
494{
495    #[inline]
496    fn upload(&self, device: &mut Device, id: u64) {
497        device
498            .backend
499            .set_buffer_data(id, bytemuck::cast_slice(self.as_slice()));
500    }
501
502    fn save_as_bytes(&self, data: &mut Vec<u8>) {
503        data.extend_from_slice(bytemuck::cast_slice(self.as_slice()));
504    }
505}
506
507impl<T> BufferData for &Vec<T>
508where
509    T: bytemuck::Pod,
510{
511    #[inline]
512    fn upload(&self, device: &mut Device, id: u64) {
513        device
514            .backend
515            .set_buffer_data(id, bytemuck::cast_slice(self.as_slice()));
516    }
517
518    fn save_as_bytes(&self, data: &mut Vec<u8>) {
519        data.extend_from_slice(bytemuck::cast_slice(self.as_slice()));
520    }
521}
522
523impl<T> BufferData for &T
524where
525    T: Uniform,
526{
527    #[inline]
528    fn upload(&self, device: &mut Device, id: u64) {
529        // TODO check opengl version or driver if it uses std140 to layout or not
530        device
531            .backend
532            .set_buffer_data(id, self.as_std140().as_bytes());
533    }
534
535    fn save_as_bytes(&self, data: &mut Vec<u8>) {
536        data.extend_from_slice(self.as_std140().as_bytes());
537    }
538}
539
540macro_rules! uniform_impl {
541    ( $( $typ:ty, )* ) => {
542        $(
543            impl Uniform for $typ {}
544        )*
545    }
546}
547
548uniform_impl! {
549    notan_math::Vec2,
550    notan_math::Vec3,
551    notan_math::Vec4,
552
553    notan_math::IVec2,
554    notan_math::IVec3,
555    notan_math::IVec4,
556
557    notan_math::UVec2,
558    notan_math::UVec3,
559    notan_math::UVec4,
560
561    notan_math::DVec2,
562    notan_math::DVec3,
563    notan_math::DVec4,
564
565    notan_math::Mat2,
566    notan_math::Mat3,
567    notan_math::Mat4,
568
569    notan_math::DMat2,
570    notan_math::DMat3,
571    notan_math::DMat4,
572}