Skip to main content

fyrox_impl/renderer/
storage.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Generic, texture-based, storage for matrices with somewhat unlimited capacity.
22
23use crate::{
24    core::algebra::Matrix4,
25    graphics::{
26        error::FrameworkError,
27        gpu_texture::{GpuTexture, GpuTextureDescriptor, GpuTextureKind, PixelKind},
28        server::GraphicsServer,
29    },
30};
31
32/// Generic, texture-based, storage for matrices with somewhat unlimited capacity.
33///
34/// ## Motivation
35///
36/// Why it uses textures instead of SSBO? This could be done with SSBO, but it is not available on macOS because
37/// SSBO was added only in OpenGL 4.3, but macOS support up to OpenGL 4.1.
38pub struct MatrixStorage {
39    texture: GpuTexture,
40    matrices: Vec<Matrix4<f32>>,
41}
42
43impl MatrixStorage {
44    /// Creates a new matrix storage.
45    pub fn new(server: &dyn GraphicsServer) -> Result<Self, FrameworkError> {
46        let identity = [Matrix4::<f32>::identity()];
47        Ok(Self {
48            texture: server.create_texture(GpuTextureDescriptor {
49                name: "MatrixStorage",
50                kind: GpuTextureKind::Rectangle {
51                    width: 4,
52                    height: 1,
53                },
54                pixel_kind: PixelKind::RGBA32F,
55                data: Some(crate::core::array_as_u8_slice(&identity)),
56                ..Default::default()
57            })?,
58            matrices: Default::default(),
59        })
60    }
61
62    /// Returns matrix storage texture.
63    pub fn texture(&self) -> &GpuTexture {
64        &self.texture
65    }
66
67    /// Updates contents of the internal texture with provided matrices.
68    pub fn upload(
69        &mut self,
70        matrices: impl Iterator<Item = Matrix4<f32>>,
71    ) -> Result<(), FrameworkError> {
72        self.matrices.clear();
73        self.matrices.extend(matrices);
74
75        // Select width for the texture by restricting width at 1024 pixels.
76        let matrices_tex_size = 1024;
77        let actual_matrices_pixel_count = self.matrices.len() * 4;
78        let matrices_w = actual_matrices_pixel_count.min(matrices_tex_size);
79        let matrices_h = (actual_matrices_pixel_count as f32 / matrices_w as f32)
80            .ceil()
81            .max(1.0) as usize;
82        // Pad data to actual size.
83        for _ in 0..(((matrices_w * matrices_h) - actual_matrices_pixel_count) / 4) {
84            self.matrices.push(Default::default());
85        }
86
87        // Upload to GPU.
88        if matrices_w != 0 && matrices_h != 0 {
89            self.texture.set_data(
90                GpuTextureKind::Rectangle {
91                    width: matrices_w,
92                    height: matrices_h,
93                },
94                PixelKind::RGBA32F,
95                1,
96                Some(crate::core::array_as_u8_slice(&self.matrices)),
97            )?;
98        }
99
100        Ok(())
101    }
102}