Skip to content

Commit

Permalink
clipping for Bezpaths
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelselleck committed Oct 31, 2024
1 parent bae98da commit 926ca8f
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 103 deletions.
24 changes: 17 additions & 7 deletions pax-pixels/src/render_backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use wgpu::{

pub mod data;
mod gpu_resources;
mod stencil;
pub mod stencil;
mod texture;

use data::{GpuGlobals, GpuPrimitive, GpuVertex};
Expand Down Expand Up @@ -293,8 +293,12 @@ impl<'w> RenderBackend<'w> {
Self::create_pipeline(&device, surface_config.format, primitive_bind_group_layout);

let texture_renderer = TextureRenderer::new(&device);
let stencil_renderer =
StencilRenderer::new(&device, config.initial_width, config.initial_height);
let stencil_renderer = StencilRenderer::new(
&device,
config.initial_width,
config.initial_height,
&globals_buffer,
);

let initial_width = config.initial_width;
let initial_height = config.initial_height;
Expand Down Expand Up @@ -396,14 +400,20 @@ impl<'w> RenderBackend<'w> {
})
}

pub fn push_stencil(&mut self, transform: Transform2D) {
pub fn push_stencil(&mut self, geometry: VertexBuffers<stencil::Vertex, u16>) {
// self.stencil_renderer.clear(&self.device, &self.queue);
self.stencil_renderer
.push_stencil(&self.device, &self.queue, transform);
.push_stencil(&self.device, &self.queue, geometry);
}

pub fn reset_stencil_depth_to(&mut self, depth: u32) {
self.stencil_renderer
.reset_stencil_depth_to(&self.device, &self.queue, depth);
}

pub fn pop_stencil(&mut self) {
self.stencil_renderer.pop_stencil(&self.device, &self.queue);
pub fn get_clip_depth(&mut self) -> u32 {
let (_, depth) = self.stencil_renderer.get_stencil();
depth
}

pub fn resize(&mut self, width: u32, height: u32) {
Expand Down
141 changes: 56 additions & 85 deletions pax-pixels/src/render_backend/stencil.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use std::path::Path;

use bytemuck::{Pod, Zeroable};
use lyon::tessellation::VertexBuffers;
use wgpu::util::DeviceExt;
use wgpu::{BufferUsages, Device, Queue, RenderPipeline};

Expand All @@ -19,36 +22,15 @@ pub struct StencilRenderer {

#[repr(C)]
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
struct Vertex {
position: [f32; 2],
pub struct Vertex {
pub position: [f32; 2],
}

impl StencilRenderer {
pub fn new(device: &Device, width: u32, height: u32) -> Self {
pub fn new(device: &Device, width: u32, height: u32, _globals: &wgpu::Buffer) -> Self {
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Stencil Shader"),
source: wgpu::ShaderSource::Wgsl(
r##"
struct VertexOutput {
@builtin(position) position: vec4<f32>,
}
@vertex
fn vs_main(
@location(0) position: vec2<f32>,
) -> VertexOutput {
var out: VertexOutput;
out.position = vec4<f32>(position, 0.0, 1.0);
return out;
}
@fragment
fn fs_main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 1.0, 1.0, 1.0);
}
"##
.into(),
),
source: wgpu::ShaderSource::Wgsl(include_str!("stencil.wgsl").into()),
});

let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
Expand Down Expand Up @@ -80,7 +62,7 @@ impl StencilRenderer {
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
front_face: wgpu::FrontFace::Ccw,
front_face: wgpu::FrontFace::Cw,
cull_mode: None,
polygon_mode: wgpu::PolygonMode::Fill,
unclipped_depth: false,
Expand Down Expand Up @@ -161,18 +143,18 @@ impl StencilRenderer {

let vertices = [Vertex {
position: [0.0, 0.0],
}; 4];
}; 1024];
let vertices_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Stencil Vertices"),
contents: bytemuck::cast_slice(&vertices),
usage: BufferUsages::VERTEX | BufferUsages::COPY_DST,
});

let indices: [u16; 6] = [0, 1, 2, 2, 1, 3];
let mut indices: [u16; 1024] = [0; 1024];
let indices_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Stencil Indices"),
contents: bytemuck::cast_slice(&indices),
usage: BufferUsages::INDEX,
usage: BufferUsages::INDEX | BufferUsages::COPY_DST,
});

