Skip to main content

rustial_renderer_wgpu/pipeline/
fill_pattern_pipeline.rs

1//! Dedicated fill-pattern render pipeline with repeating texture sampling.
2
3use crate::gpu::depth::DEPTH_FORMAT;
4use crate::gpu::fill_pattern_vertex::FillPatternVertex;
5use crate::pipeline::fill_pipeline::FillParamsUniform;
6use crate::pipeline::uniforms::ViewProjUniform;
7
8/// The fill-pattern rendering pipeline.
9///
10/// Uses a two-group bind layout:
11/// - Group 0: view-projection uniform (binding 0) + fill params (binding 1)
12/// - Group 1: pattern texture (binding 0) + sampler (binding 1)
13pub struct FillPatternPipeline {
14    /// Render pipeline configured for patterned polygon rendering.
15    pub pipeline: wgpu::RenderPipeline,
16    /// Bind group layout (group 0) for view-projection + fill params.
17    pub uniform_bind_group_layout: wgpu::BindGroupLayout,
18    /// Bind group layout (group 1) for per-batch pattern texture + sampler.
19    pub texture_bind_group_layout: wgpu::BindGroupLayout,
20}
21
22impl FillPatternPipeline {
23    /// Create the fill-pattern pipeline.
24    pub fn new(device: &wgpu::Device, surface_format: wgpu::TextureFormat) -> Self {
25        let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
26            label: Some("fill_pattern_shader"),
27            source: wgpu::ShaderSource::Wgsl(include_str!("../shaders/fill_pattern.wgsl").into()),
28        });
29
30        // Group 0: uniforms (same layout as solid fill).
31        let uniform_bind_group_layout =
32            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
33                label: Some("fill_pattern_uniform_bgl"),
34                entries: &[
35                    // binding 0: ViewProjUniform
36                    wgpu::BindGroupLayoutEntry {
37                        binding: 0,
38                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
39                        ty: wgpu::BindingType::Buffer {
40                            ty: wgpu::BufferBindingType::Uniform,
41                            has_dynamic_offset: false,
42                            min_binding_size: wgpu::BufferSize::new(std::mem::size_of::<
43                                ViewProjUniform,
44                            >()
45                                as u64),
46                        },
47                        count: None,
48                    },
49                    // binding 1: FillParamsUniform
50                    wgpu::BindGroupLayoutEntry {
51                        binding: 1,
52                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
53                        ty: wgpu::BindingType::Buffer {
54                            ty: wgpu::BufferBindingType::Uniform,
55                            has_dynamic_offset: false,
56                            min_binding_size: wgpu::BufferSize::new(std::mem::size_of::<
57                                FillParamsUniform,
58                            >()
59                                as u64),
60                        },
61                        count: None,
62                    },
63                ],
64            });
65
66        // Group 1: pattern texture + sampler.
67        let texture_bind_group_layout =
68            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
69                label: Some("fill_pattern_texture_bgl"),
70                entries: &[
71                    wgpu::BindGroupLayoutEntry {
72                        binding: 0,
73                        visibility: wgpu::ShaderStages::FRAGMENT,
74                        ty: wgpu::BindingType::Texture {
75                            multisampled: false,
76                            view_dimension: wgpu::TextureViewDimension::D2,
77                            sample_type: wgpu::TextureSampleType::Float { filterable: true },
78                        },
79                        count: None,
80                    },
81                    wgpu::BindGroupLayoutEntry {
82                        binding: 1,
83                        visibility: wgpu::ShaderStages::FRAGMENT,
84                        ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
85                        count: None,
86                    },
87                ],
88            });
89
90        let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
91            label: Some("fill_pattern_pipeline_layout"),
92            bind_group_layouts: &[&uniform_bind_group_layout, &texture_bind_group_layout],
93            push_constant_ranges: &[],
94        });
95
96        let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
97            label: Some("fill_pattern_pipeline"),
98            layout: Some(&pipeline_layout),
99            vertex: wgpu::VertexState {
100                module: &shader,
101                entry_point: Some("vs_main"),
102                buffers: &[FillPatternVertex::layout()],
103                compilation_options: wgpu::PipelineCompilationOptions::default(),
104            },
105            fragment: Some(wgpu::FragmentState {
106                module: &shader,
107                entry_point: Some("fs_main"),
108                targets: &[Some(wgpu::ColorTargetState {
109                    format: surface_format,
110                    blend: Some(wgpu::BlendState::ALPHA_BLENDING),
111                    write_mask: wgpu::ColorWrites::ALL,
112                })],
113                compilation_options: wgpu::PipelineCompilationOptions::default(),
114            }),
115            primitive: wgpu::PrimitiveState {
116                topology: wgpu::PrimitiveTopology::TriangleList,
117                front_face: wgpu::FrontFace::Ccw,
118                cull_mode: None,
119                ..Default::default()
120            },
121            depth_stencil: Some(wgpu::DepthStencilState {
122                format: DEPTH_FORMAT,
123                depth_write_enabled: true,
124                depth_compare: wgpu::CompareFunction::Less,
125                stencil: wgpu::StencilState::default(),
126                bias: wgpu::DepthBiasState::default(),
127            }),
128            multisample: wgpu::MultisampleState::default(),
129            multiview: None,
130            cache: None,
131        });
132
133        Self {
134            pipeline,
135            uniform_bind_group_layout,
136            texture_bind_group_layout,
137        }
138    }
139}