fast3d_wgpu_renderer/
defines.rs

1use crate::wgpu_program::WgpuProgram;
2use bytemuck::{Pod, Zeroable};
3use fast3d::output::gfx::{BlendState, Face};
4use fast3d::output::models::OutputStencil;
5use fast3d::output::ShaderId;
6use wgpu::util::align_to;
7use wgpu::ShaderModule;
8
9#[repr(C)]
10#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)]
11pub struct VertexUniforms {
12    pub screen_size: [f32; 2],
13    _padding: [f32; 2],
14    pub projection_matrix: [[f32; 4]; 4],
15}
16
17impl VertexUniforms {
18    pub fn new(screen_size: [f32; 2], projection_matrix: [[f32; 4]; 4]) -> Self {
19        Self {
20            screen_size,
21            _padding: [0.0; 2],
22            projection_matrix,
23        }
24    }
25}
26
27#[repr(C)]
28#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)]
29pub struct VertexWithFogUniforms {
30    pub screen_size: [f32; 2],
31    _padding: [f32; 2],
32    pub projection_matrix: [[f32; 4]; 4],
33    pub fog_multiplier: f32,
34    pub fog_offset: f32,
35    _padding2: [f32; 2],
36}
37
38impl VertexWithFogUniforms {
39    pub fn new(
40        screen_size: [f32; 2],
41        projection_matrix: [[f32; 4]; 4],
42        fog_multiplier: f32,
43        fog_offset: f32,
44    ) -> Self {
45        Self {
46            screen_size,
47            _padding: [0.0; 2],
48            projection_matrix,
49            fog_multiplier,
50            fog_offset,
51            _padding2: [0.0; 2],
52        }
53    }
54}
55
56#[repr(C)]
57#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)]
58pub struct FragmentBlendUniforms {
59    pub blend_color: [f32; 4],
60}
61
62#[repr(C)]
63#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)]
64pub struct FragmentBlendWithFogUniforms {
65    pub blend_color: [f32; 4],
66    pub fog_color: [f32; 3],
67    _padding: f32,
68}
69
70impl FragmentBlendWithFogUniforms {
71    pub fn new(blend_color: [f32; 4], fog_color: [f32; 3]) -> Self {
72        Self {
73            blend_color,
74            fog_color,
75            _padding: 0.0,
76        }
77    }
78}
79
80#[repr(C)]
81#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)]
82pub struct FragmentCombineUniforms {
83    prim_color: [f32; 4],
84    env_color: [f32; 4],
85    key_center: [f32; 3],
86    // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here
87    _padding: f32,
88    key_scale: [f32; 3],
89    // Due to uniforms requiring 16 byte (4 float) spacing, we need to use a padding field here
90    _padding2: f32,
91    prim_lod_frac: f32,
92    convert_k4: f32,
93    convert_k5: f32,
94    _padding3: f32,
95}
96
97impl FragmentCombineUniforms {
98    pub fn new(
99        prim_color: [f32; 4],
100        env_color: [f32; 4],
101        key_center: [f32; 3],
102        key_scale: [f32; 3],
103        prim_lod_frac: f32,
104        convert_k4: f32,
105        convert_k5: f32,
106    ) -> Self {
107        Self {
108            prim_color,
109            env_color,
110            key_center,
111            _padding: 0.0,
112            key_scale,
113            _padding2: 0.0,
114            prim_lod_frac,
115            convert_k4,
116            convert_k5,
117            _padding3: 0.0,
118        }
119    }
120}
121
122#[repr(C)]
123#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)]
124pub struct FragmentFrameUniforms {
125    pub count: u32,
126    pub height: u32,
127}
128
129pub struct TextureData {
130    pub texture_view: wgpu::TextureView,
131    pub sampler: wgpu::Sampler,
132}
133
134impl TextureData {
135    pub fn new(texture_view: wgpu::TextureView, sampler: wgpu::Sampler) -> Self {
136        Self {
137            texture_view,
138            sampler,
139        }
140    }
141}
142
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
144pub struct PipelineId(pub PipelineConfig);
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
147pub struct PipelineConfig {
148    pub shader: ShaderId,
149    pub blend_state: Option<BlendState>,
150    pub cull_mode: Option<Face>,
151    pub depth_stencil: Option<OutputStencil>,
152}
153
154pub struct ShaderEntry<'a> {
155    pub program: WgpuProgram<ShaderModule>,
156    pub vertex_buf_layout: wgpu::VertexBufferLayout<'a>,
157    pub vertex_uniform_bind_group_layout: wgpu::BindGroupLayout,
158    pub fragment_uniform_bind_group_layout: wgpu::BindGroupLayout,
159}
160
161impl<'a> ShaderEntry<'a> {
162    pub fn new(program: WgpuProgram<ShaderModule>, device: &wgpu::Device) -> Self {
163        let vertex_buf_layout = Self::create_vertex_buf_layout(&program);
164
165        let vertex_uniform_bind_group_layout =
166            Self::create_vertex_uniforms_resources(&program, device);
167        let fragment_uniform_bind_group_layout =
168            Self::create_fragment_uniforms_resources(&program, device);
169
170        Self {
171            program,
172
173            vertex_buf_layout,
174            vertex_uniform_bind_group_layout,
175            fragment_uniform_bind_group_layout,
176        }
177    }
178
179    fn create_vertex_buf_layout(
180        program: &WgpuProgram<ShaderModule>,
181    ) -> wgpu::VertexBufferLayout<'a> {
182        wgpu::VertexBufferLayout {
183            array_stride: (program.num_floats * std::mem::size_of::<f32>()) as u64,
184            step_mode: wgpu::VertexStepMode::Vertex,
185            attributes: if program.uses_texture_0() || program.uses_texture_1() {
186                &[
187                    wgpu::VertexAttribute {
188                        format: wgpu::VertexFormat::Float32x4,
189                        offset: 0, // position
190                        shader_location: 0,
191                    },
192                    wgpu::VertexAttribute {
193                        format: wgpu::VertexFormat::Float32x4,
194                        offset: std::mem::size_of::<[f32; 4]>() as u64, // color
195                        shader_location: 1,
196                    },
197                    wgpu::VertexAttribute {
198                        format: wgpu::VertexFormat::Float32x2,
199                        offset: std::mem::size_of::<[f32; 8]>() as u64, // texcoord
200                        shader_location: 2,
201                    },
202                ]
203            } else {
204                &[
205                    wgpu::VertexAttribute {
206                        format: wgpu::VertexFormat::Float32x4,
207                        offset: 0, // position
208                        shader_location: 0,
209                    },
210                    wgpu::VertexAttribute {
211                        format: wgpu::VertexFormat::Float32x4,
212                        offset: std::mem::size_of::<[f32; 4]>() as u64, // color
213                        shader_location: 1,
214                    },
215                ]
216            },
217        }
218    }
219
220    fn create_vertex_uniforms_resources(
221        program: &WgpuProgram<ShaderModule>,
222        device: &wgpu::Device,
223    ) -> wgpu::BindGroupLayout {
224        let vertex_uniform_size = if program.uses_fog() {
225            std::mem::size_of::<VertexWithFogUniforms>() as wgpu::BufferAddress
226        } else {
227            std::mem::size_of::<VertexUniforms>() as wgpu::BufferAddress
228        };
229
230        device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
231            label: Some("Vertex Bind Group Layout"),
232            entries: &[wgpu::BindGroupLayoutEntry {
233                binding: 0,
234                visibility: wgpu::ShaderStages::VERTEX,
235                ty: wgpu::BindingType::Buffer {
236                    ty: wgpu::BufferBindingType::Uniform,
237                    has_dynamic_offset: false,
238                    min_binding_size: wgpu::BufferSize::new(vertex_uniform_size),
239                },
240                count: None,
241            }],
242        })
243    }
244
245    fn create_fragment_uniforms_resources(
246        program: &WgpuProgram<ShaderModule>,
247        device: &wgpu::Device,
248    ) -> wgpu::BindGroupLayout {
249        // Handle blend uniforms
250        let blend_uniform_size = if program.uses_fog() {
251            std::mem::size_of::<FragmentBlendWithFogUniforms>() as wgpu::BufferAddress
252        } else {
253            std::mem::size_of::<FragmentBlendUniforms>() as wgpu::BufferAddress
254        };
255
256        // Handle combine uniforms
257        let combine_uniform_size =
258            std::mem::size_of::<FragmentCombineUniforms>() as wgpu::BufferAddress;
259
260        // Handle frame uniforms
261        let frame_uniform_buf = {
262            if program.uses_alpha() && program.uses_alpha_compare_dither() {
263                let frame_uniform_size =
264                    std::mem::size_of::<FragmentFrameUniforms>() as wgpu::BufferAddress;
265
266                let frame_uniform_alignment = {
267                    let alignment =
268                        device.limits().min_uniform_buffer_offset_alignment as wgpu::BufferAddress;
269                    align_to(frame_uniform_size, alignment)
270                };
271
272                Some(device.create_buffer(&wgpu::BufferDescriptor {
273                    label: Some("Frame Uniform Buffer"),
274                    size: frame_uniform_alignment,
275                    usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
276                    mapped_at_creation: false,
277                }))
278            } else {
279                None
280            }
281        };
282
283        // Create bind group layout
284        let mut bind_group_layout_entries = vec![
285            wgpu::BindGroupLayoutEntry {
286                binding: 0,
287                visibility: wgpu::ShaderStages::FRAGMENT,
288                ty: wgpu::BindingType::Buffer {
289                    ty: wgpu::BufferBindingType::Uniform,
290                    has_dynamic_offset: false,
291                    min_binding_size: wgpu::BufferSize::new(blend_uniform_size),
292                },
293                count: None,
294            },
295            wgpu::BindGroupLayoutEntry {
296                binding: 1,
297                visibility: wgpu::ShaderStages::FRAGMENT,
298                ty: wgpu::BindingType::Buffer {
299                    ty: wgpu::BufferBindingType::Uniform,
300                    has_dynamic_offset: false,
301                    min_binding_size: wgpu::BufferSize::new(combine_uniform_size),
302                },
303                count: None,
304            },
305        ];
306
307        if frame_uniform_buf.is_some() {
308            bind_group_layout_entries.push(wgpu::BindGroupLayoutEntry {
309                binding: 2,
310                visibility: wgpu::ShaderStages::FRAGMENT,
311                ty: wgpu::BindingType::Buffer {
312                    ty: wgpu::BufferBindingType::Uniform,
313                    has_dynamic_offset: false,
314                    min_binding_size: wgpu::BufferSize::new(
315                        std::mem::size_of::<FragmentFrameUniforms>() as wgpu::BufferAddress,
316                    ),
317                },
318                count: None,
319            });
320        }
321
322        device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
323            label: Some("Fragment Uniform Group Layout"),
324            entries: &bind_group_layout_entries,
325        })
326    }
327}