Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 10 additions & 15 deletions crates/vsvg-viewer/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,8 @@ impl LayerPainters {
if let Some(line_painter_data) = layer_data.line_painter_data() {
self.line_painter.draw(
render_pass,
&render_objects.camera_bind_group,
render_objects,
//&render_objects.camera_bind_group,
line_painter_data,
);
}
Expand All @@ -163,13 +164,13 @@ impl LayerPainters {
if let Some(bezier_handles_painter_data) = layer_data.bezier_handles_painter_data() {
self.bezier_handles_point_painter.draw(
render_pass,
&render_objects.camera_bind_group,
render_objects,
&bezier_handles_painter_data.point_painter_data,
);

self.bezier_handles_line_painter.draw(
render_pass,
&render_objects.camera_bind_group,
render_objects,
&bezier_handles_painter_data.line_painter_data,
);
}
Expand All @@ -180,19 +181,16 @@ impl LayerPainters {
{
self.display_vertices_painter.draw(
render_pass,
&render_objects.camera_bind_group,
render_objects,
display_vertices_painter_data,
);
}
}

if display_options.show_pen_up {
if let Some(pen_up_painter_data) = layer_data.pen_up_painter_data() {
self.pen_up_painter.draw(
render_pass,
&render_objects.camera_bind_group,
pen_up_painter_data,
);
self.pen_up_painter
.draw(render_pass, render_objects, pen_up_painter_data);
}
}
}
Expand All @@ -201,7 +199,7 @@ impl LayerPainters {
/// wgpu-related objects used by the engine.
///
/// They are grouped in a separate structure, so they can be provided to painters during engine
/// initialisation.
/// initialization.
pub(crate) struct EngineRenderObjects {
pub(crate) device: Arc<Device>,
pub(crate) camera_buffer: Buffer,
Expand Down Expand Up @@ -369,11 +367,8 @@ impl Engine {
vsvg::trace_function!();

if let Some(page_size_painter_data) = &self.page_size_painter_data {
self.page_size_painter.draw(
render_pass,
&self.render_objects.camera_bind_group,
page_size_painter_data,
);
self.page_size_painter
.draw(render_pass, &self.render_objects, page_size_painter_data);
}

let mut viewer_options = self.viewer_options.lock().unwrap();
Expand Down
4 changes: 2 additions & 2 deletions crates/vsvg-viewer/src/painters/basic_painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ impl Painter for BasicPainter {
fn draw(
&self,
rpass: &mut RenderPass<'static>,
camera_bind_group: &wgpu::BindGroup,
render_objects: &EngineRenderObjects,
data: &Self::Data,
) {
// `Buffer::slice(..)` panics for empty buffers in wgpu 23+
Expand All @@ -147,7 +147,7 @@ impl Painter for BasicPainter {
}

rpass.set_pipeline(&self.render_pipeline);
rpass.set_bind_group(0, camera_bind_group, &[]);
rpass.set_bind_group(0, &render_objects.camera_bind_group, &[]);
rpass.set_vertex_buffer(0, data.vertex_buffer.slice(..));
rpass.draw(0..data.vertex_count, 0..1);
}
Expand Down
133 changes: 58 additions & 75 deletions crates/vsvg-viewer/src/painters/line_painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,36 +94,10 @@
//! compliant with the [WebGPU spec](https://gpuweb.github.io/gpuweb/#dictdef-gpuvertexbufferlayout).
//! As such, it is rejected by (recent versions of) Chrome and wgpu/metal since (23.0.0).
//!
//! To work around this limitation, we bind the point buffer four times, with an offset of one to
//! three vertices, respectively. Each of these bindings gets a stride of one vertex and exposes one
//! vertex to the shader, which is spec compliant.
//! Instead, we bind points as a read-only storage buffer and directly look up vertex data in that
//! buffer.
//!
//! ```text
//! first last
//! instance instance
//! │ │
//! ▼ ▼
//! ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬ ─ ─ ─ ─ ┬ ─ ─
//! p0 │ A0 │ A0 │ A1 │ A1 │ B0 │ B0 │ B1 │ B2 │ B3 │ B3 │ C2 │ C0 │ C1 │ C2 │ C0 C1 │
//! └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴ ─ ─ ─ ─ ┴ ─ ─
//! ┌ ─ ─┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬ ─ ─ ─ ─ ┐
//! p1 A0 │ A0 │ A1 │ A1 │ B0 │ B0 │ B1 │ B2 │ B3 │ B3 │ C2 │ C0 │ C1 │ C2 │ C0 │ C1 offset = 1
//! └ ─ ─└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴ ─ ─ ─ ─ ┘
//! ─ ─ ┬ ─ ─┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬ ─ ─
//! p2 │ A0 A0 │ A1 │ A1 │ B0 │ B0 │ B1 │ B2 │ B3 │ B3 │ C2 │ C0 │ C1 │ C2 │ C0 │ C1 │ offset = 2
//! ─ ─ ┴ ─ ─└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴ ─ ─
//! ┌ ─ ─ ─ ─ ┬ ─ ─┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
//! p3 A0 │ A0 A1 │ A1 │ B0 │ B0 │ B1 │ B2 │ B3 │ B3 │ C2 │ C0 │ C1 │ C2 │ C0 │ C1 │ offset = 3
//! └ ─ ─ ─ ─ ┴ ─ ─└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
//! point buffer (bound four times)
//!
//!
//!
//! ┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
//! │ A0 │ │ │ │ B0 │ B1 │ B2 │ │ │ │ C0 │ C1 │ C2 │
//! └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
//! attributes buffer
//! ```
//! Note: this is not compatible with WebGL.

use wgpu::{
include_wgsl, util::DeviceExt, vertex_attr_array, Buffer, ColorTargetState, PrimitiveTopology,
Expand Down Expand Up @@ -179,14 +153,14 @@ impl LinePainterData {

let (vertices, attribs) = Self::build_buffers(paths, display_options);

// prepare point buffer
// prepare point buffer – used as a storage binding!
let points_buffer =
render_objects
.device
.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Point instance buffer"),
contents: bytemuck::cast_slice(vertices.as_slice()),
usage: wgpu::BufferUsages::VERTEX,
usage: wgpu::BufferUsages::STORAGE,
});

// prepare color buffer
Expand Down Expand Up @@ -282,43 +256,37 @@ impl LinePainterData {
///
/// See module documentation for details.
pub(crate) struct LinePainter {
points_bind_group_layout: wgpu::BindGroupLayout,
render_pipeline: RenderPipeline,
}

impl LinePainter {
pub(crate) fn new(render_objects: &EngineRenderObjects) -> Self {
// This is where we prepare the 4x binding of the same point buffer. Each binding has a
// stride of one vertex but a different starting offset.

let vertex_attributes = (0..4)
.map(|i| wgpu::VertexAttribute {
format: wgpu::VertexFormat::Float32x2,
offset: 0,
shader_location: i,
})
.collect::<Vec<_>>();

let mut buffer_layouts = vertex_attributes
.iter()
.map(|vertex_attrb| wgpu::VertexBufferLayout {
array_stride: size_of::<Vertex>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Instance,
attributes: std::slice::from_ref(vertex_attrb),
})
.collect::<Vec<_>>();

// add the color and width attributes

let vertex_attrib_color_width = vertex_attr_array![
4 => Uint32,
5 => Float32,
];

buffer_layouts.push(wgpu::VertexBufferLayout {
let vertex_attrib_buffer_layout = wgpu::VertexBufferLayout {
array_stride: size_of::<Attribute>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Instance,
attributes: &vertex_attrib_color_width,
});
attributes: &vertex_attr_array![
0 => Uint32,
1 => Float32,
],
};

let points_bind_group_layout =
render_objects
.device
.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Storage { read_only: true },
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
}],
label: Some("point_bind_group_layout"),
});

let shader = render_objects
.device
Expand All @@ -329,7 +297,10 @@ impl LinePainter {
.device
.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &[&render_objects.camera_bind_group_layout],
bind_group_layouts: &[
&render_objects.camera_bind_group_layout,
&points_bind_group_layout,
],
push_constant_ranges: &[],
});

Expand Down Expand Up @@ -361,7 +332,7 @@ impl LinePainter {
module: &shader,
entry_point: Some("vs_main"),
compilation_options: Default::default(),
buffers: &buffer_layouts,
buffers: &[vertex_attrib_buffer_layout],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
Expand All @@ -379,7 +350,12 @@ impl LinePainter {
cache: None,
});

Self { render_pipeline }
/////////

Self {
points_bind_group_layout,
render_pipeline,
}
}
}

Expand All @@ -389,24 +365,31 @@ impl Painter for LinePainter {
fn draw(
&self,
rpass: &mut RenderPass<'static>,
camera_bind_group: &wgpu::BindGroup,
render_objects: &EngineRenderObjects,
data: &LinePainterData,
) {
// `Buffer::slice(..)` panics for empty buffers in wgpu 23+
if data.points_buffer.size() == 0 {
// This also avoids the fact that `Buffer::slice(..)` panics for empty buffers in wgpu 23+
if data.instance_count == 0 {
return;
}

rpass.set_pipeline(&self.render_pipeline);
rpass.set_bind_group(0, camera_bind_group, &[]);
let points_bind_group =
render_objects
.device
.create_bind_group(&wgpu::BindGroupDescriptor {
layout: &self.points_bind_group_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: data.points_buffer.as_entire_binding(),
}],
label: Some("point_bind_group"),
});

let offset = size_of::<Vertex>() as u64;
rpass.set_vertex_buffer(0, data.points_buffer.slice(..));
rpass.set_vertex_buffer(1, data.points_buffer.slice(offset..));
rpass.set_vertex_buffer(2, data.points_buffer.slice((2 * offset)..));
rpass.set_vertex_buffer(3, data.points_buffer.slice((3 * offset)..));
rpass.set_pipeline(&self.render_pipeline);
rpass.set_bind_group(0, &render_objects.camera_bind_group, &[]);
rpass.set_bind_group(1, &points_bind_group, &[]);
rpass.set_vertex_buffer(0, data.attributes_buffer.slice(..));

rpass.set_vertex_buffer(4, data.attributes_buffer.slice(..));
rpass.draw(0..4, 0..data.instance_count);
}
}
3 changes: 2 additions & 1 deletion crates/vsvg-viewer/src/painters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod point_painter;
use vsvg::Point;
use wgpu::RenderPass;

