From c9f251ca577e16190311722cfbb5de1a2ff2291c Mon Sep 17 00:00:00 2001 From: Maxim Date: Wed, 24 Jan 2024 21:48:13 +0300 Subject: [PATCH] Refactor wgpu module (#29) * Move different pipelines into separate modules * Simplify bundle rendering logic * Rename point and poly pipelines into map_ref and screen_ref --- galileo/src/render/{wgpu.rs => wgpu/mod.rs} | 287 ++---------------- galileo/src/render/wgpu/pipelines/clip.rs | 78 +++++ .../src/render/wgpu/{ => pipelines}/image.rs | 125 ++------ galileo/src/render/wgpu/pipelines/map_ref.rs | 37 +++ galileo/src/render/wgpu/pipelines/mod.rs | 176 +++++++++++ .../src/render/wgpu/pipelines/screen_ref.rs | 38 +++ .../pipelines/shaders}/image.wgsl | 6 +- .../pipelines/shaders/map_ref.wgsl} | 0 .../pipelines/shaders/screen_ref.wgsl} | 0 9 files changed, 382 insertions(+), 365 deletions(-) rename galileo/src/render/{wgpu.rs => wgpu/mod.rs} (69%) create mode 100644 galileo/src/render/wgpu/pipelines/clip.rs rename galileo/src/render/wgpu/{ => pipelines}/image.rs (60%) create mode 100644 galileo/src/render/wgpu/pipelines/map_ref.rs create mode 100644 galileo/src/render/wgpu/pipelines/mod.rs create mode 100644 galileo/src/render/wgpu/pipelines/screen_ref.rs rename galileo/src/render/{wgpu_shaders => wgpu/pipelines/shaders}/image.wgsl (97%) rename galileo/src/render/{wgpu_shaders/line.wgsl => wgpu/pipelines/shaders/map_ref.wgsl} (100%) rename galileo/src/render/{wgpu_shaders/point.wgsl => wgpu/pipelines/shaders/screen_ref.wgsl} (100%) diff --git a/galileo/src/render/wgpu.rs b/galileo/src/render/wgpu/mod.rs similarity index 69% rename from galileo/src/render/wgpu.rs rename to galileo/src/render/wgpu/mod.rs index 244b378..6e78b0e 100644 --- a/galileo/src/render/wgpu.rs +++ b/galileo/src/render/wgpu/mod.rs @@ -6,10 +6,8 @@ use std::mem::size_of; use std::ops::Range; use wgpu::util::DeviceExt; use wgpu::{ - BindGroup, BindGroupLayout, Buffer, CompareFunction, DepthStencilState, Device, Extent3d, - Queue, RenderPass, RenderPassDepthStencilAttachment, StencilFaceState, StencilOperation, - StencilState, StoreOp, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages, - TextureView, TextureViewDescriptor, + Buffer, Device, Extent3d, Queue, RenderPassDepthStencilAttachment, StoreOp, TextureDescriptor, + TextureDimension, TextureFormat, TextureUsages, TextureView, TextureViewDescriptor, }; use winit::dpi::PhysicalSize; @@ -21,34 +19,27 @@ use crate::render::render_bundle::tessellating::{ TessellatingRenderBundle, }; use crate::render::render_bundle::RenderBundle; -use crate::render::wgpu::image::WgpuImage; +use crate::render::wgpu::pipelines::image::WgpuImage; +use crate::render::wgpu::pipelines::Pipelines; use crate::view::MapView; -use self::image::ImagePainter; - use super::{ Canvas, ImagePaint, LinePaint, PackedBundle, Paint, PointPaint, PrimitiveId, Renderer, UnpackedBundle, }; +mod pipelines; + pub struct WgpuRenderer { surface: wgpu::Surface, device: Device, queue: Queue, config: wgpu::SurfaceConfiguration, size: PhysicalSize, - - line_pipeline: wgpu::RenderPipeline, - image_painter: ImagePainter, - map_view_buffer: Buffer, - map_view_bind_group: BindGroup, - pub map_view_bind_group_layout: BindGroupLayout, - pub multisampling_view: TextureView, - pub point_pipeline: wgpu::RenderPipeline, - + pipelines: Pipelines, + multisampling_view: TextureView, background: Color, - pub stencil_view: TextureView, - pub clip_pipeline: wgpu::RenderPipeline, + stencil_view: TextureView, } impl Renderer for WgpuRenderer { @@ -135,201 +126,18 @@ impl WgpuRenderer { }; surface.configure(&device, &config); - - let map_view_buffer = device.create_buffer(&wgpu::BufferDescriptor { - label: Some("Map view buffer"), - size: size_of::() as wgpu::BufferAddress, - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - mapped_at_creation: false, - }); - - let map_view_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - label: Some("map_view_bind_group_layout"), - }); - - let line_shader = - device.create_shader_module(wgpu::include_wgsl!("./wgpu_shaders/line.wgsl")); - - let line_render_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Line Render Pipeline Layout"), - bind_group_layouts: &[&map_view_bind_group_layout], - push_constant_ranges: &[], - }); - - let poly_stencil_state = StencilFaceState { - compare: CompareFunction::Equal, - fail_op: StencilOperation::Keep, - depth_fail_op: StencilOperation::Keep, - pass_op: StencilOperation::Keep, - }; - - let targets = [Some(wgpu::ColorTargetState { - format: config.format, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - })]; - - let poly_pipeline_desc = wgpu::RenderPipelineDescriptor { - label: Some("Line Render Pipeline"), - layout: Some(&line_render_pipeline_layout), - vertex: wgpu::VertexState { - module: &line_shader, - entry_point: "vs_main", - buffers: &[PolyVertex::wgpu_desc()], - }, - fragment: Some(wgpu::FragmentState { - module: &line_shader, - entry_point: "fs_main", - targets: &targets, - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: None, - polygon_mode: wgpu::PolygonMode::Fill, - unclipped_depth: false, - conservative: false, - }, - depth_stencil: Some(DepthStencilState { - format: TextureFormat::Depth24PlusStencil8, - depth_write_enabled: false, - depth_compare: CompareFunction::Always, - stencil: StencilState { - front: poly_stencil_state, - back: poly_stencil_state, - read_mask: 0xff, - write_mask: 0xff, - }, - bias: Default::default(), - }), - multisample: wgpu::MultisampleState { - count: 4, - mask: !0, - alpha_to_coverage_enabled: false, - }, - multiview: None, - }; - - let line_pipeline = device.create_render_pipeline(&poly_pipeline_desc); - - let clip_stencil_state = StencilFaceState { - compare: CompareFunction::Never, - fail_op: StencilOperation::Replace, - depth_fail_op: StencilOperation::Keep, - pass_op: StencilOperation::Keep, - }; - let clip_pipeline_desc = wgpu::RenderPipelineDescriptor { - depth_stencil: Some(DepthStencilState { - format: TextureFormat::Depth24PlusStencil8, - depth_write_enabled: false, - depth_compare: CompareFunction::Always, - stencil: StencilState { - front: clip_stencil_state, - back: clip_stencil_state, - read_mask: 0xff, - write_mask: 0xff, - }, - bias: Default::default(), - }), - ..poly_pipeline_desc - }; - let clip_pipeline = device.create_render_pipeline(&clip_pipeline_desc); - - let point_shader = - device.create_shader_module(wgpu::include_wgsl!("./wgpu_shaders/point.wgsl")); - - let point_render_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Point Render Pipeline Layout"), - bind_group_layouts: &[&map_view_bind_group_layout], - push_constant_ranges: &[], - }); - - let point_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Point Render Pipeline"), - layout: Some(&point_render_pipeline_layout), - vertex: wgpu::VertexState { - module: &point_shader, - entry_point: "vs_main", - buffers: &[PointVertex::wgpu_desc(), PointInstance::wgpu_desc()], - }, - fragment: Some(wgpu::FragmentState { - module: &point_shader, - entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format: config.format, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - write_mask: wgpu::ColorWrites::ALL, - })], - }), - primitive: wgpu::PrimitiveState { - topology: wgpu::PrimitiveTopology::TriangleList, - strip_index_format: None, - front_face: wgpu::FrontFace::Ccw, - cull_mode: None, - polygon_mode: wgpu::PolygonMode::Fill, - unclipped_depth: false, - conservative: false, - }, - depth_stencil: Some(DepthStencilState { - format: TextureFormat::Depth24PlusStencil8, - depth_write_enabled: false, - depth_compare: CompareFunction::Always, - stencil: StencilState { - front: poly_stencil_state, - back: poly_stencil_state, - read_mask: 0xff, - write_mask: 0xff, - }, - bias: Default::default(), - }), - multisample: wgpu::MultisampleState { - count: 4, - mask: !0, - alpha_to_coverage_enabled: false, - }, - multiview: None, - }); - - let map_view_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &map_view_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: map_view_buffer.as_entire_binding(), - }], - label: Some("view_bind_group"), - }); - - let image_painter = ImagePainter::new(&device, config.format, &map_view_bind_group_layout); let multisampling_view = Self::create_multisample_texture(&device, size, config.format); let stencil_view = Self::create_stencil_texture(&device, size); + let pipelines = Pipelines::create(&device, surface_format); + Self { surface, device, queue, config, size, - line_pipeline, - clip_pipeline, - point_pipeline, - map_view_buffer, - map_view_bind_group, - map_view_bind_group_layout, - image_painter, + pipelines, multisampling_view, stencil_view, background: Color::rgba(255, 255, 255, 255), @@ -475,7 +283,7 @@ impl<'a> WgpuCanvas<'a> { )) .to_homogeneous(); renderer.queue.write_buffer( - &renderer.map_view_buffer, + renderer.pipelines.map_view_buffer(), 0, bytemuck::cast_slice(&[ViewUniform { view_proj: map_view.map_to_scene_mtx().unwrap(), @@ -551,59 +359,10 @@ impl<'a> Canvas for WgpuCanvas<'a> { }); for bundle in bundles { - if let Some(cast) = bundle.as_any().downcast_ref::() { - if let Some(clip_area_buffers) = &cast.clip_area_buffers { - render_pass.set_stencil_reference(1); - render_pass.set_pipeline(&self.renderer.clip_pipeline); - render_pass.set_bind_group(0, &self.renderer.map_view_bind_group, &[]); - render_pass.set_vertex_buffer(0, clip_area_buffers.vertex.slice(..)); - render_pass.set_index_buffer( - clip_area_buffers.index.slice(..), - wgpu::IndexFormat::Uint32, - ); - render_pass.draw_indexed(0..clip_area_buffers.index_count, 0, 0..1); - } - - for image in &cast.image_buffers { - self.draw_image(&mut render_pass, image); - } - - let buffers = cast.select_poly_buffers(resolution); - - render_pass.set_pipeline(&self.renderer.line_pipeline); - render_pass.set_bind_group(0, &self.renderer.map_view_bind_group, &[]); - render_pass.set_vertex_buffer(0, buffers.vertex.slice(..)); - render_pass - .set_index_buffer(buffers.index.slice(..), wgpu::IndexFormat::Uint32); - render_pass.draw_indexed(0..buffers.index_count, 0, 0..1); - - if let Some(point_buffers) = &cast.point_buffers { - render_pass.set_pipeline(&self.renderer.point_pipeline); - render_pass.set_bind_group(0, &self.renderer.map_view_bind_group, &[]); - render_pass.set_vertex_buffer(0, point_buffers.vertex.slice(..)); - render_pass.set_vertex_buffer(1, point_buffers.instance.slice(..)); - render_pass.set_index_buffer( - point_buffers.index.slice(..), - wgpu::IndexFormat::Uint32, - ); - render_pass.draw_indexed( - 0..point_buffers.index_count, - 0, - 0..point_buffers.instance_count, - ); - } - - if let Some(clip_area_buffers) = &cast.clip_area_buffers { - render_pass.set_stencil_reference(0); - render_pass.set_pipeline(&self.renderer.clip_pipeline); - render_pass.set_bind_group(0, &self.renderer.map_view_bind_group, &[]); - render_pass.set_vertex_buffer(0, clip_area_buffers.vertex.slice(..)); - render_pass.set_index_buffer( - clip_area_buffers.index.slice(..), - wgpu::IndexFormat::Uint32, - ); - render_pass.draw_indexed(0..clip_area_buffers.index_count, 0, 0..1); - } + if let Some(cast) = bundle.as_any().downcast_ref() { + self.renderer + .pipelines + .render(&mut render_pass, cast, resolution); } } } @@ -614,14 +373,6 @@ impl<'a> Canvas for WgpuCanvas<'a> { } } -impl<'a> WgpuCanvas<'a> { - fn draw_image(&self, render_pass: &mut RenderPass<'a>, image: &'a WgpuImage) { - self.renderer - .image_painter - .draw_image(render_pass, image, self.renderer) - } -} - pub struct WgpuPackedBundle { clip_area_buffers: Option, poly_tessellation: Vec, @@ -707,7 +458,7 @@ impl WgpuPackedBundle { let mut image_buffers = vec![]; for (image, vertices) in images { - let image = renderer.image_painter.create_image( + let image = renderer.pipelines.image_pipeline().create_image( &renderer.device, &renderer.queue, &image, @@ -976,8 +727,6 @@ impl PointVertex { } } -mod image; - #[repr(C)] #[derive(Debug, Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] struct ViewUniform { diff --git a/galileo/src/render/wgpu/pipelines/clip.rs b/galileo/src/render/wgpu/pipelines/clip.rs new file mode 100644 index 0000000..6702571 --- /dev/null +++ b/galileo/src/render/wgpu/pipelines/clip.rs @@ -0,0 +1,78 @@ +use crate::render::render_bundle::tessellating::PolyVertex; +use crate::render::wgpu::pipelines::{default_pipeline_descriptor, default_targets}; +use crate::render::wgpu::WgpuPolygonBuffers; +use wgpu::{ + BindGroupLayout, CompareFunction, DepthStencilState, Device, RenderPass, RenderPipeline, + RenderPipelineDescriptor, StencilFaceState, StencilOperation, StencilState, TextureFormat, +}; + +pub struct ClipPipeline { + wgpu_pipeline: RenderPipeline, +} + +impl ClipPipeline { + const UNCLIP_REFERENCE: u32 = 0; + const CLIP_STENCIL_VALUE: u32 = 1; + + pub fn create( + device: &Device, + format: TextureFormat, + map_view_layout: &BindGroupLayout, + ) -> Self { + let buffers = [PolyVertex::wgpu_desc()]; + let shader = device.create_shader_module(wgpu::include_wgsl!("./shaders/map_ref.wgsl")); + + let clip_stencil_state = StencilFaceState { + compare: CompareFunction::Never, + fail_op: StencilOperation::Replace, + depth_fail_op: StencilOperation::Keep, + pass_op: StencilOperation::Keep, + }; + let targets = default_targets(format); + let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&map_view_layout], + push_constant_ranges: &[], + }); + + let desc = RenderPipelineDescriptor { + depth_stencil: Some(DepthStencilState { + format: TextureFormat::Depth24PlusStencil8, + depth_write_enabled: false, + depth_compare: CompareFunction::Always, + stencil: StencilState { + front: clip_stencil_state, + back: clip_stencil_state, + read_mask: 0xff, + write_mask: 0xff, + }, + bias: Default::default(), + }), + ..default_pipeline_descriptor(&layout, &shader, &targets, &buffers) + }; + + let wgpu_pipeline = device.create_render_pipeline(&desc); + Self { wgpu_pipeline } + } + + pub fn clip<'a>(&'a self, buffers: &'a WgpuPolygonBuffers, render_pass: &mut RenderPass<'a>) { + self.render(buffers, render_pass, Self::CLIP_STENCIL_VALUE); + } + + pub fn unclip<'a>(&'a self, buffers: &'a WgpuPolygonBuffers, render_pass: &mut RenderPass<'a>) { + self.render(buffers, render_pass, Self::UNCLIP_REFERENCE); + } + + fn render<'a>( + &'a self, + buffers: &'a WgpuPolygonBuffers, + render_pass: &mut RenderPass<'a>, + stencil_reference: u32, + ) { + render_pass.set_stencil_reference(stencil_reference); + render_pass.set_pipeline(&self.wgpu_pipeline); + render_pass.set_vertex_buffer(0, buffers.vertex.slice(..)); + render_pass.set_index_buffer(buffers.index.slice(..), wgpu::IndexFormat::Uint32); + render_pass.draw_indexed(0..buffers.index_count, 0, 0..1); + } +} diff --git a/galileo/src/render/wgpu/image.rs b/galileo/src/render/wgpu/pipelines/image.rs similarity index 60% rename from galileo/src/render/wgpu/image.rs rename to galileo/src/render/wgpu/pipelines/image.rs index 55ba9ba..8dc08ab 100644 --- a/galileo/src/render/wgpu/image.rs +++ b/galileo/src/render/wgpu/pipelines/image.rs @@ -1,41 +1,34 @@ -use crate::primitives::{DecodedImage, Image}; +use crate::primitives::DecodedImage; use crate::render::render_bundle::tessellating::ImageVertex; -use crate::render::wgpu::WgpuRenderer; -use std::any::Any; +use crate::render::wgpu::pipelines; +use crate::render::wgpu::pipelines::default_targets; use wgpu::util::DeviceExt; use wgpu::{ - BindGroupLayout, CompareFunction, DepthStencilState, Device, Queue, StencilFaceState, - StencilOperation, StencilState, TextureFormat, + BindGroupLayout, Device, Queue, RenderPass, RenderPipeline, RenderPipelineDescriptor, + TextureFormat, }; const INDICES: &[u16] = &[1, 0, 2, 1, 2, 3]; -pub struct ImagePainter { - pipeline: wgpu::RenderPipeline, - - index_buffer: wgpu::Buffer, - pub texture_bind_group_layout: wgpu::BindGroupLayout, -} - pub struct WgpuImage { pub texture_bind_group: wgpu::BindGroup, pub vertex_buffer: wgpu::Buffer, pub vertices: [ImageVertex; 4], } -impl Image for WgpuImage { - fn as_any(&self) -> &dyn Any { - self - } +pub struct ImagePipeline { + wgpu_pipeline: RenderPipeline, + index_buffer: wgpu::Buffer, + texture_bind_group_layout: BindGroupLayout, } -impl ImagePainter { - pub fn new( - device: &wgpu::Device, - format: wgpu::TextureFormat, - map_view_bind_group_layout: &BindGroupLayout, +impl ImagePipeline { + pub fn create( + device: &Device, + format: TextureFormat, + map_view_layout: &BindGroupLayout, ) -> Self { - let shader = device.create_shader_module(wgpu::include_wgsl!("../wgpu_shaders/image.wgsl")); + let shader = device.create_shader_module(wgpu::include_wgsl!("./shaders/image.wgsl")); let texture_bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { @@ -59,65 +52,20 @@ impl ImagePainter { ], label: Some("texture_bind_group_label"), }); + let buffers = [ImageVertex::wgpu_desc()]; - let render_pipeline_layout = - device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { - label: Some("Image Render Pipeline Layout"), - bind_group_layouts: &[&texture_bind_group_layout, map_view_bind_group_layout], - push_constant_ranges: &[], - }); + let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&map_view_layout, &texture_bind_group_layout], + push_constant_ranges: &[], + }); - let poly_stencil_state = StencilFaceState { - compare: CompareFunction::Equal, - fail_op: StencilOperation::Keep, - depth_fail_op: StencilOperation::Keep, - pass_op: StencilOperation::Keep, + let targets = default_targets(format); + let desc = RenderPipelineDescriptor { + ..pipelines::default_pipeline_descriptor(&layout, &shader, &targets, &buffers) }; - let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { - label: Some("Image Render Pipeline"), - layout: Some(&render_pipeline_layout), - vertex: wgpu::VertexState { - module: &shader, - entry_point: "vs_main", - buffers: &[ImageVertex::wgpu_desc()], - }, - fragment: Some(wgpu::FragmentState { - module: &shader, - entry_point: "fs_main", - targets: &[Some(wgpu::ColorTargetState { - format, - blend: Some(wgpu::BlendState::ALPHA_BLENDING), - 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: Some(DepthStencilState { - format: TextureFormat::Depth24PlusStencil8, - depth_write_enabled: false, - depth_compare: CompareFunction::Always, - stencil: StencilState { - front: poly_stencil_state, - back: poly_stencil_state, - read_mask: 0xff, - write_mask: 0xff, - }, - bias: Default::default(), - }), - multisample: wgpu::MultisampleState { - count: 4, - mask: !0, - alpha_to_coverage_enabled: false, - }, - multiview: None, - }); + + let wgpu_pipeline = device.create_render_pipeline(&desc); let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Image index buffer"), @@ -126,9 +74,9 @@ impl ImagePainter { }); Self { - pipeline, - index_buffer, + wgpu_pipeline, texture_bind_group_layout, + index_buffer, } } @@ -200,19 +148,10 @@ impl ImagePainter { } } - pub fn draw_image<'painter, 'pass, 'image>( - &'painter self, - render_pass: &mut wgpu::RenderPass<'pass>, - image: &'image WgpuImage, - renderer: &'pass WgpuRenderer, - ) where - 'painter: 'pass, - 'image: 'pass, - { - render_pass.set_pipeline(&self.pipeline); - render_pass.set_bind_group(0, &image.texture_bind_group, &[]); - render_pass.set_bind_group(1, &renderer.map_view_bind_group, &[]); - render_pass.set_vertex_buffer(0, image.vertex_buffer.slice(..)); + pub fn render<'a>(&'a self, buffers: &'a WgpuImage, render_pass: &mut RenderPass<'a>) { + render_pass.set_pipeline(&self.wgpu_pipeline); + render_pass.set_bind_group(1, &buffers.texture_bind_group, &[]); + render_pass.set_vertex_buffer(0, buffers.vertex_buffer.slice(..)); render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16); render_pass.draw_indexed(0..INDICES.len() as u32, 0, 0..1); } diff --git a/galileo/src/render/wgpu/pipelines/map_ref.rs b/galileo/src/render/wgpu/pipelines/map_ref.rs new file mode 100644 index 0000000..b60b5c2 --- /dev/null +++ b/galileo/src/render/wgpu/pipelines/map_ref.rs @@ -0,0 +1,37 @@ +use crate::render::render_bundle::tessellating::PolyVertex; +use crate::render::wgpu::pipelines::default_targets; +use crate::render::wgpu::{pipelines, WgpuPolygonBuffers}; +use wgpu::{BindGroupLayout, Device, RenderPass, RenderPipeline, TextureFormat}; + +pub struct MapRefPipeline { + wgpu_pipeline: RenderPipeline, +} + +impl MapRefPipeline { + pub fn create( + device: &Device, + format: TextureFormat, + map_view_layout: &BindGroupLayout, + ) -> Self { + let buffers = [PolyVertex::wgpu_desc()]; + let shader = device.create_shader_module(wgpu::include_wgsl!("./shaders/map_ref.wgsl")); + + let targets = default_targets(format); + let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[map_view_layout], + push_constant_ranges: &[], + }); + let desc = pipelines::default_pipeline_descriptor(&layout, &shader, &targets, &buffers); + + let wgpu_pipeline = device.create_render_pipeline(&desc); + Self { wgpu_pipeline } + } + + pub fn render<'a>(&'a self, buffers: &'a WgpuPolygonBuffers, render_pass: &mut RenderPass<'a>) { + render_pass.set_pipeline(&self.wgpu_pipeline); + render_pass.set_vertex_buffer(0, buffers.vertex.slice(..)); + render_pass.set_index_buffer(buffers.index.slice(..), wgpu::IndexFormat::Uint32); + render_pass.draw_indexed(0..buffers.index_count, 0, 0..1); + } +} diff --git a/galileo/src/render/wgpu/pipelines/mod.rs b/galileo/src/render/wgpu/pipelines/mod.rs new file mode 100644 index 0000000..df1aba4 --- /dev/null +++ b/galileo/src/render/wgpu/pipelines/mod.rs @@ -0,0 +1,176 @@ +use crate::render::wgpu::pipelines::clip::ClipPipeline; +use crate::render::wgpu::pipelines::image::ImagePipeline; +use crate::render::wgpu::pipelines::map_ref::MapRefPipeline; +use crate::render::wgpu::pipelines::screen_ref::ScreenRefPipeline; +use crate::render::wgpu::{ViewUniform, WgpuPackedBundle}; +use std::mem::size_of; +use wgpu::{ + BindGroup, Buffer, CompareFunction, DepthStencilState, Device, PipelineLayout, RenderPass, + RenderPipelineDescriptor, ShaderModule, StencilFaceState, StencilOperation, StencilState, + TextureFormat, VertexBufferLayout, +}; + +mod clip; +pub mod image; +mod map_ref; +mod screen_ref; + +pub struct Pipelines { + map_view_binding: BindGroup, + map_view_buffer: Buffer, + + image: ImagePipeline, + screen_ref: ScreenRefPipeline, + map_ref: MapRefPipeline, + clip: ClipPipeline, +} + +impl Pipelines { + pub fn create(device: &Device, format: TextureFormat) -> Self { + let map_view_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Map view buffer"), + size: size_of::() as wgpu::BufferAddress, + usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + let map_view_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStages::VERTEX, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Uniform, + has_dynamic_offset: false, + min_binding_size: None, + }, + count: None, + }], + label: None, + }); + + let map_view_binding = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &map_view_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: map_view_buffer.as_entire_binding(), + }], + label: Some("view_bind_group"), + }); + + Self { + map_view_binding, + map_view_buffer, + image: ImagePipeline::create(device, format, &map_view_bind_group_layout), + map_ref: MapRefPipeline::create(device, format, &map_view_bind_group_layout), + screen_ref: ScreenRefPipeline::create(device, format, &map_view_bind_group_layout), + clip: ClipPipeline::create(device, format, &map_view_bind_group_layout), + } + } + + pub fn render<'a>( + &'a self, + render_pass: &mut RenderPass<'a>, + bundle: &'a WgpuPackedBundle, + resolution: f32, + ) { + self.set_bindings(render_pass); + + if let Some(clip) = &bundle.clip_area_buffers { + self.clip.clip(clip, render_pass); + } + + for image in &bundle.image_buffers { + self.image.render(image, render_pass); + } + + let selected = bundle.select_poly_buffers(resolution); + if selected.index_count > 0 { + self.map_ref.render(selected, render_pass); + } + + if let Some(point_buffers) = &bundle.point_buffers { + self.screen_ref.render(point_buffers, render_pass); + } + + if let Some(clip) = &bundle.clip_area_buffers { + self.clip.unclip(clip, render_pass); + } + } + + pub fn map_view_buffer(&self) -> &Buffer { + &self.map_view_buffer + } + + pub fn image_pipeline(&self) -> &ImagePipeline { + &self.image + } + + fn set_bindings<'a>(&'a self, render_pass: &mut RenderPass<'a>) { + render_pass.set_bind_group(0, &self.map_view_binding, &[]); + } +} + +fn default_targets(format: TextureFormat) -> [Option; 1] { + [Some(wgpu::ColorTargetState { + format, + blend: Some(wgpu::BlendState::ALPHA_BLENDING), + write_mask: wgpu::ColorWrites::ALL, + })] +} + +fn default_pipeline_descriptor<'a>( + pipeline_layout: &'a PipelineLayout, + shader: &'a ShaderModule, + targets: &'a [Option], + buffers: &'a [VertexBufferLayout<'a>], +) -> RenderPipelineDescriptor<'a> { + let stencil_state = StencilFaceState { + compare: CompareFunction::Equal, + fail_op: StencilOperation::Keep, + depth_fail_op: StencilOperation::Keep, + pass_op: StencilOperation::Keep, + }; + + RenderPipelineDescriptor { + label: None, + layout: Some(pipeline_layout), + vertex: wgpu::VertexState { + module: shader, + entry_point: "vs_main", + buffers, + }, + fragment: Some(wgpu::FragmentState { + module: shader, + entry_point: "fs_main", + targets, + }), + primitive: wgpu::PrimitiveState { + topology: wgpu::PrimitiveTopology::TriangleList, + strip_index_format: None, + front_face: wgpu::FrontFace::Ccw, + cull_mode: None, + polygon_mode: wgpu::PolygonMode::Fill, + unclipped_depth: false, + conservative: false, + }, + depth_stencil: Some(DepthStencilState { + format: TextureFormat::Depth24PlusStencil8, + depth_write_enabled: false, + depth_compare: CompareFunction::Always, + stencil: StencilState { + front: stencil_state, + back: stencil_state, + read_mask: 0xff, + write_mask: 0xff, + }, + bias: Default::default(), + }), + multisample: wgpu::MultisampleState { + count: 4, + mask: !0, + alpha_to_coverage_enabled: false, + }, + multiview: None, + } +} diff --git a/galileo/src/render/wgpu/pipelines/screen_ref.rs b/galileo/src/render/wgpu/pipelines/screen_ref.rs new file mode 100644 index 0000000..890b031 --- /dev/null +++ b/galileo/src/render/wgpu/pipelines/screen_ref.rs @@ -0,0 +1,38 @@ +use crate::render::render_bundle::tessellating::PointInstance; +use crate::render::wgpu::pipelines::default_targets; +use crate::render::wgpu::{pipelines, PointVertex, WgpuPointBuffers}; +use wgpu::{BindGroupLayout, Device, RenderPass, RenderPipeline, TextureFormat}; + +pub struct ScreenRefPipeline { + wgpu_pipeline: RenderPipeline, +} + +impl ScreenRefPipeline { + pub fn create( + device: &Device, + format: TextureFormat, + map_view_layout: &BindGroupLayout, + ) -> Self { + let buffers = [PointVertex::wgpu_desc(), PointInstance::wgpu_desc()]; + let shader = device.create_shader_module(wgpu::include_wgsl!("./shaders/screen_ref.wgsl")); + + let targets = default_targets(format); + let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[map_view_layout], + push_constant_ranges: &[], + }); + let desc = pipelines::default_pipeline_descriptor(&layout, &shader, &targets, &buffers); + + let wgpu_pipeline = device.create_render_pipeline(&desc); + Self { wgpu_pipeline } + } + + pub fn render<'a>(&'a self, buffers: &'a WgpuPointBuffers, render_pass: &mut RenderPass<'a>) { + render_pass.set_pipeline(&self.wgpu_pipeline); + render_pass.set_vertex_buffer(0, buffers.vertex.slice(..)); + render_pass.set_vertex_buffer(1, buffers.instance.slice(..)); + render_pass.set_index_buffer(buffers.index.slice(..), wgpu::IndexFormat::Uint32); + render_pass.draw_indexed(0..buffers.index_count, 0, 0..buffers.instance_count); + } +} diff --git a/galileo/src/render/wgpu_shaders/image.wgsl b/galileo/src/render/wgpu/pipelines/shaders/image.wgsl similarity index 97% rename from galileo/src/render/wgpu_shaders/image.wgsl rename to galileo/src/render/wgpu/pipelines/shaders/image.wgsl index eebdaa4..379fecf 100644 --- a/galileo/src/render/wgpu_shaders/image.wgsl +++ b/galileo/src/render/wgpu/pipelines/shaders/image.wgsl @@ -5,7 +5,7 @@ struct ViewUniform { resolution: f32, } -@group(1) @binding(0) +@group(0) @binding(0) var transform: ViewUniform; struct VertexInput { @@ -35,9 +35,9 @@ fn vs_main( // Fragment shader -@group(0) @binding(0) +@group(1) @binding(0) var t_diffuse: texture_2d; -@group(0) @binding(1) +@group(1) @binding(1) var s_diffuse: sampler; @fragment diff --git a/galileo/src/render/wgpu_shaders/line.wgsl b/galileo/src/render/wgpu/pipelines/shaders/map_ref.wgsl similarity index 100% rename from galileo/src/render/wgpu_shaders/line.wgsl rename to galileo/src/render/wgpu/pipelines/shaders/map_ref.wgsl diff --git a/galileo/src/render/wgpu_shaders/point.wgsl b/galileo/src/render/wgpu/pipelines/shaders/screen_ref.wgsl similarity index 100% rename from galileo/src/render/wgpu_shaders/point.wgsl rename to galileo/src/render/wgpu/pipelines/shaders/screen_ref.wgsl