1use crate::resource::geometry::{IndexFormat, VertexBufferLayout};
2use crate::resource::ids::{BindGroupLayoutId, BufferId, TextureId};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
6pub enum BindingType {
7 UniformBuffer,
8 UniformBufferDynamic,
9 StorageBuffer,
10 CombinedImageSampler,
11}
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
14pub struct ShaderStageFlags(u8);
15
16impl ShaderStageFlags {
17 pub const VERTEX: Self = Self(1 << 0);
18 pub const FRAGMENT: Self = Self(1 << 1);
19 pub const COMPUTE: Self = Self(1 << 2);
20
21 pub const fn empty() -> Self {
22 Self(0)
23 }
24
25 pub const fn contains(self, other: Self) -> bool {
26 (self.0 & other.0) == other.0
27 }
28
29 pub const fn union(self, other: Self) -> Self {
30 Self(self.0 | other.0)
31 }
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
35pub enum MemoryLocation {
36 #[default]
37 CpuToGpu,
38 GpuOnly,
39 GpuToCpu,
40}
41
42#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
43pub struct BindGroupLayoutEntry {
44 pub binding: u32,
45 pub visibility: ShaderStageFlags,
46 pub ty: BindingType,
47 #[serde(default)]
48 pub readonly: bool,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
52pub struct BindGroupLayoutDescriptor {
53 pub set: u32,
54 pub entries: Vec<BindGroupLayoutEntry>,
55}
56
57#[derive(Debug, Clone)]
58pub enum BindGroupEntryDescriptor {
59 Buffer {
60 binding: u32,
61 buffer: BufferId,
62 offset: u64,
63 size: u64,
64 },
65 Texture {
66 binding: u32,
67 texture: TextureId,
68 },
69}
70
71#[derive(Debug, Clone)]
72pub struct BindGroupDescriptor {
73 pub layout: BindGroupLayoutId,
74 pub entries: Vec<BindGroupEntryDescriptor>,
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
78pub enum BufferUsage {
79 Vertex,
80 Index,
81 Uniform,
82 Storage,
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
86pub struct BufferUsages(u8);
87
88impl BufferUsages {
89 pub const VERTEX: Self = Self(1 << 0);
90 pub const INDEX: Self = Self(1 << 1);
91 pub const UNIFORM: Self = Self(1 << 2);
92 pub const STORAGE: Self = Self(1 << 3);
93
94 pub const fn empty() -> Self {
95 Self(0)
96 }
97
98 pub const fn from_single(usage: BufferUsage) -> Self {
99 match usage {
100 BufferUsage::Vertex => Self::VERTEX,
101 BufferUsage::Index => Self::INDEX,
102 BufferUsage::Uniform => Self::UNIFORM,
103 BufferUsage::Storage => Self::STORAGE,
104 }
105 }
106
107 pub const fn contains(self, other: Self) -> bool {
108 (self.0 & other.0) == other.0
109 }
110
111 pub const fn union(self, other: Self) -> Self {
112 Self(self.0 | other.0)
113 }
114
115 pub const fn is_empty(self) -> bool {
116 self.0 == 0
117 }
118}
119
120impl From<BufferUsage> for BufferUsages {
121 fn from(usage: BufferUsage) -> Self {
122 Self::from_single(usage)
123 }
124}
125
126#[derive(Debug, Clone)]
127pub struct BufferDescriptor {
128 pub size: u64,
129 pub usage: BufferUsage,
130 pub usages: BufferUsages,
131 pub memory_location: MemoryLocation,
132 pub initial_data: Option<Vec<u8>>,
133}
134
135impl BufferDescriptor {
136 pub fn effective_usages(&self) -> BufferUsages {
137 if self.usages.is_empty() {
138 BufferUsages::from_single(self.usage)
139 } else {
140 self.usages
141 }
142 }
143}
144
145impl Default for BufferDescriptor {
146 fn default() -> Self {
147 Self {
148 size: 0,
149 usage: BufferUsage::Uniform,
150 usages: BufferUsages::empty(),
151 memory_location: MemoryLocation::CpuToGpu,
152 initial_data: None,
153 }
154 }
155}
156
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
158pub enum AccessType {
159 None,
160 ComputeRead,
161 ComputeWrite,
162 ComputeReadWrite,
163 VertexRead,
164 VertexShaderRead,
165 FragmentRead,
166}
167
168#[derive(Debug, Clone)]
174pub struct BufferUsageIntent {
175 pub buffer: BufferId,
176 pub access: AccessType,
177 pub set: u32,
178 pub binding: u32,
179 pub offset: u64,
180 pub size: u64,
181}
182
183#[derive(Debug, Clone)]
184pub enum VertexStreamData {
185 Static(Vec<u8>),
187 External(BufferId),
189}
190
191#[derive(Debug, Clone)]
192pub struct VertexStream {
193 pub layout: VertexBufferLayout,
194 pub data: VertexStreamData,
195}
196
197#[derive(Debug, Clone)]
198pub struct MeshDescriptor {
199 pub vertex_streams: Vec<VertexStream>,
200 pub index_data: Vec<u8>,
201 pub index_format: IndexFormat,
202 pub index_count: u32,
203}
204
205impl MeshDescriptor {
206 pub fn single(
207 vertex_data: Vec<u8>,
208 vertex_layout: VertexBufferLayout,
209 index_data: Vec<u8>,
210 index_format: IndexFormat,
211 index_count: u32,
212 ) -> Self {
213 Self {
214 vertex_streams: vec![VertexStream {
215 layout: vertex_layout,
216 data: VertexStreamData::Static(vertex_data),
217 }],
218 index_data,
219 index_format,
220 index_count,
221 }
222 }
223}
224
225#[derive(Debug, Clone, Copy)]
226pub enum TextureFormat {
227 Rgba8Unorm,
228}
229
230impl TextureFormat {
231 pub const fn bytes_per_pixel(self) -> usize {
232 match self {
233 Self::Rgba8Unorm => 4,
234 }
235 }
236
237 pub fn expected_byte_len(self, width: u32, height: u32) -> Option<usize> {
238 (width as usize)
239 .checked_mul(height as usize)?
240 .checked_mul(self.bytes_per_pixel())
241 }
242}
243
244#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
245pub enum CullMode {
246 None,
247 Front,
248 Back,
249}
250
251impl Default for CullMode {
252 fn default() -> Self {
253 Self::Back
254 }
255}
256
257#[derive(Debug, Clone)]
258pub struct TextureDescriptor {
259 pub width: u32,
260 pub height: u32,
261 pub format: TextureFormat,
262 pub data: Vec<u8>,
263 pub render_attachment: bool,
264}
265
266impl TextureDescriptor {
267 pub fn with_render_attachment(mut self, render_attachment: bool) -> Self {
268 self.render_attachment = render_attachment;
269 self
270 }
271}
272
273#[derive(Debug, Clone)]
274pub struct MaterialDescriptor {
275 pub shaders: crate::shader::GraphicsShaderPackage,
276 pub enable_depth: bool,
277 pub cull_mode: CullMode,
278 pub texture: Option<TextureId>,
279}
280
281impl MaterialDescriptor {
282 pub fn new(
283 shaders: crate::shader::GraphicsShaderPackage,
284 enable_depth: bool,
285 texture: Option<TextureId>,
286 ) -> Self {
287 Self {
288 shaders,
289 enable_depth,
290 cull_mode: CullMode::default(),
291 texture,
292 }
293 }
294
295 pub fn with_cull_mode(mut self, cull_mode: CullMode) -> Self {
296 self.cull_mode = cull_mode;
297 self
298 }
299}
300
301#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
302pub struct ComputeBindingLayout {
303 pub set: u32,
304 pub binding: u32,
305 pub readonly: bool,
306}
307
308#[derive(Debug, Clone, Hash, PartialEq, Eq)]
309pub struct ComputePipelineDescriptor {
310 pub shader_spv: Vec<u8>,
311 pub entry_point: String,
312 pub bindings: Vec<ComputeBindingLayout>,
313}
314
315impl ComputePipelineDescriptor {
316 pub fn from_raw(shader_spv: Vec<u8>, entry_point: String, bindings: Vec<ComputeBindingLayout>) -> Self {
317 Self { shader_spv, entry_point, bindings }
318 }
319
320 pub fn new(shader: crate::shader::ShaderPackage) -> Self {
321 Self {
322 shader_spv: shader.spirv_bytes().map(|b| b.to_vec()).unwrap_or_default(),
323 entry_point: shader.entry_point,
324 bindings: Vec::new(),
325 }
326 }
327}