use super::errors::*;
#[cfg(feature = "webgpu")]
#[cfg(feature = "webgpu")]
pub struct RealWebGpuDevice {
pub device: wgpu::Device,
pub queue: wgpu::Queue,
pub adapter: wgpu::Adapter,
pub capabilities: super::errors::WebGpuCapabilities,
pub limits: wgpu::Limits,
pub features: wgpu::Features,
}
#[cfg(feature = "webgpu")]
impl RealWebGpuDevice {
pub async fn new() -> Result<Self, RenderError> {
let adapter = wgpu::Instance::new(&wgpu::InstanceDescriptor::default())
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
compatible_surface: None,
force_fallback_adapter: false,
})
.await
.map_err(|e| RenderError::WebGPU(format!("Failed to get WebGPU adapter: {}", e)))?;
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor {
label: None,
required_features: wgpu::Features::VERTEX_WRITABLE_STORAGE
| wgpu::Features::MULTI_DRAW_INDIRECT,
required_limits: wgpu::Limits::default(),
memory_hints: wgpu::MemoryHints::default(),
trace: wgpu::Trace::default(),
})
.await
.map_err(|e| RenderError::WebGPU(format!("Failed to get device: {}", e)))?;
let limits = device.limits();
let features = device.features();
let capabilities = super::errors::WebGpuCapabilities {
max_texture_size: limits.max_texture_dimension_2d,
max_buffer_size: limits.max_buffer_size,
supported_formats: vec!["rgba8unorm".to_string(), "bgra8unorm".to_string()],
compute_shader_support: true, };
Ok(Self {
device,
queue,
adapter,
capabilities,
limits,
features,
})
}
pub fn is_available() -> bool {
true }
pub fn queue(&self) -> &wgpu::Queue {
&self.queue
}
pub fn adapter(&self) -> &wgpu::Adapter {
&self.adapter
}
pub fn capabilities(&self) -> &super::errors::WebGpuCapabilities {
&self.capabilities
}
pub fn limits(&self) -> &wgpu::Limits {
&self.limits
}
pub fn features(&self) -> &wgpu::Features {
&self.features
}
pub async fn create_shader_module(
&self,
source: &str,
) -> Result<wgpu::ShaderModule, RenderError> {
Ok(self
.device
.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None,
source: wgpu::ShaderSource::Wgsl(source.into()),
}))
}
}
#[cfg(feature = "webgpu")]
pub struct RealLineChartPipeline {
#[allow(dead_code)]
device: wgpu::Device,
#[allow(dead_code)]
queue: wgpu::Queue,
#[allow(dead_code)]
render_pipeline: wgpu::RenderPipeline,
#[allow(dead_code)]
vertex_buffer: wgpu::Buffer,
#[allow(dead_code)]
uniform_buffer: wgpu::Buffer,
#[allow(dead_code)]
bind_group: wgpu::BindGroup,
}
#[cfg(feature = "webgpu")]
impl RealLineChartPipeline {
pub async fn new(device: &RealWebGpuDevice) -> Result<Self, RenderError> {
let device_ref = &device.device;
let queue_ref = &device.queue;
let vertex_data: Vec<f32> = vec![
-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0,
1.0,
];
let vertex_buffer = device_ref.create_buffer(&wgpu::BufferDescriptor {
label: Some("Line Chart Vertex Buffer"),
size: (vertex_data.len() * std::mem::size_of::<f32>()) as u64,
usage: wgpu::BufferUsages::VERTEX,
mapped_at_creation: false,
});
let uniform_data: Vec<f32> = vec![
1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, ];
let uniform_buffer = device_ref.create_buffer(&wgpu::BufferDescriptor {
label: Some("Line Chart Uniform Buffer"),
size: (uniform_data.len() * std::mem::size_of::<f32>()) as u64,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let bind_group_layout =
device_ref.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Line Chart Bind Group Layout"),
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,
}],
});
let bind_group = device_ref.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Line Chart Bind Group"),
layout: &bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: uniform_buffer.as_entire_binding(),
}],
});
let shader_source = include_str!("shaders/line.wgsl");
let shader_module = device_ref.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Line Chart Shader"),
source: wgpu::ShaderSource::Wgsl(shader_source.into()),
});
let pipeline_layout = device_ref.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Line Chart Pipeline Layout"),
bind_group_layouts: &[&bind_group_layout],
push_constant_ranges: &[],
});
let render_pipeline = device_ref.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Line Chart Render Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader_module,
entry_point: Some("vs_main"),
buffers: &[wgpu::VertexBufferLayout {
array_stride: 6 * std::mem::size_of::<f32>() as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
offset: 0,
shader_location: 0,
format: wgpu::VertexFormat::Float32x2,
},
wgpu::VertexAttribute {
offset: 2 * std::mem::size_of::<f32>() as u64,
shader_location: 1,
format: wgpu::VertexFormat::Float32x4,
},
],
}],
compilation_options: wgpu::PipelineCompilationOptions::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader_module,
entry_point: Some("fs_main"),
targets: &[Some(wgpu::ColorTargetState {
format: wgpu::TextureFormat::Bgra8UnormSrgb,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
compilation_options: wgpu::PipelineCompilationOptions::default(),
}),
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: None,
multisample: wgpu::MultisampleState {
count: 1,
mask: !0,
alpha_to_coverage_enabled: false,
},
multiview: None,
cache: None,
});
Ok(Self {
device: device_ref.clone(),
queue: queue_ref.clone(),
render_pipeline,
vertex_buffer,
uniform_buffer,
bind_group,
})
}
pub fn render(&self, encoder: &mut wgpu::CommandEncoder, view: &wgpu::TextureView) {
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Line Chart Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.0,
g: 0.0,
b: 0.0,
a: 1.0,
}),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
});
render_pass.set_pipeline(&self.render_pipeline);
render_pass.set_bind_group(0, &self.bind_group, &[]);
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
render_pass.draw(0..3, 0..1);
}
}