fyrox_impl/renderer/cache/
uniform.rs1use crate::graphics::{
25 buffer::{BufferKind, BufferUsage, GpuBuffer, GpuBufferDescriptor},
26 error::FrameworkError,
27 framebuffer::{BufferDataUsage, ResourceBinding},
28 server::{GraphicsServer, SharedGraphicsServer},
29 uniform::{ByteStorage, DynamicUniformBuffer, UniformBuffer},
30};
31use fxhash::FxHashMap;
32use std::cell::RefCell;
33
34#[derive(Default)]
35struct UniformBufferSet {
36 buffers: Vec<GpuBuffer>,
37 free: usize,
38}
39
40impl UniformBufferSet {
41 fn mark_unused(&mut self) {
42 self.free = 0;
43 }
44
45 fn get_or_create(
46 &mut self,
47 size: usize,
48 server: &dyn GraphicsServer,
49 ) -> Result<GpuBuffer, FrameworkError> {
50 if self.free < self.buffers.len() {
51 let buffer = &self.buffers[self.free];
52 self.free += 1;
53 Ok(buffer.clone())
54 } else {
55 let buffer = server.create_buffer(GpuBufferDescriptor {
56 name: &format!("UniformBuffer{}", self.buffers.len()),
57 size,
58 kind: BufferKind::Uniform,
59 usage: BufferUsage::StreamCopy,
60 })?;
61 self.buffers.push(buffer);
62 self.free = self.buffers.len();
63 Ok(self.buffers.last().unwrap().clone())
64 }
65 }
66}
67
68pub struct UniformBufferCache {
74 server: SharedGraphicsServer,
75 cache: RefCell<FxHashMap<usize, UniformBufferSet>>,
76}
77
78impl UniformBufferCache {
79 pub fn new(server: SharedGraphicsServer) -> Self {
80 Self {
81 server,
82 cache: Default::default(),
83 }
84 }
85
86 pub fn get_or_create(&self, size: usize) -> Result<GpuBuffer, FrameworkError> {
89 let mut cache = self.cache.borrow_mut();
90 let set = cache.entry(size).or_default();
91 set.get_or_create(size, &*self.server)
92 }
93
94 pub fn write<T>(&self, uniform_buffer: UniformBuffer<T>) -> Result<GpuBuffer, FrameworkError>
97 where
98 T: ByteStorage,
99 {
100 let data = uniform_buffer.finish();
101 let buffer = self.get_or_create(data.bytes_count())?;
102 buffer.write_data(data.bytes())?;
103 Ok(buffer)
104 }
105
106 pub fn mark_all_unused(&mut self) {
109 for set in self.cache.borrow_mut().values_mut() {
110 set.mark_unused();
111 }
112 }
113
114 pub fn alive_count(&self) -> usize {
116 let mut count = 0;
117 for (_, set) in self.cache.borrow().iter() {
118 count += set.buffers.len();
119 }
120 count
121 }
122}
123
124struct Page {
125 dynamic: DynamicUniformBuffer,
126 is_submitted: bool,
127}
128
129#[derive(Clone, Copy, Debug)]
131pub struct UniformBlockLocation {
132 pub page: usize,
134 pub offset: usize,
136 pub size: usize,
138}
139
140pub struct UniformMemoryAllocator {
141 gpu_buffers: Vec<GpuBuffer>,
142 block_alignment: usize,
143 max_uniform_buffer_size: usize,
144 pages: Vec<Page>,
145 blocks: Vec<UniformBlockLocation>,
146}
147
148impl UniformMemoryAllocator {
149 pub fn new(max_uniform_buffer_size: usize, block_alignment: usize) -> Self {
150 Self {
151 gpu_buffers: Default::default(),
152 block_alignment,
153 max_uniform_buffer_size,
154 pages: Default::default(),
155 blocks: Default::default(),
156 }
157 }
158
159 pub fn clear(&mut self) {
160 for page in self.pages.iter_mut() {
161 page.dynamic.clear();
162 page.is_submitted = false;
163 }
164 self.blocks.clear();
165 }
166
167 pub fn allocate<T>(&mut self, buffer: UniformBuffer<T>) -> UniformBlockLocation
168 where
169 T: ByteStorage,
170 {
171 let data = buffer.finish();
172 assert!(data.bytes_count() > 0);
173 assert!(data.bytes_count() < self.max_uniform_buffer_size);
174
175 let page_index = match self.pages.iter().position(|page| {
176 let write_position = page
177 .dynamic
178 .next_write_aligned_position(self.block_alignment);
179 self.max_uniform_buffer_size - write_position >= data.bytes_count()
180 }) {
181 Some(page_index) => page_index,
182 None => {
183 let page_index = self.pages.len();
184 self.pages.push(Page {
185 dynamic: UniformBuffer::with_storage(Vec::with_capacity(
186 self.max_uniform_buffer_size,
187 )),
188 is_submitted: false,
189 });
190 page_index
191 }
192 };
193
194 let page = &mut self.pages[page_index];
195 page.is_submitted = false;
196 let offset = page
197 .dynamic
198 .write_bytes_with_alignment(data.bytes(), self.block_alignment);
199
200 let block = UniformBlockLocation {
201 page: page_index,
202 offset,
203 size: data.bytes_count(),
204 };
205 self.blocks.push(block);
206 block
207 }
208
209 pub fn upload(&mut self, server: &dyn GraphicsServer) -> Result<(), FrameworkError> {
210 if self.gpu_buffers.len() < self.pages.len() {
211 for _ in 0..(self.pages.len() - self.gpu_buffers.len()) {
212 let buffer = server.create_buffer(GpuBufferDescriptor {
213 name: &format!("UniformMemoryPage{}", self.gpu_buffers.len()),
214 size: self.max_uniform_buffer_size,
215 kind: BufferKind::Uniform,
216 usage: BufferUsage::StreamCopy,
217 })?;
218 self.gpu_buffers.push(buffer);
219 }
220 }
221
222 for (page, gpu_buffer) in self.pages.iter_mut().zip(self.gpu_buffers.iter()) {
223 if !page.is_submitted {
224 let bytes = page.dynamic.storage().bytes();
225 assert!(bytes.len() <= self.max_uniform_buffer_size);
226 gpu_buffer.write_data(bytes)?;
227 page.is_submitted = true;
228 }
229 }
230
231 Ok(())
232 }
233
234 pub fn block_to_binding(
235 &self,
236 block: UniformBlockLocation,
237 binding_point: usize,
238 ) -> ResourceBinding {
239 ResourceBinding::Buffer {
240 buffer: self.gpu_buffers[block.page].clone(),
241 binding: binding_point,
242 data_usage: BufferDataUsage::UseSegment {
243 offset: block.offset,
244 size: block.size,
245 },
246 }
247 }
248}