use crate::engine::EngineRenderObjects;
pub(crate) use basic_painter::{BasicPainter, BasicPainterData};
pub(crate) use line_painter::{LineDisplayOptions, LinePainter, LinePainterData};
pub(crate) use page_size_painter::{PageSizePainter, PageSizePainterData};
Expand All @@ -17,7 +18,7 @@ pub(crate) trait Painter {
fn draw(
&self,
rpass: &mut RenderPass<'static>,
camera_bind_group: &wgpu::BindGroup,
render_objects: &EngineRenderObjects,
data: &Self::Data,
);
}
Expand Down
10 changes: 5 additions & 5 deletions crates/vsvg-viewer/src/painters/page_size_painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::engine::{
};
use crate::painters::{BasicPainter, BasicPainterData, Painter};
use vsvg::PageSize;
use wgpu::{BindGroup, RenderPass};
use wgpu::RenderPass;

pub(crate) struct PageSizePainterData {
background: BasicPainterData,
Expand Down Expand Up @@ -64,14 +64,14 @@ impl Painter for PageSizePainter {
fn draw(
&self,
rpass: &mut RenderPass<'static>,
camera_bind_group: &BindGroup,
render_objects: &EngineRenderObjects,
data: &Self::Data,
) {
self.background_and_shadow_painter
.draw(rpass, camera_bind_group, &data.shadow);
.draw(rpass, render_objects, &data.shadow);
self.background_and_shadow_painter
.draw(rpass, camera_bind_group, &data.background);
.draw(rpass, render_objects, &data.background);
self.border_painter
.draw(rpass, camera_bind_group, &data.border);
.draw(rpass, render_objects, &data.border);
}
}
4 changes: 2 additions & 2 deletions crates/vsvg-viewer/src/painters/point_painter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ impl Painter for PointPainter {
fn draw(
&self,
rpass: &mut RenderPass<'static>,
camera_bind_group: &wgpu::BindGroup,
render_objects: &EngineRenderObjects,
data: &Self::Data,
) {
// `Buffer::slice(..)` panics for empty buffers in wgpu 23+
Expand All @@ -149,7 +149,7 @@ impl Painter for PointPainter {
}

rpass.set_pipeline(&self.render_pipeline);
rpass.set_bind_group(0, camera_bind_group, &[]);
rpass.set_bind_group(0, &render_objects.camera_bind_group, &[]);
rpass.set_vertex_buffer(0, data.instance_buffer.slice(..));
rpass.draw(0..4, 0..data.instance_count);
}
Expand Down
Loading