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 _padding: f32,
88 key_scale: [f32; 3],
89 _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, shader_location: 0,
191 },
192 wgpu::VertexAttribute {
193 format: wgpu::VertexFormat::Float32x4,
194 offset: std::mem::size_of::<[f32; 4]>() as u64, shader_location: 1,
196 },
197 wgpu::VertexAttribute {
198 format: wgpu::VertexFormat::Float32x2,
199 offset: std::mem::size_of::<[f32; 8]>() as u64, shader_location: 2,
201 },
202 ]
203 } else {
204 &[
205 wgpu::VertexAttribute {
206 format: wgpu::VertexFormat::Float32x4,
207 offset: 0, shader_location: 0,
209 },
210 wgpu::VertexAttribute {
211 format: wgpu::VertexFormat::Float32x4,
212 offset: std::mem::size_of::<[f32; 4]>() as u64, 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 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 let combine_uniform_size =
258 std::mem::size_of::<FragmentCombineUniforms>() as wgpu::BufferAddress;
259
260 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 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}