Skip to content

Commit

Permalink
Split renderer into layers (#310)
Browse files Browse the repository at this point in the history
* layers

* renderer layers
  • Loading branch information
Brendonovich authored Feb 12, 2025
1 parent b7d8dc1 commit 8be8949
Show file tree
Hide file tree
Showing 11 changed files with 1,730 additions and 1,854 deletions.
7 changes: 1 addition & 6 deletions crates/editor/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,7 @@ impl Renderer {

// frame_task = Some(tokio::spawn(async move {
let frame = frame_renderer
.render(
segment_frames,
cap_rendering::Background::from(background),
&uniforms,
resolution_base,
)
.render(segment_frames, background, &uniforms, resolution_base)
.await
.unwrap();

Expand Down
4 changes: 2 additions & 2 deletions crates/project/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ pub struct ShadowConfiguration {
#[serde(rename_all = "camelCase")]
pub struct BackgroundConfiguration {
pub source: BackgroundSource,
pub blur: u32,
pub blur: f64,
pub padding: f64,
pub rounding: f64,
pub inset: u32,
Expand All @@ -175,7 +175,7 @@ impl Default for BackgroundConfiguration {
fn default() -> Self {
Self {
source: BackgroundSource::default(),
blur: 0,
blur: 0.0,
padding: 0.0,
rounding: 0.0,
inset: 0,
Expand Down
209 changes: 209 additions & 0 deletions crates/rendering/src/composite_frame.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
use bytemuck::{Pod, Zeroable};
use wgpu::{include_wgsl, util::DeviceExt};

use crate::create_shader_render_pipeline;

pub struct CompositeVideoFramePipeline {
pub bind_group_layout: wgpu::BindGroupLayout,
pub render_pipeline: wgpu::RenderPipeline,
}

#[derive(Debug, Clone, Copy, Pod, Zeroable, Default)]
#[repr(C)]
pub struct CompositeVideoFrameUniforms {
pub crop_bounds: [f32; 4],
pub target_bounds: [f32; 4],
pub output_size: [f32; 2],
pub frame_size: [f32; 2],
pub velocity_uv: [f32; 2],
pub target_size: [f32; 2],
pub rounding_px: f32,
pub mirror_x: f32,
pub motion_blur_amount: f32,
pub camera_motion_blur_amount: f32,
pub shadow: f32,
pub shadow_size: f32,
pub shadow_opacity: f32,
pub shadow_blur: f32,
pub _padding: [f32; 3],
}

impl CompositeVideoFrameUniforms {
pub fn to_buffer(self, device: &wgpu::Device) -> wgpu::Buffer {
device.create_buffer_init(
&(wgpu::util::BufferInitDescriptor {
label: Some("CompositeVideoFrameUniforms Buffer"),
contents: bytemuck::cast_slice(&[self]),
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
}),
)
}
}

pub struct CompositeFrameResources {
pub bind_group: wgpu::BindGroup,
pub bind_group_layout: wgpu::BindGroupLayout,
pub uniforms_buffer: wgpu::Buffer,
pub sampler: wgpu::Sampler,
}

impl CompositeVideoFramePipeline {
pub fn new(device: &wgpu::Device) -> Self {
let bind_group_layout = Self::bind_group_layout(device);
let render_pipeline = create_shader_render_pipeline(
device,
&bind_group_layout,
include_wgsl!("shaders/composite-video-frame.wgsl"),
);

Self {
bind_group_layout,
render_pipeline,
}
}

// fn resources(
// device: &wgpu::Device,
// source_frame: &wgpu::TextureView,
// target_frame: &wgpu::TextureView,
// ) -> CompositeFrameResources {
// let sampler = device.create_sampler(
// &(wgpu::SamplerDescriptor {
// address_mode_u: wgpu::AddressMode::ClampToEdge,
// address_mode_v: wgpu::AddressMode::ClampToEdge,
// address_mode_w: wgpu::AddressMode::ClampToEdge,
// mag_filter: wgpu::FilterMode::Linear,
// min_filter: wgpu::FilterMode::Linear,
// mipmap_filter: wgpu::FilterMode::Nearest,
// ..Default::default()
// }),
// );

// let uniforms_buffer = CompositeVideoFrameUniforms::default().to_buffer(device);

// let bind_group_layout = Self::bind_group_layout(device);

// let bind_group = device.create_bind_group(
// &(wgpu::BindGroupDescriptor {
// layout: &bind_group_layout,
// entries: &[
// wgpu::BindGroupEntry {
// binding: 0,
// resource: uniforms_buffer.as_entire_binding(),
// },
// wgpu::BindGroupEntry {
// binding: 1,
// resource: wgpu::BindingResource::TextureView(source_frame),
// },
// wgpu::BindGroupEntry {
// binding: 2,
// resource: wgpu::BindingResource::TextureView(target_frame),
// },
// wgpu::BindGroupEntry {
// binding: 3,
// resource: wgpu::BindingResource::Sampler(&sampler),
// },
// ],
// label: Some("bind_group"),
// }),
// );

// CompositeFrameResources {
// bind_group,
// bind_group_layout,
// uniforms_buffer,
// sampler,
// }
// }

fn bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("composite-video-frame.wgsl Bind Group Layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: None,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 2,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Texture {
sample_type: wgpu::TextureSampleType::Float { filterable: true },
view_dimension: wgpu::TextureViewDimension::D2,
multisampled: false,
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 3,
visibility: wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),
count: None,
},
],
})
}

pub fn bind_group(
&self,
device: &wgpu::Device,
uniforms: &wgpu::Buffer,
frame: &wgpu::TextureView,
intermediate: &wgpu::TextureView,
) -> wgpu::BindGroup {
let sampler = device.create_sampler(
&(wgpu::SamplerDescriptor {
address_mode_u: wgpu::AddressMode::ClampToEdge,
address_mode_v: wgpu::AddressMode::ClampToEdge,
address_mode_w: wgpu::AddressMode::ClampToEdge,
mag_filter: wgpu::FilterMode::Linear,
min_filter: wgpu::FilterMode::Linear,
mipmap_filter: wgpu::FilterMode::Nearest,
..Default::default()
}),
);

let bind_group = device.create_bind_group(
&(wgpu::BindGroupDescriptor {
layout: &self.bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: uniforms.as_entire_binding(),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::TextureView(frame),
},
wgpu::BindGroupEntry {
binding: 2,
resource: wgpu::BindingResource::TextureView(intermediate),
},
wgpu::BindGroupEntry {
binding: 3,
resource: wgpu::BindingResource::Sampler(&sampler),
},
],
label: Some("bind_group"),
}),
);

bind_group
}
}
127 changes: 127 additions & 0 deletions crates/rendering/src/coord.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use std::ops::{Add, Deref, Mul, Sub};

