use crate::errors::{AleaticoError, AleaticoResult};
use crate::renderer::pipelines::Pipeline;
use crate::renderer::surface::Surface;
use crate::renderer::vertex::Vertex;
use std::sync::Arc;
use wgpu::{CurrentSurfaceTexture, PresentMode};
use winit::window::Window;
pub struct GPUContext {
pub surface: Surface,
pub pipeline: Pipeline,
window: Arc<Window>,
}
const VERTICES: &[Vertex] = &[
Vertex {
position: [0.0, 0.5, 0.0],
color: [1.0, 0.0, 0.0],
},
Vertex {
position: [-0.5, -0.5, 0.0],
color: [0.0, 1.0, 0.0],
},
Vertex {
position: [0.5, -0.5, 0.0],
color: [0.0, 0.0, 1.0],
},
];
impl GPUContext {
pub async fn new(window: Arc<Window>) -> AleaticoResult<GPUContext> {
let mut surface = Surface::new(window.clone()).await?;
let pipeline = Pipeline::from_shader_string(
&mut surface,
VERTICES,
include_str!("../../shaders/shader.wgsl"),
)?;
Ok(Self {
surface,
pipeline,
window,
})
}
pub fn render(&mut self) -> AleaticoResult<()> {
self.window.request_redraw();
if !self.surface.is_configured {
return Ok(());
}
let output = match self.surface.inner.get_current_texture() {
CurrentSurfaceTexture::Success(surface_texture) => surface_texture,
CurrentSurfaceTexture::Suboptimal(surface_texture) => {
drop(surface_texture);
self.surface
.inner
.configure(&self.surface.device, &self.surface.config);
match self.surface.inner.get_current_texture() {
CurrentSurfaceTexture::Success(surface_texture) => surface_texture,
CurrentSurfaceTexture::Suboptimal(surface_texture) => surface_texture,
_ => return Ok(()),
}
}
CurrentSurfaceTexture::Timeout
| CurrentSurfaceTexture::Occluded
| CurrentSurfaceTexture::Validation => {
return Ok(());
}
CurrentSurfaceTexture::Outdated => {
self.surface
.inner
.configure(&self.surface.device, &self.surface.config);
return Ok(());
}
CurrentSurfaceTexture::Lost => {
return Err(AleaticoError::LostDevice);
}
};
let view = output
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder =
self.surface
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
depth_slice: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 1.0,
g: 0.2,
b: 0.3,
a: 1.0,
}),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
occlusion_query_set: None,
timestamp_writes: None,
multiview_mask: None,
});
render_pass.set_pipeline(&self.pipeline.render_pipeline);
render_pass.set_vertex_buffer(0, self.pipeline.vertex_buffer.slice(..));
render_pass.draw(0..3, 0..1);
}
self.surface.queue.submit(std::iter::once(encoder.finish()));
output.present();
Ok(())
}
pub fn vsync(&mut self, enable: bool) {
self.surface.config.present_mode = if enable {
PresentMode::AutoVsync
} else {
PresentMode::Mailbox
}
}
}