pebble/graphics/pipeline/
params.rs1use crate::{
2 assets::{handle::Handle, storage::Assets},
3 graphics::{
4 pipeline::{
5 binding::{BindGroupLayout, BindingEntry},
6 buffers::{BindGroup, BindGroupBuilder, Buffer, BufferBuilder, DynamicBuffer},
7 cubemap::Cubemap,
8 samplers::{GlobalSamplers, SamplerKind},
9 texture_array::TextureArray,
10 texture_view::TextureView,
11 textures::Texture,
12 },
13 render::Backend,
14 types::flags::BufferUsages,
15 },
16};
17
18#[derive(Clone)]
21pub enum BindingValue {
22 Texture(Handle<Texture>),
23 TextureArray(Handle<TextureArray>),
24 Cubemap(Handle<Cubemap>),
25 TextureView(TextureView),
26 Sampler(SamplerKind),
27 Uniform(Vec<u8>),
28 Storage(Vec<u8>),
29 Buffer(Buffer),
30 DynamicBuffer(DynamicBuffer),
31}
32
33#[derive(Clone, Default)]
39pub struct BindGroupParams {
40 params: Vec<(&'static str, BindingValue)>,
41}
42
43impl BindGroupParams {
44 pub fn new() -> Self {
45 Self::default()
46 }
47
48 pub fn with_texture(mut self, name: &'static str, handle: Handle<Texture>) -> Self {
49 self.params.push((name, BindingValue::Texture(handle)));
50 self
51 }
52
53 pub fn with_texture_array(mut self, name: &'static str, handle: Handle<TextureArray>) -> Self {
54 self.params.push((name, BindingValue::TextureArray(handle)));
55 self
56 }
57
58 pub fn with_cubemap(mut self, name: &'static str, handle: Handle<Cubemap>) -> Self {
59 self.params.push((name, BindingValue::Cubemap(handle)));
60 self
61 }
62
63 pub fn with_texture_view(mut self, name: &'static str, view: TextureView) -> Self {
70 self.params.push((name, BindingValue::TextureView(view)));
71 self
72 }
73
74 pub fn with_sampler(mut self, name: &'static str, kind: SamplerKind) -> Self {
75 self.params.push((name, BindingValue::Sampler(kind)));
76 self
77 }
78
79 pub fn with_uniform(mut self, name: &'static str, data: Vec<u8>) -> Self {
80 self.params.push((name, BindingValue::Uniform(data)));
81 self
82 }
83
84 pub fn with_storage(mut self, name: &'static str, data: Vec<u8>) -> Self {
85 self.params.push((name, BindingValue::Storage(data)));
86 self
87 }
88
89 pub fn with_uniform_value<T>(self, name: &'static str, value: &T) -> Self
94 where
95 T: encase::ShaderType + encase::internal::WriteInto,
96 {
97 let mut buffer = encase::UniformBuffer::new(Vec::new());
98 buffer
99 .write(value)
100 .expect("encase: failed to write uniform value — this shouldn't happen for a #[derive(ShaderType)] struct");
101 self.with_uniform(name, buffer.into_inner())
102 }
103
104 pub fn with_storage_value<T>(self, name: &'static str, value: &T) -> Self
108 where
109 T: encase::ShaderType + encase::internal::WriteInto,
110 {
111 let mut buffer = encase::StorageBuffer::new(Vec::new());
112 buffer
113 .write(value)
114 .expect("encase: failed to write storage value — this shouldn't happen for a #[derive(ShaderType)] struct");
115 self.with_storage(name, buffer.into_inner())
116 }
117
118 pub fn with_buffer(mut self, name: &'static str, buffer: Buffer) -> Self {
125 self.params.push((name, BindingValue::Buffer(buffer)));
126 self
127 }
128
129 pub fn with_dynamic_buffer(mut self, name: &'static str, buffer: DynamicBuffer) -> Self {
135 self.params.push((name, BindingValue::DynamicBuffer(buffer)));
136 self
137 }
138
139 pub fn with_param(mut self, name: &'static str, entry: BindingValue) -> Self {
140 self.params.push((name, entry));
141 self
142 }
143
144 pub(crate) fn is_empty(&self) -> bool {
145 self.params.is_empty()
146 }
147}
148
149pub(crate) fn binding_index(entries: &[BindingEntry], name: &str) -> Option<u32> {
151 entries.iter().find(|e| e.name == name).map(|e| e.binding)
152}
153
154pub(crate) struct BuiltBindGroup {
159 pub bind_group: BindGroup,
160 pub buffers: Vec<(&'static str, Buffer)>,
161 pub dynamic_buffers: Vec<(&'static str, DynamicBuffer)>,
162}
163
164pub(crate) fn build_bind_group(
169 backend: &Backend,
170 params: &BindGroupParams,
171 layout: &BindGroupLayout,
172 entries: &[BindingEntry],
173 textures: &Assets<Texture>,
174 texture_arrays: &Assets<TextureArray>,
175 cubemaps: &Assets<Cubemap>,
176 samplers: &GlobalSamplers,
177) -> Option<BuiltBindGroup> {
178 let owned_buffers: Vec<(&'static str, Buffer)> = params
183 .params
184 .iter()
185 .filter_map(|(name, entry)| match entry {
186 BindingValue::Uniform(bytes) => Some((
187 *name,
188 BufferBuilder::with_data(bytes)
189 .with_usage(BufferUsages::UNIFORM | BufferUsages::COPY_DST | BufferUsages::COPY_SRC)
190 .build(backend),
191 )),
192 BindingValue::Storage(bytes) => Some((
193 *name,
194 BufferBuilder::with_data(bytes)
195 .with_usage(BufferUsages::STORAGE | BufferUsages::COPY_DST | BufferUsages::COPY_SRC)
196 .build(backend),
197 )),
198 BindingValue::Buffer(buffer) => Some((*name, buffer.clone())),
199 _ => None,
200 })
201 .collect();
202
203 let owned_dynamic_buffers: Vec<(&'static str, DynamicBuffer)> = params
207 .params
208 .iter()
209 .filter_map(|(name, entry)| match entry {
210 BindingValue::DynamicBuffer(buffer) => Some((*name, buffer.clone())),
211 _ => None,
212 })
213 .collect();
214
215 let mut builder = BindGroupBuilder::new(layout);
216 for (name, entry) in ¶ms.params {
217 let binding = binding_index(entries, name)?;
218 builder = match entry {
219 BindingValue::Texture(handle) => builder.with_texture_2d_at(binding, textures.get(*handle)?),
220 BindingValue::TextureArray(handle) => builder.with_texture_array_at(binding, texture_arrays.get(*handle)?),
221 BindingValue::Cubemap(handle) => builder.with_texture_cubemap_at(binding, cubemaps.get(*handle)?),
222 BindingValue::TextureView(view) => builder.with_texture_view_at(binding, view),
223 BindingValue::Sampler(kind) => builder.with_sampler_at(binding, samplers.get(*kind)),
224 BindingValue::Uniform(_) | BindingValue::Storage(_) | BindingValue::Buffer(_) => {
225 let buf = &owned_buffers.iter().find(|(n, _)| n == name)?.1;
226 builder.with_buffer_at(binding, buf)
227 }
228 BindingValue::DynamicBuffer(_) => {
229 let buf = &owned_dynamic_buffers.iter().find(|(n, _)| n == name)?.1;
230 builder.with_dynamic_buffer_at(binding, buf)
231 }
232 };
233 }
234
235 Some(BuiltBindGroup { bind_group: builder.build(backend), buffers: owned_buffers, dynamic_buffers: owned_dynamic_buffers })
236}