use std::sync::Arc;
use winit::window::Window;
pub struct Rect {
pub min: [f32; 2],
pub max: [f32; 2],
pub color: [f32; 4],
}
const RECT_BYTES: u64 = 32;
const MAX_RECTS: u64 = 256;
pub struct Gpu {
surface: wgpu::Surface<'static>,
device: wgpu::Device,
queue: wgpu::Queue,
config: wgpu::SurfaceConfiguration,
pipeline: wgpu::RenderPipeline,
rects: wgpu::Buffer,
}
impl Gpu {
pub fn new(window: Arc<Window>) -> Gpu {
let size = window.inner_size();
let instance =
wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle_from_env());
let surface = instance.create_surface(window).unwrap();
let adapter = pollster::block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
compatible_surface: Some(&surface),
..Default::default()
}))
.unwrap();
let (device, queue) =
pollster::block_on(adapter.request_device(&wgpu::DeviceDescriptor::default())).unwrap();
let mut config = surface
.get_default_config(&adapter, size.width.max(1), size.height.max(1))
.unwrap();
let formats = surface.get_capabilities(&adapter).formats;
if let Some(format) = formats.iter().find(|format| !format.is_srgb()) {
config.format = *format;
}
surface.configure(&device, &config);
let shader = device.create_shader_module(wgpu::include_wgsl!("rect.wgsl"));
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("rect"),
layout: None,
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs"),
compilation_options: Default::default(),
buffers: &[Some(wgpu::VertexBufferLayout {
array_stride: RECT_BYTES,
step_mode: wgpu::VertexStepMode::Instance,
attributes: &wgpu::vertex_attr_array![0 => Float32x2, 1 => Float32x2, 2 => Float32x4],
})],
},
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs"),
compilation_options: Default::default(),
targets: &[Some(config.format.into())],
}),
multiview_mask: None,
cache: None,
});
let rects = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("rects"),
size: RECT_BYTES * MAX_RECTS,
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
Gpu {
surface,
device,
queue,
config,
pipeline,
rects,
}
}
pub fn size(&self) -> (u32, u32) {
(self.config.width, self.config.height)
}
pub fn resize(&mut self, width: u32, height: u32) {
self.config.width = width.max(1);
self.config.height = height.max(1);
self.surface.configure(&self.device, &self.config);
}
pub fn render(&mut self, rects: &[Rect]) {
let frame = match self.surface.get_current_texture() {
wgpu::CurrentSurfaceTexture::Success(frame)
| wgpu::CurrentSurfaceTexture::Suboptimal(frame) => frame,
wgpu::CurrentSurfaceTexture::Outdated | wgpu::CurrentSurfaceTexture::Lost => {
self.surface.configure(&self.device, &self.config);
return;
}
wgpu::CurrentSurfaceTexture::Timeout
| wgpu::CurrentSurfaceTexture::Occluded
| wgpu::CurrentSurfaceTexture::Validation => return,
};
let count = rects.len().min(MAX_RECTS as usize);
let mut bytes = Vec::with_capacity(count * RECT_BYTES as usize);
for rect in &rects[..count] {
for value in rect.min.iter().chain(&rect.max).chain(&rect.color) {
bytes.extend_from_slice(&value.to_le_bytes());
}
}
self.queue.write_buffer(&self.rects, 0, &bytes);
let view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
pass.set_pipeline(&self.pipeline);
pass.set_vertex_buffer(0, self.rects.slice(..));
pass.draw(0..6, 0..count as u32);
}
self.queue.submit([encoder.finish()]);
self.queue.present(frame);
}
}