From dcdd7404e46d97f1a4e7ed7b74c7caa018227772 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 14 Jul 2025 16:47:45 +0800 Subject: [PATCH 01/45] wip --- .../src/platform/windows/directx_renderer.rs | 195 ++++++++++++++++-- 1 file changed, 175 insertions(+), 20 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 36c68c8eb4668327c818fe313f4c0a8cc4a448c7..ed2ec0a8c93ed059ecdbad36ce3cc7b7b840ac14 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -48,8 +48,7 @@ struct DirectXContext { struct DirectXRenderPipelines { shadow_pipeline: PipelineState, quad_pipeline: PipelineState, - paths_pipeline: PipelineState, - paths_indirect_draw_buffer: ID3D11Buffer, + paths_pipeline: PathsPipelineState, underline_pipeline: PipelineState, mono_sprites: PipelineState, poly_sprites: PipelineState, @@ -309,21 +308,37 @@ impl DirectXRenderer { }); } - update_buffer_capacity( + update_paths_buffer_capacity( &self.pipelines.paths_pipeline, - std::mem::size_of::(), sprites.len(), &self.devices.device, ) - .map(|input| update_pipeline(&mut self.pipelines.paths_pipeline, input)); + .map(|input| update_paths_pipeline_buffer(&mut self.pipelines.paths_pipeline, input)); update_buffer( &self.devices.device_context, &self.pipelines.paths_pipeline.buffer, &sprites, )?; - update_indirect_buffer( + update_paths_vertex_capacity( + &mut self.pipelines.paths_pipeline, + vertices.len(), + &self.devices.device, + ) + .map(|input| update_paths_pipeline_vertex(&mut self.pipelines.paths_pipeline, input)); + update_buffer( + &self.devices.device_context, + &self.pipelines.paths_pipeline.vertex_buffer, + &vertices, + )?; + update_indirect_buffer_capacity( + &self.pipelines.paths_pipeline, + draw_indirect_commands.len(), + &self.devices.device, + ) + .map(|input| update_paths_indirect_buffer(&mut self.pipelines.paths_pipeline, input)); + update_buffer( &self.devices.device_context, - &self.pipelines.paths_indirect_draw_buffer, + &self.pipelines.paths_pipeline.indirect_draw_buffer, &draw_indirect_commands, )?; prepare_indirect_draws( @@ -337,7 +352,7 @@ impl DirectXRenderer { for i in 0..paths.len() { draw_indirect( &self.devices.device_context, - &self.pipelines.paths_indirect_draw_buffer, + &self.pipelines.paths_pipeline.indirect_draw_buffer, (i * std::mem::size_of::()) as u32, ); } @@ -488,13 +503,14 @@ impl DirectXRenderPipelines { std::mem::size_of::(), 32, )?; - let paths_pipeline = create_pipieline( - device, - "paths_vertex", - "paths_fragment", - std::mem::size_of::(), - 32, - )?; + // let paths_pipeline = create_pipieline( + // device, + // "paths_vertex", + // "paths_fragment", + // std::mem::size_of::(), + // 32, + // )?; + let paths_pipeline = PathsPipelineState::new(device)?; let underline_pipeline = create_pipieline( device, "underline_vertex", @@ -516,13 +532,11 @@ impl DirectXRenderPipelines { std::mem::size_of::(), 32, )?; - let paths_indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?; Ok(Self { shadow_pipeline, quad_pipeline, paths_pipeline, - paths_indirect_draw_buffer, underline_pipeline, mono_sprites, poly_sprites, @@ -614,6 +628,62 @@ struct PipelineState { view: [Option; 1], } +struct PathsPipelineState { + vertex: ID3D11VertexShader, + fragment: ID3D11PixelShader, + buffer: ID3D11Buffer, + buffer_size: usize, + vertex_buffer: ID3D11Buffer, + vertex_buffer_size: usize, + indirect_draw_buffer: ID3D11Buffer, + indirect_buffer_size: usize, + view: [Option; 1], + vertex_view: [Option; 1], +} + +impl PathsPipelineState { + fn new(device: &ID3D11Device) -> Result { + let vertex = { + let shader_blob = shader_resources::build_shader_blob("paths_vertex", "vs_5_0")?; + let bytes = unsafe { + std::slice::from_raw_parts( + shader_blob.GetBufferPointer() as *mut u8, + shader_blob.GetBufferSize(), + ) + }; + create_vertex_shader(device, bytes)? + }; + let fragment = { + let shader_blob = shader_resources::build_shader_blob("paths_fragment", "ps_5_0")?; + let bytes = unsafe { + std::slice::from_raw_parts( + shader_blob.GetBufferPointer() as *mut u8, + shader_blob.GetBufferSize(), + ) + }; + create_fragment_shader(device, bytes)? + }; + let buffer = create_buffer(device, std::mem::size_of::(), 32)?; + let view = create_buffer_view(device, &buffer)?; + let vertex_buffer = + create_buffer(device, std::mem::size_of::>(), 32)?; + let vertex_view = create_buffer_view(device, &vertex_buffer)?; + let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?; + Ok(Self { + vertex, + fragment, + buffer, + buffer_size: 32, + vertex_buffer, + vertex_buffer_size: 32, + indirect_draw_buffer, + indirect_buffer_size: 32, + view, + vertex_view, + }) + } +} + #[derive(Clone, Debug, Eq, PartialEq)] #[repr(C)] struct PathSprite { @@ -996,6 +1066,67 @@ fn update_buffer_capacity( Some((buffer, buffer_size, view)) } +fn update_paths_buffer_capacity( + pipeline: &PathsPipelineState, + data_size: usize, + device: &ID3D11Device, +) -> Option<(ID3D11Buffer, usize, [Option; 1])> { + if pipeline.buffer_size >= data_size { + return None; + } + println!( + "Paths buffer too small: {} < {}", + pipeline.buffer_size, data_size + ); + let buffer_size = data_size.next_power_of_two(); + println!("Paths New size: {}", buffer_size); + let buffer = create_buffer(device, std::mem::align_of::(), buffer_size).unwrap(); + let view = create_buffer_view(device, &buffer).unwrap(); + Some((buffer, buffer_size, view)) +} + +fn update_paths_vertex_capacity( + pipeline: &PathsPipelineState, + vertex_size: usize, + device: &ID3D11Device, +) -> Option<(ID3D11Buffer, usize, [Option; 1])> { + if pipeline.vertex_buffer_size >= vertex_size { + return None; + } + println!( + "Paths vertex buffer too small: {} < {}", + pipeline.vertex_buffer_size, vertex_size + ); + let vertex_size = vertex_size.next_power_of_two(); + println!("Paths vertex New size: {}", vertex_size); + let buffer = create_buffer( + device, + std::mem::size_of::>(), + vertex_size, + ) + .unwrap(); + let view = create_buffer_view(device, &buffer).unwrap(); + Some((buffer, vertex_size, view)) +} + +fn update_indirect_buffer_capacity( + pipeline: &PathsPipelineState, + data_size: usize, + device: &ID3D11Device, +) -> Option<(ID3D11Buffer, usize)> { + if pipeline.indirect_buffer_size >= data_size { + return None; + } + println!( + "Indirect buffer too small: {} < {}", + pipeline.indirect_buffer_size, data_size + ); + let buffer_size = data_size.next_power_of_two(); + println!("Indirect New size: {}", buffer_size); + let buffer = create_indirect_draw_buffer(device, data_size as u32).unwrap(); + Some((buffer, buffer_size)) +} + fn update_pipeline( pipeline: &mut PipelineState, input: (ID3D11Buffer, usize, [Option; 1]), @@ -1005,6 +1136,29 @@ fn update_pipeline( pipeline.view = input.2; } +fn update_paths_pipeline_buffer( + pipeline: &mut PathsPipelineState, + input: (ID3D11Buffer, usize, [Option; 1]), +) { + pipeline.buffer = input.0; + pipeline.buffer_size = input.1; + pipeline.view = input.2; +} + +fn update_paths_pipeline_vertex( + pipeline: &mut PathsPipelineState, + input: (ID3D11Buffer, usize, [Option; 1]), +) { + pipeline.vertex_buffer = input.0; + pipeline.vertex_buffer_size = input.1; + pipeline.vertex_view = input.2; +} + +fn update_paths_indirect_buffer(pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize)) { + pipeline.indirect_draw_buffer = input.0; + pipeline.indirect_buffer_size = input.1; +} + fn update_buffer( device_context: &ID3D11DeviceContext, buffer: &ID3D11Buffer, @@ -1035,14 +1189,15 @@ fn update_indirect_buffer( fn prepare_indirect_draws( device_context: &ID3D11DeviceContext, - pipeline: &PipelineState, + pipeline: &PathsPipelineState, viewport: &[D3D11_VIEWPORT], global_params: &[Option], topology: D3D_PRIMITIVE_TOPOLOGY, ) -> Result<()> { unsafe { - device_context.VSSetShaderResources(1, Some(&pipeline.view)); - device_context.PSSetShaderResources(1, Some(&pipeline.view)); + device_context.VSSetShaderResources(1, Some(&pipeline.vertex_view)); + device_context.VSSetShaderResources(2, Some(&pipeline.view)); + device_context.PSSetShaderResources(2, Some(&pipeline.view)); device_context.IASetPrimitiveTopology(topology); device_context.RSSetViewports(Some(viewport)); device_context.VSSetShader(&pipeline.vertex, None); From 622a42e3aaee406560922f2239d56b1d1074485a Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 14 Jul 2025 17:49:44 +0800 Subject: [PATCH 02/45] wip --- crates/gpui/src/platform/windows/shaders.hlsl | 439 +++++++++++++++--- 1 file changed, 366 insertions(+), 73 deletions(-) diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index cf2fd4ca01709dcfa27a9dbb97dd9ee140ef5cc1..f7e371b1b7f969efbac13df780ea29182896e2fc 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -240,6 +240,23 @@ float2 to_tile_position(float2 unit_vertex, AtlasTile tile) { return (float2(tile.bounds.origin) + unit_vertex * float2(tile.bounds.size)) / atlas_size; } +// Selects corner radius based on quadrant. +float pick_corner_radius(float2 center_to_point, Corners corner_radii) { + if (center_to_point.x < 0.) { + if (center_to_point.y < 0.) { + return corner_radii.top_left; + } else { + return corner_radii.bottom_left; + } + } else { + if (center_to_point.y < 0.) { + return corner_radii.top_right; + } else { + return corner_radii.bottom_right; + } + } +} + float4 to_device_position_transformed(float2 unit_vertex, Bounds bounds, TransformationMatrix transformation) { float2 position = unit_vertex * bounds.size + bounds.origin; @@ -248,32 +265,32 @@ float4 to_device_position_transformed(float2 unit_vertex, Bounds bounds, return float4(device_position, 0.0, 1.0); } +// Implementation of quad signed distance field +float quad_sdf_impl(float2 corner_center_to_point, float corner_radius) { + if (corner_radius == 0.0) { + // Fast path for unrounded corners + return max(corner_center_to_point.x, corner_center_to_point.y); + } else { + // Signed distance of the point from a quad that is inset by corner_radius + // It is negative inside this quad, and positive outside + float signed_distance_to_inset_quad = + // 0 inside the inset quad, and positive outside + length(max(float2(0.0, 0.0), corner_center_to_point)) + + // 0 outside the inset quad, and negative inside + min(0.0, max(corner_center_to_point.x, corner_center_to_point.y)); + + return signed_distance_to_inset_quad - corner_radius; + } +} + float quad_sdf(float2 pt, Bounds bounds, Corners corner_radii) { float2 half_size = bounds.size / 2.; float2 center = bounds.origin + half_size; float2 center_to_point = pt - center; - float corner_radius; - if (center_to_point.x < 0.) { - if (center_to_point.y < 0.) { - corner_radius = corner_radii.top_left; - } else { - corner_radius = corner_radii.bottom_left; - } - } else { - if (center_to_point.y < 0.) { - corner_radius = corner_radii.top_right; - } else { - corner_radius = corner_radii.bottom_right; - } - } - - float2 rounded_edge_to_point = abs(center_to_point) - half_size + corner_radius; - float distance = - length(max(0., rounded_edge_to_point)) + - min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - - corner_radius; - - return distance; + float corner_radius = pick_corner_radius(center_to_point, corner_radii); + float2 corner_to_point = abs(center_to_point) - half_size; + float2 corner_center_to_point = corner_to_point + corner_radius; + return quad_sdf_impl(corner_center_to_point, corner_radius); } GradientColor prepare_gradient_color(uint tag, uint color_space, Hsla solid, Hsla color0, Hsla color1) { @@ -376,6 +393,57 @@ float4 gradient_color(Background background, return color; } +// Returns the dash velocity of a corner given the dash velocity of the two +// sides, by returning the slower velocity (larger dashes). +// +// Since 0 is used for dash velocity when the border width is 0 (instead of +// +inf), this returns the other dash velocity in that case. +// +// An alternative to this might be to appropriately interpolate the dash +// velocity around the corner, but that seems overcomplicated. +float corner_dash_velocity(float dv1, float dv2) { + if (dv1 == 0.0) { + return dv2; + } else if (dv2 == 0.0) { + return dv1; + } else { + return min(dv1, dv2); + } +} + +// Returns alpha used to render antialiased dashes. +// `t` is within the dash when `fmod(t, period) < length`. +float dash_alpha( + float t, float period, float length, float dash_velocity, + float antialias_threshold +) { + float half_period = period / 2.0; + float half_length = length / 2.0; + // Value in [-half_period, half_period] + // The dash is in [-half_length, half_length] + float centered = fmod(t + half_period - half_length, period) - half_period; + // Signed distance for the dash, negative values are inside the dash + float signed_distance = abs(centered) - half_length; + // Antialiased alpha based on the signed distance + return saturate(antialias_threshold - signed_distance / dash_velocity); +} + +// This approximates distance to the nearest point to a quarter ellipse in a way +// that is sufficient for anti-aliasing when the ellipse is not very eccentric. +// The components of `point` are expected to be positive. +// +// Negative on the outside and positive on the inside. +float quarter_ellipse_sdf(float2 pt, float2 radii) { + // Scale the space to treat the ellipse like a unit circle + float2 circle_vec = pt / radii; + float unit_circle_sdf = length(circle_vec) - 1.0; + // Approximate up-scaling of the length by using the average of the radii. + // + // TODO: A better solution would be to use the gradient of the implicit + // function for an ellipse to approximate a scaling factor. + return unit_circle_sdf * (radii.x + radii.y) * -0.5; +} + /* ** ** Shadows @@ -477,7 +545,7 @@ float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET { struct Quad { uint order; - uint pad; + uint border_style; Bounds bounds; Bounds content_mask; Background background; @@ -535,66 +603,286 @@ QuadVertexOutput quad_vertex(uint vertex_id: SV_VertexID, uint quad_id: SV_Insta float4 quad_fragment(QuadFragmentInput input): SV_Target { Quad quad = quads[input.quad_id]; - float2 half_size = quad.bounds.size / 2.; - float2 center = quad.bounds.origin + half_size; - float2 center_to_point = input.position.xy - center; - float4 color = gradient_color(quad.background, input.position.xy, quad.bounds, + float4 background_color = gradient_color(quad.background, input.position.xy, quad.bounds, input.background_solid, input.background_color0, input.background_color1); - // Fast path when the quad is not rounded and doesn't have any border. - if (quad.corner_radii.top_left == 0. && quad.corner_radii.bottom_left == 0. && - quad.corner_radii.top_right == 0. && - quad.corner_radii.bottom_right == 0. && quad.border_widths.top == 0. && - quad.border_widths.left == 0. && quad.border_widths.right == 0. && - quad.border_widths.bottom == 0.) { - return color; + bool unrounded = quad.corner_radii.top_left == 0.0 && + quad.corner_radii.bottom_left == 0.0 && + quad.corner_radii.top_right == 0.0 && + quad.corner_radii.bottom_right == 0.0; + + // Fast path when the quad is not rounded and doesn't have any border + if (quad.border_widths.top == 0.0 && + quad.border_widths.left == 0.0 && + quad.border_widths.right == 0.0 && + quad.border_widths.bottom == 0.0 && + unrounded) { + return background_color; } - float corner_radius; - if (center_to_point.x < 0.) { - if (center_to_point.y < 0.) { - corner_radius = quad.corner_radii.top_left; - } else { - corner_radius = quad.corner_radii.bottom_left; - } - } else { - if (center_to_point.y < 0.) { - corner_radius = quad.corner_radii.top_right; - } else { - corner_radius = quad.corner_radii.bottom_right; - } + float2 size = quad.bounds.size; + float2 half_size = size / 2.; + float2 the_point = input.position.xy - quad.bounds.origin; + float2 center_to_point = the_point - half_size; + + // Signed distance field threshold for inclusion of pixels. 0.5 is the + // minimum distance between the center of the pixel and the edge. + const float antialias_threshold = 0.5; + + // Radius of the nearest corner + float corner_radius = pick_corner_radius(center_to_point, quad.corner_radii); + + float2 border = float2( + center_to_point.x < 0.0 ? quad.border_widths.left : quad.border_widths.right, + center_to_point.y < 0.0 ? quad.border_widths.top : quad.border_widths.bottom + ); + + // 0-width borders are reduced so that `inner_sdf >= antialias_threshold`. + // The purpose of this is to not draw antialiasing pixels in this case. + float2 reduced_border = float2( + border.x == 0.0 ? -antialias_threshold : border.x, + border.y == 0.0 ? -antialias_threshold : border.y + ); + + // Vector from the corner of the quad bounds to the point, after mirroring + // the point into the bottom right quadrant. Both components are <= 0. + float2 corner_to_point = abs(center_to_point) - half_size; + + // Vector from the point to the center of the rounded corner's circle, also + // mirrored into bottom right quadrant. + float2 corner_center_to_point = corner_to_point + corner_radius; + + // Whether the nearest point on the border is rounded + bool is_near_rounded_corner = + corner_center_to_point.x >= 0.0 && + corner_center_to_point.y >= 0.0; + + // Vector from straight border inner corner to point. + // + // 0-width borders are turned into width -1 so that inner_sdf is > 1.0 near + // the border. Without this, antialiasing pixels would be drawn. + float2 straight_border_inner_corner_to_point = corner_to_point + reduced_border; + + // Whether the point is beyond the inner edge of the straight border + bool is_beyond_inner_straight_border = + straight_border_inner_corner_to_point.x > 0.0 || + straight_border_inner_corner_to_point.y > 0.0; + + // Whether the point is far enough inside the quad, such that the pixels are + // not affected by the straight border. + bool is_within_inner_straight_border = + straight_border_inner_corner_to_point.x < -antialias_threshold && + straight_border_inner_corner_to_point.y < -antialias_threshold; + + // Fast path for points that must be part of the background + if (is_within_inner_straight_border && !is_near_rounded_corner) { + return background_color; } - float2 rounded_edge_to_point = abs(center_to_point) - half_size + corner_radius; - float distance = - length(max(0., rounded_edge_to_point)) + - min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) - - corner_radius; - - float vertical_border = center_to_point.x <= 0. ? quad.border_widths.left - : quad.border_widths.right; - float horizontal_border = center_to_point.y <= 0. ? quad.border_widths.top - : quad.border_widths.bottom; - float2 inset_size = half_size - corner_radius - float2(vertical_border, horizontal_border); - float2 point_to_inset_corner = abs(center_to_point) - inset_size; - float border_width; - if (point_to_inset_corner.x < 0. && point_to_inset_corner.y < 0.) { - border_width = 0.; - } else if (point_to_inset_corner.y > point_to_inset_corner.x) { - border_width = horizontal_border; + // Signed distance of the point to the outside edge of the quad's border + float outer_sdf = quad_sdf_impl(corner_center_to_point, corner_radius); + + // Approximate signed distance of the point to the inside edge of the quad's + // border. It is negative outside this edge (within the border), and + // positive inside. + // + // This is not always an accurate signed distance: + // * The rounded portions with varying border width use an approximation of + // nearest-point-on-ellipse. + // * When it is quickly known to be outside the edge, -1.0 is used. + float inner_sdf = 0.0; + if (corner_center_to_point.x <= 0.0 || corner_center_to_point.y <= 0.0) { + // Fast paths for straight borders + inner_sdf = -max(straight_border_inner_corner_to_point.x, + straight_border_inner_corner_to_point.y); + } else if (is_beyond_inner_straight_border) { + // Fast path for points that must be outside the inner edge + inner_sdf = -1.0; + } else if (reduced_border.x == reduced_border.y) { + // Fast path for circular inner edge. + inner_sdf = -(outer_sdf + reduced_border.x); } else { - border_width = vertical_border; + float2 ellipse_radii = max(float2(0.0, 0.0), float2(corner_radius, corner_radius) - reduced_border); + inner_sdf = quarter_ellipse_sdf(corner_center_to_point, ellipse_radii); } - if (border_width != 0.) { - float inset_distance = distance + border_width; + // Negative when inside the border + float border_sdf = max(inner_sdf, outer_sdf); + + float4 color = background_color; + if (border_sdf < antialias_threshold) { + float4 border_color = input.border_color; + // Dashed border logic when border_style == 1 + if (quad.border_style == 1) { + // Position along the perimeter in "dash space", where each dash + // period has length 1 + float t = 0.0; + + // Total number of dash periods, so that the dash spacing can be + // adjusted to evenly divide it + float max_t = 0.0; + + // Border width is proportional to dash size. This is the behavior + // used by browsers, but also avoids dashes from different segments + // overlapping when dash size is smaller than the border width. + // + // Dash pattern: (2 * border width) dash, (1 * border width) gap + const float dash_length_per_width = 2.0; + const float dash_gap_per_width = 1.0; + const float dash_period_per_width = dash_length_per_width + dash_gap_per_width; + + // Since the dash size is determined by border width, the density of + // dashes varies. Multiplying a pixel distance by this returns a + // position in dash space - it has units (dash period / pixels). So + // a dash velocity of (1 / 10) is 1 dash every 10 pixels. + float dash_velocity = 0.0; + + // Dividing this by the border width gives the dash velocity + const float dv_numerator = 1.0 / dash_period_per_width; + + if (unrounded) { + // When corners aren't rounded, the dashes are separately laid + // out on each straight line, rather than around the whole + // perimeter. This way each line starts and ends with a dash. + bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y; + float border_width = is_horizontal ? border.x : border.y; + dash_velocity = dv_numerator / border_width; + t = is_horizontal ? the_point.x : the_point.y; + t *= dash_velocity; + max_t = is_horizontal ? size.x : size.y; + max_t *= dash_velocity; + } else { + // When corners are rounded, the dashes are laid out clockwise + // around the whole perimeter. + + float r_tr = quad.corner_radii.top_right; + float r_br = quad.corner_radii.bottom_right; + float r_bl = quad.corner_radii.bottom_left; + float r_tl = quad.corner_radii.top_left; + + float w_t = quad.border_widths.top; + float w_r = quad.border_widths.right; + float w_b = quad.border_widths.bottom; + float w_l = quad.border_widths.left; + + // Straight side dash velocities + float dv_t = w_t <= 0.0 ? 0.0 : dv_numerator / w_t; + float dv_r = w_r <= 0.0 ? 0.0 : dv_numerator / w_r; + float dv_b = w_b <= 0.0 ? 0.0 : dv_numerator / w_b; + float dv_l = w_l <= 0.0 ? 0.0 : dv_numerator / w_l; + + // Straight side lengths in dash space + float s_t = (size.x - r_tl - r_tr) * dv_t; + float s_r = (size.y - r_tr - r_br) * dv_r; + float s_b = (size.x - r_br - r_bl) * dv_b; + float s_l = (size.y - r_bl - r_tl) * dv_l; + + float corner_dash_velocity_tr = corner_dash_velocity(dv_t, dv_r); + float corner_dash_velocity_br = corner_dash_velocity(dv_b, dv_r); + float corner_dash_velocity_bl = corner_dash_velocity(dv_b, dv_l); + float corner_dash_velocity_tl = corner_dash_velocity(dv_t, dv_l); + + // Corner lengths in dash space + float c_tr = r_tr * (M_PI_F / 2.0) * corner_dash_velocity_tr; + float c_br = r_br * (M_PI_F / 2.0) * corner_dash_velocity_br; + float c_bl = r_bl * (M_PI_F / 2.0) * corner_dash_velocity_bl; + float c_tl = r_tl * (M_PI_F / 2.0) * corner_dash_velocity_tl; + + // Cumulative dash space upto each segment + float upto_tr = s_t; + float upto_r = upto_tr + c_tr; + float upto_br = upto_r + s_r; + float upto_b = upto_br + c_br; + float upto_bl = upto_b + s_b; + float upto_l = upto_bl + c_bl; + float upto_tl = upto_l + s_l; + max_t = upto_tl + c_tl; + + if (is_near_rounded_corner) { + float radians = atan2(corner_center_to_point.y, corner_center_to_point.x); + float corner_t = radians * corner_radius; + + if (center_to_point.x >= 0.0) { + if (center_to_point.y < 0.0) { + dash_velocity = corner_dash_velocity_tr; + // Subtracted because radians is pi/2 to 0 when + // going clockwise around the top right corner, + // since the y axis has been flipped + t = upto_r - corner_t * dash_velocity; + } else { + dash_velocity = corner_dash_velocity_br; + // Added because radians is 0 to pi/2 when going + // clockwise around the bottom-right corner + t = upto_br + corner_t * dash_velocity; + } + } else { + if (center_to_point.y >= 0.0) { + dash_velocity = corner_dash_velocity_bl; + // Subtracted because radians is pi/1 to 0 when + // going clockwise around the bottom-left corner, + // since the x axis has been flipped + t = upto_l - corner_t * dash_velocity; + } else { + dash_velocity = corner_dash_velocity_tl; + // Added because radians is 0 to pi/2 when going + // clockwise around the top-left corner, since both + // axis were flipped + t = upto_tl + corner_t * dash_velocity; + } + } + } else { + // Straight borders + bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y; + if (is_horizontal) { + if (center_to_point.y < 0.0) { + dash_velocity = dv_t; + t = (the_point.x - r_tl) * dash_velocity; + } else { + dash_velocity = dv_b; + t = upto_bl - (the_point.x - r_bl) * dash_velocity; + } + } else { + if (center_to_point.x < 0.0) { + dash_velocity = dv_l; + t = upto_tl - (the_point.y - r_tl) * dash_velocity; + } else { + dash_velocity = dv_r; + t = upto_r + (the_point.y - r_tr) * dash_velocity; + } + } + } + } + float dash_length = dash_length_per_width / dash_period_per_width; + float desired_dash_gap = dash_gap_per_width / dash_period_per_width; + + // Straight borders should start and end with a dash, so max_t is + // reduced to cause this. + max_t -= unrounded ? dash_length : 0.0; + if (max_t >= 1.0) { + // Adjust dash gap to evenly divide max_t + float dash_count = floor(max_t); + float dash_period = max_t / dash_count; + border_color.a *= dash_alpha(t, dash_period, dash_length, dash_velocity, antialias_threshold); + } else if (unrounded) { + // When there isn't enough space for the full gap between the + // two start / end dashes of a straight border, reduce gap to + // make them fit. + float dash_gap = max_t - dash_length; + if (dash_gap > 0.0) { + float dash_period = dash_length + dash_gap; + border_color.a *= dash_alpha(t, dash_period, dash_length, dash_velocity, antialias_threshold); + } + } + } + // Blend the border on top of the background and then linearly interpolate // between the two as we slide inside the background. - float4 blended_border = over(color, input.border_color); - color = lerp(blended_border, color, saturate(0.5 - inset_distance)); + float4 blended_border = over(background_color, border_color); + color = lerp(background_color, blended_border, + saturate(antialias_threshold - inner_sdf)); } - return color * float4(1., 1., 1., saturate(0.5 - distance)); + return color * float4(1.0, 1.0, 1.0, saturate(antialias_threshold - outer_sdf)); } struct PathVertex { @@ -795,7 +1083,9 @@ float4 monochrome_sprite_fragment(MonochromeSpriteFragmentInput input): SV_Targe struct PolychromeSprite { uint order; + uint pad; uint grayscale; + float opacity; Bounds bounds; Bounds content_mask; Corners corner_radii; @@ -805,14 +1095,14 @@ struct PolychromeSprite { struct PolychromeSpriteVertexOutput { float4 position: SV_Position; float2 tile_position: POSITION; - uint sprite_id: FLAT; + nointerpolation uint sprite_id: TEXCOORD0; float4 clip_distance: SV_ClipDistance; }; struct PolychromeSpriteFragmentInput { float4 position: SV_Position; float2 tile_position: POSITION; - uint sprite_id: FLAT; + nointerpolation uint sprite_id: TEXCOORD0; }; StructuredBuffer poly_sprites: register(t1); @@ -839,10 +1129,13 @@ float4 polychrome_sprite_fragment(PolychromeSpriteFragmentInput input): SV_Targe float distance = quad_sdf(input.position.xy, sprite.bounds, sprite.corner_radii); float4 color = sample; + if (sprite.grayscale) { + + } if ((sprite.grayscale & 0xFFu) != 0u) { float3 grayscale = dot(color.rgb, GRAYSCALE_FACTORS); color = float4(grayscale, sample.a); } - color.a *= saturate(0.5 - distance); + color.a *= sprite.opacity * saturate(0.5 - distance); return color; } From c82edc38a9dccc924e655e1e5358504ee91d48ca Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 14 Jul 2025 17:55:50 +0800 Subject: [PATCH 03/45] wip --- crates/gpui/src/platform/windows/shaders.hlsl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index f7e371b1b7f969efbac13df780ea29182896e2fc..fcd13ddb31d48aeaf90b0b624ec462791dad6a4c 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -1130,12 +1130,13 @@ float4 polychrome_sprite_fragment(PolychromeSpriteFragmentInput input): SV_Targe float4 color = sample; if (sprite.grayscale) { - - } - if ((sprite.grayscale & 0xFFu) != 0u) { float3 grayscale = dot(color.rgb, GRAYSCALE_FACTORS); color = float4(grayscale, sample.a); } + // if ((sprite.grayscale & 0xFFu) != 0u) { + // float3 grayscale = dot(color.rgb, GRAYSCALE_FACTORS); + // color = float4(grayscale, sample.a); + // } color.a *= sprite.opacity * saturate(0.5 - distance); return color; } From 6a918b64bf54c72ae3fd1e852a5a6298dc28de63 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 14 Jul 2025 18:35:52 +0800 Subject: [PATCH 04/45] wip --- crates/gpui/src/platform/windows/shaders.hlsl | 226 ++++++++---------- 1 file changed, 104 insertions(+), 122 deletions(-) diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index fcd13ddb31d48aeaf90b0b624ec462791dad6a4c..f93ef426dd4cd2ad026d512392485d856d097302 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -93,10 +93,9 @@ float4 to_device_position(float2 unit_vertex, Bounds bounds) { } float4 distance_from_clip_rect_impl(float2 position, Bounds clip_bounds) { - return float4(position.x - clip_bounds.origin.x, - clip_bounds.origin.x + clip_bounds.size.x - position.x, - position.y - clip_bounds.origin.y, - clip_bounds.origin.y + clip_bounds.size.y - position.y); + float2 tl = position - clip_bounds.origin; + float2 br = clip_bounds.origin + clip_bounds.size - position; + return float4(tl.x, br.x, tl.y, br.y); } float4 distance_from_clip_rect(float2 unit_vertex, Bounds bounds, Bounds clip_bounds) { @@ -293,20 +292,20 @@ float quad_sdf(float2 pt, Bounds bounds, Corners corner_radii) { return quad_sdf_impl(corner_center_to_point, corner_radius); } -GradientColor prepare_gradient_color(uint tag, uint color_space, Hsla solid, Hsla color0, Hsla color1) { +GradientColor prepare_gradient_color(uint tag, uint color_space, Hsla solid, LinearColorStop colors[2]) { GradientColor output; - if (tag == 0) { + if (tag == 0 || tag == 2) { output.solid = hsla_to_rgba(solid); } else if (tag == 1) { - output.color0 = hsla_to_rgba(color0); - output.color1 = hsla_to_rgba(color1); + output.color0 = hsla_to_rgba(colors[0].color); + output.color1 = hsla_to_rgba(colors[1].color); // Prepare color space in vertex for avoid conversion // in fragment shader for performance reasons if (color_space == 1) { - // Oklab - output.color0 = srgb_to_oklab(output.color0); - output.color1 = srgb_to_oklab(output.color1); + // Oklab + output.color0 = srgb_to_oklab(output.color0); + output.color1 = srgb_to_oklab(output.color1); } } @@ -444,99 +443,6 @@ float quarter_ellipse_sdf(float2 pt, float2 radii) { return unit_circle_sdf * (radii.x + radii.y) * -0.5; } -/* -** -** Shadows -** -*/ - -struct ShadowVertexOutput { - float4 position: SV_Position; - float4 color: COLOR; - uint shadow_id: FLAT; - float4 clip_distance: SV_ClipDistance; -}; - -struct ShadowFragmentInput { - float4 position: SV_Position; - float4 color: COLOR; - uint shadow_id: FLAT; -}; - -struct Shadow { - uint order; - float blur_radius; - Bounds bounds; - Corners corner_radii; - Bounds content_mask; - Hsla color; -}; - -StructuredBuffer shadows: register(t1); - -ShadowVertexOutput shadow_vertex(uint vertex_id: SV_VertexID, uint shadow_id: SV_InstanceID) { - float2 unit_vertex = float2(float(vertex_id & 1u), 0.5 * float(vertex_id & 2u)); - Shadow shadow = shadows[shadow_id]; - - float margin = 3.0 * shadow.blur_radius; - Bounds bounds = shadow.bounds; - bounds.origin -= margin; - bounds.size += 2.0 * margin; - - float4 device_position = to_device_position(unit_vertex, bounds); - float4 clip_distance = distance_from_clip_rect(unit_vertex, bounds, shadow.content_mask); - float4 color = hsla_to_rgba(shadow.color); - - ShadowVertexOutput output; - output.position = device_position; - output.color = color; - output.shadow_id = shadow_id; - output.clip_distance = clip_distance; - - return output; -} - -float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET { - Shadow shadow = shadows[input.shadow_id]; - - float2 half_size = shadow.bounds.size / 2.; - float2 center = shadow.bounds.origin + half_size; - float2 point0 = input.position.xy - center; - float corner_radius; - if (point0.x < 0.) { - if (point0.y < 0.) { - corner_radius = shadow.corner_radii.top_left; - } else { - corner_radius = shadow.corner_radii.bottom_left; - } - } else { - if (point0.y < 0.) { - corner_radius = shadow.corner_radii.top_right; - } else { - corner_radius = shadow.corner_radii.bottom_right; - } - } - - // The signal is only non-zero in a limited range, so don't waste samples - float low = point0.y - half_size.y; - float high = point0.y + half_size.y; - float start = clamp(-3. * shadow.blur_radius, low, high); - float end = clamp(3. * shadow.blur_radius, low, high); - - // Accumulate samples (we can get away with surprisingly few samples) - float step = (end - start) / 4.; - float y = start + step * 0.5; - float alpha = 0.; - for (int i = 0; i < 4; i++) { - alpha += blur_along_x(point0.x, point0.y - y, shadow.blur_radius, - corner_radius, half_size) * - gaussian(y, shadow.blur_radius) * step; - y += step; - } - - return input.color * float4(1., 1., 1., alpha); -} - /* ** ** Quads @@ -579,16 +485,15 @@ QuadVertexOutput quad_vertex(uint vertex_id: SV_VertexID, uint quad_id: SV_Insta float2 unit_vertex = float2(float(vertex_id & 1u), 0.5 * float(vertex_id & 2u)); Quad quad = quads[quad_id]; float4 device_position = to_device_position(unit_vertex, quad.bounds); - float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask); - float4 border_color = hsla_to_rgba(quad.border_color); GradientColor gradient = prepare_gradient_color( quad.background.tag, quad.background.color_space, quad.background.solid, - quad.background.colors[0].color, - quad.background.colors[1].color + quad.background.colors ); + float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask); + float4 border_color = hsla_to_rgba(quad.border_color); QuadVertexOutput output; output.position = device_position; @@ -885,17 +790,97 @@ float4 quad_fragment(QuadFragmentInput input): SV_Target { return color * float4(1.0, 1.0, 1.0, saturate(antialias_threshold - outer_sdf)); } -struct PathVertex { - float2 xy_position; +/* +** +** Shadows +** +*/ + +struct ShadowVertexOutput { + float4 position: SV_Position; + nointerpolation float4 color: COLOR; + nointerpolation uint shadow_id: TEXCOORD0; + float4 clip_distance: SV_ClipDistance; +}; + +struct ShadowFragmentInput { + float4 position: SV_Position; + float4 color: COLOR; + nointerpolation uint shadow_id: TEXCOORD0; +}; + +struct Shadow { + uint order; + float blur_radius; + Bounds bounds; + Corners corner_radii; Bounds content_mask; + Hsla color; }; +StructuredBuffer shadows: register(t1); + +ShadowVertexOutput shadow_vertex(uint vertex_id: SV_VertexID, uint shadow_id: SV_InstanceID) { + float2 unit_vertex = float2(float(vertex_id & 1u), 0.5 * float(vertex_id & 2u)); + Shadow shadow = shadows[shadow_id]; + + float margin = 3.0 * shadow.blur_radius; + Bounds bounds = shadow.bounds; + bounds.origin -= margin; + bounds.size += 2.0 * margin; + + float4 device_position = to_device_position(unit_vertex, bounds); + float4 clip_distance = distance_from_clip_rect(unit_vertex, bounds, shadow.content_mask); + float4 color = hsla_to_rgba(shadow.color); + + ShadowVertexOutput output; + output.position = device_position; + output.color = color; + output.shadow_id = shadow_id; + output.clip_distance = clip_distance; + + return output; +} + +float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET { + Shadow shadow = shadows[input.shadow_id]; + + float2 half_size = shadow.bounds.size / 2.; + float2 center = shadow.bounds.origin + half_size; + float2 point0 = input.position.xy - center; + float corner_radius = pick_corner_radius(point0, shadow.corner_radii); + + // The signal is only non-zero in a limited range, so don't waste samples + float low = point0.y - half_size.y; + float high = point0.y + half_size.y; + float start = clamp(-3. * shadow.blur_radius, low, high); + float end = clamp(3. * shadow.blur_radius, low, high); + + // Accumulate samples (we can get away with surprisingly few samples) + float step = (end - start) / 4.; + float y = start + step * 0.5; + float alpha = 0.; + for (int i = 0; i < 4; i++) { + alpha += blur_along_x(point0.x, point0.y - y, shadow.blur_radius, + corner_radius, half_size) * + gaussian(y, shadow.blur_radius) * step; + y += step; + } + + return input.color * float4(1., 1., 1., alpha); +} + /* ** ** Paths ** */ +struct PathVertex { + float2 xy_position; + Bounds content_mask; +}; + struct PathSprite { Bounds bounds; Background color; @@ -926,8 +911,7 @@ PathVertexOutput paths_vertex(uint vertex_id: SV_VertexID, uint instance_id: SV_ sprite.color.tag, sprite.color.color_space, sprite.color.solid, - sprite.color.colors[0].color, - sprite.color.colors[1].color + sprite.color.colors ); output.solid_color = gradient.solid; @@ -967,15 +951,15 @@ struct Underline { struct UnderlineVertexOutput { float4 position: SV_Position; - float4 color: COLOR; - uint underline_id: FLAT; + nointerpolation float4 color: COLOR; + nointerpolation uint underline_id: TEXCOORD0; float4 clip_distance: SV_ClipDistance; }; struct UnderlineFragmentInput { float4 position: SV_Position; - float4 color: COLOR; - uint underline_id: FLAT; + nointerpolation float4 color: COLOR; + nointerpolation uint underline_id: TEXCOORD0; }; StructuredBuffer underlines: register(t1); @@ -1000,10 +984,8 @@ float4 underline_fragment(UnderlineFragmentInput input): SV_Target { Underline underline = underlines[input.underline_id]; if (underline.wavy) { float half_thickness = underline.thickness * 0.5; - float2 origin = - float2(underline.bounds.origin.x, underline.bounds.origin.y); - float2 st = ((input.position.xy - origin) / underline.bounds.size.y) - - float2(0., 0.5); + float2 origin = underline.bounds.origin; + float2 st = ((input.position.xy - origin) / underline.bounds.size.y) - float2(0., 0.5); float frequency = (M_PI_F * (3. * underline.thickness)) / 8.; float amplitude = 1. / (2. * underline.thickness); float sine = sin(st.x * frequency) * amplitude; @@ -1039,14 +1021,14 @@ struct MonochromeSprite { struct MonochromeSpriteVertexOutput { float4 position: SV_Position; float2 tile_position: POSITION; - float4 color: COLOR; + nointerpolation float4 color: COLOR; float4 clip_distance: SV_ClipDistance; }; struct MonochromeSpriteFragmentInput { float4 position: SV_Position; float2 tile_position: POSITION; - float4 color: COLOR; + nointerpolation float4 color: COLOR; }; StructuredBuffer mono_sprites: register(t1); From e8bd47f66844d388de6fb47bdb77d9bca6615350 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Mon, 14 Jul 2025 19:59:26 +0800 Subject: [PATCH 05/45] wip --- crates/gpui/src/platform/windows/directx_renderer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index ed2ec0a8c93ed059ecdbad36ce3cc7b7b840ac14..132ab81320dbc1c21c6d131fb97004f0889d7089 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -281,7 +281,6 @@ impl DirectXRenderer { if paths.is_empty() { return Ok(()); } - println!("Drawing {} paths", paths.len()); let mut vertices = Vec::new(); let mut sprites = Vec::with_capacity(paths.len()); let mut draw_indirect_commands = Vec::with_capacity(paths.len()); @@ -850,6 +849,7 @@ fn set_rasterizer_state(device: &ID3D11Device, device_context: &ID3D11DeviceCont let desc = D3D11_RASTERIZER_DESC { FillMode: D3D11_FILL_SOLID, CullMode: D3D11_CULL_NONE, + // CullMode: D3D11_CULL_BACK, FrontCounterClockwise: false.into(), DepthBias: 0, DepthBiasClamp: 0.0, @@ -1080,7 +1080,7 @@ fn update_paths_buffer_capacity( ); let buffer_size = data_size.next_power_of_two(); println!("Paths New size: {}", buffer_size); - let buffer = create_buffer(device, std::mem::align_of::(), buffer_size).unwrap(); + let buffer = create_buffer(device, std::mem::size_of::(), buffer_size).unwrap(); let view = create_buffer_view(device, &buffer).unwrap(); Some((buffer, buffer_size, view)) } From 8514850ad4afddc44d03fec8be08e4b5e6b489ef Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Tue, 15 Jul 2025 12:35:33 +0800 Subject: [PATCH 06/45] temporarily disable transparancy --- crates/gpui/src/platform/windows/window.rs | 37 +++++++++++----------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 2801674a649896d33cb6b47736cd9f4117d80c80..5d1c91b5e30fbea20db63a58f067ce820923c495 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -384,7 +384,8 @@ impl WindowsWindow { (WS_EX_TOOLWINDOW | WS_EX_LAYERED, WINDOW_STYLE(0x0)) } else { ( - WS_EX_APPWINDOW | WS_EX_LAYERED, + // WS_EX_APPWINDOW | WS_EX_LAYERED, + WS_EX_APPWINDOW, WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, ) }; @@ -461,7 +462,7 @@ impl WindowsWindow { // window is going to be composited with per-pixel alpha, but the render // pipeline is responsible for effectively calling UpdateLayeredWindow // at the appropriate time. - unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? }; + // unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? }; Ok(Self(state_ptr)) } @@ -706,27 +707,27 @@ impl PlatformWindow for WindowsWindow { } fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) { - let mut window_state = self.0.state.borrow_mut(); + // let mut window_state = self.0.state.borrow_mut(); // todo(zjk) // window_state // .renderer // .update_transparency(background_appearance != WindowBackgroundAppearance::Opaque); - match background_appearance { - WindowBackgroundAppearance::Opaque => { - // ACCENT_DISABLED - set_window_composition_attribute(window_state.hwnd, None, 0); - } - WindowBackgroundAppearance::Transparent => { - // Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background - set_window_composition_attribute(window_state.hwnd, None, 2); - } - WindowBackgroundAppearance::Blurred => { - // Enable acrylic blur - // ACCENT_ENABLE_ACRYLICBLURBEHIND - set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 0)), 4); - } - } + // match background_appearance { + // WindowBackgroundAppearance::Opaque => { + // // ACCENT_DISABLED + // set_window_composition_attribute(window_state.hwnd, None, 0); + // } + // WindowBackgroundAppearance::Transparent => { + // // Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background + // set_window_composition_attribute(window_state.hwnd, None, 2); + // } + // WindowBackgroundAppearance::Blurred => { + // // Enable acrylic blur + // // ACCENT_ENABLE_ACRYLICBLURBEHIND + // set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 0)), 4); + // } + // } } fn minimize(&self) { From 6928488aad1617a5a7c1c2de2391c1a92468e8f8 Mon Sep 17 00:00:00 2001 From: Kate Date: Mon, 14 Jul 2025 20:55:16 +0200 Subject: [PATCH 07/45] initial removal attempt --- .../gpui/src/platform/windows/direct_write.rs | 336 +++++++----------- 1 file changed, 129 insertions(+), 207 deletions(-) diff --git a/crates/gpui/src/platform/windows/direct_write.rs b/crates/gpui/src/platform/windows/direct_write.rs index ada306c15c187e7014812c3026d12e966a563c80..3fc143fdcb8bbe7232cf6b0e0b22b5f00616c372 100644 --- a/crates/gpui/src/platform/windows/direct_write.rs +++ b/crates/gpui/src/platform/windows/direct_write.rs @@ -1,4 +1,4 @@ -use std::{borrow::Cow, sync::Arc}; +use std::{borrow::Cow, mem::ManuallyDrop, sync::Arc}; use ::util::ResultExt; use anyhow::Result; @@ -9,13 +9,7 @@ use windows::{ Win32::{ Foundation::*, Globalization::GetUserDefaultLocaleName, - Graphics::{ - Direct2D::{Common::*, *}, - DirectWrite::*, - Dxgi::Common::*, - Gdi::LOGFONTW, - Imaging::*, - }, + Graphics::{DirectWrite::*, Dxgi::Common::*, Gdi::LOGFONTW, Imaging::*}, System::SystemServices::LOCALE_NAME_MAX_LENGTH, UI::WindowsAndMessaging::*, }, @@ -40,7 +34,6 @@ struct DirectWriteComponent { locale: String, factory: IDWriteFactory5, bitmap_factory: AgileReference, - d2d1_factory: ID2D1Factory, in_memory_loader: IDWriteInMemoryFontFileLoader, builder: IDWriteFontSetBuilder1, text_renderer: Arc, @@ -49,7 +42,6 @@ struct DirectWriteComponent { struct GlyphRenderContext { params: IDWriteRenderingParams3, - dc_target: ID2D1DeviceContext4, } struct DirectWriteState { @@ -74,8 +66,6 @@ impl DirectWriteComponent { unsafe { let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)?; let bitmap_factory = AgileReference::new(bitmap_factory)?; - let d2d1_factory: ID2D1Factory = - D2D1CreateFactory(D2D1_FACTORY_TYPE_MULTI_THREADED, None)?; // The `IDWriteInMemoryFontFileLoader` here is supported starting from // Windows 10 Creators Update, which consequently requires the entire // `DirectWriteTextSystem` to run on `win10 1703`+. @@ -86,13 +76,12 @@ impl DirectWriteComponent { GetUserDefaultLocaleName(&mut locale_vec); let locale = String::from_utf16_lossy(&locale_vec); let text_renderer = Arc::new(TextRendererWrapper::new(&locale)); - let render_context = GlyphRenderContext::new(&factory, &d2d1_factory)?; + let render_context = GlyphRenderContext::new(&factory)?; Ok(DirectWriteComponent { locale, factory, bitmap_factory, - d2d1_factory, in_memory_loader, builder, text_renderer, @@ -103,7 +92,7 @@ impl DirectWriteComponent { } impl GlyphRenderContext { - pub fn new(factory: &IDWriteFactory5, d2d1_factory: &ID2D1Factory) -> Result { + pub fn new(factory: &IDWriteFactory5) -> Result { unsafe { let default_params: IDWriteRenderingParams3 = factory.CreateRenderingParams()?.cast()?; @@ -122,17 +111,8 @@ impl GlyphRenderContext { DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC, grid_fit_mode, )?; - let dc_target = { - let target = d2d1_factory.CreateDCRenderTarget(&get_render_target_property( - DXGI_FORMAT_B8G8R8A8_UNORM, - D2D1_ALPHA_MODE_PREMULTIPLIED, - ))?; - let target = target.cast::()?; - target.SetTextRenderingParams(¶ms); - target - }; - Ok(Self { params, dc_target }) + Ok(Self { params }) } } } @@ -649,17 +629,12 @@ impl DirectWriteState { } fn raster_bounds(&self, params: &RenderGlyphParams) -> Result> { - let render_target = &self.components.render_context.dc_target; - unsafe { - render_target.SetUnitMode(D2D1_UNIT_MODE_DIPS); - render_target.SetDpi(96.0 * params.scale_factor, 96.0 * params.scale_factor); - } let font = &self.fonts[params.font_id.0]; let glyph_id = [params.glyph_id.0 as u16]; let advance = [0.0f32]; let offset = [DWRITE_GLYPH_OFFSET::default()]; let glyph_run = DWRITE_GLYPH_RUN { - fontFace: unsafe { std::mem::transmute_copy(&font.font_face) }, + fontFace: ManuallyDrop::new(Some(font.font_face.cast()?)), fontEmSize: params.font_size.0, glyphCount: 1, glyphIndices: glyph_id.as_ptr(), @@ -668,13 +643,29 @@ impl DirectWriteState { isSideways: BOOL(0), bidiLevel: 0, }; - let bounds = unsafe { - render_target.GetGlyphRunWorldBounds( - Vector2 { X: 0.0, Y: 0.0 }, + + let transform = DWRITE_MATRIX::default(); + let rendering_mode = DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC; + let measuring_mode = DWRITE_MEASURING_MODE_NATURAL; + let baseline_origin_x = 0.0; + let baseline_origin_y = 0.0; + + let glyph_analysis = unsafe { + self.components.factory.CreateGlyphRunAnalysis( &glyph_run, - DWRITE_MEASURING_MODE_NATURAL, + Some(&transform as *const _), + rendering_mode, + measuring_mode, + DWRITE_GRID_FIT_MODE_DEFAULT, + DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, + baseline_origin_x, + baseline_origin_y, )? }; + + let texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1; + let bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(texture_type)? }; + // todo(windows) // This is a walkaround, deleted when figured out. let y_offset; @@ -696,12 +687,13 @@ impl DirectWriteState { } else { Ok(Bounds { origin: point( - ((bounds.left * params.scale_factor).ceil() as i32).into(), - ((bounds.top * params.scale_factor).ceil() as i32 + y_offset).into(), + ((bounds.left as f32 * params.scale_factor).ceil() as i32).into(), + ((bounds.top as f32 * params.scale_factor).ceil() as i32 + y_offset).into(), ), size: size( - (((bounds.right - bounds.left) * params.scale_factor).ceil() as i32).into(), - (((bounds.bottom - bounds.top) * params.scale_factor).ceil() as i32 + (((bounds.right - bounds.left) as f32 * params.scale_factor).ceil() as i32) + .into(), + (((bounds.bottom - bounds.top) as f32 * params.scale_factor).ceil() as i32 + extra_height) .into(), ), @@ -739,7 +731,7 @@ impl DirectWriteState { ascenderOffset: glyph_bounds.origin.y.0 as f32 / params.scale_factor, }]; let glyph_run = DWRITE_GLYPH_RUN { - fontFace: unsafe { std::mem::transmute_copy(&font_info.font_face) }, + fontFace: ManuallyDrop::new(Some(font_info.font_face.cast()?)), fontEmSize: params.font_size.0, glyphCount: 1, glyphIndices: glyph_id.as_ptr(), @@ -759,149 +751,108 @@ impl DirectWriteState { } let bitmap_size = bitmap_size; - let total_bytes; - let bitmap_format; - let render_target_property; - let bitmap_width; - let bitmap_height; - let bitmap_stride; - let bitmap_dpi; + let subpixel_shift = params + .subpixel_variant + .map(|v| v as f32 / SUBPIXEL_VARIANTS as f32); + let baseline_origin_x = subpixel_shift.x / params.scale_factor; + let baseline_origin_y = subpixel_shift.y / params.scale_factor; + + let transform = DWRITE_MATRIX { + m11: params.scale_factor, + m12: 0.0, + m21: 0.0, + m22: params.scale_factor, + dx: 0.0, + dy: 0.0, + }; + + let rendering_mode = if params.is_emoji { + DWRITE_RENDERING_MODE1_NATURAL + } else { + DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC + }; + + let measuring_mode = DWRITE_MEASURING_MODE_NATURAL; + + let glyph_analysis = unsafe { + self.components.factory.CreateGlyphRunAnalysis( + &glyph_run, + Some(&transform), + rendering_mode, + measuring_mode, + DWRITE_GRID_FIT_MODE_DEFAULT, + DWRITE_TEXT_ANTIALIAS_MODE_CLEARTYPE, + baseline_origin_x, + baseline_origin_y, + )? + }; + if params.is_emoji { - total_bytes = bitmap_size.height.0 as usize * bitmap_size.width.0 as usize * 4; - bitmap_format = &GUID_WICPixelFormat32bppPBGRA; - render_target_property = get_render_target_property( - DXGI_FORMAT_B8G8R8A8_UNORM, - D2D1_ALPHA_MODE_PREMULTIPLIED, - ); - bitmap_width = bitmap_size.width.0 as u32; - bitmap_height = bitmap_size.height.0 as u32; - bitmap_stride = bitmap_size.width.0 as u32 * 4; - bitmap_dpi = 96.0; + // For emoji, we need to handle color glyphs differently + // This is a simplified approach - in a full implementation you'd want to + // properly handle color glyph runs using TranslateColorGlyphRun + let texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1; + let texture_bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(texture_type)? }; + + let width = (texture_bounds.right - texture_bounds.left) as u32; + let height = (texture_bounds.bottom - texture_bounds.top) as u32; + + if width == 0 || height == 0 { + return Ok(( + bitmap_size, + vec![0u8; bitmap_size.width.0 as usize * bitmap_size.height.0 as usize * 4], + )); + } + + let mut rgba_data = vec![0u8; (width * height * 4) as usize]; + + unsafe { + glyph_analysis.CreateAlphaTexture(texture_type, &texture_bounds, &mut rgba_data)?; + } + + // Resize to match expected bitmap_size if needed + let expected_size = bitmap_size.width.0 as usize * bitmap_size.height.0 as usize * 4; + rgba_data.resize(expected_size, 0); + + Ok((bitmap_size, rgba_data)) } else { - total_bytes = bitmap_size.height.0 as usize * bitmap_size.width.0 as usize; - bitmap_format = &GUID_WICPixelFormat8bppAlpha; - render_target_property = - get_render_target_property(DXGI_FORMAT_A8_UNORM, D2D1_ALPHA_MODE_STRAIGHT); - bitmap_width = bitmap_size.width.0 as u32 * 2; - bitmap_height = bitmap_size.height.0 as u32 * 2; - bitmap_stride = bitmap_size.width.0 as u32; - bitmap_dpi = 192.0; - } + // For regular text, use grayscale or cleartype + let texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1; + let texture_bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(texture_type)? }; + + let width = (texture_bounds.right - texture_bounds.left) as u32; + let height = (texture_bounds.bottom - texture_bounds.top) as u32; + + if width == 0 || height == 0 { + return Ok(( + bitmap_size, + vec![0u8; bitmap_size.width.0 as usize * bitmap_size.height.0 as usize], + )); + } - let bitmap_factory = self.components.bitmap_factory.resolve()?; - unsafe { - let bitmap = bitmap_factory.CreateBitmap( - bitmap_width, - bitmap_height, - bitmap_format, - WICBitmapCacheOnLoad, - )?; - let render_target = self - .components - .d2d1_factory - .CreateWicBitmapRenderTarget(&bitmap, &render_target_property)?; - let brush = render_target.CreateSolidColorBrush(&BRUSH_COLOR, None)?; - let subpixel_shift = params - .subpixel_variant - .map(|v| v as f32 / SUBPIXEL_VARIANTS as f32); - let baseline_origin = Vector2 { - X: subpixel_shift.x / params.scale_factor, - Y: subpixel_shift.y / params.scale_factor, - }; + let mut alpha_data = vec![0u8; (width * height) as usize]; - // This `cast()` action here should never fail since we are running on Win10+, and - // ID2D1DeviceContext4 requires Win8+ - let render_target = render_target.cast::().unwrap(); - render_target.SetUnitMode(D2D1_UNIT_MODE_DIPS); - render_target.SetDpi( - bitmap_dpi * params.scale_factor, - bitmap_dpi * params.scale_factor, - ); - render_target.SetTextRenderingParams(&self.components.render_context.params); - render_target.BeginDraw(); - - if params.is_emoji { - // WARN: only DWRITE_GLYPH_IMAGE_FORMATS_COLR has been tested - let enumerator = self.components.factory.TranslateColorGlyphRun( - baseline_origin, - &glyph_run as _, - None, - DWRITE_GLYPH_IMAGE_FORMATS_COLR - | DWRITE_GLYPH_IMAGE_FORMATS_SVG - | DWRITE_GLYPH_IMAGE_FORMATS_PNG - | DWRITE_GLYPH_IMAGE_FORMATS_JPEG - | DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8, - DWRITE_MEASURING_MODE_NATURAL, - None, - 0, + unsafe { + glyph_analysis.CreateAlphaTexture( + texture_type, + &texture_bounds, + &mut alpha_data, )?; - while enumerator.MoveNext().is_ok() { - let Ok(color_glyph) = enumerator.GetCurrentRun() else { - break; - }; - let color_glyph = &*color_glyph; - let brush_color = translate_color(&color_glyph.Base.runColor); - brush.SetColor(&brush_color); - match color_glyph.glyphImageFormat { - DWRITE_GLYPH_IMAGE_FORMATS_PNG - | DWRITE_GLYPH_IMAGE_FORMATS_JPEG - | DWRITE_GLYPH_IMAGE_FORMATS_PREMULTIPLIED_B8G8R8A8 => render_target - .DrawColorBitmapGlyphRun( - color_glyph.glyphImageFormat, - baseline_origin, - &color_glyph.Base.glyphRun, - color_glyph.measuringMode, - D2D1_COLOR_BITMAP_GLYPH_SNAP_OPTION_DEFAULT, - ), - DWRITE_GLYPH_IMAGE_FORMATS_SVG => render_target.DrawSvgGlyphRun( - baseline_origin, - &color_glyph.Base.glyphRun, - &brush, - None, - color_glyph.Base.paletteIndex as u32, - color_glyph.measuringMode, - ), - _ => render_target.DrawGlyphRun( - baseline_origin, - &color_glyph.Base.glyphRun, - Some(color_glyph.Base.glyphRunDescription as *const _), - &brush, - color_glyph.measuringMode, - ), - } - } - } else { - render_target.DrawGlyphRun( - baseline_origin, - &glyph_run, - None, - &brush, - DWRITE_MEASURING_MODE_NATURAL, - ); } - render_target.EndDraw(None, None)?; - - let mut raw_data = vec![0u8; total_bytes]; - if params.is_emoji { - bitmap.CopyPixels(std::ptr::null() as _, bitmap_stride, &mut raw_data)?; - // Convert from BGRA with premultiplied alpha to BGRA with straight alpha. - for pixel in raw_data.chunks_exact_mut(4) { - let a = pixel[3] as f32 / 255.; - pixel[0] = (pixel[0] as f32 / a) as u8; - pixel[1] = (pixel[1] as f32 / a) as u8; - pixel[2] = (pixel[2] as f32 / a) as u8; - } - } else { - let scaler = bitmap_factory.CreateBitmapScaler()?; - scaler.Initialize( - &bitmap, - bitmap_size.width.0 as u32, - bitmap_size.height.0 as u32, - WICBitmapInterpolationModeHighQualityCubic, - )?; - scaler.CopyPixels(std::ptr::null() as _, bitmap_stride, &mut raw_data)?; + + // For cleartype, we need to convert the 3x1 subpixel data to grayscale + // This is a simplified conversion - you might want to do proper subpixel rendering + let mut grayscale_data = Vec::new(); + for chunk in alpha_data.chunks_exact(3) { + let avg = (chunk[0] as u32 + chunk[1] as u32 + chunk[2] as u32) / 3; + grayscale_data.push(avg as u8); } - Ok((bitmap_size, raw_data)) + + // Resize to match expected bitmap_size if needed + let expected_size = bitmap_size.width.0 as usize * bitmap_size.height.0 as usize; + grayscale_data.resize(expected_size, 0); + + Ok((bitmap_size, grayscale_data)) } } @@ -1471,13 +1422,8 @@ fn get_name(string: IDWriteLocalizedStrings, locale: &str) -> Result { } #[inline] -fn translate_color(color: &DWRITE_COLOR_F) -> D2D1_COLOR_F { - D2D1_COLOR_F { - r: color.r, - g: color.g, - b: color.b, - a: color.a, - } +fn translate_color(color: &DWRITE_COLOR_F) -> [f32; 4] { + [color.r, color.g, color.b, color.a] } fn get_system_ui_font_name() -> SharedString { @@ -1504,24 +1450,6 @@ fn get_system_ui_font_name() -> SharedString { } } -#[inline] -fn get_render_target_property( - pixel_format: DXGI_FORMAT, - alpha_mode: D2D1_ALPHA_MODE, -) -> D2D1_RENDER_TARGET_PROPERTIES { - D2D1_RENDER_TARGET_PROPERTIES { - r#type: D2D1_RENDER_TARGET_TYPE_DEFAULT, - pixelFormat: D2D1_PIXEL_FORMAT { - format: pixel_format, - alphaMode: alpha_mode, - }, - dpiX: 96.0, - dpiY: 96.0, - usage: D2D1_RENDER_TARGET_USAGE_NONE, - minLevel: D2D1_FEATURE_LEVEL_DEFAULT, - } -} - // One would think that with newer DirectWrite method: IDWriteFontFace4::GetGlyphImageFormats // but that doesn't seem to work for some glyphs, say ❤ fn is_color_glyph( @@ -1561,12 +1489,6 @@ fn is_color_glyph( } const DEFAULT_LOCALE_NAME: PCWSTR = windows::core::w!("en-US"); -const BRUSH_COLOR: D2D1_COLOR_F = D2D1_COLOR_F { - r: 1.0, - g: 1.0, - b: 1.0, - a: 1.0, -}; #[cfg(test)] mod tests { From a7e34ab0bc1540f7110fdf1ffa7d62a8fcd08aff Mon Sep 17 00:00:00 2001 From: Kate Date: Mon, 14 Jul 2025 21:44:20 +0200 Subject: [PATCH 08/45] make it not crash --- crates/gpui/src/platform/windows/direct_write.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/gpui/src/platform/windows/direct_write.rs b/crates/gpui/src/platform/windows/direct_write.rs index 3fc143fdcb8bbe7232cf6b0e0b22b5f00616c372..4ee94e6155e6eb746efcb3aac2fbcd108553b446 100644 --- a/crates/gpui/src/platform/windows/direct_write.rs +++ b/crates/gpui/src/platform/windows/direct_write.rs @@ -634,7 +634,7 @@ impl DirectWriteState { let advance = [0.0f32]; let offset = [DWRITE_GLYPH_OFFSET::default()]; let glyph_run = DWRITE_GLYPH_RUN { - fontFace: ManuallyDrop::new(Some(font.font_face.cast()?)), + fontFace: unsafe { std::mem::transmute_copy(&font.font_face) }, fontEmSize: params.font_size.0, glyphCount: 1, glyphIndices: glyph_id.as_ptr(), @@ -644,7 +644,6 @@ impl DirectWriteState { bidiLevel: 0, }; - let transform = DWRITE_MATRIX::default(); let rendering_mode = DWRITE_RENDERING_MODE1_NATURAL_SYMMETRIC; let measuring_mode = DWRITE_MEASURING_MODE_NATURAL; let baseline_origin_x = 0.0; @@ -653,7 +652,7 @@ impl DirectWriteState { let glyph_analysis = unsafe { self.components.factory.CreateGlyphRunAnalysis( &glyph_run, - Some(&transform as *const _), + None, rendering_mode, measuring_mode, DWRITE_GRID_FIT_MODE_DEFAULT, @@ -830,7 +829,7 @@ impl DirectWriteState { )); } - let mut alpha_data = vec![0u8; (width * height) as usize]; + let mut alpha_data = vec![0u8; (width * height * 3) as usize]; unsafe { glyph_analysis.CreateAlphaTexture( From 2fb31a9157844a868c77d12f15d7481d1a9bb048 Mon Sep 17 00:00:00 2001 From: Kate Date: Mon, 14 Jul 2025 22:34:36 +0200 Subject: [PATCH 09/45] more fixes and debugging --- crates/gpui/examples/text.rs | 36 +++++++++---------- .../gpui/src/platform/windows/direct_write.rs | 7 ++-- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index 19214aebdefccba9216e1a6e250244eb231d282a..6f1b98e81c1275b8dca177b586814ed94f854ec2 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -270,27 +270,27 @@ impl Render for TextExample { .overflow_x_hidden() .bg(rgb(0xffffff)) .size_full() - .child(div().child(CharacterGrid::new().scale(base))) + // .child(div().child(CharacterGrid::new().scale(base))) .child( div() - .child(Specimen::new(self.next_id()).scale(step_down_2)) - .child(Specimen::new(self.next_id()).scale(step_down_2).invert()) - .child(Specimen::new(self.next_id()).scale(step_down_1)) - .child(Specimen::new(self.next_id()).scale(step_down_1).invert()) + // .child(Specimen::new(self.next_id()).scale(step_down_2)) + // .child(Specimen::new(self.next_id()).scale(step_down_2).invert()) + // .child(Specimen::new(self.next_id()).scale(step_down_1)) + // .child(Specimen::new(self.next_id()).scale(step_down_1).invert()) .child(Specimen::new(self.next_id()).scale(base)) - .child(Specimen::new(self.next_id()).scale(base).invert()) - .child(Specimen::new(self.next_id()).scale(step_up_1)) - .child(Specimen::new(self.next_id()).scale(step_up_1).invert()) - .child(Specimen::new(self.next_id()).scale(step_up_2)) - .child(Specimen::new(self.next_id()).scale(step_up_2).invert()) - .child(Specimen::new(self.next_id()).scale(step_up_3)) - .child(Specimen::new(self.next_id()).scale(step_up_3).invert()) - .child(Specimen::new(self.next_id()).scale(step_up_4)) - .child(Specimen::new(self.next_id()).scale(step_up_4).invert()) - .child(Specimen::new(self.next_id()).scale(step_up_5)) - .child(Specimen::new(self.next_id()).scale(step_up_5).invert()) - .child(Specimen::new(self.next_id()).scale(step_up_6)) - .child(Specimen::new(self.next_id()).scale(step_up_6).invert()), + // .child(Specimen::new(self.next_id()).scale(base).invert()) + // .child(Specimen::new(self.next_id()).scale(step_up_1)) + // .child(Specimen::new(self.next_id()).scale(step_up_1).invert()) + // .child(Specimen::new(self.next_id()).scale(step_up_2)) + // .child(Specimen::new(self.next_id()).scale(step_up_2).invert()) + // .child(Specimen::new(self.next_id()).scale(step_up_3)) + // .child(Specimen::new(self.next_id()).scale(step_up_3).invert()) + // .child(Specimen::new(self.next_id()).scale(step_up_4)) + // .child(Specimen::new(self.next_id()).scale(step_up_4).invert()) + // .child(Specimen::new(self.next_id()).scale(step_up_5)) + // .child(Specimen::new(self.next_id()).scale(step_up_5).invert()) + // .child(Specimen::new(self.next_id()).scale(step_up_6)) + // .child(Specimen::new(self.next_id()).scale(step_up_6).invert()), ), ) .child(div().w(px(240.)).h_full().bg(colors.container)) diff --git a/crates/gpui/src/platform/windows/direct_write.rs b/crates/gpui/src/platform/windows/direct_write.rs index 4ee94e6155e6eb746efcb3aac2fbcd108553b446..8d191facbe9cede008acc3db2f9aa24b2e761a23 100644 --- a/crates/gpui/src/platform/windows/direct_write.rs +++ b/crates/gpui/src/platform/windows/direct_write.rs @@ -810,14 +810,13 @@ impl DirectWriteState { } // Resize to match expected bitmap_size if needed - let expected_size = bitmap_size.width.0 as usize * bitmap_size.height.0 as usize * 4; - rgba_data.resize(expected_size, 0); Ok((bitmap_size, rgba_data)) } else { // For regular text, use grayscale or cleartype let texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1; let texture_bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(texture_type)? }; + println!("glyph id: {:?}, variant: {:?}, size: {:?}, texture_bounds: {:?}", glyph_id, params.subpixel_variant, bitmap_size, texture_bounds); let width = (texture_bounds.right - texture_bounds.left) as u32; let height = (texture_bounds.bottom - texture_bounds.top) as u32; @@ -848,10 +847,10 @@ impl DirectWriteState { } // Resize to match expected bitmap_size if needed - let expected_size = bitmap_size.width.0 as usize * bitmap_size.height.0 as usize; + let expected_size = width as usize * height as usize; grayscale_data.resize(expected_size, 0); - Ok((bitmap_size, grayscale_data)) + Ok((size(DevicePixels(width as i32), DevicePixels(height as i32)), grayscale_data)) } } From 6fc8d7746f4918881514301c6937a93d4ccd747c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 14 Jul 2025 16:58:13 -0700 Subject: [PATCH 10/45] Translate rasterized glyphs from texture to bitmap --- crates/gpui/examples/text.rs | 36 +++--- .../gpui/src/platform/windows/direct_write.rs | 114 +++++++++++------- 2 files changed, 86 insertions(+), 64 deletions(-) diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index 6f1b98e81c1275b8dca177b586814ed94f854ec2..19214aebdefccba9216e1a6e250244eb231d282a 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -270,27 +270,27 @@ impl Render for TextExample { .overflow_x_hidden() .bg(rgb(0xffffff)) .size_full() - // .child(div().child(CharacterGrid::new().scale(base))) + .child(div().child(CharacterGrid::new().scale(base))) .child( div() - // .child(Specimen::new(self.next_id()).scale(step_down_2)) - // .child(Specimen::new(self.next_id()).scale(step_down_2).invert()) - // .child(Specimen::new(self.next_id()).scale(step_down_1)) - // .child(Specimen::new(self.next_id()).scale(step_down_1).invert()) + .child(Specimen::new(self.next_id()).scale(step_down_2)) + .child(Specimen::new(self.next_id()).scale(step_down_2).invert()) + .child(Specimen::new(self.next_id()).scale(step_down_1)) + .child(Specimen::new(self.next_id()).scale(step_down_1).invert()) .child(Specimen::new(self.next_id()).scale(base)) - // .child(Specimen::new(self.next_id()).scale(base).invert()) - // .child(Specimen::new(self.next_id()).scale(step_up_1)) - // .child(Specimen::new(self.next_id()).scale(step_up_1).invert()) - // .child(Specimen::new(self.next_id()).scale(step_up_2)) - // .child(Specimen::new(self.next_id()).scale(step_up_2).invert()) - // .child(Specimen::new(self.next_id()).scale(step_up_3)) - // .child(Specimen::new(self.next_id()).scale(step_up_3).invert()) - // .child(Specimen::new(self.next_id()).scale(step_up_4)) - // .child(Specimen::new(self.next_id()).scale(step_up_4).invert()) - // .child(Specimen::new(self.next_id()).scale(step_up_5)) - // .child(Specimen::new(self.next_id()).scale(step_up_5).invert()) - // .child(Specimen::new(self.next_id()).scale(step_up_6)) - // .child(Specimen::new(self.next_id()).scale(step_up_6).invert()), + .child(Specimen::new(self.next_id()).scale(base).invert()) + .child(Specimen::new(self.next_id()).scale(step_up_1)) + .child(Specimen::new(self.next_id()).scale(step_up_1).invert()) + .child(Specimen::new(self.next_id()).scale(step_up_2)) + .child(Specimen::new(self.next_id()).scale(step_up_2).invert()) + .child(Specimen::new(self.next_id()).scale(step_up_3)) + .child(Specimen::new(self.next_id()).scale(step_up_3).invert()) + .child(Specimen::new(self.next_id()).scale(step_up_4)) + .child(Specimen::new(self.next_id()).scale(step_up_4).invert()) + .child(Specimen::new(self.next_id()).scale(step_up_5)) + .child(Specimen::new(self.next_id()).scale(step_up_5).invert()) + .child(Specimen::new(self.next_id()).scale(step_up_6)) + .child(Specimen::new(self.next_id()).scale(step_up_6).invert()), ), ) .child(div().w(px(240.)).h_full().bg(colors.container)) diff --git a/crates/gpui/src/platform/windows/direct_write.rs b/crates/gpui/src/platform/windows/direct_write.rs index 8d191facbe9cede008acc3db2f9aa24b2e761a23..bd7bacd4fc975e03860de5cae580e3bbe40ed53b 100644 --- a/crates/gpui/src/platform/windows/direct_write.rs +++ b/crates/gpui/src/platform/windows/direct_write.rs @@ -786,50 +786,58 @@ impl DirectWriteState { )? }; - if params.is_emoji { - // For emoji, we need to handle color glyphs differently - // This is a simplified approach - in a full implementation you'd want to - // properly handle color glyph runs using TranslateColorGlyphRun - let texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1; - let texture_bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(texture_type)? }; - - let width = (texture_bounds.right - texture_bounds.left) as u32; - let height = (texture_bounds.bottom - texture_bounds.top) as u32; - - if width == 0 || height == 0 { - return Ok(( - bitmap_size, - vec![0u8; bitmap_size.width.0 as usize * bitmap_size.height.0 as usize * 4], - )); - } + let texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1; + let texture_bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(texture_type)? }; + let texture_width = (texture_bounds.right - texture_bounds.left) as u32; + let texture_height = (texture_bounds.bottom - texture_bounds.top) as u32; + + if texture_width == 0 || texture_height == 0 { + return Ok(( + bitmap_size, + vec![ + 0u8; + bitmap_size.width.0 as usize + * bitmap_size.height.0 as usize + * if params.is_emoji { 4 } else { 1 } + ], + )); + } - let mut rgba_data = vec![0u8; (width * height * 4) as usize]; + let mut bitmap_data; + if params.is_emoji { + bitmap_data = + vec![0u8; bitmap_size.width.0 as usize * bitmap_size.height.0 as usize * 4]; + let mut rgba_data = vec![0u8; (texture_width * texture_height * 4) as usize]; unsafe { glyph_analysis.CreateAlphaTexture(texture_type, &texture_bounds, &mut rgba_data)?; } - // Resize to match expected bitmap_size if needed + // Copy texture data into bitmap at correct position + let offset_x = texture_bounds.left.max(0) as usize; + let offset_y = texture_bounds.top.max(0) as usize; + for y in 0..texture_height as usize { + for x in 0..texture_width as usize { + let bitmap_x = offset_x + x; + let bitmap_y = offset_y + y; - Ok((bitmap_size, rgba_data)) - } else { - // For regular text, use grayscale or cleartype - let texture_type = DWRITE_TEXTURE_CLEARTYPE_3x1; - let texture_bounds = unsafe { glyph_analysis.GetAlphaTextureBounds(texture_type)? }; - println!("glyph id: {:?}, variant: {:?}, size: {:?}, texture_bounds: {:?}", glyph_id, params.subpixel_variant, bitmap_size, texture_bounds); - - let width = (texture_bounds.right - texture_bounds.left) as u32; - let height = (texture_bounds.bottom - texture_bounds.top) as u32; - - if width == 0 || height == 0 { - return Ok(( - bitmap_size, - vec![0u8; bitmap_size.width.0 as usize * bitmap_size.height.0 as usize], - )); - } + if bitmap_x < bitmap_size.width.0 as usize + && bitmap_y < bitmap_size.height.0 as usize + { + let texture_idx = (y * texture_width as usize + x) * 4; + let bitmap_idx = (bitmap_y * bitmap_size.width.0 as usize + bitmap_x) * 4; - let mut alpha_data = vec![0u8; (width * height * 3) as usize]; + if texture_idx + 3 < rgba_data.len() && bitmap_idx + 3 < bitmap_data.len() { + bitmap_data[bitmap_idx..bitmap_idx + 4] + .copy_from_slice(&rgba_data[texture_idx..texture_idx + 4]); + } + } + } + } + } else { + bitmap_data = vec![0u8; bitmap_size.width.0 as usize * bitmap_size.height.0 as usize]; + let mut alpha_data = vec![0u8; (texture_width * texture_height * 3) as usize]; unsafe { glyph_analysis.CreateAlphaTexture( texture_type, @@ -838,20 +846,34 @@ impl DirectWriteState { )?; } - // For cleartype, we need to convert the 3x1 subpixel data to grayscale - // This is a simplified conversion - you might want to do proper subpixel rendering - let mut grayscale_data = Vec::new(); - for chunk in alpha_data.chunks_exact(3) { - let avg = (chunk[0] as u32 + chunk[1] as u32 + chunk[2] as u32) / 3; - grayscale_data.push(avg as u8); - } + // Convert ClearType RGB data to grayscale and place in bitmap + let offset_x = texture_bounds.left.max(0) as usize; + let offset_y = texture_bounds.top.max(0) as usize; - // Resize to match expected bitmap_size if needed - let expected_size = width as usize * height as usize; - grayscale_data.resize(expected_size, 0); + for y in 0..texture_height as usize { + for x in 0..texture_width as usize { + let bitmap_x = offset_x + x; + let bitmap_y = offset_y + y; - Ok((size(DevicePixels(width as i32), DevicePixels(height as i32)), grayscale_data)) + if bitmap_x < bitmap_size.width.0 as usize + && bitmap_y < bitmap_size.height.0 as usize + { + let texture_idx = (y * texture_width as usize + x) * 3; + let bitmap_idx = bitmap_y * bitmap_size.width.0 as usize + bitmap_x; + + if texture_idx + 2 < alpha_data.len() && bitmap_idx < bitmap_data.len() { + let avg = (alpha_data[texture_idx] as u32 + + alpha_data[texture_idx + 1] as u32 + + alpha_data[texture_idx + 2] as u32) + / 3; + bitmap_data[bitmap_idx] = avg as u8; + } + } + } + } } + + Ok((bitmap_size, bitmap_data)) } fn get_typographic_bounds(&self, font_id: FontId, glyph_id: GlyphId) -> Result> { From 34d5926ebd37e58897390734a9224635a823b954 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Mon, 14 Jul 2025 17:57:52 -0700 Subject: [PATCH 11/45] Add emojis to text example --- crates/gpui/examples/text.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui/examples/text.rs b/crates/gpui/examples/text.rs index 19214aebdefccba9216e1a6e250244eb231d282a..1166bb279541c80eb8686b59c85724b4068895ed 100644 --- a/crates/gpui/examples/text.rs +++ b/crates/gpui/examples/text.rs @@ -198,7 +198,7 @@ impl RenderOnce for CharacterGrid { "χ", "ψ", "∂", "а", "в", "Ж", "ж", "З", "з", "К", "к", "л", "м", "Н", "н", "Р", "р", "У", "у", "ф", "ч", "ь", "ы", "Э", "э", "Я", "я", "ij", "öẋ", ".,", "⣝⣑", "~", "*", "_", "^", "`", "'", "(", "{", "«", "#", "&", "@", "$", "¢", "%", "|", "?", "¶", "µ", - "❮", "<=", "!=", "==", "--", "++", "=>", "->", + "❮", "<=", "!=", "==", "--", "++", "=>", "->", "🏀", "🎊", "😍", "❤️", "👍", "👎", ]; let columns = 11; From a1c00ed87f6ec69dbe6dee7b827a735253fce999 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Tue, 15 Jul 2025 23:28:25 +0800 Subject: [PATCH 12/45] fix all --- .../src/platform/windows/directx_renderer.rs | 50 ++----------------- crates/gpui/src/platform/windows/shaders.hlsl | 44 ++++++++-------- 2 files changed, 23 insertions(+), 71 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 132ab81320dbc1c21c6d131fb97004f0889d7089..3853e506c7f4a92a19a1c265c2ecdcadbafbf746 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -58,7 +58,6 @@ struct DirectXGlobalElements { global_params_buffer: [Option; 1], sampler: [Option; 1], blend_state: ID3D11BlendState, - blend_state_for_pr: ID3D11BlendState, } #[repr(C)] @@ -601,13 +600,11 @@ impl DirectXGlobalElements { }; let blend_state = create_blend_state(device)?; - let blend_state_for_pr = create_blend_state_for_path_raster(device)?; Ok(Self { global_params_buffer, sampler, blend_state, - blend_state_for_pr, }) } } @@ -849,7 +846,7 @@ fn set_rasterizer_state(device: &ID3D11Device, device_context: &ID3D11DeviceCont let desc = D3D11_RASTERIZER_DESC { FillMode: D3D11_FILL_SOLID, CullMode: D3D11_CULL_NONE, - // CullMode: D3D11_CULL_BACK, + // FrontCounterClockwise: true.into(), FrontCounterClockwise: false.into(), DepthBias: 0, DepthBiasClamp: 0.0, @@ -888,25 +885,6 @@ fn create_blend_state(device: &ID3D11Device) -> Result { } } -fn create_blend_state_for_path_raster(device: &ID3D11Device) -> Result { - // If the feature level is set to greater than D3D_FEATURE_LEVEL_9_3, the display - // device performs the blend in linear space, which is ideal. - let mut desc = D3D11_BLEND_DESC::default(); - desc.RenderTarget[0].BlendEnable = true.into(); - desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; - desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; - desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - desc.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; - desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE; - desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL.0 as u8; - unsafe { - let mut state = None; - device.CreateBlendState(&desc, Some(&mut state))?; - Ok(state.unwrap()) - } -} - fn create_pipieline( device: &ID3D11Device, vertex_entry: &str, @@ -989,13 +967,6 @@ fn create_buffer_view( } fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: u32) -> Result { - // let desc = D3D11_BUFFER_DESC { - // ByteWidth: std::mem::size_of::() as u32 * buffer_size, - // Usage: D3D11_USAGE_DYNAMIC, - // BindFlags: D3D11_BIND_INDIRECT_DRAW.0 as u32, - // MiscFlags: D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS.0 as u32, - // ..Default::default() - // }; let desc = D3D11_BUFFER_DESC { ByteWidth: std::mem::size_of::() as u32 * buffer_size, Usage: D3D11_USAGE_DYNAMIC, @@ -1173,20 +1144,6 @@ fn update_buffer( Ok(()) } -fn update_indirect_buffer( - device_context: &ID3D11DeviceContext, - buffer: &ID3D11Buffer, - data: &[DrawInstancedIndirectArgs], -) -> Result<()> { - unsafe { - let mut dest = std::mem::zeroed(); - device_context.Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut dest))?; - std::ptr::copy_nonoverlapping(data.as_ptr(), dest.pData as _, data.len()); - device_context.Unmap(buffer, 0); - } - Ok(()) -} - fn prepare_indirect_draws( device_context: &ID3D11DeviceContext, pipeline: &PathsPipelineState, @@ -1314,7 +1271,6 @@ mod shader_resources { &mut compile_blob, Some(&mut error_blob), ); - println!("Shader compile result: {:?}", ret); if ret.is_err() { let Some(error_blob) = error_blob else { return Err(anyhow::anyhow!("{ret:?}")); @@ -1325,8 +1281,8 @@ mod shader_resources { string_len, string_len, ); - let error_string = String::from_utf8_lossy(&error_string_encode); - println!("Shader compile error: {}", error_string); + let error_string = String::from_utf8_lossy(&error_string_encode).to_string(); + log::error!("Shader compile error: {}", error_string); return Err(anyhow::anyhow!("Compile error: {}", error_string)); } Ok(compile_blob.unwrap()) diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index f93ef426dd4cd2ad026d512392485d856d097302..06a65e909f7a43e5ad630617a24a52749d989de2 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -461,9 +461,9 @@ struct Quad { }; struct QuadVertexOutput { + nointerpolation uint quad_id: TEXCOORD0; float4 position: SV_Position; nointerpolation float4 border_color: COLOR0; - nointerpolation uint quad_id: TEXCOORD0; nointerpolation float4 background_solid: COLOR1; nointerpolation float4 background_color0: COLOR2; nointerpolation float4 background_color1: COLOR3; @@ -512,9 +512,9 @@ float4 quad_fragment(QuadFragmentInput input): SV_Target { input.background_solid, input.background_color0, input.background_color1); bool unrounded = quad.corner_radii.top_left == 0.0 && - quad.corner_radii.bottom_left == 0.0 && - quad.corner_radii.top_right == 0.0 && - quad.corner_radii.bottom_right == 0.0; + quad.corner_radii.top_right == 0.0 && + quad.corner_radii.bottom_left == 0.0 && + quad.corner_radii.bottom_right == 0.0; // Fast path when the quad is not rounded and doesn't have any border if (quad.border_widths.top == 0.0 && @@ -796,26 +796,26 @@ float4 quad_fragment(QuadFragmentInput input): SV_Target { ** */ +struct Shadow { + uint order; + float blur_radius; + Bounds bounds; + Corners corner_radii; + Bounds content_mask; + Hsla color; +}; + struct ShadowVertexOutput { + nointerpolation uint shadow_id: TEXCOORD0; float4 position: SV_Position; nointerpolation float4 color: COLOR; - nointerpolation uint shadow_id: TEXCOORD0; float4 clip_distance: SV_ClipDistance; }; struct ShadowFragmentInput { - float4 position: SV_Position; - float4 color: COLOR; nointerpolation uint shadow_id: TEXCOORD0; -}; - -struct Shadow { - uint order; - float blur_radius; - Bounds bounds; - Corners corner_radii; - Bounds content_mask; - Hsla color; + float4 position: SV_Position; + nointerpolation float4 color: COLOR; }; StructuredBuffer shadows: register(t1); @@ -950,16 +950,16 @@ struct Underline { }; struct UnderlineVertexOutput { + nointerpolation uint underline_id: TEXCOORD0; float4 position: SV_Position; nointerpolation float4 color: COLOR; - nointerpolation uint underline_id: TEXCOORD0; float4 clip_distance: SV_ClipDistance; }; struct UnderlineFragmentInput { + nointerpolation uint underline_id: TEXCOORD0; float4 position: SV_Position; nointerpolation float4 color: COLOR; - nointerpolation uint underline_id: TEXCOORD0; }; StructuredBuffer underlines: register(t1); @@ -1075,16 +1075,16 @@ struct PolychromeSprite { }; struct PolychromeSpriteVertexOutput { + nointerpolation uint sprite_id: TEXCOORD0; float4 position: SV_Position; float2 tile_position: POSITION; - nointerpolation uint sprite_id: TEXCOORD0; float4 clip_distance: SV_ClipDistance; }; struct PolychromeSpriteFragmentInput { + nointerpolation uint sprite_id: TEXCOORD0; float4 position: SV_Position; float2 tile_position: POSITION; - nointerpolation uint sprite_id: TEXCOORD0; }; StructuredBuffer poly_sprites: register(t1); @@ -1115,10 +1115,6 @@ float4 polychrome_sprite_fragment(PolychromeSpriteFragmentInput input): SV_Targe float3 grayscale = dot(color.rgb, GRAYSCALE_FACTORS); color = float4(grayscale, sample.a); } - // if ((sprite.grayscale & 0xFFu) != 0u) { - // float3 grayscale = dot(color.rgb, GRAYSCALE_FACTORS); - // color = float4(grayscale, sample.a); - // } color.a *= sprite.opacity * saturate(0.5 - distance); return color; } From 85cf9e405ea8b87cdebd7cd291974aff13f0069a Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Tue, 15 Jul 2025 23:29:32 +0800 Subject: [PATCH 13/45] remove debug print --- .../src/platform/windows/directx_renderer.rs | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 3853e506c7f4a92a19a1c265c2ecdcadbafbf746..609872714b8b0d9f7d51d2baf83ccf244ad49281 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -1029,9 +1029,7 @@ fn update_buffer_capacity( if pipeline.buffer_size >= data_size { return None; } - println!("buffer too small: {} < {}", pipeline.buffer_size, data_size); let buffer_size = data_size.next_power_of_two(); - println!("New size: {}", buffer_size); let buffer = create_buffer(device, element_size, buffer_size).unwrap(); let view = create_buffer_view(device, &buffer).unwrap(); Some((buffer, buffer_size, view)) @@ -1045,12 +1043,7 @@ fn update_paths_buffer_capacity( if pipeline.buffer_size >= data_size { return None; } - println!( - "Paths buffer too small: {} < {}", - pipeline.buffer_size, data_size - ); let buffer_size = data_size.next_power_of_two(); - println!("Paths New size: {}", buffer_size); let buffer = create_buffer(device, std::mem::size_of::(), buffer_size).unwrap(); let view = create_buffer_view(device, &buffer).unwrap(); Some((buffer, buffer_size, view)) @@ -1064,12 +1057,7 @@ fn update_paths_vertex_capacity( if pipeline.vertex_buffer_size >= vertex_size { return None; } - println!( - "Paths vertex buffer too small: {} < {}", - pipeline.vertex_buffer_size, vertex_size - ); let vertex_size = vertex_size.next_power_of_two(); - println!("Paths vertex New size: {}", vertex_size); let buffer = create_buffer( device, std::mem::size_of::>(), @@ -1088,12 +1076,7 @@ fn update_indirect_buffer_capacity( if pipeline.indirect_buffer_size >= data_size { return None; } - println!( - "Indirect buffer too small: {} < {}", - pipeline.indirect_buffer_size, data_size - ); let buffer_size = data_size.next_power_of_two(); - println!("Indirect New size: {}", buffer_size); let buffer = create_indirect_draw_buffer(device, data_size as u32).unwrap(); Some((buffer, buffer_size)) } @@ -1237,7 +1220,6 @@ mod shader_resources { use windows_core::{HSTRING, PCSTR}; pub(super) fn build_shader_blob(entry: &str, target: &str) -> Result { - println!("Building shader: {}", entry); unsafe { let mut entry = entry.to_owned(); let mut target = target.to_owned(); @@ -1251,11 +1233,6 @@ mod shader_resources { target.push_str("\0"); let entry_point = PCSTR::from_raw(entry.as_ptr()); let target_cstr = PCSTR::from_raw(target.as_ptr()); - println!( - "Compiling shader: {} with target: {}", - entry_point.display(), - target_cstr.display() - ); #[cfg(debug_assertions)] let compile_flag = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; #[cfg(not(debug_assertions))] From f16f07b36fa94ec9e5775b3e54ebac362a16eaed Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Tue, 15 Jul 2025 23:38:18 +0800 Subject: [PATCH 14/45] bringback our colorful avatar --- crates/gpui/src/platform/windows/shaders.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index 06a65e909f7a43e5ad630617a24a52749d989de2..1ed2de2240196640071ea88f28a63578840c2e88 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -1111,7 +1111,7 @@ float4 polychrome_sprite_fragment(PolychromeSpriteFragmentInput input): SV_Targe float distance = quad_sdf(input.position.xy, sprite.bounds, sprite.corner_radii); float4 color = sample; - if (sprite.grayscale) { + if ((sprite.grayscale & 0xFFu) != 0u) { float3 grayscale = dot(color.rgb, GRAYSCALE_FACTORS); color = float4(grayscale, sample.a); } From 83d942611f5eda5245eaddcc35e052d13b58b925 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 15 Jul 2025 15:49:30 -0700 Subject: [PATCH 15/45] Fix path rendering - draw all paths w/ one regular draw call --- .../src/platform/windows/directx_renderer.rs | 255 ++++++++---------- crates/gpui/src/platform/windows/shaders.hlsl | 29 +- 2 files changed, 131 insertions(+), 153 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 609872714b8b0d9f7d51d2baf83ccf244ad49281..3614641ced406f05e5413aa9f954d8778d2e3080 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -60,14 +60,6 @@ struct DirectXGlobalElements { blend_state: ID3D11BlendState, } -#[repr(C)] -struct DrawInstancedIndirectArgs { - vertex_count_per_instance: u32, - instance_count: u32, - start_vertex_location: u32, - start_instance_location: u32, -} - // #[cfg(not(feature = "enable-renderdoc"))] // struct DirectComposition { // comp_device: IDCompositionDevice, @@ -282,22 +274,12 @@ impl DirectXRenderer { } let mut vertices = Vec::new(); let mut sprites = Vec::with_capacity(paths.len()); - let mut draw_indirect_commands = Vec::with_capacity(paths.len()); - let mut start_vertex_location = 0; - for (i, path) in paths.iter().enumerate() { - draw_indirect_commands.push(DrawInstancedIndirectArgs { - vertex_count_per_instance: path.vertices.len() as u32, - instance_count: 1, - start_vertex_location, - start_instance_location: i as u32, - }); - start_vertex_location += path.vertices.len() as u32; - vertices.extend(path.vertices.iter().map(|v| PathVertex { + for (i, path) in paths.iter().enumerate() { + vertices.extend(path.vertices.iter().map(|v| DirectXPathVertex { xy_position: v.xy_position, - content_mask: ContentMask { - bounds: path.content_mask.bounds, - }, + content_mask: path.content_mask.bounds, + sprite_index: i as u32, })); sprites.push(PathSprite { @@ -314,7 +296,7 @@ impl DirectXRenderer { .map(|input| update_paths_pipeline_buffer(&mut self.pipelines.paths_pipeline, input)); update_buffer( &self.devices.device_context, - &self.pipelines.paths_pipeline.buffer, + &self.pipelines.paths_pipeline.instance_buffer, &sprites, )?; update_paths_vertex_capacity( @@ -328,32 +310,40 @@ impl DirectXRenderer { &self.pipelines.paths_pipeline.vertex_buffer, &vertices, )?; - update_indirect_buffer_capacity( - &self.pipelines.paths_pipeline, - draw_indirect_commands.len(), - &self.devices.device, - ) - .map(|input| update_paths_indirect_buffer(&mut self.pipelines.paths_pipeline, input)); - update_buffer( - &self.devices.device_context, - &self.pipelines.paths_pipeline.indirect_draw_buffer, - &draw_indirect_commands, - )?; - prepare_indirect_draws( - &self.devices.device_context, - &self.pipelines.paths_pipeline, - &self.context.viewport, - &self.globals.global_params_buffer, - D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, - )?; - for i in 0..paths.len() { - draw_indirect( - &self.devices.device_context, - &self.pipelines.paths_pipeline.indirect_draw_buffer, - (i * std::mem::size_of::()) as u32, + let device_context = &self.devices.device_context; + unsafe { + device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + device_context.VSSetShader(&self.pipelines.paths_pipeline.vertex, None); + device_context.PSSetShader(&self.pipelines.paths_pipeline.fragment, None); + device_context.VSSetConstantBuffers(0, Some(&self.globals.global_params_buffer)); + device_context.PSSetConstantBuffers(0, Some(&self.globals.global_params_buffer)); + device_context.VSSetShaderResources( + 2, + Some(&[Some(self.pipelines.paths_pipeline.instance_view.clone())]), + ); + device_context.PSSetShaderResources( + 2, + Some(&[Some(self.pipelines.paths_pipeline.instance_view.clone())]), ); + device_context.PSSetSamplers(0, Some(&self.globals.sampler)); + device_context.OMSetBlendState(&self.globals.blend_state, None, 0xffffffff); + let stride = std::mem::size_of::() as u32; + let offset = 0u32; + device_context.IASetVertexBuffers( + 0, + 1, + Some([Some(self.pipelines.paths_pipeline.vertex_buffer.clone())].as_ptr()), + Some(&stride), + Some(&offset), + ); + device_context.IASetInputLayout(&self.pipelines.paths_pipeline.input_layout); } + + unsafe { + device_context.Draw(vertices.len() as u32, 0); + } + Ok(()) } @@ -627,19 +617,18 @@ struct PipelineState { struct PathsPipelineState { vertex: ID3D11VertexShader, fragment: ID3D11PixelShader, - buffer: ID3D11Buffer, - buffer_size: usize, + instance_buffer: ID3D11Buffer, + instance_buffer_size: usize, vertex_buffer: ID3D11Buffer, vertex_buffer_size: usize, - indirect_draw_buffer: ID3D11Buffer, - indirect_buffer_size: usize, - view: [Option; 1], - vertex_view: [Option; 1], + instance_view: ID3D11ShaderResourceView, + vertex_view: ID3D11ShaderResourceView, + input_layout: ID3D11InputLayout, } impl PathsPipelineState { fn new(device: &ID3D11Device) -> Result { - let vertex = { + let (vertex, shader_blob) = { let shader_blob = shader_resources::build_shader_blob("paths_vertex", "vs_5_0")?; let bytes = unsafe { std::slice::from_raw_parts( @@ -647,7 +636,7 @@ impl PathsPipelineState { shader_blob.GetBufferSize(), ) }; - create_vertex_shader(device, bytes)? + (create_vertex_shader(device, bytes)?, shader_blob) }; let fragment = { let shader_blob = shader_resources::build_shader_blob("paths_fragment", "ps_5_0")?; @@ -659,23 +648,64 @@ impl PathsPipelineState { }; create_fragment_shader(device, bytes)? }; - let buffer = create_buffer(device, std::mem::size_of::(), 32)?; - let view = create_buffer_view(device, &buffer)?; - let vertex_buffer = - create_buffer(device, std::mem::size_of::>(), 32)?; + let instance_buffer = create_buffer(device, std::mem::size_of::(), 32)?; + let instance_view = create_buffer_view(device, &instance_buffer)?; + let vertex_buffer = create_buffer(device, std::mem::size_of::(), 32)?; let vertex_view = create_buffer_view(device, &vertex_buffer)?; - let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?; + + // Create input layout + let input_layout = unsafe { + let shader_bytes = std::slice::from_raw_parts( + shader_blob.GetBufferPointer() as *const u8, + shader_blob.GetBufferSize(), + ); + 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_R32G32B32A32_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: 24, + InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA, + InstanceDataStepRate: 0, + }, + ], + shader_bytes, + Some(&mut layout), + )?; + layout.unwrap() + }; + Ok(Self { vertex, fragment, - buffer, - buffer_size: 32, + instance_buffer, + instance_buffer_size: 32, vertex_buffer, vertex_buffer_size: 32, - indirect_draw_buffer, - indirect_buffer_size: 32, - view, + instance_view, vertex_view, + input_layout, }) } } @@ -687,6 +717,14 @@ struct PathSprite { color: Background, } +#[derive(Clone, Debug)] +#[repr(C)] +struct DirectXPathVertex { + xy_position: Point, + content_mask: Bounds, + sprite_index: u32, +} + fn get_dxgi_factory() -> Result { #[cfg(debug_assertions)] let factory_flag = DXGI_CREATE_FACTORY_DEBUG; @@ -919,7 +957,7 @@ fn create_pipieline( fragment, buffer, buffer_size, - view, + view: [Some(view)], }) } @@ -960,24 +998,10 @@ fn create_buffer( fn create_buffer_view( device: &ID3D11Device, buffer: &ID3D11Buffer, -) -> Result<[Option; 1]> { +) -> Result { let mut view = None; unsafe { device.CreateShaderResourceView(buffer, None, Some(&mut view)) }?; - Ok([view]) -} - -fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: u32) -> Result { - let desc = D3D11_BUFFER_DESC { - ByteWidth: std::mem::size_of::() as u32 * buffer_size, - Usage: D3D11_USAGE_DYNAMIC, - BindFlags: D3D11_BIND_INDEX_BUFFER.0 as u32, - CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32, - MiscFlags: D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS.0 as u32, - StructureByteStride: std::mem::size_of::() as u32, - }; - let mut buffer = None; - unsafe { device.CreateBuffer(&desc, None, Some(&mut buffer)) }?; - Ok(buffer.unwrap()) + Ok(view.unwrap()) } fn update_global_params( @@ -1032,15 +1056,15 @@ fn update_buffer_capacity( let buffer_size = data_size.next_power_of_two(); let buffer = create_buffer(device, element_size, buffer_size).unwrap(); let view = create_buffer_view(device, &buffer).unwrap(); - Some((buffer, buffer_size, view)) + Some((buffer, buffer_size, [Some(view)])) } fn update_paths_buffer_capacity( pipeline: &PathsPipelineState, data_size: usize, device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize, [Option; 1])> { - if pipeline.buffer_size >= data_size { +) -> Option<(ID3D11Buffer, usize, ID3D11ShaderResourceView)> { + if pipeline.instance_buffer_size >= data_size { return None; } let buffer_size = data_size.next_power_of_two(); @@ -1053,14 +1077,14 @@ fn update_paths_vertex_capacity( pipeline: &PathsPipelineState, vertex_size: usize, device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize, [Option; 1])> { +) -> Option<(ID3D11Buffer, usize, ID3D11ShaderResourceView)> { if pipeline.vertex_buffer_size >= vertex_size { return None; } let vertex_size = vertex_size.next_power_of_two(); let buffer = create_buffer( device, - std::mem::size_of::>(), + std::mem::size_of::(), vertex_size, ) .unwrap(); @@ -1068,19 +1092,6 @@ fn update_paths_vertex_capacity( Some((buffer, vertex_size, view)) } -fn update_indirect_buffer_capacity( - pipeline: &PathsPipelineState, - data_size: usize, - device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize)> { - if pipeline.indirect_buffer_size >= data_size { - return None; - } - let buffer_size = data_size.next_power_of_two(); - let buffer = create_indirect_draw_buffer(device, data_size as u32).unwrap(); - Some((buffer, buffer_size)) -} - fn update_pipeline( pipeline: &mut PipelineState, input: (ID3D11Buffer, usize, [Option; 1]), @@ -1092,27 +1103,22 @@ fn update_pipeline( fn update_paths_pipeline_buffer( pipeline: &mut PathsPipelineState, - input: (ID3D11Buffer, usize, [Option; 1]), + input: (ID3D11Buffer, usize, ID3D11ShaderResourceView), ) { - pipeline.buffer = input.0; - pipeline.buffer_size = input.1; - pipeline.view = input.2; + pipeline.instance_buffer = input.0; + pipeline.instance_buffer_size = input.1; + pipeline.instance_view = input.2; } fn update_paths_pipeline_vertex( pipeline: &mut PathsPipelineState, - input: (ID3D11Buffer, usize, [Option; 1]), + input: (ID3D11Buffer, usize, ID3D11ShaderResourceView), ) { pipeline.vertex_buffer = input.0; pipeline.vertex_buffer_size = input.1; pipeline.vertex_view = input.2; } -fn update_paths_indirect_buffer(pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize)) { - pipeline.indirect_draw_buffer = input.0; - pipeline.indirect_buffer_size = input.1; -} - fn update_buffer( device_context: &ID3D11DeviceContext, buffer: &ID3D11Buffer, @@ -1127,37 +1133,6 @@ fn update_buffer( Ok(()) } -fn prepare_indirect_draws( - device_context: &ID3D11DeviceContext, - pipeline: &PathsPipelineState, - viewport: &[D3D11_VIEWPORT], - global_params: &[Option], - topology: D3D_PRIMITIVE_TOPOLOGY, -) -> Result<()> { - unsafe { - device_context.VSSetShaderResources(1, Some(&pipeline.vertex_view)); - device_context.VSSetShaderResources(2, Some(&pipeline.view)); - device_context.PSSetShaderResources(2, Some(&pipeline.view)); - device_context.IASetPrimitiveTopology(topology); - device_context.RSSetViewports(Some(viewport)); - device_context.VSSetShader(&pipeline.vertex, None); - device_context.PSSetShader(&pipeline.fragment, None); - device_context.VSSetConstantBuffers(0, Some(global_params)); - device_context.PSSetConstantBuffers(0, Some(global_params)); - } - Ok(()) -} - -fn draw_indirect( - device_context: &ID3D11DeviceContext, - indirect_draw_buffer: &ID3D11Buffer, - offset: u32, -) { - unsafe { - device_context.DrawInstancedIndirect(indirect_draw_buffer, offset); - } -} - fn draw_normal( device_context: &ID3D11DeviceContext, pipeline: &PipelineState, diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index 1ed2de2240196640071ea88f28a63578840c2e88..b926847cbfeaedf67097e3bced2bf873996621e0 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -256,7 +256,7 @@ float pick_corner_radius(float2 center_to_point, Corners corner_radii) { } } -float4 to_device_position_transformed(float2 unit_vertex, Bounds bounds, +float4 to_device_position_transformed(float2 unit_vertex, Bounds bounds, TransformationMatrix transformation) { float2 position = unit_vertex * bounds.size + bounds.origin; float2 transformed = mul(position, transformation.rotation_scale) + transformation.translation; @@ -876,9 +876,10 @@ float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET { ** */ -struct PathVertex { - float2 xy_position; - Bounds content_mask; +struct PathVertexInput { + float2 xy_position: POSITION; + float4 content_mask: TEXCOORD0; + uint sprite_index: TEXCOORD1; }; struct PathSprite { @@ -895,17 +896,19 @@ struct PathVertexOutput { nointerpolation float4 color1: COLOR2; }; -StructuredBuffer path_vertices: register(t1); StructuredBuffer path_sprites: register(t2); -PathVertexOutput paths_vertex(uint vertex_id: SV_VertexID, uint instance_id: SV_InstanceID) { - PathVertex v = path_vertices[vertex_id]; - PathSprite sprite = path_sprites[instance_id]; +PathVertexOutput paths_vertex(PathVertexInput input) { + PathSprite sprite = path_sprites[input.sprite_index]; + + Bounds content_mask; + content_mask.origin = input.content_mask.xy; + content_mask.size = input.content_mask.zw; PathVertexOutput output; - output.position = to_device_position_impl(v.xy_position); - output.clip_distance = distance_from_clip_rect_impl(v.xy_position, v.content_mask); - output.sprite_id = instance_id; + output.position = to_device_position_impl(input.xy_position); + output.clip_distance = distance_from_clip_rect_impl(input.xy_position, content_mask); + output.sprite_id = input.sprite_index; GradientColor gradient = prepare_gradient_color( sprite.color.tag, @@ -925,7 +928,7 @@ float4 paths_fragment(PathVertexOutput input): SV_Target { if (any(input.clip_distance < zero)) { return zero; } - + PathSprite sprite = path_sprites[input.sprite_id]; Background background = sprite.color; float4 color = gradient_color(background, input.position.xy, sprite.bounds, @@ -968,7 +971,7 @@ UnderlineVertexOutput underline_vertex(uint vertex_id: SV_VertexID, uint underli float2 unit_vertex = float2(float(vertex_id & 1u), 0.5 * float(vertex_id & 2u)); Underline underline = underlines[underline_id]; float4 device_position = to_device_position(unit_vertex, underline.bounds); - float4 clip_distance = distance_from_clip_rect(unit_vertex, underline.bounds, + float4 clip_distance = distance_from_clip_rect(unit_vertex, underline.bounds, underline.content_mask); float4 color = hsla_to_rgba(underline.color); From c014dbae8ce7112e73a68bb922e3f86de4b72493 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 15 Jul 2025 16:48:19 -0700 Subject: [PATCH 16/45] Fix dxgi_factory type error in release mode --- crates/gpui/src/platform/windows/directx_renderer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 3614641ced406f05e5413aa9f954d8778d2e3080..a1f4dbeb58618f06e8be57edd23a7f088ba16b28 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -729,7 +729,7 @@ fn get_dxgi_factory() -> Result { #[cfg(debug_assertions)] let factory_flag = DXGI_CREATE_FACTORY_DEBUG; #[cfg(not(debug_assertions))] - let factory_flag = 0u32; + let factory_flag = DXGI_CREATE_FACTORY_FLAGS::default(); unsafe { Ok(CreateDXGIFactory2(factory_flag)?) } } From cdbaff8375fcb9ec04dedb1444c20fcf02b9bd46 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Tue, 15 Jul 2025 23:56:55 +0800 Subject: [PATCH 17/45] wip --- .../gpui/src/platform/windows/directx_renderer.rs | 3 +-- crates/gpui/src/platform/windows/shaders.hlsl | 15 +++++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index a1f4dbeb58618f06e8be57edd23a7f088ba16b28..542c90444d0edc7d15fa7bfd3c67281ef9618c1b 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -1,8 +1,7 @@ -use std::{collections::HashMap, hash::BuildHasherDefault, sync::Arc}; +use std::sync::Arc; use ::util::ResultExt; use anyhow::{Context, Result}; -use collections::FxHasher; // #[cfg(not(feature = "enable-renderdoc"))] // use windows::Win32::Graphics::DirectComposition::*; use windows::{ diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index b926847cbfeaedf67097e3bced2bf873996621e0..18760dcf78ae66bdefece0a6ae699c3b2231a76a 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -889,7 +889,15 @@ struct PathSprite { struct PathVertexOutput { float4 position: SV_Position; + nointerpolation uint sprite_id: TEXCOORD0; + nointerpolation float4 solid_color: COLOR0; + nointerpolation float4 color0: COLOR1; + nointerpolation float4 color1: COLOR2; float4 clip_distance: SV_ClipDistance; +}; + +struct PathFragmentInput { + float4 position: SV_Position; nointerpolation uint sprite_id: TEXCOORD0; nointerpolation float4 solid_color: COLOR0; nointerpolation float4 color0: COLOR1; @@ -923,12 +931,7 @@ PathVertexOutput paths_vertex(PathVertexInput input) { return output; } -float4 paths_fragment(PathVertexOutput input): SV_Target { - float4 zero = 0.0; - if (any(input.clip_distance < zero)) { - return zero; - } - +float4 paths_fragment(PathFragmentInput input): SV_Target { PathSprite sprite = path_sprites[input.sprite_id]; Background background = sprite.color; float4 color = gradient_color(background, input.position.xy, sprite.bounds, From 158732eb179b2469e03fab77a58b76d87d293dcb Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 11:08:30 +0800 Subject: [PATCH 18/45] Revert "Fix path rendering - draw all paths w/ one regular draw call" This reverts commit 83d942611f5eda5245eaddcc35e052d13b58b925. --- .../src/platform/windows/directx_renderer.rs | 255 ++++++++++-------- crates/gpui/src/platform/windows/shaders.hlsl | 27 +- 2 files changed, 152 insertions(+), 130 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 542c90444d0edc7d15fa7bfd3c67281ef9618c1b..4c8642e7c236aec6ca8790b29d20c32b18128e18 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -59,6 +59,14 @@ struct DirectXGlobalElements { blend_state: ID3D11BlendState, } +#[repr(C)] +struct DrawInstancedIndirectArgs { + vertex_count_per_instance: u32, + instance_count: u32, + start_vertex_location: u32, + start_instance_location: u32, +} + // #[cfg(not(feature = "enable-renderdoc"))] // struct DirectComposition { // comp_device: IDCompositionDevice, @@ -273,12 +281,22 @@ impl DirectXRenderer { } let mut vertices = Vec::new(); let mut sprites = Vec::with_capacity(paths.len()); - + let mut draw_indirect_commands = Vec::with_capacity(paths.len()); + let mut start_vertex_location = 0; for (i, path) in paths.iter().enumerate() { - vertices.extend(path.vertices.iter().map(|v| DirectXPathVertex { + draw_indirect_commands.push(DrawInstancedIndirectArgs { + vertex_count_per_instance: path.vertices.len() as u32, + instance_count: 1, + start_vertex_location, + start_instance_location: i as u32, + }); + start_vertex_location += path.vertices.len() as u32; + + vertices.extend(path.vertices.iter().map(|v| PathVertex { xy_position: v.xy_position, - content_mask: path.content_mask.bounds, - sprite_index: i as u32, + content_mask: ContentMask { + bounds: path.content_mask.bounds, + }, })); sprites.push(PathSprite { @@ -295,7 +313,7 @@ impl DirectXRenderer { .map(|input| update_paths_pipeline_buffer(&mut self.pipelines.paths_pipeline, input)); update_buffer( &self.devices.device_context, - &self.pipelines.paths_pipeline.instance_buffer, + &self.pipelines.paths_pipeline.buffer, &sprites, )?; update_paths_vertex_capacity( @@ -309,40 +327,32 @@ impl DirectXRenderer { &self.pipelines.paths_pipeline.vertex_buffer, &vertices, )?; + update_indirect_buffer_capacity( + &self.pipelines.paths_pipeline, + draw_indirect_commands.len(), + &self.devices.device, + ) + .map(|input| update_paths_indirect_buffer(&mut self.pipelines.paths_pipeline, input)); + update_buffer( + &self.devices.device_context, + &self.pipelines.paths_pipeline.indirect_draw_buffer, + &draw_indirect_commands, + )?; + prepare_indirect_draws( + &self.devices.device_context, + &self.pipelines.paths_pipeline, + &self.context.viewport, + &self.globals.global_params_buffer, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + )?; - let device_context = &self.devices.device_context; - unsafe { - device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - device_context.VSSetShader(&self.pipelines.paths_pipeline.vertex, None); - device_context.PSSetShader(&self.pipelines.paths_pipeline.fragment, None); - device_context.VSSetConstantBuffers(0, Some(&self.globals.global_params_buffer)); - device_context.PSSetConstantBuffers(0, Some(&self.globals.global_params_buffer)); - device_context.VSSetShaderResources( - 2, - Some(&[Some(self.pipelines.paths_pipeline.instance_view.clone())]), - ); - device_context.PSSetShaderResources( - 2, - Some(&[Some(self.pipelines.paths_pipeline.instance_view.clone())]), + for i in 0..paths.len() { + draw_indirect( + &self.devices.device_context, + &self.pipelines.paths_pipeline.indirect_draw_buffer, + (i * std::mem::size_of::()) as u32, ); - device_context.PSSetSamplers(0, Some(&self.globals.sampler)); - device_context.OMSetBlendState(&self.globals.blend_state, None, 0xffffffff); - let stride = std::mem::size_of::() as u32; - let offset = 0u32; - device_context.IASetVertexBuffers( - 0, - 1, - Some([Some(self.pipelines.paths_pipeline.vertex_buffer.clone())].as_ptr()), - Some(&stride), - Some(&offset), - ); - device_context.IASetInputLayout(&self.pipelines.paths_pipeline.input_layout); } - - unsafe { - device_context.Draw(vertices.len() as u32, 0); - } - Ok(()) } @@ -616,18 +626,19 @@ struct PipelineState { struct PathsPipelineState { vertex: ID3D11VertexShader, fragment: ID3D11PixelShader, - instance_buffer: ID3D11Buffer, - instance_buffer_size: usize, + buffer: ID3D11Buffer, + buffer_size: usize, vertex_buffer: ID3D11Buffer, vertex_buffer_size: usize, - instance_view: ID3D11ShaderResourceView, - vertex_view: ID3D11ShaderResourceView, - input_layout: ID3D11InputLayout, + indirect_draw_buffer: ID3D11Buffer, + indirect_buffer_size: usize, + view: [Option; 1], + vertex_view: [Option; 1], } impl PathsPipelineState { fn new(device: &ID3D11Device) -> Result { - let (vertex, shader_blob) = { + let vertex = { let shader_blob = shader_resources::build_shader_blob("paths_vertex", "vs_5_0")?; let bytes = unsafe { std::slice::from_raw_parts( @@ -635,7 +646,7 @@ impl PathsPipelineState { shader_blob.GetBufferSize(), ) }; - (create_vertex_shader(device, bytes)?, shader_blob) + create_vertex_shader(device, bytes)? }; let fragment = { let shader_blob = shader_resources::build_shader_blob("paths_fragment", "ps_5_0")?; @@ -647,64 +658,23 @@ impl PathsPipelineState { }; create_fragment_shader(device, bytes)? }; - let instance_buffer = create_buffer(device, std::mem::size_of::(), 32)?; - let instance_view = create_buffer_view(device, &instance_buffer)?; - let vertex_buffer = create_buffer(device, std::mem::size_of::(), 32)?; + let buffer = create_buffer(device, std::mem::size_of::(), 32)?; + let view = create_buffer_view(device, &buffer)?; + let vertex_buffer = + create_buffer(device, std::mem::size_of::>(), 32)?; let vertex_view = create_buffer_view(device, &vertex_buffer)?; - - // Create input layout - let input_layout = unsafe { - let shader_bytes = std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *const u8, - shader_blob.GetBufferSize(), - ); - 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_R32G32B32A32_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: 24, - InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA, - InstanceDataStepRate: 0, - }, - ], - shader_bytes, - Some(&mut layout), - )?; - layout.unwrap() - }; - + let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?; Ok(Self { vertex, fragment, - instance_buffer, - instance_buffer_size: 32, + buffer, + buffer_size: 32, vertex_buffer, vertex_buffer_size: 32, - instance_view, + indirect_draw_buffer, + indirect_buffer_size: 32, + view, vertex_view, - input_layout, }) } } @@ -716,14 +686,6 @@ struct PathSprite { color: Background, } -#[derive(Clone, Debug)] -#[repr(C)] -struct DirectXPathVertex { - xy_position: Point, - content_mask: Bounds, - sprite_index: u32, -} - fn get_dxgi_factory() -> Result { #[cfg(debug_assertions)] let factory_flag = DXGI_CREATE_FACTORY_DEBUG; @@ -956,7 +918,7 @@ fn create_pipieline( fragment, buffer, buffer_size, - view: [Some(view)], + view, }) } @@ -997,10 +959,24 @@ fn create_buffer( fn create_buffer_view( device: &ID3D11Device, buffer: &ID3D11Buffer, -) -> Result { +) -> Result<[Option; 1]> { let mut view = None; unsafe { device.CreateShaderResourceView(buffer, None, Some(&mut view)) }?; - Ok(view.unwrap()) + Ok([view]) +} + +fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: u32) -> Result { + let desc = D3D11_BUFFER_DESC { + ByteWidth: std::mem::size_of::() as u32 * buffer_size, + Usage: D3D11_USAGE_DYNAMIC, + BindFlags: D3D11_BIND_INDEX_BUFFER.0 as u32, + CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32, + MiscFlags: D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS.0 as u32, + StructureByteStride: std::mem::size_of::() as u32, + }; + let mut buffer = None; + unsafe { device.CreateBuffer(&desc, None, Some(&mut buffer)) }?; + Ok(buffer.unwrap()) } fn update_global_params( @@ -1055,15 +1031,15 @@ fn update_buffer_capacity( let buffer_size = data_size.next_power_of_two(); let buffer = create_buffer(device, element_size, buffer_size).unwrap(); let view = create_buffer_view(device, &buffer).unwrap(); - Some((buffer, buffer_size, [Some(view)])) + Some((buffer, buffer_size, view)) } fn update_paths_buffer_capacity( pipeline: &PathsPipelineState, data_size: usize, device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize, ID3D11ShaderResourceView)> { - if pipeline.instance_buffer_size >= data_size { +) -> Option<(ID3D11Buffer, usize, [Option; 1])> { + if pipeline.buffer_size >= data_size { return None; } let buffer_size = data_size.next_power_of_two(); @@ -1076,14 +1052,14 @@ fn update_paths_vertex_capacity( pipeline: &PathsPipelineState, vertex_size: usize, device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize, ID3D11ShaderResourceView)> { +) -> Option<(ID3D11Buffer, usize, [Option; 1])> { if pipeline.vertex_buffer_size >= vertex_size { return None; } let vertex_size = vertex_size.next_power_of_two(); let buffer = create_buffer( device, - std::mem::size_of::(), + std::mem::size_of::>(), vertex_size, ) .unwrap(); @@ -1091,6 +1067,19 @@ fn update_paths_vertex_capacity( Some((buffer, vertex_size, view)) } +fn update_indirect_buffer_capacity( + pipeline: &PathsPipelineState, + data_size: usize, + device: &ID3D11Device, +) -> Option<(ID3D11Buffer, usize)> { + if pipeline.indirect_buffer_size >= data_size { + return None; + } + let buffer_size = data_size.next_power_of_two(); + let buffer = create_indirect_draw_buffer(device, data_size as u32).unwrap(); + Some((buffer, buffer_size)) +} + fn update_pipeline( pipeline: &mut PipelineState, input: (ID3D11Buffer, usize, [Option; 1]), @@ -1102,22 +1091,27 @@ fn update_pipeline( fn update_paths_pipeline_buffer( pipeline: &mut PathsPipelineState, - input: (ID3D11Buffer, usize, ID3D11ShaderResourceView), + input: (ID3D11Buffer, usize, [Option; 1]), ) { - pipeline.instance_buffer = input.0; - pipeline.instance_buffer_size = input.1; - pipeline.instance_view = input.2; + pipeline.buffer = input.0; + pipeline.buffer_size = input.1; + pipeline.view = input.2; } fn update_paths_pipeline_vertex( pipeline: &mut PathsPipelineState, - input: (ID3D11Buffer, usize, ID3D11ShaderResourceView), + input: (ID3D11Buffer, usize, [Option; 1]), ) { pipeline.vertex_buffer = input.0; pipeline.vertex_buffer_size = input.1; pipeline.vertex_view = input.2; } +fn update_paths_indirect_buffer(pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize)) { + pipeline.indirect_draw_buffer = input.0; + pipeline.indirect_buffer_size = input.1; +} + fn update_buffer( device_context: &ID3D11DeviceContext, buffer: &ID3D11Buffer, @@ -1132,6 +1126,37 @@ fn update_buffer( Ok(()) } +fn prepare_indirect_draws( + device_context: &ID3D11DeviceContext, + pipeline: &PathsPipelineState, + viewport: &[D3D11_VIEWPORT], + global_params: &[Option], + topology: D3D_PRIMITIVE_TOPOLOGY, +) -> Result<()> { + unsafe { + device_context.VSSetShaderResources(1, Some(&pipeline.vertex_view)); + device_context.VSSetShaderResources(2, Some(&pipeline.view)); + device_context.PSSetShaderResources(2, Some(&pipeline.view)); + device_context.IASetPrimitiveTopology(topology); + device_context.RSSetViewports(Some(viewport)); + device_context.VSSetShader(&pipeline.vertex, None); + device_context.PSSetShader(&pipeline.fragment, None); + device_context.VSSetConstantBuffers(0, Some(global_params)); + device_context.PSSetConstantBuffers(0, Some(global_params)); + } + Ok(()) +} + +fn draw_indirect( + device_context: &ID3D11DeviceContext, + indirect_draw_buffer: &ID3D11Buffer, + offset: u32, +) { + unsafe { + device_context.DrawInstancedIndirect(indirect_draw_buffer, offset); + } +} + fn draw_normal( device_context: &ID3D11DeviceContext, pipeline: &PipelineState, diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index 18760dcf78ae66bdefece0a6ae699c3b2231a76a..3438e708a3a38154354120388f1babc3ec8ec020 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -256,7 +256,7 @@ float pick_corner_radius(float2 center_to_point, Corners corner_radii) { } } -float4 to_device_position_transformed(float2 unit_vertex, Bounds bounds, +float4 to_device_position_transformed(float2 unit_vertex, Bounds bounds, TransformationMatrix transformation) { float2 position = unit_vertex * bounds.size + bounds.origin; float2 transformed = mul(position, transformation.rotation_scale) + transformation.translation; @@ -876,10 +876,9 @@ float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET { ** */ -struct PathVertexInput { - float2 xy_position: POSITION; - float4 content_mask: TEXCOORD0; - uint sprite_index: TEXCOORD1; +struct PathVertex { + float2 xy_position; + Bounds content_mask; }; struct PathSprite { @@ -904,19 +903,17 @@ struct PathFragmentInput { nointerpolation float4 color1: COLOR2; }; +StructuredBuffer path_vertices: register(t1); StructuredBuffer path_sprites: register(t2); -PathVertexOutput paths_vertex(PathVertexInput input) { - PathSprite sprite = path_sprites[input.sprite_index]; - - Bounds content_mask; - content_mask.origin = input.content_mask.xy; - content_mask.size = input.content_mask.zw; +PathVertexOutput paths_vertex(uint vertex_id: SV_VertexID, uint instance_id: SV_InstanceID) { + PathVertex v = path_vertices[vertex_id]; + PathSprite sprite = path_sprites[instance_id]; PathVertexOutput output; - output.position = to_device_position_impl(input.xy_position); - output.clip_distance = distance_from_clip_rect_impl(input.xy_position, content_mask); - output.sprite_id = input.sprite_index; + output.position = to_device_position_impl(v.xy_position); + output.clip_distance = distance_from_clip_rect_impl(v.xy_position, v.content_mask); + output.sprite_id = instance_id; GradientColor gradient = prepare_gradient_color( sprite.color.tag, @@ -974,7 +971,7 @@ UnderlineVertexOutput underline_vertex(uint vertex_id: SV_VertexID, uint underli float2 unit_vertex = float2(float(vertex_id & 1u), 0.5 * float(vertex_id & 2u)); Underline underline = underlines[underline_id]; float4 device_position = to_device_position(unit_vertex, underline.bounds); - float4 clip_distance = distance_from_clip_rect(unit_vertex, underline.bounds, + float4 clip_distance = distance_from_clip_rect(unit_vertex, underline.bounds, underline.content_mask); float4 color = hsla_to_rgba(underline.color); From 291691ca0eb1b235fc9e100590de457f3060114d Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 11:24:55 +0800 Subject: [PATCH 19/45] fix paths rendering --- .../src/platform/windows/directx_renderer.rs | 99 +++++++++++++++++-- crates/gpui/src/platform/windows/shaders.hlsl | 10 +- 2 files changed, 93 insertions(+), 16 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 4c8642e7c236aec6ca8790b29d20c32b18128e18..9a457420aa2affb4d64b134d2a111b0f6839e695 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -324,7 +324,11 @@ impl DirectXRenderer { .map(|input| update_paths_pipeline_vertex(&mut self.pipelines.paths_pipeline, input)); update_buffer( &self.devices.device_context, - &self.pipelines.paths_pipeline.vertex_buffer, + self.pipelines + .paths_pipeline + .vertex_buffer + .as_ref() + .unwrap(), &vertices, )?; update_indirect_buffer_capacity( @@ -628,10 +632,11 @@ struct PathsPipelineState { fragment: ID3D11PixelShader, buffer: ID3D11Buffer, buffer_size: usize, - vertex_buffer: ID3D11Buffer, + vertex_buffer: Option, vertex_buffer_size: usize, indirect_draw_buffer: ID3D11Buffer, indirect_buffer_size: usize, + input_layout: ID3D11InputLayout, view: [Option; 1], vertex_view: [Option; 1], } @@ -663,7 +668,71 @@ impl PathsPipelineState { let vertex_buffer = create_buffer(device, std::mem::size_of::>(), 32)?; let vertex_view = create_buffer_view(device, &vertex_buffer)?; + let vertex_buffer = Some(vertex_buffer); let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?; + // Create input layout + let input_layout = unsafe { + let (vertex, shader_blob) = { + let shader_blob = shader_resources::build_shader_blob("paths_vertex", "vs_5_0")?; + let bytes = unsafe { + std::slice::from_raw_parts( + shader_blob.GetBufferPointer() as *mut u8, + shader_blob.GetBufferSize(), + ) + }; + (create_vertex_shader(device, bytes)?, shader_blob) + }; + let fragment = { + let shader_blob = shader_resources::build_shader_blob("paths_fragment", "ps_5_0")?; + let bytes = unsafe { + std::slice::from_raw_parts( + shader_blob.GetBufferPointer() as *mut u8, + shader_blob.GetBufferSize(), + ) + }; + create_fragment_shader(device, bytes)? + }; + let shader_bytes = std::slice::from_raw_parts( + shader_blob.GetBufferPointer() as *const u8, + shader_blob.GetBufferSize(), + ); + 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_R32G32_FLOAT, + InputSlot: 0, + AlignedByteOffset: 16, + InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA, + InstanceDataStepRate: 0, + }, + ], + shader_bytes, + Some(&mut layout), + )?; + layout.unwrap() + }; + Ok(Self { vertex, fragment, @@ -673,6 +742,7 @@ impl PathsPipelineState { vertex_buffer_size: 32, indirect_draw_buffer, indirect_buffer_size: 32, + input_layout, view, vertex_view, }) @@ -965,11 +1035,11 @@ fn create_buffer_view( Ok([view]) } -fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: u32) -> Result { +fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: usize) -> Result { let desc = D3D11_BUFFER_DESC { - ByteWidth: std::mem::size_of::() as u32 * buffer_size, + ByteWidth: (std::mem::size_of::() * buffer_size) as u32, Usage: D3D11_USAGE_DYNAMIC, - BindFlags: D3D11_BIND_INDEX_BUFFER.0 as u32, + BindFlags: D3D11_BIND_SHADER_RESOURCE.0 as u32, CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32, MiscFlags: D3D11_RESOURCE_MISC_DRAWINDIRECT_ARGS.0 as u32, StructureByteStride: std::mem::size_of::() as u32, @@ -1076,7 +1146,7 @@ fn update_indirect_buffer_capacity( return None; } let buffer_size = data_size.next_power_of_two(); - let buffer = create_indirect_draw_buffer(device, data_size as u32).unwrap(); + let buffer = create_indirect_draw_buffer(device, data_size).unwrap(); Some((buffer, buffer_size)) } @@ -1102,7 +1172,7 @@ fn update_paths_pipeline_vertex( pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize, [Option; 1]), ) { - pipeline.vertex_buffer = input.0; + pipeline.vertex_buffer = Some(input.0); pipeline.vertex_buffer_size = input.1; pipeline.vertex_view = input.2; } @@ -1134,15 +1204,24 @@ fn prepare_indirect_draws( topology: D3D_PRIMITIVE_TOPOLOGY, ) -> Result<()> { unsafe { - device_context.VSSetShaderResources(1, Some(&pipeline.vertex_view)); - device_context.VSSetShaderResources(2, Some(&pipeline.view)); - device_context.PSSetShaderResources(2, Some(&pipeline.view)); + device_context.VSSetShaderResources(1, Some(&pipeline.view)); + device_context.PSSetShaderResources(1, Some(&pipeline.view)); device_context.IASetPrimitiveTopology(topology); device_context.RSSetViewports(Some(viewport)); device_context.VSSetShader(&pipeline.vertex, None); device_context.PSSetShader(&pipeline.fragment, None); device_context.VSSetConstantBuffers(0, Some(global_params)); device_context.PSSetConstantBuffers(0, Some(global_params)); + let stride = std::mem::size_of::>() as u32; + let offset = 0u32; + device_context.IASetVertexBuffers( + 0, + 1, + Some(&pipeline.vertex_buffer), + Some(&stride), + Some(&offset), + ); + device_context.IASetInputLayout(&pipeline.input_layout); } Ok(()) } diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index 3438e708a3a38154354120388f1babc3ec8ec020..7e59bb714e07706ab4f51a0e9ac5a436777c529a 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -877,8 +877,8 @@ float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET { */ struct PathVertex { - float2 xy_position; - Bounds content_mask; + float2 xy_position: POSITION; + Bounds content_mask: TEXCOORD; }; struct PathSprite { @@ -903,11 +903,9 @@ struct PathFragmentInput { nointerpolation float4 color1: COLOR2; }; -StructuredBuffer path_vertices: register(t1); -StructuredBuffer path_sprites: register(t2); +StructuredBuffer path_sprites: register(t1); -PathVertexOutput paths_vertex(uint vertex_id: SV_VertexID, uint instance_id: SV_InstanceID) { - PathVertex v = path_vertices[vertex_id]; +PathVertexOutput paths_vertex(PathVertex v, uint instance_id: SV_InstanceID) { PathSprite sprite = path_sprites[instance_id]; PathVertexOutput output; From f715acc92a3bb4662c79cf7bf8b87ff4dcc0eb7e Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 11:37:51 +0800 Subject: [PATCH 20/45] remove unused --- .../src/platform/windows/directx_renderer.rs | 57 +++++-------------- 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 9a457420aa2affb4d64b134d2a111b0f6839e695..a3931519f974908ee9727e70acd569f6cc4b606f 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -638,12 +638,11 @@ struct PathsPipelineState { indirect_buffer_size: usize, input_layout: ID3D11InputLayout, view: [Option; 1], - vertex_view: [Option; 1], } impl PathsPipelineState { fn new(device: &ID3D11Device) -> Result { - let vertex = { + let (vertex, vertex_shader) = { let shader_blob = shader_resources::build_shader_blob("paths_vertex", "vs_5_0")?; let bytes = unsafe { std::slice::from_raw_parts( @@ -651,7 +650,7 @@ impl PathsPipelineState { shader_blob.GetBufferSize(), ) }; - create_vertex_shader(device, bytes)? + (create_vertex_shader(device, bytes)?, shader_blob) }; let fragment = { let shader_blob = shader_resources::build_shader_blob("paths_fragment", "ps_5_0")?; @@ -665,36 +664,17 @@ impl PathsPipelineState { }; let buffer = create_buffer(device, std::mem::size_of::(), 32)?; let view = create_buffer_view(device, &buffer)?; - let vertex_buffer = - create_buffer(device, std::mem::size_of::>(), 32)?; - let vertex_view = create_buffer_view(device, &vertex_buffer)?; - let vertex_buffer = Some(vertex_buffer); + let vertex_buffer = Some(create_buffer( + device, + std::mem::size_of::>(), + 32, + )?); let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?; // Create input layout let input_layout = unsafe { - let (vertex, shader_blob) = { - let shader_blob = shader_resources::build_shader_blob("paths_vertex", "vs_5_0")?; - let bytes = unsafe { - std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *mut u8, - shader_blob.GetBufferSize(), - ) - }; - (create_vertex_shader(device, bytes)?, shader_blob) - }; - let fragment = { - let shader_blob = shader_resources::build_shader_blob("paths_fragment", "ps_5_0")?; - let bytes = unsafe { - std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *mut u8, - shader_blob.GetBufferSize(), - ) - }; - create_fragment_shader(device, bytes)? - }; let shader_bytes = std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *const u8, - shader_blob.GetBufferSize(), + vertex_shader.GetBufferPointer() as *const u8, + vertex_shader.GetBufferSize(), ); let mut layout = None; device.CreateInputLayout( @@ -744,7 +724,6 @@ impl PathsPipelineState { indirect_buffer_size: 32, input_layout, view, - vertex_view, }) } } @@ -1122,7 +1101,7 @@ fn update_paths_vertex_capacity( pipeline: &PathsPipelineState, vertex_size: usize, device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize, [Option; 1])> { +) -> Option<(ID3D11Buffer, usize)> { if pipeline.vertex_buffer_size >= vertex_size { return None; } @@ -1133,8 +1112,7 @@ fn update_paths_vertex_capacity( vertex_size, ) .unwrap(); - let view = create_buffer_view(device, &buffer).unwrap(); - Some((buffer, vertex_size, view)) + Some((buffer, vertex_size)) } fn update_indirect_buffer_capacity( @@ -1168,13 +1146,9 @@ fn update_paths_pipeline_buffer( pipeline.view = input.2; } -fn update_paths_pipeline_vertex( - pipeline: &mut PathsPipelineState, - input: (ID3D11Buffer, usize, [Option; 1]), -) { +fn update_paths_pipeline_vertex(pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize)) { pipeline.vertex_buffer = Some(input.0); pipeline.vertex_buffer_size = input.1; - pipeline.vertex_view = input.2; } fn update_paths_indirect_buffer(pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize)) { @@ -1212,14 +1186,13 @@ fn prepare_indirect_draws( device_context.PSSetShader(&pipeline.fragment, None); device_context.VSSetConstantBuffers(0, Some(global_params)); device_context.PSSetConstantBuffers(0, Some(global_params)); - let stride = std::mem::size_of::>() as u32; - let offset = 0u32; + const STRIDE: u32 = std::mem::size_of::>() as u32; device_context.IASetVertexBuffers( 0, 1, Some(&pipeline.vertex_buffer), - Some(&stride), - Some(&offset), + Some(&STRIDE), + Some(&0), ); device_context.IASetInputLayout(&pipeline.input_layout); } From 2017ce3699e9e7afa746b907956f4fea1810ad2c Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 14:04:49 +0800 Subject: [PATCH 21/45] refactor --- .../src/platform/windows/directx_renderer.rs | 230 +++++++----------- 1 file changed, 94 insertions(+), 136 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index a3931519f974908ee9727e70acd569f6cc4b606f..dd5e1a5b32e58b0d6cca9e49aafe7ae8e37840a1 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -45,12 +45,12 @@ struct DirectXContext { } struct DirectXRenderPipelines { - shadow_pipeline: PipelineState, - quad_pipeline: PipelineState, + shadow_pipeline: PipelineState, + quad_pipeline: PipelineState, paths_pipeline: PathsPipelineState, - underline_pipeline: PipelineState, - mono_sprites: PipelineState, - poly_sprites: PipelineState, + underline_pipeline: PipelineState, + mono_sprites: PipelineState, + poly_sprites: PipelineState, } struct DirectXGlobalElements { @@ -225,16 +225,9 @@ impl DirectXRenderer { if shadows.is_empty() { return Ok(()); } - update_buffer_capacity( - &self.pipelines.shadow_pipeline, - std::mem::size_of::(), - shadows.len(), + self.pipelines.shadow_pipeline.update_buffer( &self.devices.device, - ) - .map(|input| update_pipeline(&mut self.pipelines.shadow_pipeline, input)); - update_buffer( &self.devices.device_context, - &self.pipelines.shadow_pipeline.buffer, shadows, )?; draw_normal( @@ -252,16 +245,9 @@ impl DirectXRenderer { if quads.is_empty() { return Ok(()); } - update_buffer_capacity( - &self.pipelines.quad_pipeline, - std::mem::size_of::(), - quads.len(), + self.pipelines.quad_pipeline.update_buffer( &self.devices.device, - ) - .map(|input| update_pipeline(&mut self.pipelines.quad_pipeline, input)); - update_buffer( &self.devices.device_context, - &self.pipelines.quad_pipeline.buffer, quads, )?; draw_normal( @@ -364,16 +350,9 @@ impl DirectXRenderer { if underlines.is_empty() { return Ok(()); } - update_buffer_capacity( - &self.pipelines.underline_pipeline, - std::mem::size_of::(), - underlines.len(), + self.pipelines.underline_pipeline.update_buffer( &self.devices.device, - ) - .map(|input| update_pipeline(&mut self.pipelines.underline_pipeline, input)); - update_buffer( &self.devices.device_context, - &self.pipelines.underline_pipeline.buffer, underlines, )?; draw_normal( @@ -395,19 +374,12 @@ impl DirectXRenderer { if sprites.is_empty() { return Ok(()); } - let texture_view = self.atlas.get_texture_view(texture_id); - update_buffer_capacity( - &self.pipelines.mono_sprites, - std::mem::size_of::(), - sprites.len(), + self.pipelines.mono_sprites.update_buffer( &self.devices.device, - ) - .map(|input| update_pipeline(&mut self.pipelines.mono_sprites, input)); - update_buffer( &self.devices.device_context, - &self.pipelines.mono_sprites.buffer, sprites, )?; + let texture_view = self.atlas.get_texture_view(texture_id); draw_with_texture( &self.devices.device_context, &self.pipelines.mono_sprites, @@ -427,19 +399,12 @@ impl DirectXRenderer { if sprites.is_empty() { return Ok(()); } - let texture_view = self.atlas.get_texture_view(texture_id); - update_buffer_capacity( - &self.pipelines.poly_sprites, - std::mem::size_of::(), - sprites.len(), + self.pipelines.poly_sprites.update_buffer( &self.devices.device, - ) - .map(|input| update_pipeline(&mut self.pipelines.poly_sprites, input)); - update_buffer( &self.devices.device_context, - &self.pipelines.poly_sprites.buffer, sprites, )?; + let texture_view = self.atlas.get_texture_view(texture_id); draw_with_texture( &self.devices.device_context, &self.pipelines.poly_sprites, @@ -490,47 +455,35 @@ impl DirectXContext { impl DirectXRenderPipelines { pub fn new(device: &ID3D11Device) -> Result { - let shadow_pipeline = create_pipieline( + let shadow_pipeline = PipelineState::new( device, + "shadow_pipeline", "shadow_vertex", "shadow_fragment", - std::mem::size_of::(), - 32, - )?; - let quad_pipeline = create_pipieline( - device, - "quad_vertex", - "quad_fragment", - std::mem::size_of::(), 32, )?; - // let paths_pipeline = create_pipieline( - // device, - // "paths_vertex", - // "paths_fragment", - // std::mem::size_of::(), - // 32, - // )?; + let quad_pipeline = + PipelineState::new(device, "quad_pipeline", "quad_vertex", "quad_fragment", 32)?; let paths_pipeline = PathsPipelineState::new(device)?; - let underline_pipeline = create_pipieline( + let underline_pipeline = PipelineState::new( device, + "underline_pipeline", "underline_vertex", "underline_fragment", - std::mem::size_of::(), 32, )?; - let mono_sprites = create_pipieline( + let mono_sprites = PipelineState::new( device, + "monochrome_sprite_pipeline", "monochrome_sprite_vertex", "monochrome_sprite_fragment", - std::mem::size_of::(), 32, )?; - let poly_sprites = create_pipieline( + let poly_sprites = PipelineState::new( device, + "polychrome_sprite_pipeline", "polychrome_sprite_vertex", "polychrome_sprite_fragment", - std::mem::size_of::(), 32, )?; @@ -619,12 +572,14 @@ struct GlobalParams { _pad: u64, } -struct PipelineState { +struct PipelineState { + label: &'static str, vertex: ID3D11VertexShader, fragment: ID3D11PixelShader, buffer: ID3D11Buffer, buffer_size: usize, view: [Option; 1], + _marker: std::marker::PhantomData, } struct PathsPipelineState { @@ -640,6 +595,71 @@ struct PathsPipelineState { view: [Option; 1], } +impl PipelineState { + fn new( + device: &ID3D11Device, + label: &'static str, + vertex_entry: &str, + fragment_entry: &str, + buffer_size: usize, + ) -> Result { + let vertex = { + let shader_blob = shader_resources::build_shader_blob(vertex_entry, "vs_5_0")?; + let bytes = unsafe { + std::slice::from_raw_parts( + shader_blob.GetBufferPointer() as *mut u8, + shader_blob.GetBufferSize(), + ) + }; + create_vertex_shader(device, bytes)? + }; + let fragment = { + let shader_blob = shader_resources::build_shader_blob(fragment_entry, "ps_5_0")?; + let bytes = unsafe { + std::slice::from_raw_parts( + shader_blob.GetBufferPointer() as *mut u8, + shader_blob.GetBufferSize(), + ) + }; + create_fragment_shader(device, bytes)? + }; + let buffer = create_buffer(device, std::mem::size_of::(), buffer_size)?; + let view = create_buffer_view(device, &buffer)?; + + Ok(PipelineState { + label, + vertex, + fragment, + buffer, + buffer_size, + view, + _marker: std::marker::PhantomData, + }) + } + + fn update_buffer( + &mut self, + device: &ID3D11Device, + device_context: &ID3D11DeviceContext, + data: &[T], + ) -> Result<()> { + if self.buffer_size < data.len() { + let new_buffer_size = data.len().next_power_of_two(); + let buffer = create_buffer(device, std::mem::size_of::(), new_buffer_size)?; + let view = create_buffer_view(device, &buffer)?; + self.buffer = buffer; + self.view = view; + } + unsafe { + let mut dest = std::mem::zeroed(); + device_context.Map(&self.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut dest))?; + std::ptr::copy_nonoverlapping(data.as_ptr(), dest.pData as _, data.len()); + device_context.Unmap(&self.buffer, 0); + } + Ok(()) + } +} + impl PathsPipelineState { fn new(device: &ID3D11Device) -> Result { let (vertex, vertex_shader) = { @@ -933,44 +953,6 @@ fn create_blend_state(device: &ID3D11Device) -> Result { } } -fn create_pipieline( - device: &ID3D11Device, - vertex_entry: &str, - fragment_entry: &str, - element_size: usize, - buffer_size: usize, -) -> Result { - let vertex = { - let shader_blob = shader_resources::build_shader_blob(vertex_entry, "vs_5_0")?; - let bytes = unsafe { - std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *mut u8, - shader_blob.GetBufferSize(), - ) - }; - create_vertex_shader(device, bytes)? - }; - let fragment = { - let shader_blob = shader_resources::build_shader_blob(fragment_entry, "ps_5_0")?; - let bytes = unsafe { - std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *mut u8, - shader_blob.GetBufferSize(), - ) - }; - create_fragment_shader(device, bytes)? - }; - let buffer = create_buffer(device, element_size, buffer_size)?; - let view = create_buffer_view(device, &buffer)?; - Ok(PipelineState { - vertex, - fragment, - buffer, - buffer_size, - view, - }) -} - fn create_vertex_shader(device: &ID3D11Device, bytes: &[u8]) -> Result { unsafe { let mut shader = None; @@ -1068,21 +1050,6 @@ fn pre_draw( Ok(()) } -fn update_buffer_capacity( - pipeline: &PipelineState, - element_size: usize, - data_size: usize, - device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize, [Option; 1])> { - if pipeline.buffer_size >= data_size { - return None; - } - let buffer_size = data_size.next_power_of_two(); - let buffer = create_buffer(device, element_size, buffer_size).unwrap(); - let view = create_buffer_view(device, &buffer).unwrap(); - Some((buffer, buffer_size, view)) -} - fn update_paths_buffer_capacity( pipeline: &PathsPipelineState, data_size: usize, @@ -1128,15 +1095,6 @@ fn update_indirect_buffer_capacity( Some((buffer, buffer_size)) } -fn update_pipeline( - pipeline: &mut PipelineState, - input: (ID3D11Buffer, usize, [Option; 1]), -) { - pipeline.buffer = input.0; - pipeline.buffer_size = input.1; - pipeline.view = input.2; -} - fn update_paths_pipeline_buffer( pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize, [Option; 1]), @@ -1209,9 +1167,9 @@ fn draw_indirect( } } -fn draw_normal( +fn draw_normal( device_context: &ID3D11DeviceContext, - pipeline: &PipelineState, + pipeline: &PipelineState, viewport: &[D3D11_VIEWPORT], global_params: &[Option], topology: D3D_PRIMITIVE_TOPOLOGY, @@ -1233,9 +1191,9 @@ fn draw_normal( Ok(()) } -fn draw_with_texture( +fn draw_with_texture( device_context: &ID3D11DeviceContext, - pipeline: &PipelineState, + pipeline: &PipelineState, texture: &[Option], viewport: &[D3D11_VIEWPORT], global_params: &[Option], From 1baafae3f7b4b3e175b9e52cff778b698902d0f9 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 14:14:31 +0800 Subject: [PATCH 22/45] refactor --- .../src/platform/windows/directx_renderer.rs | 121 ++++++++---------- 1 file changed, 54 insertions(+), 67 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index dd5e1a5b32e58b0d6cca9e49aafe7ae8e37840a1..273d5a1a2bbca0396c629bff9c56dcb0ddee5de5 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -230,13 +230,10 @@ impl DirectXRenderer { &self.devices.device_context, shadows, )?; - draw_normal( + self.pipelines.shadow_pipeline.draw( &self.devices.device_context, - &self.pipelines.shadow_pipeline, &self.context.viewport, &self.globals.global_params_buffer, - D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, - 4, shadows.len() as u32, ) } @@ -250,13 +247,10 @@ impl DirectXRenderer { &self.devices.device_context, quads, )?; - draw_normal( + self.pipelines.quad_pipeline.draw( &self.devices.device_context, - &self.pipelines.quad_pipeline, &self.context.viewport, &self.globals.global_params_buffer, - D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, - 4, quads.len() as u32, ) } @@ -355,13 +349,10 @@ impl DirectXRenderer { &self.devices.device_context, underlines, )?; - draw_normal( + self.pipelines.underline_pipeline.draw( &self.devices.device_context, - &self.pipelines.underline_pipeline, &self.context.viewport, &self.globals.global_params_buffer, - D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, - 4, underlines.len() as u32, ) } @@ -380,9 +371,8 @@ impl DirectXRenderer { sprites, )?; let texture_view = self.atlas.get_texture_view(texture_id); - draw_with_texture( + self.pipelines.mono_sprites.draw_with_texture( &self.devices.device_context, - &self.pipelines.mono_sprites, &texture_view, &self.context.viewport, &self.globals.global_params_buffer, @@ -405,9 +395,8 @@ impl DirectXRenderer { sprites, )?; let texture_view = self.atlas.get_texture_view(texture_id); - draw_with_texture( + self.pipelines.poly_sprites.draw_with_texture( &self.devices.device_context, - &self.pipelines.poly_sprites, &texture_view, &self.context.viewport, &self.globals.global_params_buffer, @@ -658,6 +647,55 @@ impl PipelineState { } Ok(()) } + + fn draw( + &self, + device_context: &ID3D11DeviceContext, + viewport: &[D3D11_VIEWPORT], + global_params: &[Option], + instance_count: u32, + ) -> Result<()> { + unsafe { + device_context.VSSetShaderResources(1, Some(&self.view)); + device_context.PSSetShaderResources(1, Some(&self.view)); + device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + device_context.RSSetViewports(Some(viewport)); + device_context.VSSetShader(&self.vertex, None); + device_context.PSSetShader(&self.fragment, None); + device_context.VSSetConstantBuffers(0, Some(global_params)); + device_context.PSSetConstantBuffers(0, Some(global_params)); + + device_context.DrawInstanced(4, instance_count, 0, 0); + } + Ok(()) + } + + fn draw_with_texture( + &self, + device_context: &ID3D11DeviceContext, + texture: &[Option], + viewport: &[D3D11_VIEWPORT], + global_params: &[Option], + sampler: &[Option], + instance_count: u32, + ) -> Result<()> { + unsafe { + device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + device_context.RSSetViewports(Some(viewport)); + device_context.VSSetShader(&self.vertex, None); + device_context.PSSetShader(&self.fragment, None); + device_context.VSSetConstantBuffers(0, Some(global_params)); + device_context.PSSetConstantBuffers(0, Some(global_params)); + device_context.VSSetShaderResources(1, Some(&self.view)); + device_context.PSSetShaderResources(1, Some(&self.view)); + device_context.PSSetSamplers(0, Some(sampler)); + device_context.VSSetShaderResources(0, Some(texture)); + device_context.PSSetShaderResources(0, Some(texture)); + + device_context.DrawInstanced(4, instance_count, 0, 0); + } + Ok(()) + } } impl PathsPipelineState { @@ -1167,57 +1205,6 @@ fn draw_indirect( } } -fn draw_normal( - device_context: &ID3D11DeviceContext, - pipeline: &PipelineState, - viewport: &[D3D11_VIEWPORT], - global_params: &[Option], - topology: D3D_PRIMITIVE_TOPOLOGY, - vertex_count: u32, - instance_count: u32, -) -> Result<()> { - unsafe { - device_context.VSSetShaderResources(1, Some(&pipeline.view)); - device_context.PSSetShaderResources(1, Some(&pipeline.view)); - device_context.IASetPrimitiveTopology(topology); - device_context.RSSetViewports(Some(viewport)); - device_context.VSSetShader(&pipeline.vertex, None); - device_context.PSSetShader(&pipeline.fragment, None); - device_context.VSSetConstantBuffers(0, Some(global_params)); - device_context.PSSetConstantBuffers(0, Some(global_params)); - - device_context.DrawInstanced(vertex_count, instance_count, 0, 0); - } - Ok(()) -} - -fn draw_with_texture( - device_context: &ID3D11DeviceContext, - pipeline: &PipelineState, - texture: &[Option], - viewport: &[D3D11_VIEWPORT], - global_params: &[Option], - sampler: &[Option], - instance_count: u32, -) -> Result<()> { - unsafe { - device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - device_context.RSSetViewports(Some(viewport)); - device_context.VSSetShader(&pipeline.vertex, None); - device_context.PSSetShader(&pipeline.fragment, None); - device_context.VSSetConstantBuffers(0, Some(global_params)); - device_context.PSSetConstantBuffers(0, Some(global_params)); - device_context.VSSetShaderResources(1, Some(&pipeline.view)); - device_context.PSSetShaderResources(1, Some(&pipeline.view)); - device_context.PSSetSamplers(0, Some(sampler)); - device_context.VSSetShaderResources(0, Some(texture)); - device_context.PSSetShaderResources(0, Some(texture)); - - device_context.DrawInstanced(4, instance_count, 0, 0); - } - Ok(()) -} - const BUFFER_COUNT: usize = 3; mod shader_resources { From 5ed8b13e4aca23e9bc410935b6ed75cd00f9620b Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 15:36:24 +0800 Subject: [PATCH 23/45] refactor --- .../src/platform/windows/directx_renderer.rs | 285 +++++++----------- 1 file changed, 112 insertions(+), 173 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 273d5a1a2bbca0396c629bff9c56dcb0ddee5de5..623383946a117e655cb10a21d08894688179b673 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -285,59 +285,19 @@ impl DirectXRenderer { }); } - update_paths_buffer_capacity( - &self.pipelines.paths_pipeline, - sprites.len(), + self.pipelines.paths_pipeline.update_buffer( &self.devices.device, - ) - .map(|input| update_paths_pipeline_buffer(&mut self.pipelines.paths_pipeline, input)); - update_buffer( &self.devices.device_context, - &self.pipelines.paths_pipeline.buffer, &sprites, - )?; - update_paths_vertex_capacity( - &mut self.pipelines.paths_pipeline, - vertices.len(), - &self.devices.device, - ) - .map(|input| update_paths_pipeline_vertex(&mut self.pipelines.paths_pipeline, input)); - update_buffer( - &self.devices.device_context, - self.pipelines - .paths_pipeline - .vertex_buffer - .as_ref() - .unwrap(), &vertices, - )?; - update_indirect_buffer_capacity( - &self.pipelines.paths_pipeline, - draw_indirect_commands.len(), - &self.devices.device, - ) - .map(|input| update_paths_indirect_buffer(&mut self.pipelines.paths_pipeline, input)); - update_buffer( - &self.devices.device_context, - &self.pipelines.paths_pipeline.indirect_draw_buffer, &draw_indirect_commands, )?; - prepare_indirect_draws( + self.pipelines.paths_pipeline.draw( &self.devices.device_context, - &self.pipelines.paths_pipeline, + paths.len(), &self.context.viewport, &self.globals.global_params_buffer, - D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, - )?; - - for i in 0..paths.len() { - draw_indirect( - &self.devices.device_context, - &self.pipelines.paths_pipeline.indirect_draw_buffer, - (i * std::mem::size_of::()) as u32, - ); - } - Ok(()) + ) } fn draw_underlines(&mut self, underlines: &[Underline]) -> Result<()> { @@ -634,18 +594,19 @@ impl PipelineState { ) -> Result<()> { if self.buffer_size < data.len() { let new_buffer_size = data.len().next_power_of_two(); + log::info!( + "Updating {} buffer size from {} to {}", + self.label, + self.buffer_size, + new_buffer_size + ); let buffer = create_buffer(device, std::mem::size_of::(), new_buffer_size)?; let view = create_buffer_view(device, &buffer)?; self.buffer = buffer; self.view = view; + self.buffer_size = new_buffer_size; } - unsafe { - let mut dest = std::mem::zeroed(); - device_context.Map(&self.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut dest))?; - std::ptr::copy_nonoverlapping(data.as_ptr(), dest.pData as _, data.len()); - device_context.Unmap(&self.buffer, 0); - } - Ok(()) + update_buffer(device_context, &self.buffer, data) } fn draw( @@ -784,6 +745,101 @@ impl PathsPipelineState { view, }) } + + fn update_buffer( + &mut self, + device: &ID3D11Device, + device_context: &ID3D11DeviceContext, + buffer_data: &[PathSprite], + vertices_data: &[PathVertex], + draw_commands: &[DrawInstancedIndirectArgs], + ) -> Result<()> { + if self.buffer_size < buffer_data.len() { + let new_buffer_size = buffer_data.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::(), 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, buffer_data)?; + 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::>(), + 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, + )?; + if self.indirect_buffer_size < draw_commands.len() { + let new_indirect_buffer_size = draw_commands.len().next_power_of_two(); + log::info!( + "Updating Paths Pipeline indirect buffer size from {} to {}", + self.indirect_buffer_size, + new_indirect_buffer_size + ); + let indirect_draw_buffer = + create_indirect_draw_buffer(device, new_indirect_buffer_size)?; + self.indirect_draw_buffer = indirect_draw_buffer; + self.indirect_buffer_size = new_indirect_buffer_size; + } + update_buffer(device_context, &self.indirect_draw_buffer, draw_commands)?; + Ok(()) + } + + fn draw( + &self, + device_context: &ID3D11DeviceContext, + count: usize, + viewport: &[D3D11_VIEWPORT], + global_params: &[Option], + ) -> Result<()> { + unsafe { + device_context.VSSetShaderResources(1, Some(&self.view)); + device_context.PSSetShaderResources(1, Some(&self.view)); + device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + device_context.RSSetViewports(Some(viewport)); + device_context.VSSetShader(&self.vertex, None); + device_context.PSSetShader(&self.fragment, None); + device_context.VSSetConstantBuffers(0, Some(global_params)); + device_context.PSSetConstantBuffers(0, Some(global_params)); + const STRIDE: u32 = std::mem::size_of::>() as u32; + device_context.IASetVertexBuffers( + 0, + 1, + Some(&self.vertex_buffer), + Some(&STRIDE), + Some(&0), + ); + device_context.IASetInputLayout(&self.input_layout); + } + for i in 0..count { + unsafe { + device_context.DrawInstancedIndirect( + &self.indirect_draw_buffer, + (i * std::mem::size_of::()) as u32, + ); + } + } + Ok(()) + } } #[derive(Clone, Debug, Eq, PartialEq)] @@ -1048,21 +1104,6 @@ fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: usize) -> Res Ok(buffer.unwrap()) } -fn update_global_params( - device_context: &ID3D11DeviceContext, - buffer: &[Option; 1], - globals: GlobalParams, -) -> Result<()> { - let buffer = buffer[0].as_ref().unwrap(); - unsafe { - let mut data = std::mem::zeroed(); - device_context.Map(buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, Some(&mut data))?; - std::ptr::copy_nonoverlapping(&globals, data.pData as *mut _, 1); - device_context.Unmap(buffer, 0); - } - Ok(()) -} - fn pre_draw( device_context: &ID3D11DeviceContext, global_params_buffer: &[Option; 1], @@ -1071,13 +1112,14 @@ fn pre_draw( clear_color: [f32; 4], blend_state: &ID3D11BlendState, ) -> Result<()> { - update_global_params( + let global_params = global_params_buffer[0].as_ref().unwrap(); + update_buffer( device_context, - global_params_buffer, - GlobalParams { + global_params, + &[GlobalParams { viewport_size: [view_port[0].Width, view_port[0].Height], ..Default::default() - }, + }], )?; unsafe { device_context.RSSetViewports(Some(view_port)); @@ -1088,70 +1130,6 @@ fn pre_draw( Ok(()) } -fn update_paths_buffer_capacity( - pipeline: &PathsPipelineState, - data_size: usize, - device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize, [Option; 1])> { - if pipeline.buffer_size >= data_size { - return None; - } - let buffer_size = data_size.next_power_of_two(); - let buffer = create_buffer(device, std::mem::size_of::(), buffer_size).unwrap(); - let view = create_buffer_view(device, &buffer).unwrap(); - Some((buffer, buffer_size, view)) -} - -fn update_paths_vertex_capacity( - pipeline: &PathsPipelineState, - vertex_size: usize, - device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize)> { - if pipeline.vertex_buffer_size >= vertex_size { - return None; - } - let vertex_size = vertex_size.next_power_of_two(); - let buffer = create_buffer( - device, - std::mem::size_of::>(), - vertex_size, - ) - .unwrap(); - Some((buffer, vertex_size)) -} - -fn update_indirect_buffer_capacity( - pipeline: &PathsPipelineState, - data_size: usize, - device: &ID3D11Device, -) -> Option<(ID3D11Buffer, usize)> { - if pipeline.indirect_buffer_size >= data_size { - return None; - } - let buffer_size = data_size.next_power_of_two(); - let buffer = create_indirect_draw_buffer(device, data_size).unwrap(); - Some((buffer, buffer_size)) -} - -fn update_paths_pipeline_buffer( - pipeline: &mut PathsPipelineState, - input: (ID3D11Buffer, usize, [Option; 1]), -) { - pipeline.buffer = input.0; - pipeline.buffer_size = input.1; - pipeline.view = input.2; -} - -fn update_paths_pipeline_vertex(pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize)) { - pipeline.vertex_buffer = Some(input.0); - pipeline.vertex_buffer_size = input.1; -} - -fn update_paths_indirect_buffer(pipeline: &mut PathsPipelineState, input: (ID3D11Buffer, usize)) { - pipeline.indirect_draw_buffer = input.0; - pipeline.indirect_buffer_size = input.1; -} - fn update_buffer( device_context: &ID3D11DeviceContext, buffer: &ID3D11Buffer, @@ -1166,45 +1144,6 @@ fn update_buffer( Ok(()) } -fn prepare_indirect_draws( - device_context: &ID3D11DeviceContext, - pipeline: &PathsPipelineState, - viewport: &[D3D11_VIEWPORT], - global_params: &[Option], - topology: D3D_PRIMITIVE_TOPOLOGY, -) -> Result<()> { - unsafe { - device_context.VSSetShaderResources(1, Some(&pipeline.view)); - device_context.PSSetShaderResources(1, Some(&pipeline.view)); - device_context.IASetPrimitiveTopology(topology); - device_context.RSSetViewports(Some(viewport)); - device_context.VSSetShader(&pipeline.vertex, None); - device_context.PSSetShader(&pipeline.fragment, None); - device_context.VSSetConstantBuffers(0, Some(global_params)); - device_context.PSSetConstantBuffers(0, Some(global_params)); - const STRIDE: u32 = std::mem::size_of::>() as u32; - device_context.IASetVertexBuffers( - 0, - 1, - Some(&pipeline.vertex_buffer), - Some(&STRIDE), - Some(&0), - ); - device_context.IASetInputLayout(&pipeline.input_layout); - } - Ok(()) -} - -fn draw_indirect( - device_context: &ID3D11DeviceContext, - indirect_draw_buffer: &ID3D11Buffer, - offset: u32, -) { - unsafe { - device_context.DrawInstancedIndirect(indirect_draw_buffer, offset); - } -} - const BUFFER_COUNT: usize = 3; mod shader_resources { From ffbb47452d85eb40cf9556242f35d3b12a56a43d Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 15:48:55 +0800 Subject: [PATCH 24/45] introduce `set_pipeline_state` --- .../src/platform/windows/directx_renderer.rs | 86 +++++++++++++------ 1 file changed, 61 insertions(+), 25 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 623383946a117e655cb10a21d08894688179b673..ee38632f9ba9effe5f6fceeb131b42a1bb559dbd 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -616,16 +616,16 @@ impl PipelineState { global_params: &[Option], instance_count: u32, ) -> Result<()> { + set_pipeline_state( + device_context, + &self.view, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + viewport, + &self.vertex, + &self.fragment, + global_params, + ); unsafe { - device_context.VSSetShaderResources(1, Some(&self.view)); - device_context.PSSetShaderResources(1, Some(&self.view)); - device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - device_context.RSSetViewports(Some(viewport)); - device_context.VSSetShader(&self.vertex, None); - device_context.PSSetShader(&self.fragment, None); - device_context.VSSetConstantBuffers(0, Some(global_params)); - device_context.PSSetConstantBuffers(0, Some(global_params)); - device_context.DrawInstanced(4, instance_count, 0, 0); } Ok(()) @@ -640,15 +640,16 @@ impl PipelineState { sampler: &[Option], instance_count: u32, ) -> Result<()> { + set_pipeline_state( + device_context, + &self.view, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, + viewport, + &self.vertex, + &self.fragment, + global_params, + ); unsafe { - device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - device_context.RSSetViewports(Some(viewport)); - device_context.VSSetShader(&self.vertex, None); - device_context.PSSetShader(&self.fragment, None); - device_context.VSSetConstantBuffers(0, Some(global_params)); - device_context.PSSetConstantBuffers(0, Some(global_params)); - device_context.VSSetShaderResources(1, Some(&self.view)); - device_context.PSSetShaderResources(1, Some(&self.view)); device_context.PSSetSamplers(0, Some(sampler)); device_context.VSSetShaderResources(0, Some(texture)); device_context.PSSetShaderResources(0, Some(texture)); @@ -811,15 +812,16 @@ impl PathsPipelineState { viewport: &[D3D11_VIEWPORT], global_params: &[Option], ) -> Result<()> { + set_pipeline_state( + device_context, + &self.view, + D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST, + viewport, + &self.vertex, + &self.fragment, + global_params, + ); unsafe { - device_context.VSSetShaderResources(1, Some(&self.view)); - device_context.PSSetShaderResources(1, Some(&self.view)); - device_context.IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - device_context.RSSetViewports(Some(viewport)); - device_context.VSSetShader(&self.vertex, None); - device_context.PSSetShader(&self.fragment, None); - device_context.VSSetConstantBuffers(0, Some(global_params)); - device_context.PSSetConstantBuffers(0, Some(global_params)); const STRIDE: u32 = std::mem::size_of::>() as u32; device_context.IASetVertexBuffers( 0, @@ -849,6 +851,7 @@ struct PathSprite { color: Background, } +#[inline] fn get_dxgi_factory() -> Result { #[cfg(debug_assertions)] let factory_flag = DXGI_CREATE_FACTORY_DEBUG; @@ -970,6 +973,7 @@ fn create_swap_chain_default( Ok(swap_chain) } +#[inline] fn set_render_target_view( swap_chain: &IDXGISwapChain1, device: &ID3D11Device, @@ -987,6 +991,7 @@ fn set_render_target_view( Ok(back_buffer) } +#[inline] fn set_viewport( device_context: &ID3D11DeviceContext, width: f32, @@ -1004,6 +1009,7 @@ fn set_viewport( viewport } +#[inline] fn set_rasterizer_state(device: &ID3D11Device, device_context: &ID3D11DeviceContext) -> Result<()> { let desc = D3D11_RASTERIZER_DESC { FillMode: D3D11_FILL_SOLID, @@ -1028,6 +1034,7 @@ fn set_rasterizer_state(device: &ID3D11Device, device_context: &ID3D11DeviceCont } // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ns-d3d11-d3d11_blend_desc +#[inline] fn create_blend_state(device: &ID3D11Device) -> Result { // If the feature level is set to greater than D3D_FEATURE_LEVEL_9_3, the display // device performs the blend in linear space, which is ideal. @@ -1047,6 +1054,7 @@ fn create_blend_state(device: &ID3D11Device) -> Result { } } +#[inline] fn create_vertex_shader(device: &ID3D11Device, bytes: &[u8]) -> Result { unsafe { let mut shader = None; @@ -1055,6 +1063,7 @@ fn create_vertex_shader(device: &ID3D11Device, bytes: &[u8]) -> Result Result { unsafe { let mut shader = None; @@ -1063,6 +1072,7 @@ fn create_fragment_shader(device: &ID3D11Device, bytes: &[u8]) -> Result Result { let desc = D3D11_BUFFER_DESC { ByteWidth: (std::mem::size_of::() * buffer_size) as u32, @@ -1104,6 +1116,7 @@ fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: usize) -> Res Ok(buffer.unwrap()) } +#[inline] fn pre_draw( device_context: &ID3D11DeviceContext, global_params_buffer: &[Option; 1], @@ -1130,6 +1143,7 @@ fn pre_draw( Ok(()) } +#[inline] fn update_buffer( device_context: &ID3D11DeviceContext, buffer: &ID3D11Buffer, @@ -1144,6 +1158,28 @@ fn update_buffer( Ok(()) } +#[inline] +fn set_pipeline_state( + device_context: &ID3D11DeviceContext, + buffer_view: &[Option], + topology: D3D_PRIMITIVE_TOPOLOGY, + viewport: &[D3D11_VIEWPORT], + vertex_shader: &ID3D11VertexShader, + fragment_shader: &ID3D11PixelShader, + global_params: &[Option], +) { + unsafe { + device_context.VSSetShaderResources(1, Some(buffer_view)); + device_context.PSSetShaderResources(1, Some(buffer_view)); + device_context.IASetPrimitiveTopology(topology); + device_context.RSSetViewports(Some(viewport)); + device_context.VSSetShader(vertex_shader, None); + device_context.PSSetShader(fragment_shader, None); + device_context.VSSetConstantBuffers(0, Some(global_params)); + device_context.PSSetConstantBuffers(0, Some(global_params)); + } +} + const BUFFER_COUNT: usize = 3; mod shader_resources { From 46fc76fdf8092225853bd8c5a832eee51fa8f017 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 17:14:24 +0800 Subject: [PATCH 25/45] reenable transparency --- .../src/platform/windows/directx_renderer.rs | 50 +++++++++++++++---- crates/gpui/src/platform/windows/window.rs | 50 +++++++++---------- 2 files changed, 65 insertions(+), 35 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index ee38632f9ba9effe5f6fceeb131b42a1bb559dbd..428464876a993bc99ac812b42bac17002bddf095 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{mem::ManuallyDrop, sync::Arc}; use ::util::ResultExt; use anyhow::{Context, Result}; @@ -37,7 +37,7 @@ pub(crate) struct DirectXDevices { } struct DirectXContext { - swap_chain: IDXGISwapChain1, + swap_chain: ManuallyDrop, back_buffer: [Option; 1], viewport: [D3D11_VIEWPORT; 1], // #[cfg(not(feature = "enable-renderdoc"))] @@ -212,13 +212,35 @@ impl DirectXRenderer { &mut self, background_appearance: WindowBackgroundAppearance, ) -> Result<()> { - if background_appearance != WindowBackgroundAppearance::Opaque { - Err(anyhow::anyhow!( - "Set transparent background not supported when feature \"enable-renderdoc\" is enabled." - )) - } else { - Ok(()) + let transparent = background_appearance != WindowBackgroundAppearance::Opaque; + if self.transparent == transparent { + return Ok(()); } + self.transparent = transparent; + // unsafe { + // // recreate the swapchain + // self.devices.device_context.OMSetRenderTargets(None, None); + // drop(self.context.back_buffer[0].take().unwrap()); + // ManuallyDrop::drop(&mut self.context.swap_chain); + // self.context.swap_chain = create_swap_chain_default( + // &self.devices.dxgi_factory, + // &self.devices.device, + // self.hwnd, + // transparent, + // )?; + // self.context.back_buffer = [Some(set_render_target_view( + // &self.context.swap_chain, + // &self.devices.device, + // &self.devices.device_context, + // )?)]; + // self.context.viewport = set_viewport( + // &self.devices.device_context, + // self.context.viewport[0].Width, + // self.context.viewport[0].Height, + // ); + // set_rasterizer_state(&self.devices.device, &self.devices.device_context)?; + // } + Ok(()) } fn draw_shadows(&mut self, shadows: &[Shadow]) -> Result<()> { @@ -851,6 +873,14 @@ struct PathSprite { color: Background, } +impl Drop for DirectXContext { + fn drop(&mut self) { + unsafe { + ManuallyDrop::drop(&mut self.swap_chain); + } + } +} + #[inline] fn get_dxgi_factory() -> Result { #[cfg(debug_assertions)] @@ -948,7 +978,7 @@ fn create_swap_chain_default( device: &ID3D11Device, hwnd: HWND, _transparent: bool, -) -> Result { +) -> Result> { use windows::Win32::Graphics::Dxgi::DXGI_MWA_NO_ALT_ENTER; let desc = DXGI_SWAP_CHAIN_DESC1 { @@ -970,7 +1000,7 @@ fn create_swap_chain_default( let swap_chain = unsafe { dxgi_factory.CreateSwapChainForHwnd(device, hwnd, &desc, None, None) }?; unsafe { dxgi_factory.MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER) }?; - Ok(swap_chain) + Ok(ManuallyDrop::new(swap_chain)) } #[inline] diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 5d1c91b5e30fbea20db63a58f067ce820923c495..74001c84e90be7c58ef66adad707a64e4c860bc9 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -384,8 +384,7 @@ impl WindowsWindow { (WS_EX_TOOLWINDOW | WS_EX_LAYERED, WINDOW_STYLE(0x0)) } else { ( - // WS_EX_APPWINDOW | WS_EX_LAYERED, - WS_EX_APPWINDOW, + WS_EX_APPWINDOW | WS_EX_LAYERED, WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, ) }; @@ -403,7 +402,7 @@ impl WindowsWindow { handle, hide_title_bar, display, - transparent: true, + transparent: false, is_movable: params.is_movable, min_size: params.window_min_size, executor, @@ -462,7 +461,7 @@ impl WindowsWindow { // window is going to be composited with per-pixel alpha, but the render // pipeline is responsible for effectively calling UpdateLayeredWindow // at the appropriate time. - // unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? }; + unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? }; Ok(Self(state_ptr)) } @@ -707,27 +706,28 @@ impl PlatformWindow for WindowsWindow { } fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) { - // let mut window_state = self.0.state.borrow_mut(); - // todo(zjk) - // window_state - // .renderer - // .update_transparency(background_appearance != WindowBackgroundAppearance::Opaque); - - // match background_appearance { - // WindowBackgroundAppearance::Opaque => { - // // ACCENT_DISABLED - // set_window_composition_attribute(window_state.hwnd, None, 0); - // } - // WindowBackgroundAppearance::Transparent => { - // // Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background - // set_window_composition_attribute(window_state.hwnd, None, 2); - // } - // WindowBackgroundAppearance::Blurred => { - // // Enable acrylic blur - // // ACCENT_ENABLE_ACRYLICBLURBEHIND - // set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 0)), 4); - // } - // } + let mut window_state = self.0.state.borrow_mut(); + window_state + .renderer + .update_transparency(background_appearance) + .context("Updating window transparency") + .log_err(); + + match background_appearance { + WindowBackgroundAppearance::Opaque => { + // ACCENT_DISABLED + set_window_composition_attribute(window_state.hwnd, None, 0); + } + WindowBackgroundAppearance::Transparent => { + // Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background + set_window_composition_attribute(window_state.hwnd, None, 2); + } + WindowBackgroundAppearance::Blurred => { + // Enable acrylic blur + // ACCENT_ENABLE_ACRYLICBLURBEHIND + set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 0)), 4); + } + } } fn minimize(&self) { From 4b2ff5e251b04484e68dd712fccdbd51006487de Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 19:56:56 +0800 Subject: [PATCH 26/45] update default buffer size --- crates/gpui/src/platform/windows/directx_renderer.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 428464876a993bc99ac812b42bac17002bddf095..27d00eeb6318e799ad86396fcea40bd34f8200bf 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -431,31 +431,31 @@ impl DirectXRenderPipelines { "shadow_pipeline", "shadow_vertex", "shadow_fragment", - 32, + 4, )?; let quad_pipeline = - PipelineState::new(device, "quad_pipeline", "quad_vertex", "quad_fragment", 32)?; + PipelineState::new(device, "quad_pipeline", "quad_vertex", "quad_fragment", 64)?; let paths_pipeline = PathsPipelineState::new(device)?; let underline_pipeline = PipelineState::new( device, "underline_pipeline", "underline_vertex", "underline_fragment", - 32, + 4, )?; let mono_sprites = PipelineState::new( device, "monochrome_sprite_pipeline", "monochrome_sprite_vertex", "monochrome_sprite_fragment", - 32, + 512, )?; let poly_sprites = PipelineState::new( device, "polychrome_sprite_pipeline", "polychrome_sprite_vertex", "polychrome_sprite_fragment", - 32, + 16, )?; Ok(Self { From da3736bd5f8344467c49f61d024bebfe81cae4e6 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 21:26:11 +0800 Subject: [PATCH 27/45] add msaa --- .../src/platform/windows/directx_renderer.rs | 66 ++++++++++++++++++- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 27d00eeb6318e799ad86396fcea40bd34f8200bf..410da3162d4f618035a97f2a2d9d7a95026a30ed 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -18,6 +18,9 @@ use windows::{ use crate::*; +const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM; +const BACK_BUFFER_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; + pub(crate) struct DirectXRenderer { atlas: Arc, devices: DirectXDevices, @@ -39,6 +42,8 @@ pub(crate) struct DirectXDevices { struct DirectXContext { swap_chain: ManuallyDrop, back_buffer: [Option; 1], + msaa_target: ID3D11Texture2D, + msaa_view: ID3D11RenderTargetView, viewport: [D3D11_VIEWPORT; 1], // #[cfg(not(feature = "enable-renderdoc"))] // direct_composition: DirectComposition, @@ -164,7 +169,7 @@ impl DirectXRenderer { BUFFER_COUNT as u32, new_size.width.0 as u32, new_size.height.0 as u32, - DXGI_FORMAT_B8G8R8A8_UNORM, + RENDER_TARGET_FORMAT, DXGI_SWAP_CHAIN_FLAG(0), )?; } @@ -174,6 +179,15 @@ impl DirectXRenderer { &self.devices.device_context, )?; self.context.back_buffer[0] = Some(backbuffer); + + let (msaa_target, msaa_view) = create_msaa_target_and_its_view( + &self.devices.device, + new_size.width.0 as u32, + new_size.height.0 as u32, + )?; + self.context.msaa_target = msaa_target; + self.context.msaa_view = msaa_view; + self.context.viewport = set_viewport( &self.devices.device_context, new_size.width.0 as f32, @@ -411,12 +425,15 @@ impl DirectXContext { &devices.device, &devices.device_context, )?)]; + let (msaa_target, msaa_view) = create_msaa_target_and_its_view(&devices.device, 1, 1)?; let viewport = set_viewport(&devices.device_context, 1.0, 1.0); set_rasterizer_state(&devices.device, &devices.device_context)?; Ok(Self { swap_chain, back_buffer, + msaa_target, + msaa_view, viewport, // #[cfg(not(feature = "enable-renderdoc"))] // direct_composition, @@ -984,7 +1001,7 @@ fn create_swap_chain_default( let desc = DXGI_SWAP_CHAIN_DESC1 { Width: 1, Height: 1, - Format: DXGI_FORMAT_B8G8R8A8_UNORM, + Format: RENDER_TARGET_FORMAT, Stereo: false.into(), SampleDesc: DXGI_SAMPLE_DESC { Count: 1, @@ -1013,14 +1030,57 @@ fn set_render_target_view( // https://stackoverflow.com/questions/65246961/does-the-backbuffer-that-a-rendertargetview-points-to-automagically-change-after let back_buffer = unsafe { let resource: ID3D11Texture2D = swap_chain.GetBuffer(0)?; + let desc = D3D11_RENDER_TARGET_VIEW_DESC { + Format: BACK_BUFFER_FORMAT, + ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D, + ..Default::default() + }; let mut buffer: Option = None; - device.CreateRenderTargetView(&resource, None, Some(&mut buffer))?; + device.CreateRenderTargetView(&resource, Some(&desc), Some(&mut buffer))?; buffer.unwrap() }; unsafe { device_context.OMSetRenderTargets(Some(&[Some(back_buffer.clone())]), None) }; Ok(back_buffer) } +fn create_msaa_target_and_its_view( + device: &ID3D11Device, + width: u32, + height: u32, +) -> Result<(ID3D11Texture2D, ID3D11RenderTargetView)> { + let msaa_target = unsafe { + let mut output = None; + let desc = D3D11_TEXTURE2D_DESC { + Width: width, + Height: height, + MipLevels: 1, + ArraySize: 1, + Format: BACK_BUFFER_FORMAT, + SampleDesc: DXGI_SAMPLE_DESC { + Count: 4, + Quality: D3D11_STANDARD_MULTISAMPLE_PATTERN.0 as u32, + }, + Usage: D3D11_USAGE_DEFAULT, + BindFlags: D3D11_BIND_RENDER_TARGET.0 as u32, + CPUAccessFlags: 0, + MiscFlags: 0, + }; + device.CreateTexture2D(&desc, None, Some(&mut output))?; + output.unwrap() + }; + let msaa_view = unsafe { + let desc = D3D11_RENDER_TARGET_VIEW_DESC { + Format: BACK_BUFFER_FORMAT, + ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2DMS, + ..Default::default() + }; + let mut output = None; + device.CreateRenderTargetView(&msaa_target, Some(&desc), Some(&mut output))?; + output.unwrap() + }; + Ok((msaa_target, msaa_view)) +} + #[inline] fn set_viewport( device_context: &ID3D11DeviceContext, From 55edee58fb939608043eebe70b55854290bc84e2 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 22:20:38 +0800 Subject: [PATCH 28/45] checkpoint msaa --- .../src/platform/windows/directx_renderer.rs | 161 ++++++++++++++---- 1 file changed, 129 insertions(+), 32 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 410da3162d4f618035a97f2a2d9d7a95026a30ed..74c1c6828602392a8b8ab53cfe772e48ffbef99b 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -18,7 +18,7 @@ use windows::{ use crate::*; -const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_R8G8B8A8_UNORM; +const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM; const BACK_BUFFER_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; pub(crate) struct DirectXRenderer { @@ -41,7 +41,8 @@ pub(crate) struct DirectXDevices { struct DirectXContext { swap_chain: ManuallyDrop, - back_buffer: [Option; 1], + render_target: ManuallyDrop, + render_target_view: [Option; 1], msaa_target: ID3D11Texture2D, msaa_view: ID3D11RenderTargetView, viewport: [D3D11_VIEWPORT; 1], @@ -124,15 +125,48 @@ impl DirectXRenderer { self.atlas.clone() } - pub(crate) fn draw(&mut self, scene: &Scene) -> Result<()> { - pre_draw( + fn pre_draw(&self) -> Result<()> { + update_buffer( &self.devices.device_context, - &self.globals.global_params_buffer, - &self.context.viewport, - &self.context.back_buffer, - [0.0, 0.0, 0.0, 0.0], - &self.globals.blend_state, + self.globals.global_params_buffer[0].as_ref().unwrap(), + &[GlobalParams { + viewport_size: [ + self.context.viewport[0].Width, + self.context.viewport[0].Height, + ], + ..Default::default() + }], )?; + unsafe { + self.devices + .device_context + .ClearRenderTargetView(&self.context.msaa_view, &[0.0; 4]); + self.devices + .device_context + .OMSetRenderTargets(Some(&[Some(self.context.msaa_view.clone())]), None); + self.devices + .device_context + .RSSetViewports(Some(&self.context.viewport)); + self.devices.device_context.OMSetBlendState( + &self.globals.blend_state, + None, + 0xFFFFFFFF, + ); + } + Ok(()) + } + + pub(crate) fn draw(&mut self, scene: &Scene) -> Result<()> { + // pre_draw( + // &self.devices.device_context, + // &self.globals.global_params_buffer, + // &self.context.viewport, + // &self.context.back_buffer, + // [0.0, 0.0, 0.0, 0.0], + // &self.globals.blend_state, + // )?; + println!("Pre-draw: {:?}", self.context.render_target_view); + self.pre_draw()?; for batch in scene.batches() { match batch { PrimitiveBatch::Shadows(shadows) => self.draw_shadows(shadows), @@ -157,28 +191,56 @@ impl DirectXRenderer { scene.polychrome_sprites.len(), scene.surfaces.len(),))?; } - unsafe { self.context.swap_chain.Present(0, DXGI_PRESENT(0)) }.ok()?; + unsafe { + self.devices.device_context.ResolveSubresource( + &*self.context.render_target, + 0, + &self.context.msaa_target, + 0, + BACK_BUFFER_FORMAT, + ); + self.devices + .device_context + .OMSetRenderTargets(Some(&self.context.render_target_view), None); + self.context.swap_chain.Present(0, DXGI_PRESENT(0)).ok()?; + } Ok(()) } pub(crate) fn resize(&mut self, new_size: Size) -> Result<()> { - unsafe { self.devices.device_context.OMSetRenderTargets(None, None) }; - drop(self.context.back_buffer[0].take().unwrap()); + println!("Resize: {:?}", self.context.render_target_view); unsafe { - self.context.swap_chain.ResizeBuffers( - BUFFER_COUNT as u32, - new_size.width.0 as u32, - new_size.height.0 as u32, - RENDER_TARGET_FORMAT, - DXGI_SWAP_CHAIN_FLAG(0), - )?; + self.devices.device_context.OMSetRenderTargets(None, None); + ManuallyDrop::drop(&mut self.context.render_target); + } + drop(self.context.render_target_view[0].take().unwrap()); + unsafe { + self.context + .swap_chain + .ResizeBuffers( + BUFFER_COUNT as u32, + new_size.width.0 as u32, + new_size.height.0 as u32, + RENDER_TARGET_FORMAT, + DXGI_SWAP_CHAIN_FLAG(0), + ) + .unwrap(); + } + // let backbuffer = set_render_target_view( + // &self.context.swap_chain, + // &self.devices.device, + // &self.devices.device_context, + // )?; + let (render_target, render_target_view) = + create_render_target_and_its_view(&self.context.swap_chain, &self.devices.device) + .unwrap(); + self.context.render_target = render_target; + self.context.render_target_view = render_target_view; + unsafe { + self.devices + .device_context + .OMSetRenderTargets(Some(&self.context.render_target_view), None); } - let backbuffer = set_render_target_view( - &self.context.swap_chain, - &self.devices.device, - &self.devices.device_context, - )?; - self.context.back_buffer[0] = Some(backbuffer); let (msaa_target, msaa_view) = create_msaa_target_and_its_view( &self.devices.device, @@ -420,18 +482,26 @@ impl DirectXContext { // let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?; // #[cfg(not(feature = "enable-renderdoc"))] // direct_composition.set_swap_chain(&swap_chain)?; - let back_buffer = [Some(set_render_target_view( - &swap_chain, - &devices.device, - &devices.device_context, - )?)]; + let (render_target, render_target_view) = + create_render_target_and_its_view(&swap_chain, &devices.device)?; + // let back_buffer = [Some(set_render_target_view( + // &swap_chain, + // &devices.device, + // &devices.device_context, + // )?)]; let (msaa_target, msaa_view) = create_msaa_target_and_its_view(&devices.device, 1, 1)?; let viewport = set_viewport(&devices.device_context, 1.0, 1.0); + unsafe { + devices + .device_context + .OMSetRenderTargets(Some(&render_target_view), None); + } set_rasterizer_state(&devices.device, &devices.device_context)?; Ok(Self { swap_chain, - back_buffer, + render_target, + render_target_view, msaa_target, msaa_view, viewport, @@ -893,6 +963,7 @@ struct PathSprite { impl Drop for DirectXContext { fn drop(&mut self) { unsafe { + ManuallyDrop::drop(&mut self.render_target); ManuallyDrop::drop(&mut self.swap_chain); } } @@ -1020,6 +1091,30 @@ fn create_swap_chain_default( Ok(ManuallyDrop::new(swap_chain)) } +#[inline] +fn create_render_target_and_its_view( + swap_chain: &IDXGISwapChain1, + device: &ID3D11Device, +) -> Result<( + ManuallyDrop, + [Option; 1], +)> { + let render_target: ID3D11Texture2D = unsafe { swap_chain.GetBuffer(0) }?; + let desc = D3D11_RENDER_TARGET_VIEW_DESC { + Format: BACK_BUFFER_FORMAT, + ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D, + ..Default::default() + }; + let mut render_target_view = None; + unsafe { + device.CreateRenderTargetView(&render_target, Some(&desc), Some(&mut render_target_view))? + }; + Ok(( + ManuallyDrop::new(render_target), + [Some(render_target_view.unwrap())], + )) +} + #[inline] fn set_render_target_view( swap_chain: &IDXGISwapChain1, @@ -1043,6 +1138,7 @@ fn set_render_target_view( Ok(back_buffer) } +#[inline] fn create_msaa_target_and_its_view( device: &ID3D11Device, width: u32, @@ -1111,7 +1207,8 @@ fn set_rasterizer_state(device: &ID3D11Device, device_context: &ID3D11DeviceCont SlopeScaledDepthBias: 0.0, DepthClipEnable: true.into(), ScissorEnable: false.into(), - MultisampleEnable: false.into(), + // MultisampleEnable: false.into(), + MultisampleEnable: true.into(), AntialiasedLineEnable: false.into(), }; let rasterizer_state = unsafe { From 398d492f85b27302ff5b39b6d13dbacba511cc80 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 22:58:51 +0800 Subject: [PATCH 29/45] wip --- crates/gpui/src/platform/windows/directx_renderer.rs | 4 ++-- crates/gpui/src/platform/windows/shaders.hlsl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 74c1c6828602392a8b8ab53cfe772e48ffbef99b..47f6f3945da86e7fd3e1beb113679d0c9228a4ae 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -19,7 +19,8 @@ use windows::{ use crate::*; const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM; -const BACK_BUFFER_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; +// const BACK_BUFFER_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; +const BACK_BUFFER_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM; pub(crate) struct DirectXRenderer { atlas: Arc, @@ -1200,7 +1201,6 @@ fn set_rasterizer_state(device: &ID3D11Device, device_context: &ID3D11DeviceCont let desc = D3D11_RASTERIZER_DESC { FillMode: D3D11_FILL_SOLID, CullMode: D3D11_CULL_NONE, - // FrontCounterClockwise: true.into(), FrontCounterClockwise: false.into(), DepthBias: 0, DepthBiasClamp: 0.0, diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index 7e59bb714e07706ab4f51a0e9ac5a436777c529a..a67e2cde60b6f542caf83902fa1611f399317018 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -342,8 +342,8 @@ float4 gradient_color(Background background, } // Get the t value for the linear gradient with the color stop percentages. - float2 half_size = float2(bounds.size.x, bounds.size.y) / 2.; - float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size; + float2 half_size = bounds.size * 0.5; + float2 center = bounds.origin + half_size; float2 center_to_point = position - center; float t = dot(center_to_point, direction) / length(direction); // Check the direct to determine the use x or y From b0fe5fd56fa1ed29d2f5d1b0b6ff0e0ab69fa748 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Wed, 16 Jul 2025 23:55:32 +0800 Subject: [PATCH 30/45] wip --- .../src/platform/windows/directx_renderer.rs | 31 ++++++++++++++----- crates/gpui/src/platform/windows/shaders.hlsl | 11 ++++--- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 47f6f3945da86e7fd3e1beb113679d0c9228a4ae..53b22a05e3d6a167c047b4ce9df8db37dda8c0d0 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -371,11 +371,10 @@ impl DirectXRenderer { }); start_vertex_location += path.vertices.len() as u32; - vertices.extend(path.vertices.iter().map(|v| PathVertex { + vertices.extend(path.vertices.iter().map(|v| DirectXPathVertex { xy_position: v.xy_position, - content_mask: ContentMask { - bounds: path.content_mask.bounds, - }, + content_mask: path.content_mask.bounds, + sprite_index: i as u32, })); sprites.push(PathSprite { @@ -796,7 +795,7 @@ impl PathsPipelineState { let view = create_buffer_view(device, &buffer)?; let vertex_buffer = Some(create_buffer( device, - std::mem::size_of::>(), + std::mem::size_of::(), 32, )?); let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?; @@ -836,6 +835,15 @@ impl PathsPipelineState { InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA, InstanceDataStepRate: 0, }, + D3D11_INPUT_ELEMENT_DESC { + SemanticName: windows::core::s!("GLOBALIDX"), + SemanticIndex: 0, + Format: DXGI_FORMAT_R32_UINT, + InputSlot: 0, + AlignedByteOffset: 24, + InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA, + InstanceDataStepRate: 0, + }, ], shader_bytes, Some(&mut layout), @@ -862,7 +870,7 @@ impl PathsPipelineState { device: &ID3D11Device, device_context: &ID3D11DeviceContext, buffer_data: &[PathSprite], - vertices_data: &[PathVertex], + vertices_data: &[DirectXPathVertex], draw_commands: &[DrawInstancedIndirectArgs], ) -> Result<()> { if self.buffer_size < buffer_data.len() { @@ -888,7 +896,7 @@ impl PathsPipelineState { ); let vertex_buffer = create_buffer( device, - std::mem::size_of::>(), + std::mem::size_of::(), new_vertex_buffer_size, )?; self.vertex_buffer = Some(vertex_buffer); @@ -932,7 +940,7 @@ impl PathsPipelineState { global_params, ); unsafe { - const STRIDE: u32 = std::mem::size_of::>() as u32; + const STRIDE: u32 = std::mem::size_of::() as u32; device_context.IASetVertexBuffers( 0, 1, @@ -954,6 +962,13 @@ impl PathsPipelineState { } } +#[repr(C)] +struct DirectXPathVertex { + xy_position: Point, + content_mask: Bounds, + sprite_index: u32, +} + #[derive(Clone, Debug, Eq, PartialEq)] #[repr(C)] struct PathSprite { diff --git a/crates/gpui/src/platform/windows/shaders.hlsl b/crates/gpui/src/platform/windows/shaders.hlsl index a67e2cde60b6f542caf83902fa1611f399317018..f0c773a6732306e07bc072fa9648a3bf4043cf80 100644 --- a/crates/gpui/src/platform/windows/shaders.hlsl +++ b/crates/gpui/src/platform/windows/shaders.hlsl @@ -879,6 +879,7 @@ float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET { struct PathVertex { float2 xy_position: POSITION; Bounds content_mask: TEXCOORD; + uint idx: GLOBALIDX; }; struct PathSprite { @@ -905,13 +906,13 @@ struct PathFragmentInput { StructuredBuffer path_sprites: register(t1); -PathVertexOutput paths_vertex(PathVertex v, uint instance_id: SV_InstanceID) { - PathSprite sprite = path_sprites[instance_id]; +PathVertexOutput paths_vertex(PathVertex input) { + PathSprite sprite = path_sprites[input.idx]; PathVertexOutput output; - output.position = to_device_position_impl(v.xy_position); - output.clip_distance = distance_from_clip_rect_impl(v.xy_position, v.content_mask); - output.sprite_id = instance_id; + output.position = to_device_position_impl(input.xy_position); + output.clip_distance = distance_from_clip_rect_impl(input.xy_position, input.content_mask); + output.sprite_id = input.idx; GradientColor gradient = prepare_gradient_color( sprite.color.tag, From b1b5a383e0fb154a80a59bf6782631a743064fcc Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 00:05:46 +0800 Subject: [PATCH 31/45] remove unused --- .../src/platform/windows/directx_renderer.rs | 39 +++---------------- 1 file changed, 5 insertions(+), 34 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 53b22a05e3d6a167c047b4ce9df8db37dda8c0d0..99126186c79c582971e771177ec1dad961fefd80 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -19,8 +19,6 @@ use windows::{ use crate::*; const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM; -// const BACK_BUFFER_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM_SRGB; -const BACK_BUFFER_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM; pub(crate) struct DirectXRenderer { atlas: Arc, @@ -158,15 +156,6 @@ impl DirectXRenderer { } pub(crate) fn draw(&mut self, scene: &Scene) -> Result<()> { - // pre_draw( - // &self.devices.device_context, - // &self.globals.global_params_buffer, - // &self.context.viewport, - // &self.context.back_buffer, - // [0.0, 0.0, 0.0, 0.0], - // &self.globals.blend_state, - // )?; - println!("Pre-draw: {:?}", self.context.render_target_view); self.pre_draw()?; for batch in scene.batches() { match batch { @@ -198,7 +187,7 @@ impl DirectXRenderer { 0, &self.context.msaa_target, 0, - BACK_BUFFER_FORMAT, + RENDER_TARGET_FORMAT, ); self.devices .device_context @@ -209,7 +198,6 @@ impl DirectXRenderer { } pub(crate) fn resize(&mut self, new_size: Size) -> Result<()> { - println!("Resize: {:?}", self.context.render_target_view); unsafe { self.devices.device_context.OMSetRenderTargets(None, None); ManuallyDrop::drop(&mut self.context.render_target); @@ -1116,15 +1104,8 @@ fn create_render_target_and_its_view( [Option; 1], )> { let render_target: ID3D11Texture2D = unsafe { swap_chain.GetBuffer(0) }?; - let desc = D3D11_RENDER_TARGET_VIEW_DESC { - Format: BACK_BUFFER_FORMAT, - ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D, - ..Default::default() - }; let mut render_target_view = None; - unsafe { - device.CreateRenderTargetView(&render_target, Some(&desc), Some(&mut render_target_view))? - }; + unsafe { device.CreateRenderTargetView(&render_target, None, Some(&mut render_target_view))? }; Ok(( ManuallyDrop::new(render_target), [Some(render_target_view.unwrap())], @@ -1141,13 +1122,8 @@ fn set_render_target_view( // https://stackoverflow.com/questions/65246961/does-the-backbuffer-that-a-rendertargetview-points-to-automagically-change-after let back_buffer = unsafe { let resource: ID3D11Texture2D = swap_chain.GetBuffer(0)?; - let desc = D3D11_RENDER_TARGET_VIEW_DESC { - Format: BACK_BUFFER_FORMAT, - ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2D, - ..Default::default() - }; let mut buffer: Option = None; - device.CreateRenderTargetView(&resource, Some(&desc), Some(&mut buffer))?; + device.CreateRenderTargetView(&resource, None, Some(&mut buffer))?; buffer.unwrap() }; unsafe { device_context.OMSetRenderTargets(Some(&[Some(back_buffer.clone())]), None) }; @@ -1167,7 +1143,7 @@ fn create_msaa_target_and_its_view( Height: height, MipLevels: 1, ArraySize: 1, - Format: BACK_BUFFER_FORMAT, + Format: RENDER_TARGET_FORMAT, SampleDesc: DXGI_SAMPLE_DESC { Count: 4, Quality: D3D11_STANDARD_MULTISAMPLE_PATTERN.0 as u32, @@ -1181,13 +1157,8 @@ fn create_msaa_target_and_its_view( output.unwrap() }; let msaa_view = unsafe { - let desc = D3D11_RENDER_TARGET_VIEW_DESC { - Format: BACK_BUFFER_FORMAT, - ViewDimension: D3D11_RTV_DIMENSION_TEXTURE2DMS, - ..Default::default() - }; let mut output = None; - device.CreateRenderTargetView(&msaa_target, Some(&desc), Some(&mut output))?; + device.CreateRenderTargetView(&msaa_target, None, Some(&mut output))?; output.unwrap() }; Ok((msaa_target, msaa_view)) From b8314e74db13e2ac6c9deaecf4a1717961fc71b2 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 11:29:44 +0800 Subject: [PATCH 32/45] add transparency --- Cargo.toml | 1 + .../src/platform/windows/directx_renderer.rs | 320 +++++++++--------- crates/gpui/src/platform/windows/window.rs | 5 +- 3 files changed, 169 insertions(+), 157 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bf1eb9c3259a83e169eaaae7556f7d4b3022b4af..a57f29baa4b8766338d0ea815ecc848acee41237 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -666,6 +666,7 @@ features = [ "Win32_Graphics_Direct3D", "Win32_Graphics_Direct3D11", "Win32_Graphics_Direct3D_Fxc", + "Win32_Graphics_DirectComposition", "Win32_Graphics_DirectWrite", "Win32_Graphics_Dwm", "Win32_Graphics_Dxgi", diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 99126186c79c582971e771177ec1dad961fefd80..ed39f3bedffd8a8a01fd07efd34be3f89c4849d0 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -3,7 +3,8 @@ use std::{mem::ManuallyDrop, sync::Arc}; use ::util::ResultExt; use anyhow::{Context, Result}; // #[cfg(not(feature = "enable-renderdoc"))] -// use windows::Win32::Graphics::DirectComposition::*; +use windows::Win32::Graphics::DirectComposition::*; +use windows::Win32::UI::WindowsAndMessaging::GetWindowRect; use windows::{ Win32::{ Foundation::{HMODULE, HWND}, @@ -26,7 +27,6 @@ pub(crate) struct DirectXRenderer { context: DirectXContext, globals: DirectXGlobalElements, pipelines: DirectXRenderPipelines, - hwnd: HWND, transparent: bool, } @@ -46,7 +46,7 @@ struct DirectXContext { msaa_view: ID3D11RenderTargetView, viewport: [D3D11_VIEWPORT; 1], // #[cfg(not(feature = "enable-renderdoc"))] - // direct_composition: DirectComposition, + direct_composition: DirectComposition, } struct DirectXRenderPipelines { @@ -73,11 +73,11 @@ struct DrawInstancedIndirectArgs { } // #[cfg(not(feature = "enable-renderdoc"))] -// struct DirectComposition { -// comp_device: IDCompositionDevice, -// comp_target: IDCompositionTarget, -// comp_visual: IDCompositionVisual, -// } +struct DirectComposition { + comp_device: IDCompositionDevice, + comp_target: IDCompositionTarget, + comp_visual: IDCompositionVisual, +} impl DirectXDevices { pub(crate) fn new() -> Result { @@ -115,7 +115,6 @@ impl DirectXRenderer { context, globals, pipelines, - hwnd, transparent, }) } @@ -215,11 +214,6 @@ impl DirectXRenderer { ) .unwrap(); } - // let backbuffer = set_render_target_view( - // &self.context.swap_chain, - // &self.devices.device, - // &self.devices.device_context, - // )?; let (render_target, render_target_view) = create_render_target_and_its_view(&self.context.swap_chain, &self.devices.device) .unwrap(); @@ -248,31 +242,6 @@ impl DirectXRenderer { } // #[cfg(not(feature = "enable-renderdoc"))] - // pub(crate) fn update_transparency( - // &mut self, - // background_appearance: WindowBackgroundAppearance, - // ) -> Result<()> { - // // We only support setting `Transparent` and `Opaque` for now. - // match background_appearance { - // WindowBackgroundAppearance::Opaque => { - // if self.transparent { - // return Err(anyhow::anyhow!( - // "Set opaque backgroud from transparent background, a restart is required. Or, you can open a new window." - // )); - // } - // } - // WindowBackgroundAppearance::Transparent | WindowBackgroundAppearance::Blurred => { - // if !self.transparent { - // return Err(anyhow::anyhow!( - // "Set transparent backgroud from opaque background, a restart is required. Or, you can open a new window." - // )); - // } - // } - // } - // Ok(()) - // } - - // #[cfg(feature = "enable-renderdoc")] pub(crate) fn update_transparency( &mut self, background_appearance: WindowBackgroundAppearance, @@ -281,33 +250,84 @@ impl DirectXRenderer { if self.transparent == transparent { return Ok(()); } - self.transparent = transparent; - // unsafe { - // // recreate the swapchain + // self.transparent = transparent; + // let (width, height) = unsafe { // self.devices.device_context.OMSetRenderTargets(None, None); - // drop(self.context.back_buffer[0].take().unwrap()); + // ManuallyDrop::drop(&mut self.context.render_target); + // drop(self.context.render_target_view[0].take().unwrap()); + // let desc = self.context.swap_chain.GetDesc1().unwrap(); // ManuallyDrop::drop(&mut self.context.swap_chain); - // self.context.swap_chain = create_swap_chain_default( - // &self.devices.dxgi_factory, - // &self.devices.device, - // self.hwnd, - // transparent, - // )?; - // self.context.back_buffer = [Some(set_render_target_view( - // &self.context.swap_chain, - // &self.devices.device, - // &self.devices.device_context, - // )?)]; - // self.context.viewport = set_viewport( - // &self.devices.device_context, - // self.context.viewport[0].Width, - // self.context.viewport[0].Height, - // ); - // set_rasterizer_state(&self.devices.device, &self.devices.device_context)?; + // (desc.Width, desc.Height) + // }; + // self.context.swap_chain = create_swap_chain( + // &self.devices.dxgi_factory, + // &self.devices.device, + // transparent, + // width, + // height, + // ) + // .unwrap(); + // self.context + // .direct_composition + // .set_swap_chain(&self.context.swap_chain) + // .context("Failed to set swap chain for DirectComposition")?; + // let (render_target, render_target_view) = + // create_render_target_and_its_view(&self.context.swap_chain, &self.devices.device) + // .unwrap(); + // self.context.render_target = render_target; + // self.context.render_target_view = render_target_view; + // unsafe { + // self.devices + // .device_context + // .OMSetRenderTargets(Some(&self.context.render_target_view), None); // } + + // let (msaa_target, msaa_view) = + // create_msaa_target_and_its_view(&self.devices.device, width, height)?; + // self.context.msaa_target = msaa_target; + // self.context.msaa_view = msaa_view; + + // self.context.viewport = set_viewport(&self.devices.device_context, width as _, height as _); + // set_rasterizer_state(&self.devices.device, &self.devices.device_context)?; Ok(()) } + // #[cfg(feature = "enable-renderdoc")] + // pub(crate) fn update_transparency( + // &mut self, + // background_appearance: WindowBackgroundAppearance, + // ) -> Result<()> { + // let transparent = background_appearance != WindowBackgroundAppearance::Opaque; + // if self.transparent == transparent { + // return Ok(()); + // } + // self.transparent = transparent; + // unsafe { + // // recreate the swapchain + // self.devices.device_context.OMSetRenderTargets(None, None); + // drop(self.context.back_buffer[0].take().unwrap()); + // ManuallyDrop::drop(&mut self.context.swap_chain); + // self.context.swap_chain = create_swap_chain_default( + // &self.devices.dxgi_factory, + // &self.devices.device, + // self.hwnd, + // transparent, + // )?; + // self.context.back_buffer = [Some(set_render_target_view( + // &self.context.swap_chain, + // &self.devices.device, + // &self.devices.device_context, + // )?)]; + // self.context.viewport = set_viewport( + // &self.devices.device_context, + // self.context.viewport[0].Width, + // self.context.viewport[0].Height, + // ); + // set_rasterizer_state(&self.devices.device, &self.devices.device_context)?; + // } + // Ok(()) + // } + fn draw_shadows(&mut self, shadows: &[Shadow]) -> Result<()> { if shadows.is_empty() { return Ok(()); @@ -461,24 +481,35 @@ impl DirectXRenderer { impl DirectXContext { pub fn new(devices: &DirectXDevices, hwnd: HWND, transparent: bool) -> Result { + let (width, height) = unsafe { + let mut rect = std::mem::zeroed(); + GetWindowRect(hwnd, &mut rect)?; + (rect.right - rect.left, rect.bottom - rect.top) + }; + assert!( + width > 0 && height > 0, + "Window size must be greater than zero" + ); // #[cfg(not(feature = "enable-renderdoc"))] - // let swap_chain = create_swap_chain(&devices.dxgi_factory, &devices.device, transparent)?; + let swap_chain = create_swap_chain( + &devices.dxgi_factory, + &devices.device, + transparent, + width as u32, + height as u32, + )?; // #[cfg(feature = "enable-renderdoc")] - let swap_chain = - create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?; + // let swap_chain = + // create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?; // #[cfg(not(feature = "enable-renderdoc"))] - // let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?; + let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?; // #[cfg(not(feature = "enable-renderdoc"))] - // direct_composition.set_swap_chain(&swap_chain)?; + direct_composition.set_swap_chain(&swap_chain)?; let (render_target, render_target_view) = create_render_target_and_its_view(&swap_chain, &devices.device)?; - // let back_buffer = [Some(set_render_target_view( - // &swap_chain, - // &devices.device, - // &devices.device_context, - // )?)]; - let (msaa_target, msaa_view) = create_msaa_target_and_its_view(&devices.device, 1, 1)?; - let viewport = set_viewport(&devices.device_context, 1.0, 1.0); + let (msaa_target, msaa_view) = + create_msaa_target_and_its_view(&devices.device, width as u32, height as u32)?; + let viewport = set_viewport(&devices.device_context, width as f32, height as f32); unsafe { devices .device_context @@ -494,7 +525,7 @@ impl DirectXContext { msaa_view, viewport, // #[cfg(not(feature = "enable-renderdoc"))] - // direct_composition, + direct_composition, }) } } @@ -545,28 +576,28 @@ impl DirectXRenderPipelines { } // #[cfg(not(feature = "enable-renderdoc"))] -// impl DirectComposition { -// pub fn new(dxgi_device: &IDXGIDevice, hwnd: HWND) -> Result { -// let comp_device = get_comp_device(&dxgi_device)?; -// let comp_target = unsafe { comp_device.CreateTargetForHwnd(hwnd, true) }?; -// let comp_visual = unsafe { comp_device.CreateVisual() }?; - -// Ok(Self { -// comp_device, -// comp_target, -// comp_visual, -// }) -// } - -// pub fn set_swap_chain(&self, swap_chain: &IDXGISwapChain1) -> Result<()> { -// unsafe { -// self.comp_visual.SetContent(swap_chain)?; -// self.comp_target.SetRoot(&self.comp_visual)?; -// self.comp_device.Commit()?; -// } -// Ok(()) -// } -// } +impl DirectComposition { + pub fn new(dxgi_device: &IDXGIDevice, hwnd: HWND) -> Result { + let comp_device = get_comp_device(&dxgi_device)?; + let comp_target = unsafe { comp_device.CreateTargetForHwnd(hwnd, true) }?; + let comp_visual = unsafe { comp_device.CreateVisual() }?; + + Ok(Self { + comp_device, + comp_target, + comp_visual, + }) + } + + pub fn set_swap_chain(&self, swap_chain: &IDXGISwapChain1) -> Result<()> { + unsafe { + self.comp_visual.SetContent(swap_chain)?; + self.comp_target.SetRoot(&self.comp_visual)?; + self.comp_device.Commit()?; + } + Ok(()) + } +} impl DirectXGlobalElements { pub fn new(device: &ID3D11Device) -> Result { @@ -1030,39 +1061,45 @@ fn get_device( } // #[cfg(not(feature = "enable-renderdoc"))] -// fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result { -// Ok(unsafe { DCompositionCreateDevice(dxgi_device)? }) -// } - -// fn create_swap_chain( -// dxgi_factory: &IDXGIFactory6, -// device: &ID3D11Device, -// transparent: bool, -// ) -> Result { -// let alpha_mode = if transparent { -// DXGI_ALPHA_MODE_PREMULTIPLIED -// } else { -// DXGI_ALPHA_MODE_IGNORE -// }; -// let desc = DXGI_SWAP_CHAIN_DESC1 { -// Width: 1, -// Height: 1, -// Format: DXGI_FORMAT_B8G8R8A8_UNORM, -// Stereo: false.into(), -// SampleDesc: DXGI_SAMPLE_DESC { -// Count: 1, -// Quality: 0, -// }, -// BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT, -// BufferCount: BUFFER_COUNT as u32, -// // Composition SwapChains only support the DXGI_SCALING_STRETCH Scaling. -// Scaling: DXGI_SCALING_STRETCH, -// SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, -// AlphaMode: alpha_mode, -// Flags: 0, -// }; -// Ok(unsafe { dxgi_factory.CreateSwapChainForComposition(device, &desc, None)? }) -// } +fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result { + Ok(unsafe { DCompositionCreateDevice(dxgi_device)? }) +} + +fn create_swap_chain( + dxgi_factory: &IDXGIFactory6, + device: &ID3D11Device, + transparent: bool, + width: u32, + height: u32, +) -> Result> { + println!("Creating swap chain for DirectComposition: {}", transparent); + let transparent = true; + let alpha_mode = if transparent { + DXGI_ALPHA_MODE_PREMULTIPLIED + } else { + DXGI_ALPHA_MODE_IGNORE + }; + let desc = DXGI_SWAP_CHAIN_DESC1 { + Width: width, + Height: height, + Format: RENDER_TARGET_FORMAT, + Stereo: false.into(), + SampleDesc: DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT, + BufferCount: BUFFER_COUNT as u32, + // Composition SwapChains only support the DXGI_SCALING_STRETCH Scaling. + Scaling: DXGI_SCALING_STRETCH, + SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, + AlphaMode: alpha_mode, + Flags: 0, + }; + Ok(ManuallyDrop::new(unsafe { + dxgi_factory.CreateSwapChainForComposition(device, &desc, None)? + })) +} // #[cfg(feature = "enable-renderdoc")] fn create_swap_chain_default( @@ -1289,33 +1326,6 @@ fn create_indirect_draw_buffer(device: &ID3D11Device, buffer_size: usize) -> Res Ok(buffer.unwrap()) } -#[inline] -fn pre_draw( - device_context: &ID3D11DeviceContext, - global_params_buffer: &[Option; 1], - view_port: &[D3D11_VIEWPORT; 1], - render_target_view: &[Option; 1], - clear_color: [f32; 4], - blend_state: &ID3D11BlendState, -) -> Result<()> { - let global_params = global_params_buffer[0].as_ref().unwrap(); - update_buffer( - device_context, - global_params, - &[GlobalParams { - viewport_size: [view_port[0].Width, view_port[0].Height], - ..Default::default() - }], - )?; - unsafe { - device_context.RSSetViewports(Some(view_port)); - device_context.OMSetRenderTargets(Some(render_target_view), None); - device_context.ClearRenderTargetView(render_target_view[0].as_ref().unwrap(), &clear_color); - device_context.OMSetBlendState(blend_state, None, 0xFFFFFFFF); - } - Ok(()) -} - #[inline] fn update_buffer( device_context: &ID3D11DeviceContext, diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 74001c84e90be7c58ef66adad707a64e4c860bc9..077ba82e92669da09f081672e7d0ea8cedddb5ce 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -384,7 +384,8 @@ impl WindowsWindow { (WS_EX_TOOLWINDOW | WS_EX_LAYERED, WINDOW_STYLE(0x0)) } else { ( - WS_EX_APPWINDOW | WS_EX_LAYERED, + WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP, + // WS_EX_APPWINDOW | WS_EX_LAYERED, WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, ) }; @@ -461,7 +462,7 @@ impl WindowsWindow { // window is going to be composited with per-pixel alpha, but the render // pipeline is responsible for effectively calling UpdateLayeredWindow // at the appropriate time. - unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? }; + // unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? }; Ok(Self(state_ptr)) } From 602bd189f6d5a10234cb79f5c18f4b7b23307537 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 14:36:41 +0800 Subject: [PATCH 33/45] finetune transpanrency --- .../src/platform/windows/directx_renderer.rs | 128 +----------------- crates/gpui/src/platform/windows/window.rs | 33 ++--- 2 files changed, 15 insertions(+), 146 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index ed39f3bedffd8a8a01fd07efd34be3f89c4849d0..ebd4c4730ba7bb4ed327fe8bbec29207fed5d0d1 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -27,7 +27,6 @@ pub(crate) struct DirectXRenderer { context: DirectXContext, globals: DirectXGlobalElements, pipelines: DirectXRenderPipelines, - transparent: bool, } #[derive(Clone)] @@ -46,7 +45,7 @@ struct DirectXContext { msaa_view: ID3D11RenderTargetView, viewport: [D3D11_VIEWPORT; 1], // #[cfg(not(feature = "enable-renderdoc"))] - direct_composition: DirectComposition, + _direct_composition: DirectComposition, } struct DirectXRenderPipelines { @@ -101,12 +100,12 @@ impl DirectXDevices { } impl DirectXRenderer { - pub(crate) fn new(devices: &DirectXDevices, hwnd: HWND, transparent: bool) -> Result { + pub(crate) fn new(devices: &DirectXDevices, hwnd: HWND) -> Result { let atlas = Arc::new(DirectXAtlas::new( devices.device.clone(), devices.device_context.clone(), )); - let context = DirectXContext::new(devices, hwnd, transparent)?; + let context = DirectXContext::new(devices, hwnd)?; let globals = DirectXGlobalElements::new(&devices.device)?; let pipelines = DirectXRenderPipelines::new(&devices.device)?; Ok(DirectXRenderer { @@ -115,7 +114,6 @@ impl DirectXRenderer { context, globals, pipelines, - transparent, }) } @@ -241,93 +239,6 @@ impl DirectXRenderer { Ok(()) } - // #[cfg(not(feature = "enable-renderdoc"))] - pub(crate) fn update_transparency( - &mut self, - background_appearance: WindowBackgroundAppearance, - ) -> Result<()> { - let transparent = background_appearance != WindowBackgroundAppearance::Opaque; - if self.transparent == transparent { - return Ok(()); - } - // self.transparent = transparent; - // let (width, height) = unsafe { - // self.devices.device_context.OMSetRenderTargets(None, None); - // ManuallyDrop::drop(&mut self.context.render_target); - // drop(self.context.render_target_view[0].take().unwrap()); - // let desc = self.context.swap_chain.GetDesc1().unwrap(); - // ManuallyDrop::drop(&mut self.context.swap_chain); - // (desc.Width, desc.Height) - // }; - // self.context.swap_chain = create_swap_chain( - // &self.devices.dxgi_factory, - // &self.devices.device, - // transparent, - // width, - // height, - // ) - // .unwrap(); - // self.context - // .direct_composition - // .set_swap_chain(&self.context.swap_chain) - // .context("Failed to set swap chain for DirectComposition")?; - // let (render_target, render_target_view) = - // create_render_target_and_its_view(&self.context.swap_chain, &self.devices.device) - // .unwrap(); - // self.context.render_target = render_target; - // self.context.render_target_view = render_target_view; - // unsafe { - // self.devices - // .device_context - // .OMSetRenderTargets(Some(&self.context.render_target_view), None); - // } - - // let (msaa_target, msaa_view) = - // create_msaa_target_and_its_view(&self.devices.device, width, height)?; - // self.context.msaa_target = msaa_target; - // self.context.msaa_view = msaa_view; - - // self.context.viewport = set_viewport(&self.devices.device_context, width as _, height as _); - // set_rasterizer_state(&self.devices.device, &self.devices.device_context)?; - Ok(()) - } - - // #[cfg(feature = "enable-renderdoc")] - // pub(crate) fn update_transparency( - // &mut self, - // background_appearance: WindowBackgroundAppearance, - // ) -> Result<()> { - // let transparent = background_appearance != WindowBackgroundAppearance::Opaque; - // if self.transparent == transparent { - // return Ok(()); - // } - // self.transparent = transparent; - // unsafe { - // // recreate the swapchain - // self.devices.device_context.OMSetRenderTargets(None, None); - // drop(self.context.back_buffer[0].take().unwrap()); - // ManuallyDrop::drop(&mut self.context.swap_chain); - // self.context.swap_chain = create_swap_chain_default( - // &self.devices.dxgi_factory, - // &self.devices.device, - // self.hwnd, - // transparent, - // )?; - // self.context.back_buffer = [Some(set_render_target_view( - // &self.context.swap_chain, - // &self.devices.device, - // &self.devices.device_context, - // )?)]; - // self.context.viewport = set_viewport( - // &self.devices.device_context, - // self.context.viewport[0].Width, - // self.context.viewport[0].Height, - // ); - // set_rasterizer_state(&self.devices.device, &self.devices.device_context)?; - // } - // Ok(()) - // } - fn draw_shadows(&mut self, shadows: &[Shadow]) -> Result<()> { if shadows.is_empty() { return Ok(()); @@ -480,7 +391,7 @@ impl DirectXRenderer { } impl DirectXContext { - pub fn new(devices: &DirectXDevices, hwnd: HWND, transparent: bool) -> Result { + pub fn new(devices: &DirectXDevices, hwnd: HWND) -> Result { let (width, height) = unsafe { let mut rect = std::mem::zeroed(); GetWindowRect(hwnd, &mut rect)?; @@ -494,7 +405,6 @@ impl DirectXContext { let swap_chain = create_swap_chain( &devices.dxgi_factory, &devices.device, - transparent, width as u32, height as u32, )?; @@ -525,7 +435,7 @@ impl DirectXContext { msaa_view, viewport, // #[cfg(not(feature = "enable-renderdoc"))] - direct_composition, + _direct_composition: direct_composition, }) } } @@ -1068,17 +978,9 @@ fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result { fn create_swap_chain( dxgi_factory: &IDXGIFactory6, device: &ID3D11Device, - transparent: bool, width: u32, height: u32, ) -> Result> { - println!("Creating swap chain for DirectComposition: {}", transparent); - let transparent = true; - let alpha_mode = if transparent { - DXGI_ALPHA_MODE_PREMULTIPLIED - } else { - DXGI_ALPHA_MODE_IGNORE - }; let desc = DXGI_SWAP_CHAIN_DESC1 { Width: width, Height: height, @@ -1093,7 +995,7 @@ fn create_swap_chain( // Composition SwapChains only support the DXGI_SCALING_STRETCH Scaling. Scaling: DXGI_SCALING_STRETCH, SwapEffect: DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL, - AlphaMode: alpha_mode, + AlphaMode: DXGI_ALPHA_MODE_PREMULTIPLIED, Flags: 0, }; Ok(ManuallyDrop::new(unsafe { @@ -1149,24 +1051,6 @@ fn create_render_target_and_its_view( )) } -#[inline] -fn set_render_target_view( - swap_chain: &IDXGISwapChain1, - device: &ID3D11Device, - device_context: &ID3D11DeviceContext, -) -> Result { - // In dx11, ID3D11RenderTargetView is supposed to always point to the new back buffer. - // https://stackoverflow.com/questions/65246961/does-the-backbuffer-that-a-rendertargetview-points-to-automagically-change-after - let back_buffer = unsafe { - let resource: ID3D11Texture2D = swap_chain.GetBuffer(0)?; - let mut buffer: Option = None; - device.CreateRenderTargetView(&resource, None, Some(&mut buffer))?; - buffer.unwrap() - }; - unsafe { device_context.OMSetRenderTargets(Some(&[Some(back_buffer.clone())]), None) }; - Ok(back_buffer) -} - #[inline] fn create_msaa_target_and_its_view( device: &ID3D11Device, diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index 077ba82e92669da09f081672e7d0ea8cedddb5ce..e712d939c87742ee3f7c5df043112853a8ae7a39 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -80,7 +80,6 @@ pub(crate) struct WindowsWindowStatePtr { impl WindowsWindowState { fn new( hwnd: HWND, - transparent: bool, cs: &CREATESTRUCTW, current_cursor: Option, display: WindowsDisplay, @@ -104,7 +103,7 @@ impl WindowsWindowState { let border_offset = WindowBorderOffset::default(); let restore_from_minimized = None; // let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?; - let renderer = DirectXRenderer::new(gpu_context, hwnd, transparent)?; + let renderer = DirectXRenderer::new(gpu_context, hwnd)?; let callbacks = Callbacks::default(); let input_handler = None; let pending_surrogate = None; @@ -207,7 +206,6 @@ impl WindowsWindowStatePtr { fn new(context: &WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result> { let state = RefCell::new(WindowsWindowState::new( hwnd, - context.transparent, cs, context.current_cursor, context.display, @@ -335,7 +333,6 @@ struct WindowCreateContext<'a> { handle: AnyWindowHandle, hide_title_bar: bool, display: WindowsDisplay, - transparent: bool, is_movable: bool, min_size: Option>, executor: ForegroundExecutor, @@ -381,11 +378,13 @@ impl WindowsWindow { .unwrap_or(""), ); let (dwexstyle, mut dwstyle) = if params.kind == WindowKind::PopUp { - (WS_EX_TOOLWINDOW | WS_EX_LAYERED, WINDOW_STYLE(0x0)) + ( + WS_EX_TOOLWINDOW | WS_EX_NOREDIRECTIONBITMAP, + WINDOW_STYLE(0x0), + ) } else { ( WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP, - // WS_EX_APPWINDOW | WS_EX_LAYERED, WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, ) }; @@ -403,7 +402,6 @@ impl WindowsWindow { handle, hide_title_bar, display, - transparent: false, is_movable: params.is_movable, min_size: params.window_min_size, executor, @@ -455,14 +453,6 @@ impl WindowsWindow { state: WindowOpenState::Windowed, }); } - // The render pipeline will perform compositing on the GPU when the - // swapchain is configured correctly (see downstream of - // update_transparency). - // The following configuration is a one-time setup to ensure that the - // window is going to be composited with per-pixel alpha, but the render - // pipeline is responsible for effectively calling UpdateLayeredWindow - // at the appropriate time. - // unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? }; Ok(Self(state_ptr)) } @@ -707,26 +697,21 @@ impl PlatformWindow for WindowsWindow { } fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) { - let mut window_state = self.0.state.borrow_mut(); - window_state - .renderer - .update_transparency(background_appearance) - .context("Updating window transparency") - .log_err(); + let hwnd = self.0.hwnd; match background_appearance { WindowBackgroundAppearance::Opaque => { // ACCENT_DISABLED - set_window_composition_attribute(window_state.hwnd, None, 0); + set_window_composition_attribute(hwnd, None, 0); } WindowBackgroundAppearance::Transparent => { // Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background - set_window_composition_attribute(window_state.hwnd, None, 2); + set_window_composition_attribute(hwnd, None, 2); } WindowBackgroundAppearance::Blurred => { // Enable acrylic blur // ACCENT_ENABLE_ACRYLICBLURBEHIND - set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 0)), 4); + set_window_composition_attribute(hwnd, Some((0, 0, 0, 0)), 4); } } } From 63727f99da1e922797d24a886086524e7c1a82fa Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 14:53:28 +0800 Subject: [PATCH 34/45] rename to `DirectXResources` --- .../src/platform/windows/directx_renderer.rs | 95 ++++++++++--------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index ebd4c4730ba7bb4ed327fe8bbec29207fed5d0d1..bc74ad778259f845df6f0b9dc19c51073e3dc04e 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -20,15 +20,18 @@ use windows::{ use crate::*; const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM; +// This configuration is used for MSAA rendering, and it's guaranteed to be supported by DirectX 11. +const MULTISAMPLE_COUNT: u32 = 4; pub(crate) struct DirectXRenderer { atlas: Arc, devices: DirectXDevices, - context: DirectXContext, + resources: DirectXResources, globals: DirectXGlobalElements, pipelines: DirectXRenderPipelines, } +/// Direct3D objects #[derive(Clone)] pub(crate) struct DirectXDevices { dxgi_factory: IDXGIFactory6, @@ -37,13 +40,17 @@ pub(crate) struct DirectXDevices { device_context: ID3D11DeviceContext, } -struct DirectXContext { +struct DirectXResources { + // Direct3D rendering objects swap_chain: ManuallyDrop, render_target: ManuallyDrop, render_target_view: [Option; 1], msaa_target: ID3D11Texture2D, msaa_view: ID3D11RenderTargetView, + + // Cached viewport viewport: [D3D11_VIEWPORT; 1], + // #[cfg(not(feature = "enable-renderdoc"))] _direct_composition: DirectComposition, } @@ -105,13 +112,13 @@ impl DirectXRenderer { devices.device.clone(), devices.device_context.clone(), )); - let context = DirectXContext::new(devices, hwnd)?; + let resources = DirectXResources::new(devices, hwnd)?; let globals = DirectXGlobalElements::new(&devices.device)?; let pipelines = DirectXRenderPipelines::new(&devices.device)?; Ok(DirectXRenderer { atlas, devices: devices.clone(), - context, + resources, globals, pipelines, }) @@ -127,8 +134,8 @@ impl DirectXRenderer { self.globals.global_params_buffer[0].as_ref().unwrap(), &[GlobalParams { viewport_size: [ - self.context.viewport[0].Width, - self.context.viewport[0].Height, + self.resources.viewport[0].Width, + self.resources.viewport[0].Height, ], ..Default::default() }], @@ -136,13 +143,13 @@ impl DirectXRenderer { unsafe { self.devices .device_context - .ClearRenderTargetView(&self.context.msaa_view, &[0.0; 4]); + .ClearRenderTargetView(&self.resources.msaa_view, &[0.0; 4]); self.devices .device_context - .OMSetRenderTargets(Some(&[Some(self.context.msaa_view.clone())]), None); + .OMSetRenderTargets(Some(&[Some(self.resources.msaa_view.clone())]), None); self.devices .device_context - .RSSetViewports(Some(&self.context.viewport)); + .RSSetViewports(Some(&self.resources.viewport)); self.devices.device_context.OMSetBlendState( &self.globals.blend_state, None, @@ -180,16 +187,16 @@ impl DirectXRenderer { } unsafe { self.devices.device_context.ResolveSubresource( - &*self.context.render_target, + &*self.resources.render_target, 0, - &self.context.msaa_target, + &self.resources.msaa_target, 0, RENDER_TARGET_FORMAT, ); self.devices .device_context - .OMSetRenderTargets(Some(&self.context.render_target_view), None); - self.context.swap_chain.Present(0, DXGI_PRESENT(0)).ok()?; + .OMSetRenderTargets(Some(&self.resources.render_target_view), None); + self.resources.swap_chain.Present(0, DXGI_PRESENT(0)).ok()?; } Ok(()) } @@ -197,11 +204,11 @@ impl DirectXRenderer { pub(crate) fn resize(&mut self, new_size: Size) -> Result<()> { unsafe { self.devices.device_context.OMSetRenderTargets(None, None); - ManuallyDrop::drop(&mut self.context.render_target); + ManuallyDrop::drop(&mut self.resources.render_target); } - drop(self.context.render_target_view[0].take().unwrap()); + drop(self.resources.render_target_view[0].take().unwrap()); unsafe { - self.context + self.resources .swap_chain .ResizeBuffers( BUFFER_COUNT as u32, @@ -213,14 +220,14 @@ impl DirectXRenderer { .unwrap(); } let (render_target, render_target_view) = - create_render_target_and_its_view(&self.context.swap_chain, &self.devices.device) + create_render_target_and_its_view(&self.resources.swap_chain, &self.devices.device) .unwrap(); - self.context.render_target = render_target; - self.context.render_target_view = render_target_view; + self.resources.render_target = render_target; + self.resources.render_target_view = render_target_view; unsafe { self.devices .device_context - .OMSetRenderTargets(Some(&self.context.render_target_view), None); + .OMSetRenderTargets(Some(&self.resources.render_target_view), None); } let (msaa_target, msaa_view) = create_msaa_target_and_its_view( @@ -228,10 +235,10 @@ impl DirectXRenderer { new_size.width.0 as u32, new_size.height.0 as u32, )?; - self.context.msaa_target = msaa_target; - self.context.msaa_view = msaa_view; + self.resources.msaa_target = msaa_target; + self.resources.msaa_view = msaa_view; - self.context.viewport = set_viewport( + self.resources.viewport = set_viewport( &self.devices.device_context, new_size.width.0 as f32, new_size.height.0 as f32, @@ -250,7 +257,7 @@ impl DirectXRenderer { )?; self.pipelines.shadow_pipeline.draw( &self.devices.device_context, - &self.context.viewport, + &self.resources.viewport, &self.globals.global_params_buffer, shadows.len() as u32, ) @@ -267,7 +274,7 @@ impl DirectXRenderer { )?; self.pipelines.quad_pipeline.draw( &self.devices.device_context, - &self.context.viewport, + &self.resources.viewport, &self.globals.global_params_buffer, quads.len() as u32, ) @@ -312,7 +319,7 @@ impl DirectXRenderer { self.pipelines.paths_pipeline.draw( &self.devices.device_context, paths.len(), - &self.context.viewport, + &self.resources.viewport, &self.globals.global_params_buffer, ) } @@ -328,7 +335,7 @@ impl DirectXRenderer { )?; self.pipelines.underline_pipeline.draw( &self.devices.device_context, - &self.context.viewport, + &self.resources.viewport, &self.globals.global_params_buffer, underlines.len() as u32, ) @@ -351,7 +358,7 @@ impl DirectXRenderer { self.pipelines.mono_sprites.draw_with_texture( &self.devices.device_context, &texture_view, - &self.context.viewport, + &self.resources.viewport, &self.globals.global_params_buffer, &self.globals.sampler, sprites.len() as u32, @@ -375,7 +382,7 @@ impl DirectXRenderer { self.pipelines.poly_sprites.draw_with_texture( &self.devices.device_context, &texture_view, - &self.context.viewport, + &self.resources.viewport, &self.globals.global_params_buffer, &self.globals.sampler, sprites.len() as u32, @@ -390,24 +397,17 @@ impl DirectXRenderer { } } -impl DirectXContext { +impl DirectXResources { pub fn new(devices: &DirectXDevices, hwnd: HWND) -> Result { let (width, height) = unsafe { let mut rect = std::mem::zeroed(); GetWindowRect(hwnd, &mut rect)?; - (rect.right - rect.left, rect.bottom - rect.top) + let width = (rect.right - rect.left).max(1) as u32; + let height = (rect.bottom - rect.top).max(1) as u32; + (width, height) }; - assert!( - width > 0 && height > 0, - "Window size must be greater than zero" - ); // #[cfg(not(feature = "enable-renderdoc"))] - let swap_chain = create_swap_chain( - &devices.dxgi_factory, - &devices.device, - width as u32, - height as u32, - )?; + let swap_chain = create_swap_chain(&devices.dxgi_factory, &devices.device, width, height)?; // #[cfg(feature = "enable-renderdoc")] // let swap_chain = // create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?; @@ -418,7 +418,7 @@ impl DirectXContext { let (render_target, render_target_view) = create_render_target_and_its_view(&swap_chain, &devices.device)?; let (msaa_target, msaa_view) = - create_msaa_target_and_its_view(&devices.device, width as u32, height as u32)?; + create_msaa_target_and_its_view(&devices.device, width, height)?; let viewport = set_viewport(&devices.device_context, width as f32, height as f32); unsafe { devices @@ -905,7 +905,7 @@ struct PathSprite { color: Background, } -impl Drop for DirectXContext { +impl Drop for DirectXResources { fn drop(&mut self) { unsafe { ManuallyDrop::drop(&mut self.render_target); @@ -1008,13 +1008,14 @@ fn create_swap_chain_default( dxgi_factory: &IDXGIFactory6, device: &ID3D11Device, hwnd: HWND, - _transparent: bool, + width: u32, + height: u32, ) -> Result> { use windows::Win32::Graphics::Dxgi::DXGI_MWA_NO_ALT_ENTER; let desc = DXGI_SWAP_CHAIN_DESC1 { - Width: 1, - Height: 1, + Width: width, + Height: height, Format: RENDER_TARGET_FORMAT, Stereo: false.into(), SampleDesc: DXGI_SAMPLE_DESC { @@ -1066,7 +1067,7 @@ fn create_msaa_target_and_its_view( ArraySize: 1, Format: RENDER_TARGET_FORMAT, SampleDesc: DXGI_SAMPLE_DESC { - Count: 4, + Count: MULTISAMPLE_COUNT, Quality: D3D11_STANDARD_MULTISAMPLE_PATTERN.0 as u32, }, Usage: D3D11_USAGE_DEFAULT, From 1888f21a1455dc611f54dc8c4065a181ec43d56e Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 15:52:51 +0800 Subject: [PATCH 35/45] refactor --- .../src/platform/windows/directx_renderer.rs | 178 ++++++++++-------- 1 file changed, 99 insertions(+), 79 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index bc74ad778259f845df6f0b9dc19c51073e3dc04e..87c98512b99857921c57bed1145e81dadc267b88 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -29,6 +29,8 @@ pub(crate) struct DirectXRenderer { resources: DirectXResources, globals: DirectXGlobalElements, pipelines: DirectXRenderPipelines, + // #[cfg(not(feature = "enable-renderdoc"))] + _direct_composition: DirectComposition, } /// Direct3D objects @@ -42,17 +44,14 @@ pub(crate) struct DirectXDevices { struct DirectXResources { // Direct3D rendering objects - swap_chain: ManuallyDrop, + swap_chain: IDXGISwapChain1, render_target: ManuallyDrop, render_target_view: [Option; 1], msaa_target: ID3D11Texture2D, - msaa_view: ID3D11RenderTargetView, + msaa_view: [Option; 1], // Cached viewport viewport: [D3D11_VIEWPORT; 1], - - // #[cfg(not(feature = "enable-renderdoc"))] - _direct_composition: DirectComposition, } struct DirectXRenderPipelines { @@ -115,12 +114,18 @@ impl DirectXRenderer { let resources = DirectXResources::new(devices, hwnd)?; let globals = DirectXGlobalElements::new(&devices.device)?; let pipelines = DirectXRenderPipelines::new(&devices.device)?; + // #[cfg(not(feature = "enable-renderdoc"))] + let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?; + // #[cfg(not(feature = "enable-renderdoc"))] + direct_composition.set_swap_chain(&resources.swap_chain)?; Ok(DirectXRenderer { atlas, devices: devices.clone(), resources, globals, pipelines, + // #[cfg(not(feature = "enable-renderdoc"))] + _direct_composition: direct_composition, }) } @@ -143,10 +148,10 @@ impl DirectXRenderer { unsafe { self.devices .device_context - .ClearRenderTargetView(&self.resources.msaa_view, &[0.0; 4]); + .ClearRenderTargetView(self.resources.msaa_view[0].as_ref().unwrap(), &[0.0; 4]); self.devices .device_context - .OMSetRenderTargets(Some(&[Some(self.resources.msaa_view.clone())]), None); + .OMSetRenderTargets(Some(&self.resources.msaa_view), None); self.devices .device_context .RSSetViewports(Some(&self.resources.viewport)); @@ -159,6 +164,23 @@ impl DirectXRenderer { Ok(()) } + fn present(&self) -> Result<()> { + unsafe { + self.devices.device_context.ResolveSubresource( + &*self.resources.render_target, + 0, + &self.resources.msaa_target, + 0, + RENDER_TARGET_FORMAT, + ); + self.devices + .device_context + .OMSetRenderTargets(Some(&self.resources.render_target_view), None); + self.resources.swap_chain.Present(0, DXGI_PRESENT(0)).ok()?; + } + Ok(()) + } + pub(crate) fn draw(&mut self, scene: &Scene) -> Result<()> { self.pre_draw()?; for batch in scene.batches() { @@ -185,64 +207,29 @@ impl DirectXRenderer { scene.polychrome_sprites.len(), scene.surfaces.len(),))?; } - unsafe { - self.devices.device_context.ResolveSubresource( - &*self.resources.render_target, - 0, - &self.resources.msaa_target, - 0, - RENDER_TARGET_FORMAT, - ); - self.devices - .device_context - .OMSetRenderTargets(Some(&self.resources.render_target_view), None); - self.resources.swap_chain.Present(0, DXGI_PRESENT(0)).ok()?; - } - Ok(()) + self.present() } pub(crate) fn resize(&mut self, new_size: Size) -> Result<()> { unsafe { + let width = new_size.width.0 as u32; + let height = new_size.height.0 as u32; self.devices.device_context.OMSetRenderTargets(None, None); ManuallyDrop::drop(&mut self.resources.render_target); - } - drop(self.resources.render_target_view[0].take().unwrap()); - unsafe { + drop(self.resources.render_target_view[0].take().unwrap()); + self.resources.swap_chain.ResizeBuffers( + BUFFER_COUNT as u32, + width, + height, + RENDER_TARGET_FORMAT, + DXGI_SWAP_CHAIN_FLAG(0), + )?; self.resources - .swap_chain - .ResizeBuffers( - BUFFER_COUNT as u32, - new_size.width.0 as u32, - new_size.height.0 as u32, - RENDER_TARGET_FORMAT, - DXGI_SWAP_CHAIN_FLAG(0), - ) - .unwrap(); - } - let (render_target, render_target_view) = - create_render_target_and_its_view(&self.resources.swap_chain, &self.devices.device) - .unwrap(); - self.resources.render_target = render_target; - self.resources.render_target_view = render_target_view; - unsafe { + .recreate_resources(&self.devices, width, height)?; self.devices .device_context .OMSetRenderTargets(Some(&self.resources.render_target_view), None); } - - let (msaa_target, msaa_view) = create_msaa_target_and_its_view( - &self.devices.device, - new_size.width.0 as u32, - new_size.height.0 as u32, - )?; - self.resources.msaa_target = msaa_target; - self.resources.msaa_view = msaa_view; - - self.resources.viewport = set_viewport( - &self.devices.device_context, - new_size.width.0 as f32, - new_size.height.0 as f32, - ); Ok(()) } @@ -411,20 +398,13 @@ impl DirectXResources { // #[cfg(feature = "enable-renderdoc")] // let swap_chain = // create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?; - // #[cfg(not(feature = "enable-renderdoc"))] - let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?; - // #[cfg(not(feature = "enable-renderdoc"))] - direct_composition.set_swap_chain(&swap_chain)?; - let (render_target, render_target_view) = - create_render_target_and_its_view(&swap_chain, &devices.device)?; - let (msaa_target, msaa_view) = - create_msaa_target_and_its_view(&devices.device, width, height)?; - let viewport = set_viewport(&devices.device_context, width as f32, height as f32); - unsafe { - devices - .device_context - .OMSetRenderTargets(Some(&render_target_view), None); - } + let (render_target, render_target_view, msaa_target, msaa_view, viewport) = + create_resources(devices, &swap_chain, width, height)?; + // unsafe { + // devices + // .device_context + // .OMSetRenderTargets(Some(&render_target_view), None); + // } set_rasterizer_state(&devices.device, &devices.device_context)?; Ok(Self { @@ -434,10 +414,25 @@ impl DirectXResources { msaa_target, msaa_view, viewport, - // #[cfg(not(feature = "enable-renderdoc"))] - _direct_composition: direct_composition, }) } + + #[inline] + fn recreate_resources( + &mut self, + devices: &DirectXDevices, + width: u32, + height: u32, + ) -> Result<()> { + let (render_target, render_target_view, msaa_target, msaa_view, viewport) = + create_resources(devices, &self.swap_chain, width, height)?; + self.render_target = render_target; + self.render_target_view = render_target_view; + self.msaa_target = msaa_target; + self.msaa_view = msaa_view; + self.viewport = viewport; + Ok(()) + } } impl DirectXRenderPipelines { @@ -909,7 +904,6 @@ impl Drop for DirectXResources { fn drop(&mut self) { unsafe { ManuallyDrop::drop(&mut self.render_target); - ManuallyDrop::drop(&mut self.swap_chain); } } } @@ -961,6 +955,8 @@ fn get_device( D3D_DRIVER_TYPE_UNKNOWN, HMODULE::default(), device_flags, + // 4x MSAA is required for Direct3D Feature Level 10.1 or better + // 8x MSAA is required for Direct3D Feature Level 11.0 or better Some(&[D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1]), D3D11_SDK_VERSION, device, @@ -980,7 +976,7 @@ fn create_swap_chain( device: &ID3D11Device, width: u32, height: u32, -) -> Result> { +) -> Result { let desc = DXGI_SWAP_CHAIN_DESC1 { Width: width, Height: height, @@ -998,9 +994,7 @@ fn create_swap_chain( AlphaMode: DXGI_ALPHA_MODE_PREMULTIPLIED, Flags: 0, }; - Ok(ManuallyDrop::new(unsafe { - dxgi_factory.CreateSwapChainForComposition(device, &desc, None)? - })) + Ok(unsafe { dxgi_factory.CreateSwapChainForComposition(device, &desc, None)? }) } // #[cfg(feature = "enable-renderdoc")] @@ -1010,7 +1004,7 @@ fn create_swap_chain_default( hwnd: HWND, width: u32, height: u32, -) -> Result> { +) -> Result { use windows::Win32::Graphics::Dxgi::DXGI_MWA_NO_ALT_ENTER; let desc = DXGI_SWAP_CHAIN_DESC1 { @@ -1032,7 +1026,33 @@ fn create_swap_chain_default( let swap_chain = unsafe { dxgi_factory.CreateSwapChainForHwnd(device, hwnd, &desc, None, None) }?; unsafe { dxgi_factory.MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER) }?; - Ok(ManuallyDrop::new(swap_chain)) + Ok(swap_chain) +} + +#[inline] +fn create_resources( + devices: &DirectXDevices, + swap_chain: &IDXGISwapChain1, + width: u32, + height: u32, +) -> Result<( + ManuallyDrop, + [Option; 1], + ID3D11Texture2D, + [Option; 1], + [D3D11_VIEWPORT; 1], +)> { + let (render_target, render_target_view) = + create_render_target_and_its_view(&swap_chain, &devices.device)?; + let (msaa_target, msaa_view) = create_msaa_target_and_its_view(&devices.device, width, height)?; + let viewport = set_viewport(&devices.device_context, width as f32, height as f32); + Ok(( + render_target, + render_target_view, + msaa_target, + msaa_view, + viewport, + )) } #[inline] @@ -1057,7 +1077,7 @@ fn create_msaa_target_and_its_view( device: &ID3D11Device, width: u32, height: u32, -) -> Result<(ID3D11Texture2D, ID3D11RenderTargetView)> { +) -> Result<(ID3D11Texture2D, [Option; 1])> { let msaa_target = unsafe { let mut output = None; let desc = D3D11_TEXTURE2D_DESC { @@ -1083,7 +1103,7 @@ fn create_msaa_target_and_its_view( device.CreateRenderTargetView(&msaa_target, None, Some(&mut output))?; output.unwrap() }; - Ok((msaa_target, msaa_view)) + Ok((msaa_target, [Some(msaa_view)])) } #[inline] From 7cf10d110c4dd865740e8f97a5292c189d9d728a Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 16:34:09 +0800 Subject: [PATCH 36/45] wip --- .../src/platform/windows/directx_renderer.rs | 32 +++++++++++-------- crates/gpui/src/platform/windows/events.rs | 4 --- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 87c98512b99857921c57bed1145e81dadc267b88..d6d5d442af01a52e2050793112a77561ae525dd1 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -4,7 +4,6 @@ use ::util::ResultExt; use anyhow::{Context, Result}; // #[cfg(not(feature = "enable-renderdoc"))] use windows::Win32::Graphics::DirectComposition::*; -use windows::Win32::UI::WindowsAndMessaging::GetWindowRect; use windows::{ Win32::{ Foundation::{HMODULE, HWND}, @@ -50,7 +49,9 @@ struct DirectXResources { msaa_target: ID3D11Texture2D, msaa_view: [Option; 1], - // Cached viewport + // Cached window size and viewport + width: u32, + height: u32, viewport: [D3D11_VIEWPORT; 1], } @@ -111,7 +112,7 @@ impl DirectXRenderer { devices.device.clone(), devices.device_context.clone(), )); - let resources = DirectXResources::new(devices, hwnd)?; + let resources = DirectXResources::new(devices)?; let globals = DirectXGlobalElements::new(&devices.device)?; let pipelines = DirectXRenderPipelines::new(&devices.device)?; // #[cfg(not(feature = "enable-renderdoc"))] @@ -211,12 +212,17 @@ impl DirectXRenderer { } pub(crate) fn resize(&mut self, new_size: Size) -> Result<()> { + let width = new_size.width.0.max(1) as u32; + let height = new_size.height.0.max(1) as u32; + if self.resources.width == width && self.resources.height == height { + return Ok(()); + } unsafe { - let width = new_size.width.0 as u32; - let height = new_size.height.0 as u32; + // Clear the render target before resizing self.devices.device_context.OMSetRenderTargets(None, None); ManuallyDrop::drop(&mut self.resources.render_target); drop(self.resources.render_target_view[0].take().unwrap()); + self.resources.swap_chain.ResizeBuffers( BUFFER_COUNT as u32, width, @@ -224,6 +230,7 @@ impl DirectXRenderer { RENDER_TARGET_FORMAT, DXGI_SWAP_CHAIN_FLAG(0), )?; + self.resources .recreate_resources(&self.devices, width, height)?; self.devices @@ -385,14 +392,9 @@ impl DirectXRenderer { } impl DirectXResources { - pub fn new(devices: &DirectXDevices, hwnd: HWND) -> Result { - let (width, height) = unsafe { - let mut rect = std::mem::zeroed(); - GetWindowRect(hwnd, &mut rect)?; - let width = (rect.right - rect.left).max(1) as u32; - let height = (rect.bottom - rect.top).max(1) as u32; - (width, height) - }; + pub fn new(devices: &DirectXDevices) -> Result { + let width = 1; + let height = 1; // #[cfg(not(feature = "enable-renderdoc"))] let swap_chain = create_swap_chain(&devices.dxgi_factory, &devices.device, width, height)?; // #[cfg(feature = "enable-renderdoc")] @@ -413,6 +415,8 @@ impl DirectXResources { render_target_view, msaa_target, msaa_view, + width, + height, viewport, }) } @@ -431,6 +435,8 @@ impl DirectXResources { self.msaa_target = msaa_target; self.msaa_view = msaa_view; self.viewport = viewport; + self.width = width; + self.height = height; Ok(()) } } diff --git a/crates/gpui/src/platform/windows/events.rs b/crates/gpui/src/platform/windows/events.rs index 461aae5e25e5b1ccbbf3d9e174bf5c6cadd0e7b3..6fd899cbef864a5ff019e4496d3768345208dad5 100644 --- a/crates/gpui/src/platform/windows/events.rs +++ b/crates/gpui/src/platform/windows/events.rs @@ -181,12 +181,8 @@ fn handle_size_msg( let new_size = size(DevicePixels(width), DevicePixels(height)); let scale_factor = lock.scale_factor; if lock.restore_from_minimized.is_some() { - // lock.renderer - // .update_drawable_size_even_if_unchanged(new_size); - lock.renderer.resize(new_size).log_err(); lock.callbacks.request_frame = lock.restore_from_minimized.take(); } else { - // lock.renderer.update_drawable_size(new_size); lock.renderer.resize(new_size).log_err(); } let new_size = new_size.to_pixels(scale_factor); From a57cbe46361d6d8bf27c7324f1f57a74a7f217ef Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 16:34:34 +0800 Subject: [PATCH 37/45] remove unused --- crates/gpui/src/platform/windows/directx_renderer.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index d6d5d442af01a52e2050793112a77561ae525dd1..02469043b55b2000c6ccb8d71e707c7aaa81ad7b 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -402,11 +402,6 @@ impl DirectXResources { // create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?; let (render_target, render_target_view, msaa_target, msaa_view, viewport) = create_resources(devices, &swap_chain, width, height)?; - // unsafe { - // devices - // .device_context - // .OMSetRenderTargets(Some(&render_target_view), None); - // } set_rasterizer_state(&devices.device, &devices.device_context)?; Ok(Self { From e560c6813fe63af5bb0586c516c3b900a1197908 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 16:57:23 +0800 Subject: [PATCH 38/45] add new feature `enable-renderdoc` --- crates/gpui/Cargo.toml | 1 + .../src/platform/windows/directx_renderer.rs | 61 +++++++++++-------- crates/zed/Cargo.toml | 1 + 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 4e718b442867d2335715e2e963fa9330d9f04525..284664d02f3d8a1cbeff54b490b8010615578d32 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -71,6 +71,7 @@ screen-capture = [ "scap", ] windows-manifest = [] +enable-renderdoc = [] [lib] path = "src/gpui.rs" diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 02469043b55b2000c6ccb8d71e707c7aaa81ad7b..062f0a43150708d0c8fd90eb9429e1c331d90e73 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -2,18 +2,15 @@ use std::{mem::ManuallyDrop, sync::Arc}; use ::util::ResultExt; use anyhow::{Context, Result}; -// #[cfg(not(feature = "enable-renderdoc"))] +#[cfg(not(feature = "enable-renderdoc"))] use windows::Win32::Graphics::DirectComposition::*; -use windows::{ - Win32::{ - Foundation::{HMODULE, HWND}, - Graphics::{ - Direct3D::*, - Direct3D11::*, - Dxgi::{Common::*, *}, - }, +use windows::Win32::{ + Foundation::{HMODULE, HWND}, + Graphics::{ + Direct3D::*, + Direct3D11::*, + Dxgi::{Common::*, *}, }, - core::*, }; use crate::*; @@ -28,7 +25,7 @@ pub(crate) struct DirectXRenderer { resources: DirectXResources, globals: DirectXGlobalElements, pipelines: DirectXRenderPipelines, - // #[cfg(not(feature = "enable-renderdoc"))] + #[cfg(not(feature = "enable-renderdoc"))] _direct_composition: DirectComposition, } @@ -36,6 +33,7 @@ pub(crate) struct DirectXRenderer { #[derive(Clone)] pub(crate) struct DirectXDevices { dxgi_factory: IDXGIFactory6, + #[cfg(not(feature = "enable-renderdoc"))] dxgi_device: IDXGIDevice, device: ID3D11Device, device_context: ID3D11DeviceContext, @@ -78,7 +76,7 @@ struct DrawInstancedIndirectArgs { start_instance_location: u32, } -// #[cfg(not(feature = "enable-renderdoc"))] +#[cfg(not(feature = "enable-renderdoc"))] struct DirectComposition { comp_device: IDCompositionDevice, comp_target: IDCompositionTarget, @@ -95,10 +93,12 @@ impl DirectXDevices { get_device(&adapter, Some(&mut device), Some(&mut context))?; (device.unwrap(), context.unwrap()) }; + #[cfg(not(feature = "enable-renderdoc"))] let dxgi_device: IDXGIDevice = device.cast()?; Ok(Self { dxgi_factory, + #[cfg(not(feature = "enable-renderdoc"))] dxgi_device, device, device_context, @@ -112,20 +112,27 @@ impl DirectXRenderer { devices.device.clone(), devices.device_context.clone(), )); + + #[cfg(not(feature = "enable-renderdoc"))] let resources = DirectXResources::new(devices)?; + #[cfg(feature = "enable-renderdoc")] + let resources = DirectXResources::new(devices, hwnd)?; + let globals = DirectXGlobalElements::new(&devices.device)?; let pipelines = DirectXRenderPipelines::new(&devices.device)?; - // #[cfg(not(feature = "enable-renderdoc"))] + + #[cfg(not(feature = "enable-renderdoc"))] let direct_composition = DirectComposition::new(&devices.dxgi_device, hwnd)?; - // #[cfg(not(feature = "enable-renderdoc"))] + #[cfg(not(feature = "enable-renderdoc"))] direct_composition.set_swap_chain(&resources.swap_chain)?; + Ok(DirectXRenderer { atlas, devices: devices.clone(), resources, globals, pipelines, - // #[cfg(not(feature = "enable-renderdoc"))] + #[cfg(not(feature = "enable-renderdoc"))] _direct_composition: direct_composition, }) } @@ -392,14 +399,19 @@ impl DirectXRenderer { } impl DirectXResources { - pub fn new(devices: &DirectXDevices) -> Result { + pub fn new( + devices: &DirectXDevices, + #[cfg(feature = "enable-renderdoc")] hwnd: HWND, + ) -> Result { let width = 1; let height = 1; - // #[cfg(not(feature = "enable-renderdoc"))] + + #[cfg(not(feature = "enable-renderdoc"))] let swap_chain = create_swap_chain(&devices.dxgi_factory, &devices.device, width, height)?; - // #[cfg(feature = "enable-renderdoc")] - // let swap_chain = - // create_swap_chain_default(&devices.dxgi_factory, &devices.device, hwnd, transparent)?; + #[cfg(feature = "enable-renderdoc")] + let swap_chain = + create_swap_chain(&devices.dxgi_factory, &devices.device, hwnd, width, height)?; + let (render_target, render_target_view, msaa_target, msaa_view, viewport) = create_resources(devices, &swap_chain, width, height)?; set_rasterizer_state(&devices.device, &devices.device_context)?; @@ -481,7 +493,7 @@ impl DirectXRenderPipelines { } } -// #[cfg(not(feature = "enable-renderdoc"))] +#[cfg(not(feature = "enable-renderdoc"))] impl DirectComposition { pub fn new(dxgi_device: &IDXGIDevice, hwnd: HWND) -> Result { let comp_device = get_comp_device(&dxgi_device)?; @@ -967,11 +979,12 @@ fn get_device( }) } -// #[cfg(not(feature = "enable-renderdoc"))] +#[cfg(not(feature = "enable-renderdoc"))] fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result { Ok(unsafe { DCompositionCreateDevice(dxgi_device)? }) } +#[cfg(not(feature = "enable-renderdoc"))] fn create_swap_chain( dxgi_factory: &IDXGIFactory6, device: &ID3D11Device, @@ -998,8 +1011,8 @@ fn create_swap_chain( Ok(unsafe { dxgi_factory.CreateSwapChainForComposition(device, &desc, None)? }) } -// #[cfg(feature = "enable-renderdoc")] -fn create_swap_chain_default( +#[cfg(feature = "enable-renderdoc")] +fn create_swap_chain( dxgi_factory: &IDXGIFactory6, device: &ID3D11Device, hwnd: HWND, diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 3af1709b74af3d65539d80d4e39a9978a8da86d5..9b170a84f36faff844290ca403891872152dbf79 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -69,6 +69,7 @@ gpui = { workspace = true, features = [ "x11", "font-kit", "windows-manifest", + "enable-renderdoc", ] } gpui_tokio.workspace = true From 29b5acf27b313c5e6e58eb98a5c622713e147a93 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 17:04:36 +0800 Subject: [PATCH 39/45] show err if failed to create new window --- crates/gpui/src/platform/windows/platform.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index a14e9ecb54bc543f02353eac1fc1c5a66a20cad7..ca205cc61a626311c0d3320c71137f1627b0b8da 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -462,7 +462,8 @@ impl Platform for WindowsPlatform { options, self.generate_creation_info(), &self.directx_devices, - )?; + ) + .inspect_err(|err| show_error("Failed to open new window", err.to_string()))?; let handle = window.get_raw_handle(); self.raw_window_handles.write().push(handle); From 76fb80eaeb24a3cb3334c29d1cd3ea01731ed13a Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 17:12:27 +0800 Subject: [PATCH 40/45] fix --- crates/gpui/src/platform/windows/directx_renderer.rs | 4 ++-- crates/zed/Cargo.toml | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 062f0a43150708d0c8fd90eb9429e1c331d90e73..4bc80851beb3b4c511749d3478e0f6b6e6888fb1 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -2,8 +2,6 @@ use std::{mem::ManuallyDrop, sync::Arc}; use ::util::ResultExt; use anyhow::{Context, Result}; -#[cfg(not(feature = "enable-renderdoc"))] -use windows::Win32::Graphics::DirectComposition::*; use windows::Win32::{ Foundation::{HMODULE, HWND}, Graphics::{ @@ -12,6 +10,8 @@ use windows::Win32::{ Dxgi::{Common::*, *}, }, }; +#[cfg(not(feature = "enable-renderdoc"))] +use windows::{Win32::Graphics::DirectComposition::*, core::Interface}; use crate::*; diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 9b170a84f36faff844290ca403891872152dbf79..3af1709b74af3d65539d80d4e39a9978a8da86d5 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -69,7 +69,6 @@ gpui = { workspace = true, features = [ "x11", "font-kit", "windows-manifest", - "enable-renderdoc", ] } gpui_tokio.workspace = true From 4d936845f35435aa9a823921b992c758df36e054 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 19:30:49 +0800 Subject: [PATCH 41/45] implement gpu driver version for nvidia --- .../src/platform/windows/directx_renderer.rs | 116 +++++++++++++++++- crates/gpui/src/platform/windows/window.rs | 3 +- 2 files changed, 112 insertions(+), 7 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 4bc80851beb3b4c511749d3478e0f6b6e6888fb1..22bd5b0b95d7cc5e5c444a87b342b584913ced5c 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -32,6 +32,7 @@ pub(crate) struct DirectXRenderer { /// Direct3D objects #[derive(Clone)] pub(crate) struct DirectXDevices { + adapter: IDXGIAdapter1, dxgi_factory: IDXGIFactory6, #[cfg(not(feature = "enable-renderdoc"))] dxgi_device: IDXGIDevice, @@ -97,6 +98,7 @@ impl DirectXDevices { let dxgi_device: IDXGIDevice = device.cast()?; Ok(Self { + adapter, dxgi_factory, #[cfg(not(feature = "enable-renderdoc"))] dxgi_device, @@ -396,6 +398,34 @@ impl DirectXRenderer { } Ok(()) } + + pub(crate) fn gpu_specs(&self) -> Result { + let desc = unsafe { self.devices.adapter.GetDesc1() }?; + let is_software_emulated = (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE.0 as u32) != 0; + let device_name = String::from_utf16_lossy(&desc.Description) + .trim_matches(char::from(0)) + .to_string(); + let driver_name = match desc.VendorId { + 0x10DE => "NVIDIA Corporation".to_string(), + 0x1002 => "AMD Corporation".to_string(), + 0x8086 => "Intel Corporation".to_string(), + _ => "Unknown Vendor".to_string(), + }; + let driver_version = match desc.VendorId { + 0x10DE => nvidia::get_driver_version().context("Failed to get NVIDIA driver info"), + 0x1002 => Err(anyhow::anyhow!("AMD driver info not implemented yet")), + 0x8086 => Err(anyhow::anyhow!("Intel driver info not implemented yet")), + _ => Err(anyhow::anyhow!("Unknown vendor detected.")), + } + .log_err() + .unwrap_or("Unknown Driver".to_string()); + Ok(GpuSpecs { + is_software_emulated, + device_name, + driver_name, + driver_info: driver_version, + }) + } } impl DirectXResources { @@ -936,12 +966,11 @@ fn get_adapter(dxgi_factory: &IDXGIFactory6) -> Result { dxgi_factory .EnumAdapterByGpuPreference(adapter_index, DXGI_GPU_PREFERENCE_MINIMUM_POWER) }?; - { - let desc = unsafe { adapter.GetDesc1() }?; - println!( - "Select GPU: {}", - String::from_utf16_lossy(&desc.Description) - ); + if let Ok(desc) = unsafe { adapter.GetDesc1() } { + let gpu_name = String::from_utf16_lossy(&desc.Description) + .trim_matches(char::from(0)) + .to_string(); + log::info!("Using GPU: {}", gpu_name); } // Check to see whether the adapter supports Direct3D 11, but don't // create the actual device yet. @@ -1339,3 +1368,78 @@ mod shader_resources { } } } + +mod nvidia { + use std::os::raw::{c_char, c_int, c_uint}; + + use anyhow::{Context, Result}; + use windows::{ + Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA}, + core::s, + }; + + // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_lite_common.h#L180 + const NVAPI_SHORT_STRING_MAX: usize = 64; + + // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_lite_common.h#L235 + #[allow(non_camel_case_types)] + type NvAPI_ShortString = [c_char; NVAPI_SHORT_STRING_MAX]; + + // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi.h#L87 + #[allow(non_camel_case_types)] + type NvAPI_Initialize_t = unsafe extern "C" fn() -> c_int; + + // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_lite_common.h#L447 + #[allow(non_camel_case_types)] + type NvAPI_SYS_GetDriverAndBranchVersion_t = unsafe extern "C" fn( + driver_version: *mut c_uint, + build_branch_string: *mut NvAPI_ShortString, + ) -> c_int; + + pub(super) fn get_driver_version() -> Result { + unsafe { + // Try to load the NVIDIA driver DLL + let nvidia_dll = LoadLibraryA(s!("nvapi64.dll")).context("Can't load nvapi64.dll")?; + let nvapi_query_addr = GetProcAddress(nvidia_dll, s!("nvapi_QueryInterface")) + .ok_or_else(|| anyhow::anyhow!("Failed to get nvapi_QueryInterface address"))?; + let nvapi_query: extern "C" fn(u32) -> *mut () = std::mem::transmute(nvapi_query_addr); + + // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_interface.h#L33 + let nvapi_init_ptr = nvapi_query(0x0150e828); + if nvapi_init_ptr.is_null() { + anyhow::bail!("Failed to get NVIDIA API function pointer"); + } + let nvapi_init: NvAPI_Initialize_t = std::mem::transmute(nvapi_init_ptr); + + let result = nvapi_init(); + if result != 0 { + anyhow::bail!("Failed to initialize NVIDIA API, error code: {}", result); + } + + // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_interface.h#L41 + let nvapi_get_driver_version_ptr = nvapi_query(0x2926aaad); + if nvapi_get_driver_version_ptr.is_null() { + anyhow::bail!("Failed to get NVIDIA driver version function pointer"); + } + let nvapi_get_driver_version: NvAPI_SYS_GetDriverAndBranchVersion_t = + std::mem::transmute(nvapi_get_driver_version_ptr); + + let mut driver_version: c_uint = 0; + let mut build_branch_string: NvAPI_ShortString = [0; NVAPI_SHORT_STRING_MAX]; + let result = nvapi_get_driver_version( + &mut driver_version as *mut c_uint, + &mut build_branch_string as *mut NvAPI_ShortString, + ); + + if result != 0 { + anyhow::bail!( + "Failed to get NVIDIA driver version, error code: {}", + result + ); + } + let major = driver_version / 100; + let minor = driver_version % 100; + Ok(format!("{}.{}", major, minor)) + } + } +} diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index e712d939c87742ee3f7c5df043112853a8ae7a39..a2bc854484cb1e696f950bea07756258091d831a 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -104,6 +104,7 @@ impl WindowsWindowState { let restore_from_minimized = None; // let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?; let renderer = DirectXRenderer::new(gpu_context, hwnd)?; + println!("GPU specs: {:#?}", renderer.gpu_specs()); let callbacks = Callbacks::default(); let input_handler = None; let pending_surrogate = None; @@ -801,7 +802,7 @@ impl PlatformWindow for WindowsWindow { } fn update_ime_position(&self, _bounds: Bounds) { - // todo(windows) + // There is no such thing on Windows. } } From 78824390d0e73a3340eca7f53b75002d06c2c774 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 19:48:42 +0800 Subject: [PATCH 42/45] cleanup --- crates/gpui/src/platform.rs | 1 - .../src/platform/windows/directx_atlas.rs | 40 ++++++-------- crates/gpui/src/platform/windows/platform.rs | 2 +- crates/gpui/src/platform/windows/window.rs | 53 +------------------ 4 files changed, 18 insertions(+), 78 deletions(-) diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 0250e59a9bbc363a61377dc8c0ab01bccd820df3..8be6a0d5fabcae9abf3a97f5da9a8a71ebd4c4b5 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -13,7 +13,6 @@ mod mac; any(target_os = "linux", target_os = "freebsd"), any(feature = "x11", feature = "wayland") ), - target_os = "windows", feature = "macos-blade" ))] mod blade; diff --git a/crates/gpui/src/platform/windows/directx_atlas.rs b/crates/gpui/src/platform/windows/directx_atlas.rs index abd6e4ad40ba083183ebfdedb63d6d4f6b6e07f2..1abeab8928d28258c13a7a08a9da2466f599583d 100644 --- a/crates/gpui/src/platform/windows/directx_atlas.rs +++ b/crates/gpui/src/platform/windows/directx_atlas.rs @@ -12,7 +12,7 @@ use windows::Win32::Graphics::{ use crate::{ AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas, - Size, platform::AtlasTextureList, + Point, Size, platform::AtlasTextureList, }; pub(crate) struct DirectXAtlas(Mutex); @@ -53,25 +53,6 @@ impl DirectXAtlas { let tex = lock.texture(id); tex.view.clone() } - - pub(crate) fn allocate( - &self, - size: Size, - texture_kind: AtlasTextureKind, - ) -> Option { - self.0.lock().allocate(size, texture_kind) - } - - pub(crate) fn clear_textures(&self, texture_kind: AtlasTextureKind) { - let mut lock = self.0.lock(); - let textures = match texture_kind { - AtlasTextureKind::Monochrome => &mut lock.monochrome_textures, - AtlasTextureKind::Polychrome => &mut lock.polychrome_textures, - }; - for texture in textures.iter_mut() { - texture.clear(); - } - } } impl PlatformAtlas for DirectXAtlas { @@ -249,10 +230,6 @@ impl DirectXAtlasState { } impl DirectXAtlasTexture { - fn clear(&mut self) { - self.allocator.clear(); - } - fn allocate(&mut self, size: Size) -> Option { let allocation = self.allocator.allocate(size.into())?; let tile = AtlasTile { @@ -301,3 +278,18 @@ impl DirectXAtlasTexture { self.live_atlas_keys == 0 } } + +impl From> for etagere::Size { + fn from(size: Size) -> Self { + etagere::Size::new(size.width.into(), size.height.into()) + } +} + +impl From for Point { + fn from(value: etagere::Point) -> Self { + Point { + x: DevicePixels::from(value.x), + y: DevicePixels::from(value.y), + } + } +} diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index ca205cc61a626311c0d3320c71137f1627b0b8da..3123f943e1f1fdc9a77b6cf598a056dc86bc38ae 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -28,7 +28,7 @@ use windows::{ core::*, }; -use crate::{platform::blade::BladeContext, *}; +use crate::*; pub(crate) struct WindowsPlatform { state: RefCell, diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index a2bc854484cb1e696f950bea07756258091d831a..a972cead2b6f4a1e1144b260789b4fc150f8a2da 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -26,7 +26,6 @@ use windows::{ core::*, }; -use crate::platform::blade::{BladeContext, BladeRenderer}; use crate::*; pub(crate) struct WindowsWindow(pub Rc); @@ -102,9 +101,7 @@ impl WindowsWindowState { }; let border_offset = WindowBorderOffset::default(); let restore_from_minimized = None; - // let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?; let renderer = DirectXRenderer::new(gpu_context, hwnd)?; - println!("GPU specs: {:#?}", renderer.gpu_specs()); let callbacks = Callbacks::default(); let input_handler = None; let pending_surrogate = None; @@ -796,9 +793,7 @@ impl PlatformWindow for WindowsWindow { } fn gpu_specs(&self) -> Option { - // todo(zjk) - // Some(self.0.state.borrow().renderer.gpu_specs()) - None + self.0.state.borrow().renderer.gpu_specs().log_err() } fn update_ime_position(&self, _bounds: Bounds) { @@ -1298,52 +1293,6 @@ fn set_window_composition_attribute(hwnd: HWND, color: Option, state: u32 } } -mod windows_renderer { - use crate::platform::blade::{BladeContext, BladeRenderer, BladeSurfaceConfig}; - use raw_window_handle as rwh; - use std::num::NonZeroIsize; - use windows::Win32::{Foundation::HWND, UI::WindowsAndMessaging::GWLP_HINSTANCE}; - - use crate::{get_window_long, show_error}; - - pub(super) fn init( - context: &BladeContext, - hwnd: HWND, - transparent: bool, - ) -> anyhow::Result { - let raw = RawWindow { hwnd }; - let config = BladeSurfaceConfig { - size: Default::default(), - transparent, - }; - BladeRenderer::new(context, &raw, config) - .inspect_err(|err| show_error("Failed to initialize BladeRenderer", err.to_string())) - } - - struct RawWindow { - hwnd: HWND, - } - - impl rwh::HasWindowHandle for RawWindow { - fn window_handle(&self) -> Result, rwh::HandleError> { - Ok(unsafe { - let hwnd = NonZeroIsize::new_unchecked(self.hwnd.0 as isize); - let mut handle = rwh::Win32WindowHandle::new(hwnd); - let hinstance = get_window_long(self.hwnd, GWLP_HINSTANCE); - handle.hinstance = NonZeroIsize::new(hinstance); - rwh::WindowHandle::borrow_raw(handle.into()) - }) - } - } - - impl rwh::HasDisplayHandle for RawWindow { - fn display_handle(&self) -> Result, rwh::HandleError> { - let handle = rwh::WindowsDisplayHandle::new(); - Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) }) - } - } -} - #[cfg(test)] mod tests { use super::ClickState; From 7627097875ca3909e628d4d8a15a90494444f770 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 21:10:33 +0800 Subject: [PATCH 43/45] impl intel driver version --- .../src/platform/windows/directx_renderer.rs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 22bd5b0b95d7cc5e5c444a87b342b584913ced5c..8b549c2ae4c3a7c3b891da8beba5da429fb57584 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -412,11 +412,12 @@ impl DirectXRenderer { _ => "Unknown Vendor".to_string(), }; let driver_version = match desc.VendorId { - 0x10DE => nvidia::get_driver_version().context("Failed to get NVIDIA driver info"), + 0x10DE => nvidia::get_driver_version(), 0x1002 => Err(anyhow::anyhow!("AMD driver info not implemented yet")), - 0x8086 => Err(anyhow::anyhow!("Intel driver info not implemented yet")), + 0x8086 => intel::get_driver_version(&self.devices.adapter), _ => Err(anyhow::anyhow!("Unknown vendor detected.")), } + .context("Failed to get gpu driver info") .log_err() .unwrap_or("Unknown Driver".to_string()); Ok(GpuSpecs { @@ -1443,3 +1444,21 @@ mod nvidia { } } } + +mod intel { + use windows::{ + Win32::Graphics::Dxgi::{IDXGIAdapter1, IDXGIDevice}, + core::Interface, + }; + + pub(super) fn get_driver_version(adapter: &IDXGIAdapter1) -> anyhow::Result { + let number = unsafe { adapter.CheckInterfaceSupport(&IDXGIDevice::IID as _) }?; + Ok(format!( + "{}.{}.{}.{}", + number >> 48, + (number >> 32) & 0xFFFF, + (number >> 16) & 0xFFFF, + number & 0xFFFF + )) + } +} From 84f75fe6839fee381e09bf16e68829cb046c7207 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 21:31:00 +0800 Subject: [PATCH 44/45] better output for nvidia --- .../src/platform/windows/directx_renderer.rs | 29 +++++++------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 8b549c2ae4c3a7c3b891da8beba5da429fb57584..54478e9b02dc4a982e72d0fdd487cea158d7dae7 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -1371,7 +1371,10 @@ mod shader_resources { } mod nvidia { - use std::os::raw::{c_char, c_int, c_uint}; + use std::{ + ffi::CStr, + os::raw::{c_char, c_int, c_uint}, + }; use anyhow::{Context, Result}; use windows::{ @@ -1386,10 +1389,6 @@ mod nvidia { #[allow(non_camel_case_types)] type NvAPI_ShortString = [c_char; NVAPI_SHORT_STRING_MAX]; - // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi.h#L87 - #[allow(non_camel_case_types)] - type NvAPI_Initialize_t = unsafe extern "C" fn() -> c_int; - // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_lite_common.h#L447 #[allow(non_camel_case_types)] type NvAPI_SYS_GetDriverAndBranchVersion_t = unsafe extern "C" fn( @@ -1405,18 +1404,6 @@ mod nvidia { .ok_or_else(|| anyhow::anyhow!("Failed to get nvapi_QueryInterface address"))?; let nvapi_query: extern "C" fn(u32) -> *mut () = std::mem::transmute(nvapi_query_addr); - // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_interface.h#L33 - let nvapi_init_ptr = nvapi_query(0x0150e828); - if nvapi_init_ptr.is_null() { - anyhow::bail!("Failed to get NVIDIA API function pointer"); - } - let nvapi_init: NvAPI_Initialize_t = std::mem::transmute(nvapi_init_ptr); - - let result = nvapi_init(); - if result != 0 { - anyhow::bail!("Failed to initialize NVIDIA API, error code: {}", result); - } - // https://github.com/NVIDIA/nvapi/blob/7cb76fce2f52de818b3da497af646af1ec16ce27/nvapi_interface.h#L41 let nvapi_get_driver_version_ptr = nvapi_query(0x2926aaad); if nvapi_get_driver_version_ptr.is_null() { @@ -1440,7 +1427,13 @@ mod nvidia { } let major = driver_version / 100; let minor = driver_version % 100; - Ok(format!("{}.{}", major, minor)) + let branch_string = CStr::from_ptr(build_branch_string.as_ptr()); + Ok(format!( + "{}.{} {}", + major, + minor, + branch_string.to_string_lossy() + )) } } } From 6477a9b0567a25c73d8f088c9ce678305eacdef9 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Thu, 17 Jul 2025 21:35:42 +0800 Subject: [PATCH 45/45] remove unused --- crates/gpui/src/platform/windows/platform.rs | 2 -- crates/gpui/src/platform/windows/window.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/crates/gpui/src/platform/windows/platform.rs b/crates/gpui/src/platform/windows/platform.rs index 3123f943e1f1fdc9a77b6cf598a056dc86bc38ae..ae6c4cc73d460b2c00fcbe3a09392fc02d85e2ad 100644 --- a/crates/gpui/src/platform/windows/platform.rs +++ b/crates/gpui/src/platform/windows/platform.rs @@ -34,7 +34,6 @@ pub(crate) struct WindowsPlatform { state: RefCell, raw_window_handles: RwLock>, // The below members will never change throughout the entire lifecycle of the app. - // gpu_context: BladeContext, directx_devices: DirectXDevices, icon: HICON, main_receiver: flume::Receiver, @@ -112,7 +111,6 @@ impl WindowsPlatform { let icon = load_icon().unwrap_or_default(); let state = RefCell::new(WindowsPlatformState::new()); let raw_window_handles = RwLock::new(SmallVec::new()); - // let gpu_context = BladeContext::new().context("Unable to init GPU context")?; let directx_devices = DirectXDevices::new().context("Unable to init directx devices.")?; let windows_version = WindowsVersion::new().context("Error retrieve windows version")?; diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index a972cead2b6f4a1e1144b260789b4fc150f8a2da..eda75956b64e337aef2fba9efd1f6a1a176d25d5 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -475,7 +475,6 @@ impl rwh::HasDisplayHandle for WindowsWindow { impl Drop for WindowsWindow { fn drop(&mut self) { - // self.0.state.borrow_mut().renderer.destroy(); // clone this `Rc` to prevent early release of the pointer let this = self.0.clone(); self.0