1use std::{fs::File, io::Read};
3
4use bind_group::BindGroupEntryBuilder;
5use bytemuck::NoUninit;
6use errors::{RendererSetupError, TextureError};
7use texture::{Texture, TextureBuilder, TextureDimensions};
8use tracing::*;
9use vertex::Vertex;
10use wgpu::{
11 BackendOptions, Backends, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
12 Buffer, BufferDescriptor, BufferUsages, CommandEncoder, InstanceFlags, PresentMode,
13 SurfaceTexture, TextureFormat, TextureView, TextureViewDescriptor, Trace,
14 util::{BufferInitDescriptor, DeviceExt},
15};
16
17use winit::window::Window;
18
19pub mod bind_group;
21pub mod errors;
23#[macro_use]
25pub mod render_pass;
26pub mod instances;
27pub mod render_pipeline;
29pub mod texture;
31pub mod vertex;
33
34pub struct RendererBuilder {
36 backends: Backends,
37 flags: InstanceFlags,
38 backend_options: BackendOptions,
39 power_preference: wgpu::PowerPreference,
40 force_fallback_adapter: bool,
41 required_features: wgpu::Features,
42 required_limits: wgpu::Limits,
43 memory_hints: wgpu::MemoryHints,
44 surface_format: fn(caps: &wgpu::SurfaceCapabilities) -> wgpu::TextureFormat,
45 usage: wgpu::TextureUsages,
46 present_mode: fn(caps: &wgpu::SurfaceCapabilities) -> PresentMode,
47 alpha_mode: fn(caps: &wgpu::SurfaceCapabilities) -> wgpu::CompositeAlphaMode,
48 view_formats: Vec<wgpu::TextureFormat>,
49 trace: Trace,
50 desired_maximum_frame_latency: u32,
51}
52impl RendererBuilder {
53 pub fn new() -> Self {
54 RendererBuilder {
55 backends: Backends::all(),
56 flags: InstanceFlags::empty(),
57 backend_options: BackendOptions::default(),
58 power_preference: wgpu::PowerPreference::default(),
59 force_fallback_adapter: false,
60 required_features: wgpu::Features::empty(),
61 required_limits: wgpu::Limits::downlevel_defaults(),
62 memory_hints: wgpu::MemoryHints::default(),
63 surface_format: |caps| {
64 caps.formats
65 .iter()
66 .copied()
67 .find(|f| f.is_srgb())
68 .unwrap_or(caps.formats[0])
69 },
70 trace: Trace::Off,
71 usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
72 present_mode: |caps| caps.present_modes[0],
73 alpha_mode: |caps| caps.alpha_modes[0],
74 view_formats: Vec::new(),
75 desired_maximum_frame_latency: 2,
76 }
77 }
78 pub fn backends(mut self, backends: Backends) -> Self {
80 self.backends = backends;
81 self
82 }
83 pub fn flags(mut self, flags: InstanceFlags) -> Self {
85 self.flags = flags;
86 self
87 }
88 pub fn backend_options(mut self, backend_options: BackendOptions) -> Self {
90 self.backend_options = backend_options;
91 self
92 }
93 pub fn power_preference(mut self, power_preference: wgpu::PowerPreference) -> Self {
95 self.power_preference = power_preference;
96 self
97 }
98 pub fn force_fallback_adapter(mut self, force_fallback_adapter: bool) -> Self {
99 self.force_fallback_adapter = force_fallback_adapter;
100 self
101 }
102 pub fn required_features(mut self, required_features: wgpu::Features) -> Self {
103 self.required_features = required_features;
104 self
105 }
106 pub fn required_limits(mut self, required_limits: wgpu::Limits) -> Self {
107 self.required_limits = required_limits;
108 self
109 }
110 pub fn memory_hints(mut self, memory_hints: wgpu::MemoryHints) -> Self {
111 self.memory_hints = memory_hints;
112 self
113 }
114 pub fn surface_format(
115 mut self,
116 surface_format: fn(caps: &wgpu::SurfaceCapabilities) -> wgpu::TextureFormat,
117 ) -> Self {
118 self.surface_format = surface_format;
119 self
120 }
121 pub fn usage(mut self, usage: wgpu::TextureUsages) -> Self {
122 self.usage = usage;
123 self
124 }
125 pub fn present_mode(
126 mut self,
127 present_mode: fn(caps: &wgpu::SurfaceCapabilities) -> PresentMode,
128 ) -> Self {
129 self.present_mode = present_mode;
130 self
131 }
132 pub fn alpha_mode(
133 mut self,
134 alpha_mode: fn(caps: &wgpu::SurfaceCapabilities) -> wgpu::CompositeAlphaMode,
135 ) -> Self {
136 self.alpha_mode = alpha_mode;
137 self
138 }
139 pub fn view_formats(mut self, view_formats: Vec<wgpu::TextureFormat>) -> Self {
140 self.view_formats = view_formats;
141 self
142 }
143 pub fn desired_maximum_frame_latency(mut self, desired_maximum_frame_latency: u32) -> Self {
144 self.desired_maximum_frame_latency = desired_maximum_frame_latency;
145 self
146 }
147 pub fn trace(mut self, trace: Trace) -> Self {
148 self.trace = trace;
149 self
150 }
151 pub async fn build<'a>(
152 self,
153 window: std::sync::Arc<Window>,
154 size: (u32, u32),
155 ) -> Result<Renderer<'a>, RendererSetupError> {
156 trace!("Creating renderer");
159 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor {
160 backends: self.backends,
161 flags: self.flags,
162 backend_options: self.backend_options,
163 });
164
165 let surface = instance.create_surface(window)?;
166
167 trace!("Surface created");
168 let adapter = instance
169 .request_adapter(&wgpu::RequestAdapterOptions {
170 power_preference: self.power_preference,
171 compatible_surface: Some(&surface),
172 force_fallback_adapter: self.force_fallback_adapter,
173 })
174 .await?;
175 let features = adapter.features();
176 if !features.contains(self.required_features) {
177 error!("The device dont support the features")
178 }
179 trace!("Adapter created");
180 let (device, queue) = adapter
181 .request_device(&wgpu::DeviceDescriptor {
182 label: None,
183 required_features: self.required_features,
184 required_limits: self.required_limits,
187 memory_hints: self.memory_hints,
188 trace: self.trace,
189 })
190 .await?;
191 trace!("Device and Queue created");
192
193 let surface_caps = surface.get_capabilities(&adapter);
194 let surface_format = (self.surface_format)(&surface_caps);
198 let config = wgpu::SurfaceConfiguration {
199 usage: self.usage,
200 format: surface_format,
201 width: size.0,
202 height: size.1,
203 present_mode: (self.present_mode)(&surface_caps),
204 alpha_mode: (self.alpha_mode)(&surface_caps),
205 view_formats: self.view_formats,
206 desired_maximum_frame_latency: self.desired_maximum_frame_latency,
207 };
208 trace!("Config created");
209 let surface = std::sync::RwLock::new(surface);
210 let config = std::sync::RwLock::new(config);
211 let size = std::sync::RwLock::new(size);
212 trace!("Renderer builded");
213 Ok(Renderer {
214 surface,
215 device,
216 queue,
217 config,
218 size,
219 })
220 }
221}
222pub struct Renderer<'a> {
224 pub surface: std::sync::RwLock<wgpu::Surface<'a>>,
225 pub device: wgpu::Device,
226 pub queue: wgpu::Queue,
227 pub config: std::sync::RwLock<wgpu::SurfaceConfiguration>,
228 pub size: std::sync::RwLock<(u32, u32)>,
229}
230
231impl<'a> Renderer<'a> {
232 pub fn create_encoder(
234 &self,
235 ) -> Result<(CommandEncoder, TextureView, SurfaceTexture), wgpu::SurfaceError> {
236 trace!("Renderer creating encoder");
237 let output = self
238 .surface
239 .read()
240 .expect("Cannot read surface")
241 .get_current_texture()?;
242 let view = output
243 .texture
244 .create_view(&wgpu::TextureViewDescriptor::default());
245
246 Ok((
247 self.device
248 .create_command_encoder(&wgpu::CommandEncoderDescriptor {
249 label: Some("Render Encoder"),
250 }),
251 view,
252 output,
253 ))
254 }
255 pub fn surface(&self) -> std::sync::RwLockReadGuard<wgpu::Surface> {
257 self.surface.read().expect("Cannot read surface")
258 }
259 pub fn device(&self) -> &wgpu::Device {
261 &self.device
262 }
263 pub fn queue(&self) -> &wgpu::Queue {
265 &self.queue
266 }
267 pub fn config(&self) -> std::sync::RwLockReadGuard<wgpu::SurfaceConfiguration> {
269 self.config.read().expect("Cannot read config")
270 }
271 pub fn size(&self) -> (u32, u32) {
273 self.size.read().unwrap().clone()
274 }
275 pub fn resize(&self, new_size: &(u32, u32)) {
276 if new_size.0 > 0 && new_size.1 > 0 {
277 *self.size.write().expect("Cannot write size") = new_size.clone();
278 self.config.write().expect("Cannot write config").width = new_size.0;
279 self.config.write().expect("Cannot write config").height = new_size.1;
280 self.surface
281 .write()
282 .unwrap()
283 .configure(&self.device, &self.config.read().unwrap());
284 }
285 }
286 pub fn init_buffer<A>(&self, label: &str, usage: BufferUsages, content: &[A]) -> Buffer
288 where
289 A: NoUninit,
290 {
291 self.device.create_buffer_init(&BufferInitDescriptor {
292 label: Some(label),
293 contents: bytemuck::cast_slice(content),
294 usage,
295 })
296 }
297 pub fn create_buffer(&self, label: &str, usage: BufferUsages, size: u64) -> Buffer {
298 self.device().create_buffer(&BufferDescriptor {
299 size,
300 usage,
301 label: Some(label),
302 mapped_at_creation: false,
303 })
304 }
305 pub fn bind_group(
307 &self,
308 label: &str,
309 entries: &[BindGroupEntryBuilder],
310 ) -> (wgpu::BindGroup, wgpu::BindGroupLayout) {
311 trace!("Renderer building bind group -- {}", label);
312 let layout_entries: Vec<wgpu::BindGroupLayoutEntry> = entries
313 .iter()
314 .map(|entry| BindGroupLayoutEntry {
315 binding: entry.binding,
316 visibility: entry.visibility,
317 ty: entry.ty,
318 count: entry.count,
319 })
320 .collect();
321 trace!("With {} entries -- {}", layout_entries.len(), label);
322 let layout = self
323 .device
324 .create_bind_group_layout(&BindGroupLayoutDescriptor {
325 label: Some(label),
326 entries: &layout_entries,
327 });
328 trace!("Layout created -- {}", label);
329 let entries: Vec<_> = entries
330 .iter()
331 .map(|entry| BindGroupEntry {
332 binding: entry.binding,
333 resource: entry
334 .resource
335 .clone()
336 .expect("Resource binding in bind group not defined"),
337 })
338 .collect();
339 trace!("{} Entries builded into BindGroupEntry", label);
340 let bind_group = self.device.create_bind_group(&wgpu::BindGroupDescriptor {
341 label: Some(label),
342 layout: &layout,
343 entries: &entries,
344 });
345 trace!("Finnish bind group creation -- {}", label);
346 (bind_group, layout)
347 }
348 pub fn init_texture(
350 &self,
351 label: &'static str,
352 view_formats: Option<&'static [TextureFormat]>,
353 builder: TextureBuilder,
354 ) -> Texture {
355 builder.build(label, view_formats, self)
356 }
357 pub fn simple_png_texture_file(&self, file: &mut File) -> Result<Texture, TextureError> {
359 let mut buffer = Vec::new();
360 file.read_to_end(&mut buffer)?;
361 self.simple_png_texture_bytes(buffer.as_slice())
362 }
363 pub fn simple_png_texture_bytes(&self, bytes: &[u8]) -> Result<Texture, TextureError> {
365 let diffuse_image = image::load_from_memory(bytes)?;
366 let diffuse_rgba = diffuse_image.to_rgba8();
367 use image::GenericImageView;
368 let dimensions = diffuse_image.dimensions();
369
370 let mut texture = self.init_texture(
371 "texture",
372 None,
373 TextureBuilder::new()
374 .dimension(TextureDimensions::D2(dimensions.0, dimensions.1))
375 .data(diffuse_rgba.to_vec()),
376 );
377
378 texture.texture_view(TextureViewDescriptor::default());
379
380 texture.texture_sampler(
381 wgpu::SamplerDescriptor {
382 address_mode_u: wgpu::AddressMode::ClampToEdge,
383 address_mode_v: wgpu::AddressMode::ClampToEdge,
384 address_mode_w: wgpu::AddressMode::ClampToEdge,
385 mag_filter: wgpu::FilterMode::Linear,
386 min_filter: wgpu::FilterMode::Nearest,
387 mipmap_filter: wgpu::FilterMode::Nearest,
388 ..Default::default()
389 },
390 self,
391 );
392
393 texture.default_bind_group("texture bind group", self);
394 Ok(texture)
395 }
396 pub fn init_buffer_from_vertices<A: Vertex>(&self, label: &str, vertices: &[A]) -> Buffer {
398 self.init_buffer(label, BufferUsages::VERTEX, vertices)
399 }
400 pub fn init_buffer_from_indices<A: NoUninit>(&self, label: &str, indices: &[A]) -> Buffer {
402 self.init_buffer(label, BufferUsages::INDEX, indices)
403 }
404 pub fn init_buffers_from_model<A: Vertex, B: NoUninit>(
407 &self,
408 label: &str,
409 vertices: &[A],
410 indices: &[B],
411 ) -> (Buffer, Buffer) {
412 trace!(
413 "Initializing model buffers with {} vertices and {} indices -- {}",
414 vertices.len(),
415 indices.len(),
416 label
417 );
418 let vertices_label = format!("{} - VERTICES", label);
419 let indices_label = format!("{} - INDICES", label);
420
421 let vertices_buffer = self.init_buffer_from_vertices(vertices_label.as_str(), vertices);
422 let indices_buffer = self.init_buffer_from_indices(indices_label.as_str(), indices);
423
424 (vertices_buffer, indices_buffer)
425 }
426 pub fn update_buffer<A: NoUninit>(&self, buffer: &Buffer, data: &[A]) {
427 self.queue()
428 .write_buffer(buffer, 0, bytemuck::cast_slice(data));
429 }
430 pub fn update_buffer_entry<A: NoUninit>(&self, buffer: &Buffer, id: u64, data: A) {
431 let size = std::mem::size_of::<A>();
432 let offset = size as u64 * id;
433 self.queue()
434 .write_buffer(buffer, offset, bytemuck::cast_slice(&[data]));
435 }
436}