use std::sync::Arc;
use crate::display_scale::display_dims;
#[derive(Debug)]
pub struct GpuDisplay {
pub width: u32,
pub height: u32,
pub render_pipeline: wgpu::RenderPipeline,
pub render_bind_group: wgpu::BindGroup,
}
#[derive(Debug)]
pub struct DisplayTarget {
pub view: wgpu::TextureView,
pub dims: (u32, u32),
pub display: Arc<GpuDisplay>,
}
#[cfg_attr(
all(target_arch = "wasm32", target_feature = "atomics"),
expect(
clippy::arc_with_non_send_sync,
reason = "a display holds wgpu handles, which atomics leave unsendable"
)
)]
pub fn build_display_target(
device: &wgpu::Device,
target_format: wgpu::TextureFormat,
width: u32,
height: u32,
) -> DisplayTarget {
let (tex_w, tex_h) = display_dims(width, height, device.limits().max_texture_dimension_2d);
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("henad_gpu_display_texture"),
size: wgpu::Extent3d {
width: tex_w,
height: tex_h,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Rgba8Unorm,
usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING,
view_formats: &[],
});
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
let sampler = device.create_sampler(&wgpu::SamplerDescriptor {
label: Some("henad_gpu_display_sampler"),
mag_filter: wgpu::FilterMode::Nearest,
min_filter: wgpu::FilterMode::Nearest,
..Default::default()
});
let shader = device.create_shader_module(wgpu::include_wgsl!("display.wgsl"));
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("henad_gpu_display_bind_group_layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
});
let render_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("henad_gpu_display_bind_group"),
layout: &bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&view),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Sampler(&sampler),
},
],
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("henad_gpu_display_pipeline_layout"),
bind_group_layouts: &[Some(&bind_group_layout)],
immediate_size: 0,
});
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("henad_gpu_display_pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: target_format,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
DisplayTarget {
view,
dims: (tex_w, tex_h),
display: Arc::new(GpuDisplay {
width,
height,
render_pipeline,
render_bind_group,
}),
}
}