Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add debug logging, improve error messages, shuffle some render stuff around #2035

Merged
merged 4 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions crates/fj-viewer/src/graphics/device.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#[derive(Debug)]
pub struct Device {
pub device: wgpu::Device,
pub queue: wgpu::Queue,
}

impl Device {
pub async fn new(
adapter: &wgpu::Adapter,
) -> Result<(Self, wgpu::Features), wgpu::RequestDeviceError> {
let features = {
let desired_features = wgpu::Features::POLYGON_MODE_LINE;
let available_features = adapter.features();

// By requesting the intersection of desired and available features,
// we prevent two things:
//
// 1. That requesting the device panics, which would happen if we
// requested unavailable features.
// 2. That a developer ends up accidentally using features that
// happen to be available on their machine, but that aren't
// necessarily available for all the users.
desired_features.intersection(available_features)
};

let limits = {
// This is the lowest of the available defaults. It should guarantee
// that we can run pretty much everywhere.
let lowest_limits = wgpu::Limits::downlevel_webgl2_defaults();

// However, these lowest limits aren't necessarily capable of
// supporting the screen resolution of our current platform, so
// let's amend them.
let supported_limits = adapter.limits();
lowest_limits.using_resolution(supported_limits)
};

let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
features,
limits,
},
None,
)
.await?;

Ok((Device { device, queue }, features))
}
}
1 change: 1 addition & 0 deletions crates/fj-viewer/src/graphics/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Rendering primitives, routines, and structures.

mod device;
mod draw_config;
mod drawables;
mod geometries;
Expand Down
149 changes: 67 additions & 82 deletions crates/fj-viewer/src/graphics/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,17 @@ use crate::{
};

use super::{
draw_config::DrawConfig, drawables::Drawables, geometries::Geometries,
navigation_cube::NavigationCubeRenderer, pipelines::Pipelines,
transform::Transform, uniforms::Uniforms, vertices::Vertices, DEPTH_FORMAT,
SAMPLE_COUNT,
device::Device, draw_config::DrawConfig, drawables::Drawables,
geometries::Geometries, navigation_cube::NavigationCubeRenderer,
pipelines::Pipelines, transform::Transform, uniforms::Uniforms,
vertices::Vertices, DEPTH_FORMAT, SAMPLE_COUNT,
};

/// Graphics rendering state and target abstraction
#[derive(Debug)]
pub struct Renderer {
surface: wgpu::Surface,
device: wgpu::Device,
queue: wgpu::Queue,
device: Device,

surface_config: wgpu::SurfaceConfiguration,
frame_buffer: wgpu::TextureView,
Expand All @@ -47,6 +46,10 @@ impl Renderer {
// This is sound, as `window` is an object to create a surface upon.
let surface = unsafe { instance.create_surface(screen.window()) }?;

for adapter in instance.enumerate_adapters(wgpu::Backends::all()) {
debug!("Available adapter: {:?}", adapter.get_info());
}

let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::None,
Expand All @@ -58,43 +61,7 @@ impl Renderer {

debug!("Using adapter: {:?}", adapter.get_info());

let features = {
let desired_features = wgpu::Features::POLYGON_MODE_LINE;
let available_features = adapter.features();

// By requesting the intersection of desired and available features,
// we prevent two things:
//
// 1. That requesting the device panics, which would happen if we
// requested unavailable features.
// 2. That a developer ends up accidentally using features that
// happen to be available on their machine, but that aren't
// necessarily available for all the users.
desired_features.intersection(available_features)
};

let limits = {
// This is the lowest of the available defaults. It should guarantee
// that we can run pretty much everywhere.
let lowest_limits = wgpu::Limits::downlevel_webgl2_defaults();

// However, these lowest limits aren't necessarily capable of
// supporting the screen resolution of our current platform, so
// let's amend them.
let supported_limits = adapter.limits();
lowest_limits.using_resolution(supported_limits)
};

let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
features,
limits,
},
None,
)
.await?;
let (device, features) = Device::new(&adapter).await?;

let color_format = 'color_format: {
let capabilities = surface.get_capabilities(&adapter);
Expand Down Expand Up @@ -142,20 +109,23 @@ impl Renderer {
alpha_mode: wgpu::CompositeAlphaMode::Auto,
view_formats: vec![],
};
surface.configure(&device, &surface_config);
surface.configure(&device.device, &surface_config);

let frame_buffer = Self::create_frame_buffer(&device, &surface_config);
let depth_view = Self::create_depth_buffer(&device, &surface_config);
let frame_buffer =
Self::create_frame_buffer(&device.device, &surface_config);
let depth_view =
Self::create_depth_buffer(&device.device, &surface_config);

let uniform_buffer =
device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
let uniform_buffer = device.device.create_buffer_init(
&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&[Uniforms::default()]),
usage: wgpu::BufferUsages::UNIFORM
| wgpu::BufferUsages::COPY_DST,
});
let bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
},
);
let bind_group_layout = device.device.create_bind_group_layout(
&wgpu::BindGroupLayoutDescriptor {
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::all(),
Expand All @@ -171,31 +141,41 @@ impl Renderer {
count: None,
}],
label: None,
},
);
let bind_group =
device.device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(
wgpu::BufferBinding {
buffer: &uniform_buffer,
offset: 0,
size: None,
},
),
}],
label: None,
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer: &uniform_buffer,
offset: 0,
size: None,
}),
}],
label: None,
});

