fix `PathRasterization` pipeline

Junkui Zhang created

Change summary

crates/gpui/src/platform/windows/directx_renderer.rs | 363 ++++++-------
crates/gpui/src/platform/windows/shaders.hlsl        |  96 +--
2 files changed, 201 insertions(+), 258 deletions(-)

Detailed changes

crates/gpui/src/platform/windows/directx_renderer.rs 🔗

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

crates/gpui/src/platform/windows/shaders.hlsl 🔗

@@ -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 {
-    Bounds bounds;
+    float2 xy_position;
+    float2 st_position;
     Background color;
-};
-
-struct PathSprite {
     Bounds bounds;
 };
 
@@ -896,68 +888,52 @@ StructuredBuffer<PathRasterizationSprite> path_rasterization_sprites: register(t
 struct PathVertexOutput {
     float4 position: SV_Position;
     float2 st_position: TEXCOORD0;
-    nointerpolation uint tag: 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;
+    nointerpolation uint vertex_id: TEXCOORD1;
+    float4 clip_distance: SV_ClipDistance;
 };
 
 struct PathFragmentInput {
     float4 position: SV_Position;
     float2 st_position: TEXCOORD0;
-    nointerpolation uint tag: 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;
+    nointerpolation uint vertex_id: TEXCOORD1;
 };
 
-PathVertexOutput path_rasterization_vertex(PathVertex input) {
-    PathRasterizationSprite sprite = path_rasterization_sprites[input.path_index];
+PathVertexOutput path_rasterization_vertex(uint vertex_id: SV_VertexID) {
+    PathRasterizationSprite sprite = path_rasterization_sprites[vertex_id];
 
     PathVertexOutput output;
-    output.position = to_device_position_impl(input.xy_position);
-    output.st_position = input.st_position;
-    output.bounds = sprite.bounds;
-    output.tag = sprite.color.tag;
-    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;
+    output.position = to_device_position_impl(sprite.xy_position);
+    output.st_position = sprite.st_position;
+    output.vertex_id = vertex_id;
+    output.clip_distance = distance_from_clip_rect_impl(sprite.xy_position, sprite.bounds);
 
     return output;
 }
 
 float4 path_rasterization_fragment(PathFragmentInput input): SV_Target {
-    Background background;
-    background.tag = input.tag;
-    background.color_space = input.color_space;
-    background.solid = (Hsla)0; // Not used when tag != 0
-    background.gradient_angle_or_pattern_height = input.gradient_angle;
-    background.colors[0].color = (Hsla)0; // Not used when colors are pre-computed
-    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,
-        input.solid_color, input.color0, input.color1);
-    return color;
+    float2 dx = ddx(input.st_position);
+    float2 dy = ddy(input.st_position);
+    PathRasterizationSprite sprite = path_rasterization_sprites[input.vertex_id];
+    
+    Background background = sprite.color;
+    Bounds bounds = sprite.bounds;
+
+    float alpha;
+    if (length(float2(dx.x, dy.x))) {
+        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 {
     float4 position: SV_Position;
     float2 texture_coords: TEXCOORD0;