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 renderer::framework::{
26 error::FrameworkError,
27 gpu_texture::{
28 GpuTexture, GpuTextureDescriptor, GpuTextureKind, MagnificationFilter,
29 MinificationFilter, PixelKind, WrapMode,
30 },
31 server::GraphicsServer,
32 },
33};
34use std::{cell::RefCell, rc::Rc};
35
36/// Generic, texture-based, storage for matrices with somewhat unlimited capacity.
37///
38/// ## Motivation
39///
40/// Why it uses textures instead of SSBO? This could be done with SSBO, but it is not available on macOS because
41/// SSBO was added only in OpenGL 4.3, but macOS support up to OpenGL 4.1.
42pub struct MatrixStorage {
43 texture: Rc<RefCell<dyn GpuTexture>>,
44 matrices: Vec<Matrix4<f32>>,
45}
46
47impl MatrixStorage {
48 /// Creates a new matrix storage.
49 pub fn new(server: &dyn GraphicsServer) -> Result<Self, FrameworkError> {
50 let identity = [Matrix4::<f32>::identity()];
51 Ok(Self {
52 texture: server.create_texture(GpuTextureDescriptor {
53 kind: GpuTextureKind::Rectangle {
54 width: 4,
55 height: 1,
56 },
57 pixel_kind: PixelKind::RGBA32F,
58 min_filter: MinificationFilter::Nearest,
59 mag_filter: MagnificationFilter::Nearest,
60 s_wrap_mode: WrapMode::ClampToEdge,
61 t_wrap_mode: WrapMode::ClampToEdge,
62 r_wrap_mode: WrapMode::ClampToEdge,
63 data: Some(crate::core::array_as_u8_slice(&identity)),
64 ..Default::default()
65 })?,
66 matrices: Default::default(),
67 })
68 }
69
70 /// Returns matrix storage texture.
71 pub fn texture(&self) -> &Rc<RefCell<dyn GpuTexture>> {
72 &self.texture
73 }
74
75 /// Updates contents of the internal texture with provided matrices.
76 pub fn upload(
77 &mut self,
78 matrices: impl Iterator<Item = Matrix4<f32>>,
79 ) -> Result<(), FrameworkError> {
80 self.matrices.clear();
81 self.matrices.extend(matrices);
82
83 // Select width for the texture by restricting width at 1024 pixels.
84 let matrices_tex_size = 1024;
85 let actual_matrices_pixel_count = self.matrices.len() * 4;
86 let matrices_w = actual_matrices_pixel_count.min(matrices_tex_size);
87 let matrices_h = (actual_matrices_pixel_count as f32 / matrices_w as f32)
88 .ceil()
89 .max(1.0) as usize;
90 // Pad data to actual size.
91 for _ in 0..(((matrices_w * matrices_h) - actual_matrices_pixel_count) / 4) {
92 self.matrices.push(Default::default());
93 }
94
95 // Upload to GPU.
96 if matrices_w != 0 && matrices_h != 0 {
97 self.texture.borrow_mut().set_data(
98 GpuTextureKind::Rectangle {
99 width: matrices_w,
100 height: matrices_h,
101 },
102 PixelKind::RGBA32F,
103 1,
104 Some(crate::core::array_as_u8_slice(&self.matrices)),
105 )?;
106 }
107
108 Ok(())
109 }
110}