let geometries = Geometries::new(&device, &Vertices::empty());
let pipelines =
Pipelines::new(&device, &bind_group_layout, color_format, features);
let geometries = Geometries::new(&device.device, &Vertices::empty());
let pipelines = Pipelines::new(
&device.device,
&bind_group_layout,
color_format,
features,
);

let navigation_cube_renderer =
NavigationCubeRenderer::new(&device, &queue, &surface_config);
let navigation_cube_renderer = NavigationCubeRenderer::new(
&device.device,
&device.queue,
&surface_config,
);

Ok(Self {
surface,
device,
queue,

surface_config,
frame_buffer,
Expand All @@ -213,7 +193,7 @@ impl Renderer {

/// Updates the geometry of the model being rendered.
pub fn update_geometry(&mut self, mesh: Vertices) {
self.geometries = Geometries::new(&self.device, &mesh);
self.geometries = Geometries::new(&self.device.device, &mesh);
}

/// Resizes the render surface.
Expand All @@ -224,12 +204,17 @@ impl Renderer {
self.surface_config.width = size.width;
self.surface_config.height = size.height;

self.surface.configure(&self.device, &self.surface_config);
self.surface
.configure(&self.device.device, &self.surface_config);

self.frame_buffer =
Self::create_frame_buffer(&self.device, &self.surface_config);
self.depth_view =
Self::create_depth_buffer(&self.device, &self.surface_config);
self.frame_buffer = Self::create_frame_buffer(
&self.device.device,
&self.surface_config,
);
self.depth_view = Self::create_depth_buffer(
&self.device.device,
&self.surface_config,
);
}

/// Draws the renderer, camera, and config state to the window.
Expand All @@ -245,7 +230,7 @@ impl Renderer {
transform_normals: Transform::for_normals(camera),
};

self.queue.write_buffer(
self.device.queue.write_buffer(
&self.uniform_buffer,
0,
bytemuck::cast_slice(&[uniforms]),
Expand All @@ -269,7 +254,7 @@ impl Renderer {
.texture
.create_view(&wgpu::TextureViewDescriptor::default());

let mut encoder = self.device.create_command_encoder(
let mut encoder = self.device.device.create_command_encoder(
&wgpu::CommandEncoderDescriptor { label: None },
);

Expand Down Expand Up @@ -319,13 +304,13 @@ impl Renderer {
self.navigation_cube_renderer.draw(
&color_view,
&mut encoder,
&self.queue,
&self.device.queue,
aspect_ratio,
camera.rotation,
);

let command_buffer = encoder.finish();
self.queue.submit(Some(command_buffer));
self.device.queue.submit(Some(command_buffer));

trace!("Presenting...");
surface_texture.present();
Expand Down Expand Up @@ -382,11 +367,11 @@ impl Renderer {
#[derive(Error, Debug)]
pub enum RendererInitError {
/// General IO error
#[error("I/O error: {0}")]
#[error("I/O error")]
Io(#[from] io::Error),

/// Surface creating error
#[error("Error creating surface: {0}")]
#[error("Error creating surface")]
CreateSurface(#[from] wgpu::CreateSurfaceError),

/// Graphics accelerator acquisition error
Expand All @@ -396,7 +381,7 @@ pub enum RendererInitError {
/// Device request errors
///
/// See: [wgpu::RequestDeviceError](https://docs.rs/wgpu/latest/wgpu/struct.RequestDeviceError.html)
#[error("Error requesting device: {0}")]
#[error("Error requesting device")]
RequestDevice(#[from] wgpu::RequestDeviceError),
}

Expand Down