1use rootvg_core::{
2 buffer::Buffer,
3 math::{PhysicalSizeI32, ScaleFactor},
4 pipeline::DefaultConstantUniforms,
5};
6use wgpu::PipelineCompilationOptions;
7
8use super::INITIAL_INSTANCES;
9
10use crate::SolidQuadPrimitive;
11
12pub struct SolidQuadBatchBuffer {
13 buffer: Buffer<SolidQuadPrimitive>,
14 num_primitives: usize,
15}
16
17#[derive(Debug)]
18pub struct SolidQuadPipeline {
19 pipeline: wgpu::RenderPipeline,
20
21 constants_buffer: wgpu::Buffer,
22 constants_bind_group: wgpu::BindGroup,
23
24 screen_size: PhysicalSizeI32,
25 scale_factor: ScaleFactor,
26}
27
28impl SolidQuadPipeline {
29 pub fn new(
30 device: &wgpu::Device,
31 format: wgpu::TextureFormat,
32 multisample: wgpu::MultisampleState,
33 ) -> Self {
34 let (constants_layout, constants_buffer, constants_bind_group) =
35 DefaultConstantUniforms::layout_buffer_and_bind_group(device);
36
37 let layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
38 label: Some("rootvg-quad solid pipeline layout"),
39 push_constant_ranges: &[],
40 bind_group_layouts: &[&constants_layout],
41 });
42
43 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
44 label: Some("rootvg-quad solid shader"),
45 source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(concat!(
46 include_str!("../shader/quad.wgsl"),
47 "\n",
48 include_str!("../shader/solid.wgsl"),
49 ))),
50 });
51
52 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
53 label: Some("rootvg-quad solid pipeline"),
54 layout: Some(&layout),
55 vertex: wgpu::VertexState {
56 module: &shader,
57 entry_point: "solid_vs_main",
58 buffers: &[wgpu::VertexBufferLayout {
59 array_stride: std::mem::size_of::<SolidQuadPrimitive>() as u64,
60 step_mode: wgpu::VertexStepMode::Instance,
61 attributes: &wgpu::vertex_attr_array!(
62 0 => Float32x4,
64 1 => Float32x2,
66 2 => Float32x2,
68 3 => Float32x4,
70 4 => Float32x4,
72 5 => Float32,
74 ),
83 }],
84 compilation_options: PipelineCompilationOptions::default(),
85 },
86 fragment: Some(wgpu::FragmentState {
87 module: &shader,
88 entry_point: "solid_fs_main",
89 targets: &super::color_target_state(format),
90 compilation_options: PipelineCompilationOptions::default(),
91 }),
92 primitive: wgpu::PrimitiveState {
93 topology: wgpu::PrimitiveTopology::TriangleList,
94 front_face: wgpu::FrontFace::Cw,
95 ..Default::default()
96 },
97 depth_stencil: None,
98 multisample,
99 multiview: None,
100 });
101
102 Self {
103 constants_buffer,
104 constants_bind_group,
105 pipeline,
106 screen_size: PhysicalSizeI32::default(),
107 scale_factor: ScaleFactor::default(),
108 }
109 }
110
111 pub fn create_batch(&mut self, device: &wgpu::Device) -> SolidQuadBatchBuffer {
112 SolidQuadBatchBuffer {
113 buffer: Buffer::new(
114 device,
115 "rootvg-quad solid buffer",
116 INITIAL_INSTANCES,
117 wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
118 ),
119 num_primitives: 0,
120 }
121 }
122
123 pub fn start_preparations(
124 &mut self,
125 _device: &wgpu::Device,
126 queue: &wgpu::Queue,
127 screen_size: PhysicalSizeI32,
128 scale_factor: ScaleFactor,
129 ) {
130 if self.screen_size == screen_size && self.scale_factor == scale_factor {
131 return;
132 }
133
134 self.screen_size = screen_size;
135 self.scale_factor = scale_factor;
136
137 DefaultConstantUniforms::prepare_buffer(
138 &self.constants_buffer,
139 screen_size,
140 scale_factor,
141 queue,
142 );
143 }
144
145 pub fn prepare_batch(
146 &mut self,
147 batch: &mut SolidQuadBatchBuffer,
148 primitives: &[SolidQuadPrimitive],
149 device: &wgpu::Device,
150 queue: &wgpu::Queue,
151 ) {
152 let _ = batch
153 .buffer
154 .expand_to_fit_new_size(device, primitives.len());
155 let _ = batch.buffer.write(queue, 0, primitives);
156
157 batch.num_primitives = primitives.len();
158 }
159
160 pub fn render_batch<'pass>(
161 &'pass self,
162 batch: &'pass SolidQuadBatchBuffer,
163 render_pass: &mut wgpu::RenderPass<'pass>,
164 ) {
165 if batch.num_primitives == 0 {
166 return;
167 }
168
169 render_pass.set_pipeline(&self.pipeline);
170 render_pass.set_bind_group(0, &self.constants_bind_group, &[]);
171
172 render_pass.set_vertex_buffer(0, batch.buffer.slice(0..batch.num_primitives));
173
174 render_pass.draw(0..6, 0..batch.num_primitives as u32);
175 }
176}