// Create fullscreen quad vertices for decrement operation
Expand Down Expand Up @@ -245,14 +227,26 @@ impl StencilRenderer {
self.height = height;
}

pub fn push_stencil(&mut self, device: &Device, queue: &Queue, transform: Transform2D) {
pub fn push_stencil(
&mut self,
device: &Device,
queue: &Queue,
geometry: VertexBuffers<Vertex, u16>,
) {
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Stencil Encoder"),
});

let vertices = create_transformed_rect(&transform);
log::debug!("vertices: {:?}", vertices);
queue.write_buffer(&self.vertices_buffer, 0, bytemuck::cast_slice(&vertices));
queue.write_buffer(
&self.vertices_buffer,
0,
bytemuck::cast_slice(&geometry.vertices),
);
queue.write_buffer(
&self.indices_buffer,
0,
bytemuck::cast_slice(&geometry.indices),
);

{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
Expand All @@ -273,46 +267,47 @@ impl StencilRenderer {
render_pass.set_pipeline(&self.stencil_pipeline);
render_pass.set_vertex_buffer(0, self.vertices_buffer.slice(..));
render_pass.set_index_buffer(self.indices_buffer.slice(..), wgpu::IndexFormat::Uint16);
render_pass.draw_indexed(0..6, 0, 0..1);
render_pass.draw_indexed(0..(geometry.indices.len() as u32), 0, 0..1);
}

queue.submit(std::iter::once(encoder.finish()));
self.stencil_layer += 1;
}

pub fn pop_stencil(&mut self, device: &Device, queue: &Queue) {
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Stencil Pop Encoder"),
});

{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Stencil Pop Pass"),
color_attachments: &[None],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.stencil_view,
depth_ops: None,
stencil_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
}),
}),
timestamp_writes: None,
occlusion_query_set: None,
pub fn reset_stencil_depth_to(&mut self, device: &Device, queue: &Queue, depth: u32) {
while self.stencil_layer > depth {
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Stencil Pop Encoder"),
});

// Use the decrement pipeline and fullscreen quad to decrease all stencil values
render_pass.set_pipeline(&self.decrement_pipeline);
render_pass.set_vertex_buffer(0, self.fullscreen_vertices_buffer.slice(..));
render_pass.draw(0..3, 0..1);
{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Stencil Pop Pass"),
color_attachments: &[None],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.stencil_view,
depth_ops: None,
stencil_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: wgpu::StoreOp::Store,
}),
}),
timestamp_writes: None,
occlusion_query_set: None,
});

// Use the decrement pipeline and fullscreen quad to decrease all stencil values
render_pass.set_pipeline(&self.decrement_pipeline);
render_pass.set_vertex_buffer(0, self.fullscreen_vertices_buffer.slice(..));
render_pass.draw(0..3, 0..1);
}

queue.submit(std::iter::once(encoder.finish()));
self.stencil_layer = self.stencil_layer.saturating_sub(1);
}

queue.submit(std::iter::once(encoder.finish()));
self.stencil_layer = self.stencil_layer.saturating_sub(1);
}

pub fn get_stencil(&self) -> (&wgpu::TextureView, u32) {
log::debug!("layer: {:?}", self.stencil_layer);
(&self.stencil_view, self.stencil_layer)
}

Expand Down Expand Up @@ -344,27 +339,3 @@ impl StencilRenderer {
self.stencil_layer = 0;
}
}

fn create_transformed_rect(transform: &Transform2D) -> [Vertex; 4] {
let points = [
transform.transform_point([0.0, 0.0].into()),
transform.transform_point([1.0, 0.0].into()),
transform.transform_point([0.0, 1.0].into()),
transform.transform_point([1.0, 1.0].into()),
];

[
Vertex {
position: [points[0].x, points[0].y],
},
Vertex {
position: [points[1].x, points[1].y],
},
Vertex {
position: [points[2].x, points[2].y],
},
Vertex {
position: [points[3].x, points[3].y],
},
]
}
32 changes: 32 additions & 0 deletions pax-pixels/src/render_backend/stencil.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
struct Globals {
resolution: vec2<f32>,
dpr: u32,
_pad2: u32,
};


// @group(0) @binding(0) var<uniform> globals: Globals;

struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
}

@vertex
fn vs_main(
@location(0) position: vec2<f32>,
) -> VertexOutput {
var out: VertexOutput;
// var pos = position;
// pos /= globals.resolution;
// pos *= 2.0;
// pos -= 1.0;
// pos.y *= -1.0;
out.clip_position = vec4<f32>(position, 0.0, 1.0);
return out;
}