use cap_project::{ProjectConfiguration, XY};

use crate::{ProjectUniforms, RenderOptions};

#[derive(Default, Clone, Copy, Debug)]
pub struct RawDisplaySpace;

// raw cursor data
#[derive(Default, Clone, Copy, Debug)]
pub struct RawDisplayUVSpace;

#[derive(Default, Clone, Copy, Debug)]
pub struct CroppedDisplaySpace;

#[derive(Default, Clone, Copy, Debug)]
pub struct FrameSpace;

#[derive(Default, Clone, Copy, Debug)]
pub struct TransformedDisplaySpace;

#[derive(Clone, Copy, Debug)]
pub struct Coord<TSpace> {
pub coord: XY<f64>,
pub space: TSpace,
}

impl<TSpace: Default> Coord<TSpace> {
pub fn new(coord: XY<f64>) -> Self {
Self {
coord,
space: TSpace::default(),
}
}

pub fn clamp(self, min: XY<f64>, max: XY<f64>) -> Self {
Self {
coord: XY {
x: self.coord.x.clamp(min.x, max.x),
y: self.coord.y.clamp(min.y, max.y),
},
space: self.space,
}
}
}

impl<T> Deref for Coord<T> {
type Target = XY<f64>;

fn deref(&self) -> &Self::Target {
&self.coord
}
}

impl Coord<RawDisplayUVSpace> {
pub fn to_raw_display_space(&self, options: &RenderOptions) -> Coord<RawDisplaySpace> {
Coord::new(self.coord * options.screen_size.map(|v| v as f64))
}

pub fn to_frame_space(
&self,
options: &RenderOptions,
project: &ProjectConfiguration,
resolution_base: XY<u32>,
) -> Coord<FrameSpace> {
self.to_raw_display_space(options)
.to_cropped_display_space(options, project)
.to_frame_space(options, project, resolution_base)
}
}

impl Coord<RawDisplaySpace> {
pub fn to_cropped_display_space(
&self,
options: &RenderOptions,
project: &ProjectConfiguration,
) -> Coord<CroppedDisplaySpace> {
let crop = ProjectUniforms::get_crop(options, project);
Coord::new(self.coord - crop.position.map(|v| v as f64))
}
}

impl Coord<CroppedDisplaySpace> {
pub fn to_frame_space(
&self,
options: &RenderOptions,
project: &ProjectConfiguration,
resolution_base: XY<u32>,
) -> Coord<FrameSpace> {
let padding = ProjectUniforms::get_display_offset(options, project, resolution_base);
Coord::new(self.coord + *padding)
}
}

impl<T> Add for Coord<T> {
type Output = Self;

fn add(self, rhs: Self) -> Self {
Coord {
coord: self.coord + rhs.coord,
space: self.space,
}
}
}

impl<T> Sub for Coord<T> {
type Output = Self;

fn sub(self, rhs: Self) -> Self {
Coord {
coord: self.coord - rhs.coord,
space: self.space,
}
}
}

impl<T> Mul<f64> for Coord<T> {
type Output = Self;

fn mul(self, rhs: f64) -> Self {
Coord {
coord: self.coord * rhs,
space: self.space,
}
}
}
Loading

1 comment on commit 8be8949

@vercel
Copy link

@vercel vercel bot commented on 8be8949 Feb 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.