| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use std::{borrow::Cow, mem, slice}; |
| |
| use bytemuck::{Pod, Zeroable}; |
| pub use wgpu; |
| use wgpu::util::DeviceExt; |
| |
| // mod compact_pixel_segment; |
| |
| // pub use compact_pixel_segment::CompactPixelSegment; |
| |
| pub const TILE_WIDTH: usize = 16; |
| pub const TILE_HEIGHT: usize = 4; |
| |
| #[derive(Clone, Copy, Debug, Pod, Zeroable)] |
| #[repr(C)] |
| pub struct Style { |
| pub fill_rule: u32, |
| pub color: Color, |
| pub blend_mode: u32, |
| } |
| |
| #[derive(Clone, Copy, Debug, Pod, Zeroable)] |
| #[repr(C)] |
| pub struct Color { |
| pub r: f32, |
| pub g: f32, |
| pub b: f32, |
| pub a: f32, |
| } |
| |
| #[derive(Copy, Clone)] |
| #[repr(C)] |
| pub struct Config { |
| pub segments_len: u32, |
| pub width: u32, |
| pub height: u32, |
| pub _padding: u32, |
| pub clear_color: Color, |
| } |
| |
| impl Config { |
| pub fn as_byte_slice(&self) -> &[u8] { |
| unsafe { slice::from_raw_parts((self as *const _) as *const u8, mem::size_of::<Self>()) } |
| } |
| } |
| |
| #[derive(Debug)] |
| pub struct PaintContext { |
| pub pipeline: wgpu::ComputePipeline, |
| pub bind_group_layout: wgpu::BindGroupLayout, |
| } |
| |
| pub fn init(device: &wgpu::Device) -> PaintContext { |
| let module = device.create_shader_module(&wgpu::ShaderModuleDescriptor { |
| label: Some("paint.wgsl"), |
| source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("paint.wgsl"))), |
| }); |
| |
| let pipeline = device.create_compute_pipeline(&wgpu::ComputePipelineDescriptor { |
| label: None, |
| layout: None, |
| module: &module, |
| entry_point: "paint", |
| }); |
| |
| let bind_group_layout = pipeline.get_bind_group_layout(0); |
| |
| PaintContext { pipeline, bind_group_layout } |
| } |
| |
| pub fn encode( |
| device: &wgpu::Device, |
| encoder: &mut wgpu::CommandEncoder, |
| context: &PaintContext, |
| texture_view: &wgpu::TextureView, |
| segments_buffer: &wgpu::Buffer, |
| segments_len: u32, |
| style_offsets_buffer: &wgpu::Buffer, |
| styles_buffer: &wgpu::Buffer, |
| width: u32, |
| height: u32, |
| clear_color: Color, |
| timestamp: Option<(&wgpu::QuerySet, u32, u32)>, |
| ) { |
| let config = Config { segments_len, width, height, clear_color, _padding: 0 }; |
| |
| let config_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { |
| label: None, |
| contents: config.as_byte_slice(), |
| usage: wgpu::BufferUsages::UNIFORM, |
| }); |
| |
| let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { |
| label: None, |
| layout: &context.bind_group_layout, |
| entries: &[ |
| wgpu::BindGroupEntry { binding: 0, resource: config_buffer.as_entire_binding() }, |
| wgpu::BindGroupEntry { binding: 1, resource: segments_buffer.as_entire_binding() }, |
| wgpu::BindGroupEntry { binding: 2, resource: style_offsets_buffer.as_entire_binding() }, |
| wgpu::BindGroupEntry { binding: 3, resource: styles_buffer.as_entire_binding() }, |
| wgpu::BindGroupEntry { |
| binding: 4, |
| resource: wgpu::BindingResource::TextureView(&texture_view), |
| }, |
| ], |
| }); |
| |
| let mut pass = encoder.begin_compute_pass(&wgpu::ComputePassDescriptor { label: None }); |
| pass.set_pipeline(&context.pipeline); |
| pass.set_bind_group(0, &bind_group, &[]); |
| |
| if let Some((timestamp, start_index, _)) = timestamp { |
| pass.write_timestamp(×tamp, start_index); |
| } |
| |
| pass.dispatch_workgroups(((height as usize + TILE_HEIGHT - 1) / TILE_HEIGHT) as u32, 1, 1); |
| |
| if let Some((timestamp, _, end_index)) = timestamp { |
| pass.write_timestamp(×tamp, end_index); |
| } |
| } |