Another project
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 7.9 kB View raw
1use crate::gpu::Gpu; 2 3#[repr(C, align(16))] 4#[derive(Copy, Clone, Debug, PartialEq, bytemuck::Pod, bytemuck::Zeroable)] 5pub struct ChromeInstance { 6 pub rect_xywh_px: [f32; 4], 7 pub fill_premul_rgba: [f32; 4], 8 pub border_premul_rgba: [f32; 4], 9 pub thickness_radius_px: [f32; 2], 10 pub(crate) pad: [f32; 2], 11} 12 13impl ChromeInstance { 14 #[must_use] 15 pub const fn new( 16 rect_xywh_px: [f32; 4], 17 fill_premul_rgba: [f32; 4], 18 border_premul_rgba: [f32; 4], 19 thickness_radius_px: [f32; 2], 20 ) -> Self { 21 Self { 22 rect_xywh_px, 23 fill_premul_rgba, 24 border_premul_rgba, 25 thickness_radius_px, 26 pad: [0.0, 0.0], 27 } 28 } 29} 30 31const INSTANCE_STRIDE: u64 = core::mem::size_of::<ChromeInstance>() as u64; 32const INITIAL_INSTANCE_CAP: u64 = 256; 33 34#[repr(C, align(16))] 35#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)] 36struct ChromeFrame { 37 viewport_px: [f32; 2], 38 pad: [f32; 2], 39} 40 41const FRAME_SIZE: u64 = core::mem::size_of::<ChromeFrame>() as u64; 42 43pub struct ChromePipeline { 44 device: wgpu::Device, 45 queue: wgpu::Queue, 46 pipeline: wgpu::RenderPipeline, 47 uniform_buffer: wgpu::Buffer, 48 bind_group: wgpu::BindGroup, 49 instance_buffer: wgpu::Buffer, 50 instance_capacity: u64, 51} 52 53impl ChromePipeline { 54 #[must_use] 55 pub fn new(gpu: &Gpu, color_format: wgpu::TextureFormat) -> Self { 56 let device = gpu.device().clone(); 57 let queue = gpu.queue().clone(); 58 let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { 59 label: Some("bone-render:chrome-shader"), 60 source: wgpu::ShaderSource::Wgsl(include_str!("chrome.wgsl").into()), 61 }); 62 let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { 63 label: Some("bone-render:chrome-bgl"), 64 entries: &[wgpu::BindGroupLayoutEntry { 65 binding: 0, 66 visibility: wgpu::ShaderStages::VERTEX_FRAGMENT, 67 ty: wgpu::BindingType::Buffer { 68 ty: wgpu::BufferBindingType::Uniform, 69 has_dynamic_offset: false, 70 min_binding_size: wgpu::BufferSize::new(FRAME_SIZE), 71 }, 72 count: None, 73 }], 74 }); 75 let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { 76 label: Some("bone-render:chrome-layout"), 77 bind_group_layouts: &[Some(&bind_group_layout)], 78 immediate_size: 0, 79 }); 80 let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { 81 label: Some("bone-render:chrome-pipeline"), 82 layout: Some(&pipeline_layout), 83 vertex: wgpu::VertexState { 84 module: &shader, 85 entry_point: Some("vs"), 86 compilation_options: wgpu::PipelineCompilationOptions::default(), 87 buffers: &[wgpu::VertexBufferLayout { 88 array_stride: INSTANCE_STRIDE, 89 step_mode: wgpu::VertexStepMode::Instance, 90 attributes: &INSTANCE_ATTRS, 91 }], 92 }, 93 fragment: Some(wgpu::FragmentState { 94 module: &shader, 95 entry_point: Some("fs"), 96 compilation_options: wgpu::PipelineCompilationOptions::default(), 97 targets: &[Some(wgpu::ColorTargetState { 98 format: color_format, 99 blend: Some(wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING), 100 write_mask: wgpu::ColorWrites::ALL, 101 })], 102 }), 103 primitive: wgpu::PrimitiveState { 104 topology: wgpu::PrimitiveTopology::TriangleList, 105 strip_index_format: None, 106 front_face: wgpu::FrontFace::Ccw, 107 cull_mode: None, 108 polygon_mode: wgpu::PolygonMode::Fill, 109 conservative: false, 110 unclipped_depth: false, 111 }, 112 depth_stencil: None, 113 multisample: wgpu::MultisampleState::default(), 114 multiview_mask: None, 115 cache: None, 116 }); 117 let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor { 118 label: Some("bone-render:chrome-uniform"), 119 size: FRAME_SIZE, 120 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, 121 mapped_at_creation: false, 122 }); 123 let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { 124 label: Some("bone-render:chrome-bg"), 125 layout: &bind_group_layout, 126 entries: &[wgpu::BindGroupEntry { 127 binding: 0, 128 resource: uniform_buffer.as_entire_binding(), 129 }], 130 }); 131 let instance_buffer = create_instance_buffer(&device, INITIAL_INSTANCE_CAP); 132 Self { 133 device, 134 queue, 135 pipeline, 136 uniform_buffer, 137 bind_group, 138 instance_buffer, 139 instance_capacity: INITIAL_INSTANCE_CAP, 140 } 141 } 142 143 pub fn upload(&mut self, viewport_px: [f32; 2], instances: &[ChromeInstance]) { 144 let frame = ChromeFrame { 145 viewport_px, 146 pad: [0.0, 0.0], 147 }; 148 self.queue 149 .write_buffer(&self.uniform_buffer, 0, bytemuck::bytes_of(&frame)); 150 if instances.is_empty() { 151 return; 152 } 153 let needed = instances.len() as u64; 154 if needed > self.instance_capacity { 155 let new_cap = needed.next_power_of_two().max(self.instance_capacity * 2); 156 self.instance_buffer = create_instance_buffer(&self.device, new_cap); 157 self.instance_capacity = new_cap; 158 } 159 self.queue 160 .write_buffer(&self.instance_buffer, 0, bytemuck::cast_slice(instances)); 161 } 162 163 pub fn draw_range( 164 &self, 165 encoder: &mut wgpu::CommandEncoder, 166 color_view: &wgpu::TextureView, 167 range: core::ops::Range<u32>, 168 ) { 169 if range.start >= range.end { 170 return; 171 } 172 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { 173 label: Some("bone-render:chrome-pass"), 174 color_attachments: &[Some(wgpu::RenderPassColorAttachment { 175 view: color_view, 176 resolve_target: None, 177 depth_slice: None, 178 ops: wgpu::Operations { 179 load: wgpu::LoadOp::Load, 180 store: wgpu::StoreOp::Store, 181 }, 182 })], 183 depth_stencil_attachment: None, 184 timestamp_writes: None, 185 occlusion_query_set: None, 186 multiview_mask: None, 187 }); 188 pass.set_pipeline(&self.pipeline); 189 pass.set_bind_group(0, &self.bind_group, &[]); 190 let start_bytes = u64::from(range.start) * INSTANCE_STRIDE; 191 let end_bytes = u64::from(range.end) * INSTANCE_STRIDE; 192 pass.set_vertex_buffer(0, self.instance_buffer.slice(start_bytes..end_bytes)); 193 pass.draw(0..6, 0..(range.end - range.start)); 194 } 195} 196 197fn create_instance_buffer(device: &wgpu::Device, capacity: u64) -> wgpu::Buffer { 198 device.create_buffer(&wgpu::BufferDescriptor { 199 label: Some("bone-render:chrome-instances"), 200 size: capacity * INSTANCE_STRIDE, 201 usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, 202 mapped_at_creation: false, 203 }) 204} 205 206impl core::fmt::Debug for ChromePipeline { 207 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 208 f.debug_struct("ChromePipeline").finish_non_exhaustive() 209 } 210} 211 212const INSTANCE_ATTRS: [wgpu::VertexAttribute; 4] = wgpu::vertex_attr_array![ 213 0 => Float32x4, 214 1 => Float32x4, 215 2 => Float32x4, 216 3 => Float32x2, 217];