fix PathRasterization pipeline

This commit is contained in:
Junkui Zhang 2025-07-29 14:05:38 +08:00
parent d7b14d8dc5
commit 62d1b7e36f
2 changed files with 196 additions and 253 deletions

View file

@ -68,7 +68,8 @@ struct DirectXResources {
struct DirectXRenderPipelines { struct DirectXRenderPipelines {
shadow_pipeline: PipelineState<Shadow>, shadow_pipeline: PipelineState<Shadow>,
quad_pipeline: PipelineState<Quad>, quad_pipeline: PipelineState<Quad>,
path_rasterization_pipeline: PathRasterizationPipelineState, // path_rasterization_pipeline: PathRasterizationPipelineState,
path_rasterization_pipeline: PipelineState<PathRasterizationSprite>,
path_sprite_pipeline: PipelineState<PathSprite>, path_sprite_pipeline: PipelineState<PathSprite>,
underline_pipeline: PipelineState<Underline>, underline_pipeline: PipelineState<Underline>,
mono_sprites: PipelineState<MonochromeSprite>, mono_sprites: PipelineState<MonochromeSprite>,
@ -341,6 +342,8 @@ impl DirectXRenderer {
&self.devices.device_context, &self.devices.device_context,
&self.resources.viewport, &self.resources.viewport,
&self.globals.global_params_buffer, &self.globals.global_params_buffer,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
4,
shadows.len() as u32, shadows.len() as u32,
) )
} }
@ -358,6 +361,8 @@ impl DirectXRenderer {
&self.devices.device_context, &self.devices.device_context,
&self.resources.viewport, &self.resources.viewport,
&self.globals.global_params_buffer, &self.globals.global_params_buffer,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
4,
quads.len() as u32, quads.len() as u32,
) )
} }
@ -383,35 +388,29 @@ impl DirectXRenderer {
// Collect all vertices and sprites for a single draw call // Collect all vertices and sprites for a single draw call
let mut vertices = Vec::new(); let mut vertices = Vec::new();
let mut sprites = Vec::new();
for (path_index, path) in paths.iter().enumerate() { for path in paths {
vertices.extend(path.vertices.iter().map(|v| DirectXPathVertex { vertices.extend(path.vertices.iter().map(|v| PathRasterizationSprite {
xy_position: v.xy_position, xy_position: v.xy_position,
st_position: v.st_position, st_position: v.st_position,
path_index: path_index as u32,
}));
sprites.push(PathRasterizationSprite {
bounds: path.bounds.intersect(&path.content_mask.bounds),
color: path.color, color: path.color,
}); bounds: path.bounds.intersect(&path.content_mask.bounds),
}));
} }
if !vertices.is_empty() { self.pipelines.path_rasterization_pipeline.update_buffer(
self.pipelines.path_rasterization_pipeline.update_buffer( &self.devices.device,
&self.devices.device, &self.devices.device_context,
&self.devices.device_context, &vertices,
&sprites, )?;
&vertices, self.pipelines.path_rasterization_pipeline.draw(
)?; &self.devices.device_context,
self.pipelines.path_rasterization_pipeline.draw( &self.resources.viewport,
&self.devices.device_context, &self.globals.global_params_buffer,
vertices.len() as u32, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
&self.resources.viewport, vertices.len() as u32,
&self.globals.global_params_buffer, 1,
)?; )?;
}
// Resolve MSAA to non-MSAA intermediate texture // Resolve MSAA to non-MSAA intermediate texture
unsafe { unsafe {
@ -490,6 +489,8 @@ impl DirectXRenderer {
&self.devices.device_context, &self.devices.device_context,
&self.resources.viewport, &self.resources.viewport,
&self.globals.global_params_buffer, &self.globals.global_params_buffer,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP,
4,
underlines.len() as u32, underlines.len() as u32,
) )
} }
@ -655,7 +656,12 @@ impl DirectXRenderPipelines {
let shadow_pipeline = let shadow_pipeline =
PipelineState::new(device, "shadow_pipeline", ShaderModule::Shadow, 4)?; PipelineState::new(device, "shadow_pipeline", ShaderModule::Shadow, 4)?;
let quad_pipeline = PipelineState::new(device, "quad_pipeline", ShaderModule::Quad, 64)?; let quad_pipeline = PipelineState::new(device, "quad_pipeline", ShaderModule::Quad, 64)?;
let path_rasterization_pipeline = PathRasterizationPipelineState::new(device)?; let path_rasterization_pipeline = PipelineState::new(
device,
"path_rasterization_pipeline",
ShaderModule::PathRasterization,
32,
)?;
let path_sprite_pipeline = let path_sprite_pipeline =
PipelineState::new(device, "path_sprite_pipeline", ShaderModule::PathSprite, 1)?; PipelineState::new(device, "path_sprite_pipeline", ShaderModule::PathSprite, 1)?;
let underline_pipeline = let underline_pipeline =
@ -769,16 +775,16 @@ struct PipelineState<T> {
_marker: std::marker::PhantomData<T>, _marker: std::marker::PhantomData<T>,
} }
struct PathRasterizationPipelineState { // struct PathRasterizationPipelineState {
vertex: ID3D11VertexShader, // vertex: ID3D11VertexShader,
fragment: ID3D11PixelShader, // fragment: ID3D11PixelShader,
buffer: ID3D11Buffer, // buffer: ID3D11Buffer,
buffer_size: usize, // buffer_size: usize,
view: [Option<ID3D11ShaderResourceView>; 1], // view: [Option<ID3D11ShaderResourceView>; 1],
vertex_buffer: Option<ID3D11Buffer>, // vertex_buffer: Option<ID3D11Buffer>,
vertex_buffer_size: usize, // vertex_buffer_size: usize,
input_layout: ID3D11InputLayout, // input_layout: ID3D11InputLayout,
} // }
impl<T> PipelineState<T> { impl<T> PipelineState<T> {
fn new( fn new(
@ -837,19 +843,21 @@ impl<T> PipelineState<T> {
device_context: &ID3D11DeviceContext, device_context: &ID3D11DeviceContext,
viewport: &[D3D11_VIEWPORT], viewport: &[D3D11_VIEWPORT],
global_params: &[Option<ID3D11Buffer>], global_params: &[Option<ID3D11Buffer>],
topology: D3D_PRIMITIVE_TOPOLOGY,
vertex_count: u32,
instance_count: u32, instance_count: u32,
) -> Result<()> { ) -> Result<()> {
set_pipeline_state( set_pipeline_state(
device_context, device_context,
&self.view, &self.view,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, topology,
viewport, viewport,
&self.vertex, &self.vertex,
&self.fragment, &self.fragment,
global_params, global_params,
); );
unsafe { unsafe {
device_context.DrawInstanced(4, instance_count, 0, 0); device_context.DrawInstanced(vertex_count, instance_count, 0, 0);
} }
Ok(()) Ok(())
} }
@ -883,175 +891,130 @@ impl<T> PipelineState<T> {
} }
} }
impl PathRasterizationPipelineState { // impl PathRasterizationPipelineState {
fn new(device: &ID3D11Device) -> Result<Self> { // fn new(device: &ID3D11Device) -> Result<Self> {
let (vertex, vertex_shader) = { // let (vertex, vertex_shader) = {
let raw_vertex_shader = // let raw_vertex_shader =
RawShaderBytes::new(ShaderModule::PathRasterization, ShaderTarget::Vertex)?; // RawShaderBytes::new(ShaderModule::PathRasterization, ShaderTarget::Vertex)?;
( // (
create_vertex_shader(device, raw_vertex_shader.as_bytes())?, // create_vertex_shader(device, raw_vertex_shader.as_bytes())?,
raw_vertex_shader, // raw_vertex_shader,
) // )
}; // };
let fragment = { // let fragment = {
let raw_shader = // let raw_shader =
RawShaderBytes::new(ShaderModule::PathRasterization, ShaderTarget::Fragment)?; // RawShaderBytes::new(ShaderModule::PathRasterization, ShaderTarget::Fragment)?;
create_fragment_shader(device, raw_shader.as_bytes())? // create_fragment_shader(device, raw_shader.as_bytes())?
}; // };
let buffer = create_buffer(device, std::mem::size_of::<PathRasterizationSprite>(), 32)?; // let buffer = create_buffer(device, std::mem::size_of::<PathRasterizationSprite>(), 32)?;
let view = create_buffer_view(device, &buffer)?; // let view = create_buffer_view(device, &buffer)?;
let vertex_buffer = Some(create_buffer( // let vertex_buffer = Some(create_buffer(
device, // device,
std::mem::size_of::<DirectXPathVertex>(), // std::mem::size_of::<PathRasterizationSprite>(),
32, // 32,
)?); // )?);
let input_layout = unsafe { // Ok(Self {
let mut layout = None; // vertex,
device.CreateInputLayout( // fragment,
&[ // buffer,
D3D11_INPUT_ELEMENT_DESC { // buffer_size: 32,
SemanticName: windows::core::s!("POSITION"), // view,
SemanticIndex: 0, // vertex_buffer,
Format: DXGI_FORMAT_R32G32_FLOAT, // vertex_buffer_size: 32,
InputSlot: 0, // })
AlignedByteOffset: 0, // }
InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
InstanceDataStepRate: 0,
},
D3D11_INPUT_ELEMENT_DESC {
SemanticName: windows::core::s!("TEXCOORD"),
SemanticIndex: 0,
Format: DXGI_FORMAT_R32G32_FLOAT,
InputSlot: 0,
AlignedByteOffset: 8,
InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
InstanceDataStepRate: 0,
},
D3D11_INPUT_ELEMENT_DESC {
SemanticName: windows::core::s!("TEXCOORD"),
SemanticIndex: 1,
Format: DXGI_FORMAT_R32_UINT,
InputSlot: 0,
AlignedByteOffset: 16,
InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
InstanceDataStepRate: 0,
},
],
vertex_shader.as_bytes(),
Some(&mut layout),
)?;
layout.unwrap()
};
Ok(Self { // fn update_buffer(
vertex, // &mut self,
fragment, // device: &ID3D11Device,
buffer, // device_context: &ID3D11DeviceContext,
buffer_size: 32, // sprites: &[PathRasterizationSprite],
view, // vertices_data: &[DirectXPathVertex],
vertex_buffer, // ) -> Result<()> {
vertex_buffer_size: 32, // if self.buffer_size < sprites.len() {
input_layout, // let new_buffer_size = sprites.len().next_power_of_two();
}) // log::info!(
} // "Updating Paths Pipeline buffer size from {} to {}",
// self.buffer_size,
// new_buffer_size
// );
// let buffer = create_buffer(
// device,
// std::mem::size_of::<PathRasterizationSprite>(),
// new_buffer_size,
// )?;
// let view = create_buffer_view(device, &buffer)?;
// self.buffer = buffer;
// self.view = view;
// self.buffer_size = new_buffer_size;
// }
// update_buffer(device_context, &self.buffer, sprites)?;
fn update_buffer( // if self.vertex_buffer_size < vertices_data.len() {
&mut self, // let new_vertex_buffer_size = vertices_data.len().next_power_of_two();
device: &ID3D11Device, // log::info!(
device_context: &ID3D11DeviceContext, // "Updating Paths Pipeline vertex buffer size from {} to {}",
sprites: &[PathRasterizationSprite], // self.vertex_buffer_size,
vertices_data: &[DirectXPathVertex], // new_vertex_buffer_size
) -> Result<()> { // );
if self.buffer_size < sprites.len() { // let vertex_buffer = create_buffer(
let new_buffer_size = sprites.len().next_power_of_two(); // device,
log::info!( // std::mem::size_of::<DirectXPathVertex>(),
"Updating Paths Pipeline buffer size from {} to {}", // new_vertex_buffer_size,
self.buffer_size, // )?;
new_buffer_size // self.vertex_buffer = Some(vertex_buffer);
); // self.vertex_buffer_size = new_vertex_buffer_size;
let buffer = create_buffer( // }
device, // update_buffer(
std::mem::size_of::<PathRasterizationSprite>(), // device_context,
new_buffer_size, // self.vertex_buffer.as_ref().unwrap(),
)?; // vertices_data,
let view = create_buffer_view(device, &buffer)?; // )?;
self.buffer = buffer;
self.view = view;
self.buffer_size = new_buffer_size;
}
update_buffer(device_context, &self.buffer, sprites)?;
if self.vertex_buffer_size < vertices_data.len() { // Ok(())
let new_vertex_buffer_size = vertices_data.len().next_power_of_two(); // }
log::info!(
"Updating Paths Pipeline vertex buffer size from {} to {}",
self.vertex_buffer_size,
new_vertex_buffer_size
);
let vertex_buffer = create_buffer(
device,
std::mem::size_of::<DirectXPathVertex>(),
new_vertex_buffer_size,
)?;
self.vertex_buffer = Some(vertex_buffer);
self.vertex_buffer_size = new_vertex_buffer_size;
}
update_buffer(
device_context,
self.vertex_buffer.as_ref().unwrap(),
vertices_data,
)?;
Ok(()) // fn draw(
} // &self,
// device_context: &ID3D11DeviceContext,
fn draw( // vertex_count: u32,
&self, // viewport: &[D3D11_VIEWPORT],
device_context: &ID3D11DeviceContext, // global_params: &[Option<ID3D11Buffer>],
vertex_count: u32, // ) -> Result<()> {
viewport: &[D3D11_VIEWPORT], // set_pipeline_state(
global_params: &[Option<ID3D11Buffer>], // device_context,
) -> Result<()> { // &self.view,
set_pipeline_state( // D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST,
device_context, // viewport,
&self.view, // &self.vertex,
D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, // &self.fragment,
viewport, // global_params,
&self.vertex, // );
&self.fragment, // unsafe {
global_params, // const STRIDE: u32 = std::mem::size_of::<DirectXPathVertex>() as u32;
); // const OFFSET: u32 = 0;
unsafe { // device_context.IASetInputLayout(&self.input_layout);
const STRIDE: u32 = std::mem::size_of::<DirectXPathVertex>() as u32; // device_context.IASetVertexBuffers(
const OFFSET: u32 = 0; // 0,
device_context.IASetInputLayout(&self.input_layout); // 1,
device_context.IASetVertexBuffers( // Some(&self.vertex_buffer),
0, // Some(&STRIDE),
1, // Some(&OFFSET),
Some(&self.vertex_buffer), // );
Some(&STRIDE), // device_context.Draw(vertex_count, 0);
Some(&OFFSET), // }
); // Ok(())
device_context.Draw(vertex_count, 0); // }
} // }
Ok(())
}
}
#[derive(Clone, Copy)]
#[repr(C)]
struct DirectXPathVertex {
xy_position: Point<ScaledPixels>,
st_position: Point<f32>,
path_index: u32,
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
#[repr(C)] #[repr(C)]
struct PathRasterizationSprite { struct PathRasterizationSprite {
bounds: Bounds<ScaledPixels>, xy_position: Point<ScaledPixels>,
st_position: Point<f32>,
color: Background, color: Background,
bounds: Bounds<ScaledPixels>,
} }
#[derive(Clone, Copy)] #[derive(Clone, Copy)]

View file

@ -876,18 +876,10 @@ float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET {
** **
*/ */
struct PathVertex {
float2 xy_position: POSITION;
float2 st_position: TEXCOORD0;
uint path_index: TEXCOORD1;
};
struct PathRasterizationSprite { struct PathRasterizationSprite {
Bounds bounds; float2 xy_position;
float2 st_position;
Background color; Background color;
};
struct PathSprite {
Bounds bounds; Bounds bounds;
}; };
@ -896,68 +888,52 @@ StructuredBuffer<PathRasterizationSprite> path_rasterization_sprites: register(t
struct PathVertexOutput { struct PathVertexOutput {
float4 position: SV_Position; float4 position: SV_Position;
float2 st_position: TEXCOORD0; float2 st_position: TEXCOORD0;
nointerpolation uint tag: TEXCOORD1; nointerpolation uint vertex_id: TEXCOORD1;
nointerpolation uint color_space: TEXCOORD2; float4 clip_distance: SV_ClipDistance;
nointerpolation float gradient_angle: TEXCOORD3;
nointerpolation float4 solid_color: COLOR0;
nointerpolation float4 color0: COLOR1;
nointerpolation float4 color1: COLOR2;
nointerpolation float2 stop_percentages: COLOR3;
nointerpolation Bounds bounds: BOUNDS;
}; };
struct PathFragmentInput { struct PathFragmentInput {
float4 position: SV_Position; float4 position: SV_Position;
float2 st_position: TEXCOORD0; float2 st_position: TEXCOORD0;
nointerpolation uint tag: TEXCOORD1; nointerpolation uint vertex_id: TEXCOORD1;
nointerpolation uint color_space: TEXCOORD2;
nointerpolation float gradient_angle: TEXCOORD3;
nointerpolation float4 solid_color: COLOR0;
nointerpolation float4 color0: COLOR1;
nointerpolation float4 color1: COLOR2;
nointerpolation float2 stop_percentages: COLOR3;
nointerpolation Bounds bounds: BOUNDS;
}; };
PathVertexOutput path_rasterization_vertex(PathVertex input) { PathVertexOutput path_rasterization_vertex(uint vertex_id: SV_VertexID) {
PathRasterizationSprite sprite = path_rasterization_sprites[input.path_index]; PathRasterizationSprite sprite = path_rasterization_sprites[vertex_id];
PathVertexOutput output; PathVertexOutput output;
output.position = to_device_position_impl(input.xy_position); output.position = to_device_position_impl(sprite.xy_position);
output.st_position = input.st_position; output.st_position = sprite.st_position;
output.bounds = sprite.bounds; output.vertex_id = vertex_id;
output.tag = sprite.color.tag; output.clip_distance = distance_from_clip_rect_impl(sprite.xy_position, sprite.bounds);
output.color_space = sprite.color.color_space;
output.gradient_angle = sprite.color.gradient_angle_or_pattern_height;
output.stop_percentages = float2(sprite.color.colors[0].percentage, sprite.color.colors[1].percentage);
GradientColor gradient = prepare_gradient_color(
sprite.color.tag,
sprite.color.color_space,
sprite.color.solid,
sprite.color.colors
);
output.solid_color = gradient.solid;
output.color0 = gradient.color0;
output.color1 = gradient.color1;
return output; return output;
} }
float4 path_rasterization_fragment(PathFragmentInput input): SV_Target { float4 path_rasterization_fragment(PathFragmentInput input): SV_Target {
Background background; float2 dx = ddx(input.st_position);
background.tag = input.tag; float2 dy = ddy(input.st_position);
background.color_space = input.color_space; PathRasterizationSprite sprite = path_rasterization_sprites[input.vertex_id];
background.solid = (Hsla)0; // Not used when tag != 0
background.gradient_angle_or_pattern_height = input.gradient_angle; Background background = sprite.color;
background.colors[0].color = (Hsla)0; // Not used when colors are pre-computed Bounds bounds = sprite.bounds;
background.colors[0].percentage = input.stop_percentages.x;
background.colors[1].color = (Hsla)0; // Not used when colors are pre-computed
background.colors[1].percentage = input.stop_percentages.y;
float4 color = gradient_color(background, input.position.xy, input.bounds, float alpha;
input.solid_color, input.color0, input.color1); if (length(float2(dx.x, dy.x))) {
return color; alpha = 1.0;
} else {
float2 gradient = 2.0 * input.st_position.xx * float2(dx.x, dy.x) - float2(dx.y, dy.y);
float f = input.st_position.x * input.st_position.x - input.st_position.y;
float distance = f / length(gradient);
alpha = saturate(0.5 - distance);
}
GradientColor gradient = prepare_gradient_color(
background.tag, background.color_space, background.solid, background.colors);
float4 color = gradient_color(background, input.position.xy, bounds,
gradient.solid, gradient.color0, gradient.color1);
return float4(color.rgb * color.a * alpha, alpha * color.a);
} }
/* /*
@ -966,6 +942,10 @@ float4 path_rasterization_fragment(PathFragmentInput input): SV_Target {
** **
*/ */
struct PathSprite {
Bounds bounds;
};
struct PathSpriteVertexOutput { struct PathSpriteVertexOutput {
float4 position: SV_Position; float4 position: SV_Position;
float2 texture_coords: TEXCOORD0; float2 texture_coords: TEXCOORD0;