summaryrefslogtreecommitdiffstats
path: root/src/wgpuctx
diff options
context:
space:
mode:
Diffstat (limited to 'src/wgpuctx')
-rw-r--r--src/wgpuctx/mod.rs245
-rw-r--r--src/wgpuctx/pipeline.rs121
2 files changed, 366 insertions, 0 deletions
diff --git a/src/wgpuctx/mod.rs b/src/wgpuctx/mod.rs
new file mode 100644
index 0000000..f8aa3ec
--- /dev/null
+++ b/src/wgpuctx/mod.rs
@@ -0,0 +1,245 @@
+use std::sync::Arc;
+use std::error::Error;
+use wgpu::util::DeviceExt;
+use winit::window::{Window};
+
+use crate::texture::Texture;
+
+pub mod pipeline;
+
+pub struct WgpuCtx
+{
+ surface: wgpu::Surface<'static>,
+ surface_conf: wgpu::SurfaceConfiguration,
+ surface_texture: Option<wgpu::SurfaceTexture>,
+ is_configured: bool,
+
+ adapter: wgpu::Adapter,
+ device: wgpu::Device,
+ queue: wgpu::Queue,
+}
+
+pub struct RenderPassBuilder<'encoder>
+{
+ label: &'static str,
+ view: &'encoder wgpu::TextureView,
+ clear_color: wgpu::Color
+}
+
+impl WgpuCtx
+{
+ pub async fn new(
+ instance: &wgpu::Instance,
+ window: Arc<Window>,
+ ) -> Self {
+ let surface = instance.create_surface(window.clone()).unwrap();
+
+ let adapter = instance
+ .request_adapter(&wgpu::RequestAdapterOptions {
+ compatible_surface: Some(&surface),
+ ..Default::default()
+ }).await.expect("Failed to find valid adapter");
+
+ let (device, queue) = adapter
+ .request_device(&wgpu::DeviceDescriptor {
+ label: None,
+ required_features: wgpu::Features::empty(),
+ required_limits: wgpu::Limits::downlevel_defaults(),
+ experimental_features: wgpu::ExperimentalFeatures::disabled(),
+ memory_hints: wgpu::MemoryHints::Performance,
+ trace: wgpu::Trace::Off
+ }).await.expect("Failed to find device and queue");
+
+ let size = window.inner_size();
+ let surface_config = surface.get_default_config(&adapter, size.width, size.height).unwrap();
+
+ Self {
+ surface: surface,
+ surface_conf: surface_config,
+ surface_texture: None,
+ is_configured: false,
+ adapter: adapter,
+ device: device,
+ queue: queue
+ }
+ }
+
+ pub fn resize(
+ &mut self,
+ width: u32,
+ height: u32)
+ {
+ self.surface_conf.width = width;
+ self.surface_conf.height = height;
+ self.surface.configure(&self.device, &self.surface_conf);
+ self.is_configured = true;
+ }
+
+ pub fn is_ready(
+ &self)
+ -> bool {
+ self.is_configured
+ }
+
+ pub fn surface_config(
+ &self)
+ -> wgpu::SurfaceConfiguration {
+ self.surface_conf.clone()
+ }
+
+ pub fn adapter(
+ &self)
+ -> &wgpu::Adapter {
+ &self.adapter
+ }
+
+ pub fn device(
+ &self)
+ -> &wgpu::Device {
+ &self.device
+ }
+
+ pub fn queue(
+ &self)
+ -> &wgpu::Queue {
+ &self.queue
+ }
+
+ pub fn prepare_surface(
+ &mut self,
+ view_descr: &wgpu::TextureViewDescriptor)
+ -> Result<wgpu::TextureView, wgpu::SurfaceError>
+ {
+ let texture = self.surface.get_current_texture()?;
+ let view = texture.texture.create_view(view_descr);
+
+ self.surface_texture = Some(texture);
+ Ok(view)
+ }
+
+ pub fn create_encoder(
+ &self,
+ descr: &wgpu::CommandEncoderDescriptor)
+ -> wgpu::CommandEncoder
+ {
+ self.device.create_command_encoder(descr)
+ }
+
+ pub fn create_default_encoder(
+ &self,
+ label: &'static str)
+ -> wgpu::CommandEncoder {
+ self.create_encoder(
+ &wgpu::CommandEncoderDescriptor {
+ label: Some(label)
+ }
+ )
+ }
+
+ pub fn submit_encoder(
+ &self,
+ encoder: wgpu::CommandEncoder)
+ {
+ self.queue.submit(std::iter::once(encoder.finish()));
+ }
+
+ pub fn present_surface(
+ &mut self)
+ {
+ let texture = self.surface_texture.take();
+ match texture {
+ Some(t) => t.present(),
+ None => {}
+ }
+ }
+
+ pub fn create_shader(
+ &self,
+ module_descr: wgpu::ShaderModuleDescriptor)
+ -> wgpu::ShaderModule {
+ self.device.create_shader_module(module_descr)
+ }
+
+ pub fn create_pipeline_layout(
+ &self,
+ layout_descr: &wgpu::PipelineLayoutDescriptor)
+ -> wgpu::PipelineLayout {
+ self.device.create_pipeline_layout(layout_descr)
+ }
+
+ pub fn create_render_pipeline(
+ &self,
+ pipeline_layout: &wgpu::RenderPipelineDescriptor)
+ -> wgpu::RenderPipeline {
+ self.device.create_render_pipeline(pipeline_layout)
+ }
+
+ pub fn create_buffer_init(
+ &self,
+ descr: &wgpu::util::BufferInitDescriptor
+ ) -> wgpu::Buffer {
+ self.device.create_buffer_init(descr)
+ }
+
+ pub fn create_buffer(
+ &self,
+ descr: &wgpu::BufferDescriptor)
+ -> wgpu::Buffer {
+ self.device.create_buffer(descr)
+ }
+
+ pub fn new_texture(
+ &self,
+ descr: wgpu::TextureDescriptor)
+ -> Texture
+ {
+ Texture::new(&self.device, descr)
+ }
+
+} //impl WgpuCtx
+
+impl<'encoder> RenderPassBuilder<'encoder>
+{
+ pub fn new(
+ label: &'static str,
+ view: &'encoder wgpu::TextureView)
+ -> Self {
+ Self {
+ label: label,
+ view: view,
+ clear_color: wgpu::Color { r: 0.0, g: 0.0, b: 0.0, a: 1.0 }
+ }
+ }
+
+ pub fn clear_color(
+ mut self,
+ color: wgpu::Color)
+ -> Self {
+ self.clear_color = color;
+ self
+ }
+
+ pub fn build(
+ self,
+ encoder: &'encoder mut wgpu::CommandEncoder)
+ -> wgpu::RenderPass<'encoder>
+ {
+ encoder.begin_render_pass(
+ &wgpu::RenderPassDescriptor {
+ label: Some(self.label),
+ color_attachments: &[Some(wgpu::RenderPassColorAttachment {
+ view: self.view,
+ resolve_target: None,
+ depth_slice: None,
+ ops: wgpu::Operations {
+ load: wgpu::LoadOp::Clear(self.clear_color),
+ store: wgpu::StoreOp::Store
+ }
+ })],
+ depth_stencil_attachment: None,
+ occlusion_query_set: None,
+ timestamp_writes: None,
+ }
+ )
+ }
+}
diff --git a/src/wgpuctx/pipeline.rs b/src/wgpuctx/pipeline.rs
new file mode 100644
index 0000000..7606203
--- /dev/null
+++ b/src/wgpuctx/pipeline.rs
@@ -0,0 +1,121 @@
+
+use crate::wgpuctx::WgpuCtx;
+
+pub struct RenderPipelineBuilder<'a>
+{
+ bind_groups: Vec<&'a wgpu::BindGroupLayout>,
+ shader: &'a wgpu::ShaderModule,
+
+ vertex_entry_point: Option<&'static str>,
+ fragment_entry_point: Option<&'static str>,
+
+ vertex_comp_options: Option<wgpu::PipelineCompilationOptions<'a>>,
+ fragment_comp_options: Option<wgpu::PipelineCompilationOptions<'a>>,
+
+ vertex_buffer_layouts: Vec<wgpu::VertexBufferLayout<'a>>
+}
+
+impl<'a> RenderPipelineBuilder<'a>
+{
+ pub fn new(
+ shader: &'a wgpu::ShaderModule)
+ -> Self {
+ Self {
+ bind_groups: Vec::new(),
+ shader: shader,
+
+ vertex_entry_point: Some("vs_main"),
+ fragment_entry_point: Some("fs_main"),
+
+ vertex_comp_options: None,
+ fragment_comp_options: None,
+
+ vertex_buffer_layouts: Vec::new()
+ }
+ }
+
+ pub fn add_bindgroup(
+ mut self,
+ bindgroup: &'a wgpu::BindGroupLayout)
+ -> Self {
+ self.bind_groups.push(bindgroup);
+ self
+ }
+
+ pub fn add_vertex_layout(
+ mut self,
+ layout: wgpu::VertexBufferLayout<'a>)
+ -> Self {
+ self.vertex_buffer_layouts.push(layout);
+ self
+ }
+
+ pub fn build(
+ self,
+ label: Option<&'static str>,
+ wgpuctx: &WgpuCtx)
+ -> wgpu::RenderPipeline
+ {
+ let layout_descr = wgpu::PipelineLayoutDescriptor {
+ label: label,
+ bind_group_layouts: self.bind_groups.as_slice(),
+ push_constant_ranges: &[]
+ };
+
+ let layout = wgpuctx.create_pipeline_layout(&layout_descr);
+
+ wgpuctx.create_render_pipeline(
+ &wgpu::RenderPipelineDescriptor {
+ label: label,
+ layout: Some(&layout),
+ vertex: wgpu::VertexState {
+ module: self.shader,
+ entry_point: self.vertex_entry_point,
+ compilation_options: match self.vertex_comp_options {
+ Some(option) => option,
+ None => wgpu::PipelineCompilationOptions::default()
+ },
+ buffers: self.vertex_buffer_layouts.as_slice()
+ },
+ fragment: Some(wgpu::FragmentState {
+ module: self.shader,
+ entry_point: self.fragment_entry_point,
+ compilation_options: match self.fragment_comp_options {
+ Some(option) => option,
+ None => wgpu::PipelineCompilationOptions::default()
+ },
+ targets: &[Some(wgpu::ColorTargetState {
+ format: wgpuctx.surface_config().format,
+ blend: Some(wgpu::BlendState{
+ color: wgpu::BlendComponent {
+ src_factor: wgpu::BlendFactor::SrcAlpha,
+ dst_factor: wgpu::BlendFactor::OneMinusSrcAlpha,
+ operation: wgpu::BlendOperation::Add
+ },
+ alpha: wgpu::BlendComponent::OVER
+ }),
+ write_mask: wgpu::ColorWrites::ALL
+ })],
+ }),
+ primitive: wgpu::PrimitiveState {
+ topology: wgpu::PrimitiveTopology::TriangleList,
+ strip_index_format: None,
+ front_face: wgpu::FrontFace::Ccw,
+ cull_mode: Some(wgpu::Face::Back),
+ polygon_mode: wgpu::PolygonMode::Fill,
+ unclipped_depth: false,
+ conservative: false
+ },
+ depth_stencil: None,
+ multisample: wgpu::MultisampleState {
+ count: 1,
+ mask: !0,
+ alpha_to_coverage_enabled: false
+ },
+ multiview: None,
+ cache: None
+
+ }
+ )
+ }
+}