@fragment
fn fs_main() -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 1.0, 1.0, 1.0);
}

25 changes: 20 additions & 5 deletions pax-pixels/src/render_context.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::render_backend::stencil;
use crate::render_backend::CpuBuffers;
use crate::Box2D;
use crate::Image;
Expand Down Expand Up @@ -26,7 +27,8 @@ pub struct WgpuRenderer<'w> {
render_backend: RenderBackend<'w>,
// these reference indicies in the CpuBuffer "transforms"
transform_index_stack: Vec<usize>,
saves: Vec<usize>,
// tuble of transform stack index to go to, and clip depth to go to
saves: Vec<(usize, usize)>,
tolerance: f32,
}

Expand Down Expand Up @@ -180,12 +182,15 @@ impl<'w> WgpuRenderer<'w> {

pub fn save(&mut self) {
let transform_len = self.transform_index_stack.len();
self.saves.push(transform_len);
self.saves
.push((transform_len, self.render_backend.get_clip_depth() as usize));
}

pub fn restore(&mut self) {
if let Some(t_pen) = self.saves.pop() {
if let Some((t_pen, clip_depth)) = self.saves.pop() {
self.transform_index_stack.truncate(t_pen);
self.render_backend
.reset_stencil_depth_to(clip_depth as u32);
}
}

Expand All @@ -199,8 +204,18 @@ impl<'w> WgpuRenderer<'w> {
self.transform_index_stack.push(new_ind);
}

pub fn set_clip_rect_test(&mut self, transform: Transform2D) {
self.render_backend.push_stencil(transform);
pub fn push_clipping(&mut self, path: Path) {
let options = FillOptions::tolerance(self.tolerance);
let mut geometry = VertexBuffers::new();
let mut geometry_builder =
BuffersBuilder::new(&mut geometry, |vertex: FillVertex| stencil::Vertex {
position: vertex.position().to_array(),
});
match FillTessellator::new().tessellate_path(&path, &options, &mut geometry_builder) {
Ok(_) => {}
Err(e) => log::warn!("{:?}", e),
};
self.render_backend.push_stencil(geometry);
}

pub fn resize(&mut self, width: f32, height: f32) {
Expand Down
2 changes: 1 addition & 1 deletion pax-runtime/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ impl PaxEngine {
.unwrap_or(false)
{
rcs.clear(i);
rcs.clip(i, BezPath::new()) // only for testing, REMOVE
rcs.clip(i, Rect::new(0.0, 0.0, 0.5, 0.5).into_path(0.01)) // only for testing, REMOVE
}
}
// This is pretty useful during debugging - left it here since I use it often. /Sam
Expand Down
6 changes: 4 additions & 2 deletions pax-runtime/src/engine/pax_pixels_render_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,11 @@ impl RenderContext for PaxPixelsRenderer {
context.restore();
});
}
fn clip(&mut self, layer: usize, _path: kurbo::BezPath) {
fn clip(&mut self, layer: usize, path: kurbo::BezPath) {
self.with_layer_context(layer, |context| {
context.set_clip_rect_test(Transform2D::scale(0.5, 0.5));
log::debug!("pax_pixels_render_context path {:?}", path);
let path = convert_kurbo_to_lyon_path(&path);
context.push_clipping(path);
});
}
fn transform(&mut self, layer: usize, affine: kurbo::Affine) {
Expand Down
2 changes: 1 addition & 1 deletion pax-std/src/core/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl InstanceNode for FrameInstance {
for layer in 0..layers {
//our "save point" before clipping — restored to in the post_render
rcs.save(layer);
rcs.clip(layer, transformed_bez_path.clone());
// rcs.clip(layer, transformed_bez_path.clone());
}
}

Expand Down
2 changes: 1 addition & 1 deletion pax-std/src/drawing/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ impl InstanceNode for ImageInstance {
let clip_path = kurbo::Rect::new(0.0, 0.0, container_width, container_height);
rc.save(layer_id);
rc.transform(layer_id, t_and_b.transform.into());
rc.clip(layer_id, clip_path.into_path(0.01));
// rc.clip(layer_id, clip_path.into_path(0.01));
rc.draw_image(layer_id, &path, transformed_bounds);
rc.restore(layer_id);
self.initial_load
Expand Down
Loading

0 comments on commit 926ca8f

Please sign in to comment.