mirror of https://github.com/AxioDL/metaforce.git
195 lines
6.9 KiB
Rust
195 lines
6.9 KiB
Rust
use std::{num::NonZeroU8, sync::Arc};
|
|
|
|
use pollster::block_on;
|
|
|
|
#[derive(Clone)]
|
|
pub(crate) struct GraphicsConfig {
|
|
pub(crate) color_format: wgpu::TextureFormat,
|
|
pub(crate) depth_format: wgpu::TextureFormat,
|
|
pub(crate) texture_anistropy: Option<NonZeroU8>,
|
|
pub(crate) msaa_samples: u32,
|
|
}
|
|
|
|
pub struct DeviceHolder {
|
|
pub(crate) instance: wgpu::Instance,
|
|
pub(crate) surface: wgpu::Surface,
|
|
pub(crate) adapter: wgpu::Adapter,
|
|
pub(crate) backend: wgpu::Backend,
|
|
pub(crate) device: Arc<wgpu::Device>,
|
|
pub(crate) queue: Arc<wgpu::Queue>,
|
|
pub(crate) config: GraphicsConfig,
|
|
pub(crate) surface_config: wgpu::SurfaceConfiguration,
|
|
pub(crate) framebuffer: TextureWithSampler,
|
|
pub(crate) depth: TextureWithSampler,
|
|
}
|
|
|
|
pub(crate) struct TextureWithSampler {
|
|
pub(crate) texture: wgpu::Texture,
|
|
pub(crate) view: wgpu::TextureView,
|
|
pub(crate) sampler: wgpu::Sampler,
|
|
}
|
|
|
|
pub(crate) fn create_render_texture(
|
|
device: &wgpu::Device,
|
|
config: &wgpu::SurfaceConfiguration,
|
|
graphics_config: &GraphicsConfig,
|
|
) -> TextureWithSampler {
|
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
|
label: Some("Render texture"),
|
|
size: wgpu::Extent3d {
|
|
width: config.width,
|
|
height: config.height,
|
|
depth_or_array_layers: 1,
|
|
},
|
|
mip_level_count: 1,
|
|
sample_count: graphics_config.msaa_samples,
|
|
dimension: wgpu::TextureDimension::D2,
|
|
format: graphics_config.color_format,
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
});
|
|
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
|
label: Some("Render sampler"),
|
|
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
|
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
|
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
|
mag_filter: wgpu::FilterMode::Linear,
|
|
min_filter: wgpu::FilterMode::Linear,
|
|
mipmap_filter: wgpu::FilterMode::Linear,
|
|
lod_min_clamp: 0.0,
|
|
lod_max_clamp: f32::MAX,
|
|
compare: None,
|
|
anisotropy_clamp: None,
|
|
border_color: None,
|
|
});
|
|
TextureWithSampler { texture, view, sampler }
|
|
}
|
|
|
|
pub(crate) fn create_depth_texture(
|
|
device: &wgpu::Device,
|
|
config: &wgpu::SurfaceConfiguration,
|
|
graphics_config: &GraphicsConfig,
|
|
) -> TextureWithSampler {
|
|
let texture = device.create_texture(&wgpu::TextureDescriptor {
|
|
label: Some("Depth texture"),
|
|
size: wgpu::Extent3d {
|
|
width: config.width,
|
|
height: config.height,
|
|
depth_or_array_layers: 1,
|
|
},
|
|
mip_level_count: 1,
|
|
sample_count: graphics_config.msaa_samples,
|
|
dimension: wgpu::TextureDimension::D2,
|
|
format: graphics_config.depth_format,
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
});
|
|
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
|
|
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
|
|
label: Some("Depth sampler"),
|
|
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
|
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
|
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
|
mag_filter: wgpu::FilterMode::Linear,
|
|
min_filter: wgpu::FilterMode::Linear,
|
|
mipmap_filter: wgpu::FilterMode::Linear,
|
|
lod_min_clamp: 0.0,
|
|
lod_max_clamp: f32::MAX,
|
|
compare: None,
|
|
anisotropy_clamp: None,
|
|
border_color: None,
|
|
});
|
|
TextureWithSampler { texture, view, sampler }
|
|
}
|
|
|
|
pub(crate) fn initialize_gpu(window: &winit::window::Window) -> DeviceHolder {
|
|
log::info!("Creating wgpu instance");
|
|
let instance = wgpu::Instance::new(wgpu::Backends::all());
|
|
let surface = unsafe { instance.create_surface(window) };
|
|
let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
|
|
power_preference: wgpu::PowerPreference::HighPerformance,
|
|
compatible_surface: Some(&surface),
|
|
force_fallback_adapter: false,
|
|
}))
|
|
.expect("Failed to find an appropriate adapter");
|
|
let best_limits = adapter.limits();
|
|
let backend = adapter.get_info().backend;
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
let needs_denorm = true;
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
let _needs_denorm = backend == wgpu::Backend::Gl;
|
|
|
|
let required_features = if backend == wgpu::Backend::Vulkan {
|
|
wgpu::Features::SPIRV_SHADER_PASSTHROUGH
|
|
} else {
|
|
wgpu::Features::empty()
|
|
};
|
|
let optional_features = wgpu::Features::TEXTURE_COMPRESSION_BC
|
|
| wgpu::Features::ADDRESS_MODE_CLAMP_TO_BORDER
|
|
| required_features;
|
|
log::info!("Requesting device with features: {:?}", optional_features);
|
|
let limits = wgpu::Limits::downlevel_defaults()
|
|
.using_resolution(best_limits.clone())
|
|
.using_alignment(best_limits);
|
|
let (device, queue) = block_on(adapter.request_device(
|
|
&wgpu::DeviceDescriptor {
|
|
label: Some("Device with optional features"),
|
|
features: optional_features,
|
|
limits: limits.clone(),
|
|
},
|
|
None,
|
|
))
|
|
.unwrap_or_else(|_| {
|
|
log::warn!("Failed... requesting device with no features");
|
|
block_on(adapter.request_device(
|
|
&wgpu::DeviceDescriptor {
|
|
label: Some("Device without optional features"),
|
|
features: required_features,
|
|
limits,
|
|
},
|
|
None,
|
|
))
|
|
.expect("Failed to create device")
|
|
});
|
|
log::info!("Successfully created device");
|
|
|
|
let mut swapchain_format = surface.get_preferred_format(&adapter).unwrap();
|
|
if backend != wgpu::Backend::Gl {
|
|
swapchain_format = match swapchain_format {
|
|
wgpu::TextureFormat::Rgba8UnormSrgb => wgpu::TextureFormat::Rgba8Unorm,
|
|
wgpu::TextureFormat::Bgra8UnormSrgb => wgpu::TextureFormat::Bgra8Unorm,
|
|
_ => swapchain_format,
|
|
};
|
|
}
|
|
let graphics_config = GraphicsConfig {
|
|
color_format: swapchain_format,
|
|
depth_format: wgpu::TextureFormat::Depth32Float,
|
|
texture_anistropy: NonZeroU8::new(16),
|
|
msaa_samples: 4,
|
|
};
|
|
|
|
let size = window.inner_size();
|
|
let surface_config = wgpu::SurfaceConfiguration {
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
|
format: swapchain_format,
|
|
width: size.width,
|
|
height: size.height,
|
|
present_mode: wgpu::PresentMode::Fifo,
|
|
};
|
|
surface.configure(&device, &surface_config);
|
|
let depth = create_depth_texture(&device, &surface_config, &graphics_config);
|
|
let framebuffer = create_render_texture(&device, &surface_config, &graphics_config);
|
|
|
|
DeviceHolder {
|
|
instance,
|
|
surface,
|
|
adapter,
|
|
backend,
|
|
device: Arc::new(device),
|
|
queue: Arc::new(queue),
|
|
config: graphics_config,
|
|
surface_config,
|
|
framebuffer,
|
|
depth,
|
|
}
|
|
}
|