From 0fffaf0a3e9738604e040cbf998dd3f5f60b3c5f Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 8 Jan 2025 16:54:12 +0800 Subject: [PATCH 01/16] Add MSAA for Anti-Aliasing to blade. --- crates/gpui/Cargo.toml | 2 +- .../gpui/src/platform/blade/apple_compat.rs | 1 + crates/gpui/src/platform/blade/blade_atlas.rs | 39 +++- .../gpui/src/platform/blade/blade_renderer.rs | 184 +++++++++++++++--- crates/gpui/src/platform/windows/window.rs | 1 + 5 files changed, 194 insertions(+), 33 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 63aac122a8af28..55f2e561424f72 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -11,7 +11,7 @@ license = "Apache-2.0" workspace = true [features] -default = ["http_client", "font-kit", "wayland", "x11"] +default = ["http_client", "font-kit", "wayland", "x11", "macos-blade"] test-support = [ "backtrace", "collections/test-support", diff --git a/crates/gpui/src/platform/blade/apple_compat.rs b/crates/gpui/src/platform/blade/apple_compat.rs index b1baab8854aca6..ed6de875776ae1 100644 --- a/crates/gpui/src/platform/blade/apple_compat.rs +++ b/crates/gpui/src/platform/blade/apple_compat.rs @@ -54,6 +54,7 @@ pub unsafe fn new_renderer( depth: 1, }, transparent, + sample_count: 4, }, ) .unwrap() diff --git a/crates/gpui/src/platform/blade/blade_atlas.rs b/crates/gpui/src/platform/blade/blade_atlas.rs index fb703f2a411c07..e7c272f3f5c1fe 100644 --- a/crates/gpui/src/platform/blade/blade_atlas.rs +++ b/crates/gpui/src/platform/blade/blade_atlas.rs @@ -27,6 +27,7 @@ struct BladeAtlasState { tiles_by_key: FxHashMap, initializations: Vec, uploads: Vec, + sample_count: u32, } #[cfg(gles)] @@ -42,10 +43,11 @@ impl BladeAtlasState { pub struct BladeTextureInfo { pub size: gpu::Extent, pub raw_view: gpu::TextureView, + pub msaa_view: Option, } impl BladeAtlas { - pub(crate) fn new(gpu: &Arc) -> Self { + pub(crate) fn new(gpu: &Arc, sample_count: u32) -> Self { BladeAtlas(Mutex::new(BladeAtlasState { gpu: Arc::clone(gpu), upload_belt: BufferBelt::new(BufferBeltDescriptor { @@ -57,6 +59,7 @@ impl BladeAtlas { tiles_by_key: Default::default(), initializations: Vec::new(), uploads: Vec::new(), + sample_count, })) } @@ -106,6 +109,7 @@ impl BladeAtlas { depth: 1, }, raw_view: texture.raw_view, + msaa_view: texture.msaa_view, } } } @@ -227,6 +231,34 @@ impl BladeAtlasState { subresources: &Default::default(), }, ); + let msaa_view = if self.sample_count > 1 { + let msaa = self.gpu.create_texture(gpu::TextureDesc { + name: "msaa texture", + format, + size: gpu::Extent { + width: size.width.into(), + height: size.height.into(), + depth: 1, + }, + array_layer_count: 1, + mip_level_count: 1, + sample_count: self.sample_count, + dimension: gpu::TextureDimension::D2, + usage: gpu::TextureUsage::TARGET, + }); + + Some(self.gpu.create_texture_view( + msaa, + gpu::TextureViewDesc { + name: "msaa texture view", + format, + dimension: gpu::ViewDimension::D2, + subresources: &Default::default(), + }, + )) + } else { + None + }; let texture_list = &mut self.storage[kind]; let index = texture_list.free_list.pop(); @@ -240,6 +272,7 @@ impl BladeAtlasState { format, raw, raw_view, + msaa_view, live_atlas_keys: 0, }; @@ -354,6 +387,7 @@ struct BladeAtlasTexture { allocator: BucketedAtlasAllocator, raw: gpu::Texture, raw_view: gpu::TextureView, + msaa_view: Option, format: gpu::TextureFormat, live_atlas_keys: u32, } @@ -381,6 +415,9 @@ impl BladeAtlasTexture { fn destroy(&mut self, gpu: &gpu::Context) { gpu.destroy_texture(self.raw); gpu.destroy_texture_view(self.raw_view); + if let Some(msaa_view) = self.msaa_view { + gpu.destroy_texture_view(msaa_view); + } } fn bytes_per_pixel(&self) -> u8 { diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index ee8ffdfda7fa26..f6cf285be909a6 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -128,7 +128,7 @@ struct BladePipelines { } impl BladePipelines { - fn new(gpu: &gpu::Context, surface_info: gpu::SurfaceInfo) -> Self { + fn new(gpu: &gpu::Context, surface_info: gpu::SurfaceInfo, sample_count: u32) -> Self { use gpu::ShaderData as _; log::info!( @@ -176,7 +176,10 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_quad")), color_targets, - multisample_state: gpu::MultisampleState::default(), + multisample_state: gpu::MultisampleState { + sample_count, + ..Default::default() + }, }), shadows: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "shadows", @@ -190,7 +193,10 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_shadow")), color_targets, - multisample_state: gpu::MultisampleState::default(), + multisample_state: gpu::MultisampleState { + sample_count, + ..Default::default() + }, }), path_rasterization: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "path_rasterization", @@ -208,7 +214,10 @@ impl BladePipelines { blend: Some(gpu::BlendState::ADDITIVE), write_mask: gpu::ColorWrites::default(), }], - multisample_state: gpu::MultisampleState::default(), + multisample_state: gpu::MultisampleState { + sample_count, + ..Default::default() + }, }), paths: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "paths", @@ -222,7 +231,10 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_path")), color_targets, - multisample_state: gpu::MultisampleState::default(), + multisample_state: gpu::MultisampleState { + sample_count, + ..Default::default() + }, }), underlines: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "underlines", @@ -236,7 +248,10 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_underline")), color_targets, - multisample_state: gpu::MultisampleState::default(), + multisample_state: gpu::MultisampleState { + sample_count, + ..Default::default() + }, }), mono_sprites: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "mono-sprites", @@ -250,7 +265,10 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_mono_sprite")), color_targets, - multisample_state: gpu::MultisampleState::default(), + multisample_state: gpu::MultisampleState { + sample_count, + ..Default::default() + }, }), poly_sprites: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "poly-sprites", @@ -264,7 +282,10 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_poly_sprite")), color_targets, - multisample_state: gpu::MultisampleState::default(), + multisample_state: gpu::MultisampleState { + sample_count, + ..Default::default() + }, }), surfaces: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "surfaces", @@ -278,7 +299,10 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_surface")), color_targets, - multisample_state: gpu::MultisampleState::default(), + multisample_state: gpu::MultisampleState { + sample_count, + ..Default::default() + }, }), } } @@ -298,6 +322,7 @@ impl BladePipelines { pub struct BladeSurfaceConfig { pub size: gpu::Extent, pub transparent: bool, + pub sample_count: u32, } //Note: we could see some of these fields moved into `BladeContext` @@ -317,6 +342,9 @@ pub struct BladeRenderer { atlas_sampler: gpu::Sampler, #[cfg(target_os = "macos")] core_video_texture_cache: CVMetalTextureCache, + msaa_texture: Option, + msaa_view: Option, + sample_count: u32, } impl BladeRenderer { @@ -342,13 +370,13 @@ impl BladeRenderer { name: "main", buffer_count: 2, }); - let pipelines = BladePipelines::new(&context.gpu, surface.info()); + let pipelines = BladePipelines::new(&context.gpu, surface.info(), config.sample_count); let instance_belt = BufferBelt::new(BufferBeltDescriptor { memory: gpu::Memory::Shared, min_chunk_size: 0x1000, alignment: 0x40, // Vulkan `minStorageBufferOffsetAlignment` on Intel Xe }); - let atlas = Arc::new(BladeAtlas::new(&context.gpu)); + let atlas = Arc::new(BladeAtlas::new(&context.gpu, config.sample_count)); let atlas_sampler = context.gpu.create_sampler(gpu::SamplerDesc { name: "atlas", mag_filter: gpu::FilterMode::Linear, @@ -377,6 +405,9 @@ impl BladeRenderer { atlas_sampler, #[cfg(target_os = "macos")] core_video_texture_cache, + msaa_texture: None, + msaa_view: None, + sample_count: config.sample_count, }) } @@ -391,6 +422,15 @@ impl BladeRenderer { pub fn update_drawable_size(&mut self, size: Size) { self.update_drawable_size_impl(size, false); + + // Reset the MSAA texture if the size has changed + let surface_info = self.surface.info(); + self.msaa_texture = None; + self.msaa_view = None; + self.recreate_msaa_texutres_if_needed( + (size.width.into(), size.height.into()), + surface_info.format, + ); } /// Like `update_drawable_size` but skips the check that the size has changed. This is useful in @@ -401,6 +441,46 @@ impl BladeRenderer { self.update_drawable_size_impl(size, true); } + fn recreate_msaa_texutres_if_needed( + &mut self, + (width, height): (u32, u32), + format: gpu::TextureFormat, + ) { + if self.sample_count <= 1 { + return; + } + if self.msaa_texture.is_some() { + return; + } + + let msaa_texture = self.gpu.create_texture(gpu::TextureDesc { + name: "msaa texture", + format, + size: gpu::Extent { + width, + height, + depth: 1, + }, + sample_count: self.sample_count, + dimension: gpu::TextureDimension::D2, + usage: gpu::TextureUsage::TARGET, + array_layer_count: 1, + mip_level_count: 1, + }); + let msaa_view = self.gpu.create_texture_view( + msaa_texture, + gpu::TextureViewDesc { + name: "msaa texture view", + format, + dimension: gpu::ViewDimension::D2, + subresources: &Default::default(), + }, + ); + + self.msaa_texture = Some(msaa_texture); + self.msaa_view = Some(msaa_view); + } + fn update_drawable_size_impl(&mut self, size: Size, always_resize: bool) { let gpu_size = gpu::Extent { width: size.width.0 as u32, @@ -423,7 +503,7 @@ impl BladeRenderer { self.gpu .reconfigure_surface(&mut self.surface, self.surface_config); self.pipelines.destroy(&self.gpu); - self.pipelines = BladePipelines::new(&self.gpu, self.surface.info()); + self.pipelines = BladePipelines::new(&self.gpu, self.surface.info(), self.sample_count); } } @@ -497,27 +577,38 @@ impl BladeRenderer { }; let vertex_buf = unsafe { self.instance_belt.alloc_typed(&vertices, &self.gpu) }; - let mut pass = self.command_encoder.render( - "paths", + let frame_view = tex_info.raw_view; + let render_target = if let Some(msaa_view) = tex_info.msaa_view { gpu::RenderTargetSet { colors: &[gpu::RenderTarget { - view: tex_info.raw_view, + view: msaa_view, + init_op: gpu::InitOp::Clear(gpu::TextureColor::OpaqueBlack), + finish_op: gpu::FinishOp::ResolveTo(frame_view), + }], + depth_stencil: None, + } + } else { + gpu::RenderTargetSet { + colors: &[gpu::RenderTarget { + view: frame_view, init_op: gpu::InitOp::Clear(gpu::TextureColor::OpaqueBlack), finish_op: gpu::FinishOp::Store, }], depth_stencil: None, - }, - ); + } + }; - let mut encoder = pass.with(&self.pipelines.path_rasterization); - encoder.bind( - 0, - &ShaderPathRasterizationData { - globals, - b_path_vertices: vertex_buf, - }, - ); - encoder.draw(0, vertices.len() as u32, 0, 1); + if let mut pass = self.command_encoder.render("paths", render_target) { + let mut encoder = pass.with(&self.pipelines.path_rasterization); + encoder.bind( + 0, + &ShaderPathRasterizationData { + globals, + b_path_vertices: vertex_buf, + }, + ); + encoder.draw(0, vertices.len() as u32, 0, 1); + } } } @@ -529,9 +620,28 @@ impl BladeRenderer { self.gpu.destroy_command_encoder(&mut self.command_encoder); self.pipelines.destroy(&self.gpu); self.gpu.destroy_surface(&mut self.surface); + + if let Some(msaa_texture) = self.msaa_texture.take() { + self.gpu.destroy_texture(msaa_texture); + } + if let Some(msaa_view) = self.msaa_view.take() { + self.gpu.destroy_texture_view(msaa_view); + } } pub fn draw(&mut self, scene: &Scene) { + self.recreate_msaa_texutres_if_needed( + ( + self.surface_config.size.width, + self.surface_config.size.height, + ), + self.surface.info().format, + ); + + if let Some(msaa_texture) = self.msaa_texture { + self.command_encoder.init_texture(msaa_texture); + } + self.command_encoder.start(); self.atlas.before_frame(&mut self.command_encoder); self.rasterize_paths(scene.paths()); @@ -554,17 +664,29 @@ impl BladeRenderer { pad: 0, }; - if let mut pass = self.command_encoder.render( - "main", + let frame_view = frame.texture_view(); + + let target_set = if self.sample_count > 1 { gpu::RenderTargetSet { colors: &[gpu::RenderTarget { - view: frame.texture_view(), + view: self.msaa_view.unwrap(), + init_op: gpu::InitOp::Clear(gpu::TextureColor::TransparentBlack), + finish_op: gpu::FinishOp::ResolveTo(frame_view), + }], + depth_stencil: None, + } + } else { + gpu::RenderTargetSet { + colors: &[gpu::RenderTarget { + view: frame_view, init_op: gpu::InitOp::Clear(gpu::TextureColor::TransparentBlack), finish_op: gpu::FinishOp::Store, }], depth_stencil: None, - }, - ) { + } + }; + + if let mut pass = self.command_encoder.render("main", target_set) { profiling::scope!("render pass"); for batch in scene.batches() { match batch { diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index e2389f0dba443f..d9d7c36e4695cd 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -1257,6 +1257,7 @@ mod windows_renderer { let config = BladeSurfaceConfig { size: Default::default(), transparent, + sample_count: 4, }; BladeRenderer::new(context, &raw, config) } From c2757b7e8966e131757999d78f79f5aab2300e95 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 8 Jan 2025 17:39:31 +0800 Subject: [PATCH 02/16] Remove unnecessary changes. --- .../gpui/src/platform/blade/blade_renderer.rs | 129 ++---------------- 1 file changed, 12 insertions(+), 117 deletions(-) diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index f6cf285be909a6..6b1f9554abac0a 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -176,10 +176,7 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_quad")), color_targets, - multisample_state: gpu::MultisampleState { - sample_count, - ..Default::default() - }, + multisample_state: gpu::MultisampleState::default(), }), shadows: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "shadows", @@ -193,10 +190,7 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_shadow")), color_targets, - multisample_state: gpu::MultisampleState { - sample_count, - ..Default::default() - }, + multisample_state: gpu::MultisampleState::default(), }), path_rasterization: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "path_rasterization", @@ -231,10 +225,7 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_path")), color_targets, - multisample_state: gpu::MultisampleState { - sample_count, - ..Default::default() - }, + multisample_state: gpu::MultisampleState::default(), }), underlines: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "underlines", @@ -248,10 +239,7 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_underline")), color_targets, - multisample_state: gpu::MultisampleState { - sample_count, - ..Default::default() - }, + multisample_state: gpu::MultisampleState::default(), }), mono_sprites: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "mono-sprites", @@ -265,10 +253,7 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_mono_sprite")), color_targets, - multisample_state: gpu::MultisampleState { - sample_count, - ..Default::default() - }, + multisample_state: gpu::MultisampleState::default(), }), poly_sprites: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "poly-sprites", @@ -282,10 +267,7 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_poly_sprite")), color_targets, - multisample_state: gpu::MultisampleState { - sample_count, - ..Default::default() - }, + multisample_state: gpu::MultisampleState::default(), }), surfaces: gpu.create_render_pipeline(gpu::RenderPipelineDesc { name: "surfaces", @@ -299,10 +281,7 @@ impl BladePipelines { depth_stencil: None, fragment: Some(shader.at("fs_surface")), color_targets, - multisample_state: gpu::MultisampleState { - sample_count, - ..Default::default() - }, + multisample_state: gpu::MultisampleState::default(), }), } } @@ -342,8 +321,6 @@ pub struct BladeRenderer { atlas_sampler: gpu::Sampler, #[cfg(target_os = "macos")] core_video_texture_cache: CVMetalTextureCache, - msaa_texture: Option, - msaa_view: Option, sample_count: u32, } @@ -405,8 +382,6 @@ impl BladeRenderer { atlas_sampler, #[cfg(target_os = "macos")] core_video_texture_cache, - msaa_texture: None, - msaa_view: None, sample_count: config.sample_count, }) } @@ -422,15 +397,6 @@ impl BladeRenderer { pub fn update_drawable_size(&mut self, size: Size) { self.update_drawable_size_impl(size, false); - - // Reset the MSAA texture if the size has changed - let surface_info = self.surface.info(); - self.msaa_texture = None; - self.msaa_view = None; - self.recreate_msaa_texutres_if_needed( - (size.width.into(), size.height.into()), - surface_info.format, - ); } /// Like `update_drawable_size` but skips the check that the size has changed. This is useful in @@ -441,46 +407,6 @@ impl BladeRenderer { self.update_drawable_size_impl(size, true); } - fn recreate_msaa_texutres_if_needed( - &mut self, - (width, height): (u32, u32), - format: gpu::TextureFormat, - ) { - if self.sample_count <= 1 { - return; - } - if self.msaa_texture.is_some() { - return; - } - - let msaa_texture = self.gpu.create_texture(gpu::TextureDesc { - name: "msaa texture", - format, - size: gpu::Extent { - width, - height, - depth: 1, - }, - sample_count: self.sample_count, - dimension: gpu::TextureDimension::D2, - usage: gpu::TextureUsage::TARGET, - array_layer_count: 1, - mip_level_count: 1, - }); - let msaa_view = self.gpu.create_texture_view( - msaa_texture, - gpu::TextureViewDesc { - name: "msaa texture view", - format, - dimension: gpu::ViewDimension::D2, - subresources: &Default::default(), - }, - ); - - self.msaa_texture = Some(msaa_texture); - self.msaa_view = Some(msaa_view); - } - fn update_drawable_size_impl(&mut self, size: Size, always_resize: bool) { let gpu_size = gpu::Extent { width: size.width.0 as u32, @@ -620,28 +546,9 @@ impl BladeRenderer { self.gpu.destroy_command_encoder(&mut self.command_encoder); self.pipelines.destroy(&self.gpu); self.gpu.destroy_surface(&mut self.surface); - - if let Some(msaa_texture) = self.msaa_texture.take() { - self.gpu.destroy_texture(msaa_texture); - } - if let Some(msaa_view) = self.msaa_view.take() { - self.gpu.destroy_texture_view(msaa_view); - } } pub fn draw(&mut self, scene: &Scene) { - self.recreate_msaa_texutres_if_needed( - ( - self.surface_config.size.width, - self.surface_config.size.height, - ), - self.surface.info().format, - ); - - if let Some(msaa_texture) = self.msaa_texture { - self.command_encoder.init_texture(msaa_texture); - } - self.command_encoder.start(); self.atlas.before_frame(&mut self.command_encoder); self.rasterize_paths(scene.paths()); @@ -664,29 +571,17 @@ impl BladeRenderer { pad: 0, }; - let frame_view = frame.texture_view(); - - let target_set = if self.sample_count > 1 { - gpu::RenderTargetSet { - colors: &[gpu::RenderTarget { - view: self.msaa_view.unwrap(), - init_op: gpu::InitOp::Clear(gpu::TextureColor::TransparentBlack), - finish_op: gpu::FinishOp::ResolveTo(frame_view), - }], - depth_stencil: None, - } - } else { + if let mut pass = self.command_encoder.render( + "main", gpu::RenderTargetSet { colors: &[gpu::RenderTarget { - view: frame_view, + view: frame.texture_view(), init_op: gpu::InitOp::Clear(gpu::TextureColor::TransparentBlack), finish_op: gpu::FinishOp::Store, }], depth_stencil: None, - } - }; - - if let mut pass = self.command_encoder.render("main", target_set) { + }, + ) { profiling::scope!("render pass"); for batch in scene.batches() { match batch { From bde1d57dc9fe841dc1208e8d80570d6188efa335 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 8 Jan 2025 18:11:42 +0800 Subject: [PATCH 03/16] Support for Metal --- crates/gpui/Cargo.toml | 2 +- crates/gpui/src/platform/mac/metal_atlas.rs | 21 +++++++++++++- .../gpui/src/platform/mac/metal_renderer.rs | 29 +++++++++++++++---- crates/gpui/src/platform/mac/window.rs | 1 + 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 55f2e561424f72..63aac122a8af28 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -11,7 +11,7 @@ license = "Apache-2.0" workspace = true [features] -default = ["http_client", "font-kit", "wayland", "x11", "macos-blade"] +default = ["http_client", "font-kit", "wayland", "x11"] test-support = [ "backtrace", "collections/test-support", diff --git a/crates/gpui/src/platform/mac/metal_atlas.rs b/crates/gpui/src/platform/mac/metal_atlas.rs index ca595c5ce34753..52d08f068b6072 100644 --- a/crates/gpui/src/platform/mac/metal_atlas.rs +++ b/crates/gpui/src/platform/mac/metal_atlas.rs @@ -13,13 +13,14 @@ use std::borrow::Cow; pub(crate) struct MetalAtlas(Mutex); impl MetalAtlas { - pub(crate) fn new(device: Device) -> Self { + pub(crate) fn new(device: Device, sample_count: u32) -> Self { MetalAtlas(Mutex::new(MetalAtlasState { device: AssertSend(device), monochrome_textures: Default::default(), polychrome_textures: Default::default(), path_textures: Default::default(), tiles_by_key: Default::default(), + sample_count, })) } @@ -27,6 +28,10 @@ impl MetalAtlas { self.0.lock().texture(id).metal_texture.clone() } + pub(crate) fn msaa_texture(&self, id: AtlasTextureId) -> Option { + self.0.lock().texture(id).msaa_texture.clone() + } + pub(crate) fn allocate( &self, size: Size, @@ -54,6 +59,7 @@ struct MetalAtlasState { polychrome_textures: AtlasTextureList, path_textures: AtlasTextureList, tiles_by_key: FxHashMap, + sample_count: u32, } impl PlatformAtlas for MetalAtlas { @@ -176,6 +182,17 @@ impl MetalAtlasState { texture_descriptor.set_usage(usage); let metal_texture = self.device.new_texture(&texture_descriptor); + let msaa_texture = if self.sample_count > 1 { + let mut descriptor = texture_descriptor.clone(); + descriptor.set_texture_type(metal::MTLTextureType::D2Multisample); + descriptor.set_storage_mode(metal::MTLStorageMode::Private); + descriptor.set_sample_count(self.sample_count as _); + let msaa_texture = self.device.new_texture(&descriptor); + Some(msaa_texture) + } else { + None + }; + let texture_list = match kind { AtlasTextureKind::Monochrome => &mut self.monochrome_textures, AtlasTextureKind::Polychrome => &mut self.polychrome_textures, @@ -191,6 +208,7 @@ impl MetalAtlasState { }, allocator: etagere::BucketedAtlasAllocator::new(size.into()), metal_texture: AssertSend(metal_texture), + msaa_texture: AssertSend(msaa_texture), live_atlas_keys: 0, }; @@ -217,6 +235,7 @@ struct MetalAtlasTexture { id: AtlasTextureId, allocator: BucketedAtlasAllocator, metal_texture: AssertSend, + msaa_texture: AssertSend>, live_atlas_keys: u32, } diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index c290d12f7e7521..4706cbc70dd348 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -38,8 +38,9 @@ pub unsafe fn new_renderer( _native_view: *mut c_void, _bounds: crate::Size, _transparent: bool, + sample_count: u32, ) -> Renderer { - MetalRenderer::new(context) + MetalRenderer::new(context, sample_count) } pub(crate) struct InstanceBufferPool { @@ -108,7 +109,7 @@ pub(crate) struct MetalRenderer { } impl MetalRenderer { - pub fn new(instance_buffer_pool: Arc>) -> Self { + pub fn new(instance_buffer_pool: Arc>, sample_count: u32) -> Self { // Prefer low‐power integrated GPUs on Intel Mac. On Apple // Silicon, there is only ever one GPU, so this is equivalent to // `metal::Device::system_default()`. @@ -170,6 +171,7 @@ impl MetalRenderer { "path_rasterization_vertex", "path_rasterization_fragment", MTLPixelFormat::R16Float, + sample_count, ); let path_sprites_pipeline_state = build_pipeline_state( &device, @@ -229,7 +231,7 @@ impl MetalRenderer { ); let command_queue = device.new_command_queue(); - let sprite_atlas = Arc::new(MetalAtlas::new(device.clone())); + let sprite_atlas = Arc::new(MetalAtlas::new(device.clone(), sample_count)); let core_video_texture_cache = unsafe { CVMetalTextureCache::new(device.as_ptr()).unwrap() }; @@ -531,9 +533,19 @@ impl MetalRenderer { .unwrap(); let texture = self.sprite_atlas.metal_texture(texture_id); - color_attachment.set_texture(Some(&texture)); - color_attachment.set_load_action(metal::MTLLoadAction::Clear); - color_attachment.set_store_action(metal::MTLStoreAction::Store); + let msaa_texture = self.sprite_atlas.msaa_texture(texture_id); + + if let Some(msaa_texture) = msaa_texture { + color_attachment.set_texture(Some(&msaa_texture)); + color_attachment.set_resolve_texture(Some(&texture)); + color_attachment.set_load_action(metal::MTLLoadAction::Clear); + color_attachment.set_store_action(metal::MTLStoreAction::MultisampleResolve); + color_attachment.set_resolve_level(0); + } else { + color_attachment.set_texture(Some(&texture)); + color_attachment.set_load_action(metal::MTLLoadAction::Clear); + color_attachment.set_store_action(metal::MTLStoreAction::Store); + } color_attachment.set_clear_color(metal::MTLClearColor::new(0., 0., 0., 1.)); let command_encoder = command_buffer.new_render_command_encoder(render_pass_descriptor); command_encoder.set_render_pipeline_state(&self.paths_rasterization_pipeline_state); @@ -1160,6 +1172,7 @@ fn build_path_rasterization_pipeline_state( vertex_fn_name: &str, fragment_fn_name: &str, pixel_format: metal::MTLPixelFormat, + sample_count: u32, ) -> metal::RenderPipelineState { let vertex_fn = library .get_function(vertex_fn_name, None) @@ -1172,6 +1185,10 @@ fn build_path_rasterization_pipeline_state( descriptor.set_label(label); descriptor.set_vertex_function(Some(vertex_fn.as_ref())); descriptor.set_fragment_function(Some(fragment_fn.as_ref())); + if sample_count > 1 { + descriptor.set_raster_sample_count(sample_count as _); + descriptor.set_alpha_to_coverage_enabled(true); + } let color_attachment = descriptor.color_attachments().object_at(0).unwrap(); color_attachment.set_pixel_format(pixel_format); color_attachment.set_blending_enabled(true); diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 04fda6294a0ae1..8ca9b1d19ff43b 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -589,6 +589,7 @@ impl MacWindow { native_view as *mut _, bounds.size.map(|pixels| pixels.0), false, + 4, ), request_frame_callback: None, event_callback: None, From 2ea3a6c96a2a967f2dc46dd1fdbd455d8670256e Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 8 Jan 2025 18:36:19 +0800 Subject: [PATCH 04/16] Set sample_count by support. --- crates/gpui/Cargo.toml | 2 +- .../gpui/src/platform/blade/apple_compat.rs | 1 - .../gpui/src/platform/blade/blade_renderer.rs | 25 ++++++++++++++++--- .../gpui/src/platform/mac/metal_renderer.rs | 14 ++++++++--- crates/gpui/src/platform/mac/window.rs | 1 - crates/gpui/src/platform/windows/window.rs | 1 - 6 files changed, 33 insertions(+), 11 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 63aac122a8af28..55f2e561424f72 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -11,7 +11,7 @@ license = "Apache-2.0" workspace = true [features] -default = ["http_client", "font-kit", "wayland", "x11"] +default = ["http_client", "font-kit", "wayland", "x11", "macos-blade"] test-support = [ "backtrace", "collections/test-support", diff --git a/crates/gpui/src/platform/blade/apple_compat.rs b/crates/gpui/src/platform/blade/apple_compat.rs index ed6de875776ae1..b1baab8854aca6 100644 --- a/crates/gpui/src/platform/blade/apple_compat.rs +++ b/crates/gpui/src/platform/blade/apple_compat.rs @@ -54,7 +54,6 @@ pub unsafe fn new_renderer( depth: 1, }, transparent, - sample_count: 4, }, ) .unwrap() diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index 6b1f9554abac0a..767275c0c66dce 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -14,6 +14,7 @@ use media::core_video::CVMetalTextureCache; use blade_graphics as gpu; use blade_util::{BufferBelt, BufferBeltDescriptor}; +use objc2_metal::MTLDevice; use std::{mem, sync::Arc}; const MAX_FRAME_TIME_MS: u32 = 10000; @@ -301,7 +302,6 @@ impl BladePipelines { pub struct BladeSurfaceConfig { pub size: gpu::Extent, pub transparent: bool, - pub sample_count: u32, } //Note: we could see some of these fields moved into `BladeContext` @@ -343,17 +343,34 @@ impl BladeRenderer { .create_surface_configured(window, surface_config) .unwrap(); + // Determine the sample count based on the device's capabilities. + let mut sample_count = 1; + #[cfg(target_os = "macos")] + { + for &n in &[4, 2] { + if context.gpu.metal_device().supportsTextureSampleCount(n) { + sample_count = n as _; + break; + } + } + } + // TODO: Determine on non-macOS platforms, until Blade supports querying sample counts. + #[cfg(not(target_os = "macos"))] + { + sample_count = 4; + } + let command_encoder = context.gpu.create_command_encoder(gpu::CommandEncoderDesc { name: "main", buffer_count: 2, }); - let pipelines = BladePipelines::new(&context.gpu, surface.info(), config.sample_count); + let pipelines = BladePipelines::new(&context.gpu, surface.info(), sample_count); let instance_belt = BufferBelt::new(BufferBeltDescriptor { memory: gpu::Memory::Shared, min_chunk_size: 0x1000, alignment: 0x40, // Vulkan `minStorageBufferOffsetAlignment` on Intel Xe }); - let atlas = Arc::new(BladeAtlas::new(&context.gpu, config.sample_count)); + let atlas = Arc::new(BladeAtlas::new(&context.gpu, sample_count)); let atlas_sampler = context.gpu.create_sampler(gpu::SamplerDesc { name: "atlas", mag_filter: gpu::FilterMode::Linear, @@ -382,7 +399,7 @@ impl BladeRenderer { atlas_sampler, #[cfg(target_os = "macos")] core_video_texture_cache, - sample_count: config.sample_count, + sample_count, }) } diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 4706cbc70dd348..6cf2d02f1d9bfc 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -38,9 +38,8 @@ pub unsafe fn new_renderer( _native_view: *mut c_void, _bounds: crate::Size, _transparent: bool, - sample_count: u32, ) -> Renderer { - MetalRenderer::new(context, sample_count) + MetalRenderer::new(context) } pub(crate) struct InstanceBufferPool { @@ -109,7 +108,7 @@ pub(crate) struct MetalRenderer { } impl MetalRenderer { - pub fn new(instance_buffer_pool: Arc>, sample_count: u32) -> Self { + pub fn new(instance_buffer_pool: Arc>) -> Self { // Prefer low‐power integrated GPUs on Intel Mac. On Apple // Silicon, there is only ever one GPU, so this is equivalent to // `metal::Device::system_default()`. @@ -120,6 +119,15 @@ impl MetalRenderer { std::process::exit(1); }; + // Determine the sample count based on the device's capabilities. + let mut sample_count = 1; + for &n in &[4, 2] { + if device.supports_texture_sample_count(n) { + sample_count = n as _; + break; + } + } + let layer = metal::MetalLayer::new(); layer.set_device(&device); layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm); diff --git a/crates/gpui/src/platform/mac/window.rs b/crates/gpui/src/platform/mac/window.rs index 8ca9b1d19ff43b..04fda6294a0ae1 100644 --- a/crates/gpui/src/platform/mac/window.rs +++ b/crates/gpui/src/platform/mac/window.rs @@ -589,7 +589,6 @@ impl MacWindow { native_view as *mut _, bounds.size.map(|pixels| pixels.0), false, - 4, ), request_frame_callback: None, event_callback: None, diff --git a/crates/gpui/src/platform/windows/window.rs b/crates/gpui/src/platform/windows/window.rs index d9d7c36e4695cd..e2389f0dba443f 100644 --- a/crates/gpui/src/platform/windows/window.rs +++ b/crates/gpui/src/platform/windows/window.rs @@ -1257,7 +1257,6 @@ mod windows_renderer { let config = BladeSurfaceConfig { size: Default::default(), transparent, - sample_count: 4, }; BladeRenderer::new(context, &raw, config) } From 489ec91f221fab7cbf8e8f73ae2305a05d14a42d Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 8 Jan 2025 18:41:22 +0800 Subject: [PATCH 05/16] . --- .../gpui/src/platform/blade/blade_renderer.rs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index 767275c0c66dce..3f7287cb4af683 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -7,13 +7,13 @@ use crate::{ MonochromeSprite, Path, PathId, PathVertex, PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size, Underline, }; +use blade_graphics as gpu; +use blade_util::{BufferBelt, BufferBeltDescriptor}; use bytemuck::{Pod, Zeroable}; use collections::HashMap; #[cfg(target_os = "macos")] use media::core_video::CVMetalTextureCache; - -use blade_graphics as gpu; -use blade_util::{BufferBelt, BufferBeltDescriptor}; +#[cfg(target_os = "macos")] use objc2_metal::MTLDevice; use std::{mem, sync::Arc}; @@ -343,10 +343,15 @@ impl BladeRenderer { .create_surface_configured(window, surface_config) .unwrap(); - // Determine the sample count based on the device's capabilities. - let mut sample_count = 1; + #[cfg(not(target_os = "macos"))] + { + // TODO: Determine on non-macOS platforms, until Blade supports querying sample counts. + let mut sample_count = 4; + } #[cfg(target_os = "macos")] { + // Determine the sample count based on the device's capabilities. + let mut sample_count = 1; for &n in &[4, 2] { if context.gpu.metal_device().supportsTextureSampleCount(n) { sample_count = n as _; @@ -354,11 +359,6 @@ impl BladeRenderer { } } } - // TODO: Determine on non-macOS platforms, until Blade supports querying sample counts. - #[cfg(not(target_os = "macos"))] - { - sample_count = 4; - } let command_encoder = context.gpu.create_command_encoder(gpu::CommandEncoderDesc { name: "main", From ae4f381fdb9ab4a8a9093e472d18b72a504bb3e7 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 8 Jan 2025 18:44:28 +0800 Subject: [PATCH 06/16] . --- crates/gpui/Cargo.toml | 2 +- crates/gpui/src/platform/blade/blade_renderer.rs | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 55f2e561424f72..63aac122a8af28 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -11,7 +11,7 @@ license = "Apache-2.0" workspace = true [features] -default = ["http_client", "font-kit", "wayland", "x11", "macos-blade"] +default = ["http_client", "font-kit", "wayland", "x11"] test-support = [ "backtrace", "collections/test-support", diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index 3f7287cb4af683..b2451212771b93 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -343,21 +343,18 @@ impl BladeRenderer { .create_surface_configured(window, surface_config) .unwrap(); - #[cfg(not(target_os = "macos"))] - { - // TODO: Determine on non-macOS platforms, until Blade supports querying sample counts. - let mut sample_count = 4; - } - #[cfg(target_os = "macos")] - { + let mut sample_count = 1; + if cfg!(target_os = "macos") { // Determine the sample count based on the device's capabilities. - let mut sample_count = 1; for &n in &[4, 2] { if context.gpu.metal_device().supportsTextureSampleCount(n) { sample_count = n as _; break; } } + } else { + // TODO: Determine on non-macOS platforms, until Blade supports querying sample counts. + sample_count = 4; } let command_encoder = context.gpu.create_command_encoder(gpu::CommandEncoderDesc { From b1efcd3c3bf08e431bcebe101eb5efc25a313a4a Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Wed, 8 Jan 2025 18:46:52 +0800 Subject: [PATCH 07/16] . --- .../gpui/src/platform/blade/blade_renderer.rs | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index b2451212771b93..c00f8b9cdf46f4 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -343,20 +343,21 @@ impl BladeRenderer { .create_surface_configured(window, surface_config) .unwrap(); + // Determine the sample count based on the device's capabilities. + #[cfg(target_os = "macos")] let mut sample_count = 1; - if cfg!(target_os = "macos") { - // Determine the sample count based on the device's capabilities. - for &n in &[4, 2] { - if context.gpu.metal_device().supportsTextureSampleCount(n) { - sample_count = n as _; - break; - } + #[cfg(target_os = "macos")] + for &n in &[4, 2] { + if context.gpu.metal_device().supportsTextureSampleCount(n) { + sample_count = n as _; + break; } - } else { - // TODO: Determine on non-macOS platforms, until Blade supports querying sample counts. - sample_count = 4; } + // TODO: Determine on non-macOS platforms, until Blade supports querying sample counts. + #[cfg(not(target_os = "macos"))] + let sample_count = 4; + let command_encoder = context.gpu.create_command_encoder(gpu::CommandEncoderDesc { name: "main", buffer_count: 2, From 693258f6eb9aa0f15e29b013a7da67eb862453b3 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 9 Jan 2025 11:03:39 +0800 Subject: [PATCH 08/16] Improve path_sprite_fragment to use `gather` to sample avg with 4 points. --- crates/gpui/src/platform/blade/shaders.wgsl | 5 +++-- crates/gpui/src/platform/mac/shaders.metal | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/crates/gpui/src/platform/blade/shaders.wgsl b/crates/gpui/src/platform/blade/shaders.wgsl index d497c40d7aa426..edab6008847ead 100644 --- a/crates/gpui/src/platform/blade/shaders.wgsl +++ b/crates/gpui/src/platform/blade/shaders.wgsl @@ -625,8 +625,9 @@ fn vs_path(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index) insta @fragment fn fs_path(input: PathVarying) -> @location(0) vec4 { - let sample = textureSample(t_sprite, s_sprite, input.tile_position).r; - let mask = 1.0 - abs(1.0 - sample % 2.0); + let sample = textureGather(0, t_sprite, s_sprite, input.tile_position); + let sample_avg = (sample.x + sample.y + sample.z + sample.w) * 0.25; + let mask = 1.0 - abs(1.0 - sample_avg % 2.0); let sprite = b_path_sprites[input.instance_id]; let background = sprite.color; let color = gradient_color(background, input.position.xy, sprite.bounds, diff --git a/crates/gpui/src/platform/mac/shaders.metal b/crates/gpui/src/platform/mac/shaders.metal index 7ee5d63add1516..e9cc1db5ef82e6 100644 --- a/crates/gpui/src/platform/mac/shaders.metal +++ b/crates/gpui/src/platform/mac/shaders.metal @@ -515,9 +515,10 @@ fragment float4 path_sprite_fragment( texture2d atlas_texture [[texture(SpriteInputIndex_AtlasTexture)]]) { constexpr sampler atlas_texture_sampler(mag_filter::linear, min_filter::linear); - float4 sample = - atlas_texture.sample(atlas_texture_sampler, input.tile_position); - float mask = 1. - abs(1. - fmod(sample.r, 2.)); + // Sample the texture and get the average of the color channels. + float4 sample = atlas_texture.gather(atlas_texture_sampler, input.tile_position); + float sample_avg = (sample.x + sample.y + sample.z + sample.w) * 0.25; + float mask = 1. - abs(1. - fmod(sample_avg, 2.)); PathSprite sprite = sprites[input.sprite_id]; Background background = sprite.color; float4 color = gradient_color(background, input.position.xy, sprite.bounds, From 0842198199c426b702711a27bca7b4fee5913128 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Thu, 9 Jan 2025 11:10:04 +0800 Subject: [PATCH 09/16] Revert "Improve path_sprite_fragment to use `gather` to sample avg with 4 points." This reverts commit 693258f6eb9aa0f15e29b013a7da67eb862453b3. --- crates/gpui/src/platform/blade/shaders.wgsl | 5 ++--- crates/gpui/src/platform/mac/shaders.metal | 7 +++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/gpui/src/platform/blade/shaders.wgsl b/crates/gpui/src/platform/blade/shaders.wgsl index edab6008847ead..d497c40d7aa426 100644 --- a/crates/gpui/src/platform/blade/shaders.wgsl +++ b/crates/gpui/src/platform/blade/shaders.wgsl @@ -625,9 +625,8 @@ fn vs_path(@builtin(vertex_index) vertex_id: u32, @builtin(instance_index) insta @fragment fn fs_path(input: PathVarying) -> @location(0) vec4 { - let sample = textureGather(0, t_sprite, s_sprite, input.tile_position); - let sample_avg = (sample.x + sample.y + sample.z + sample.w) * 0.25; - let mask = 1.0 - abs(1.0 - sample_avg % 2.0); + let sample = textureSample(t_sprite, s_sprite, input.tile_position).r; + let mask = 1.0 - abs(1.0 - sample % 2.0); let sprite = b_path_sprites[input.instance_id]; let background = sprite.color; let color = gradient_color(background, input.position.xy, sprite.bounds, diff --git a/crates/gpui/src/platform/mac/shaders.metal b/crates/gpui/src/platform/mac/shaders.metal index e9cc1db5ef82e6..7ee5d63add1516 100644 --- a/crates/gpui/src/platform/mac/shaders.metal +++ b/crates/gpui/src/platform/mac/shaders.metal @@ -515,10 +515,9 @@ fragment float4 path_sprite_fragment( texture2d atlas_texture [[texture(SpriteInputIndex_AtlasTexture)]]) { constexpr sampler atlas_texture_sampler(mag_filter::linear, min_filter::linear); - // Sample the texture and get the average of the color channels. - float4 sample = atlas_texture.gather(atlas_texture_sampler, input.tile_position); - float sample_avg = (sample.x + sample.y + sample.z + sample.w) * 0.25; - float mask = 1. - abs(1. - fmod(sample_avg, 2.)); + float4 sample = + atlas_texture.sample(atlas_texture_sampler, input.tile_position); + float mask = 1. - abs(1. - fmod(sample.r, 2.)); PathSprite sprite = sprites[input.sprite_id]; Background background = sprite.color; float4 color = gradient_color(background, input.position.xy, sprite.bounds, From d8f6dddf2a2322070847adb99056d8ca2f15c78c Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 10 Jan 2025 14:06:58 +0800 Subject: [PATCH 10/16] Update --- Cargo.lock | 8 +-- Cargo.toml | 6 +- crates/gpui/Cargo.toml | 2 +- crates/gpui/src/platform/blade/blade_atlas.rs | 60 ++++++++++--------- .../gpui/src/platform/blade/blade_renderer.rs | 25 ++++---- crates/gpui/src/platform/mac/metal_atlas.rs | 9 +-- .../gpui/src/platform/mac/metal_renderer.rs | 19 +++--- 7 files changed, 63 insertions(+), 66 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d10fe090a9b23..cba80068d77364 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1805,7 +1805,7 @@ dependencies = [ [[package]] name = "blade-graphics" version = "0.6.0" -source = "git+https://github.com/kvark/blade?rev=091a8401033847bb9b6ace3fcf70448d069621c5#091a8401033847bb9b6ace3fcf70448d069621c5" +source = "git+https://github.com/kvark/blade?rev=b16f5c7bd873c7126f48c82c39e7ae64602ae74f#b16f5c7bd873c7126f48c82c39e7ae64602ae74f" dependencies = [ "ash", "ash-window", @@ -1837,7 +1837,7 @@ dependencies = [ [[package]] name = "blade-macros" version = "0.3.0" -source = "git+https://github.com/kvark/blade?rev=091a8401033847bb9b6ace3fcf70448d069621c5#091a8401033847bb9b6ace3fcf70448d069621c5" +source = "git+https://github.com/kvark/blade?rev=b16f5c7bd873c7126f48c82c39e7ae64602ae74f#b16f5c7bd873c7126f48c82c39e7ae64602ae74f" dependencies = [ "proc-macro2", "quote", @@ -1847,7 +1847,7 @@ dependencies = [ [[package]] name = "blade-util" version = "0.2.0" -source = "git+https://github.com/kvark/blade?rev=091a8401033847bb9b6ace3fcf70448d069621c5#091a8401033847bb9b6ace3fcf70448d069621c5" +source = "git+https://github.com/kvark/blade?rev=b16f5c7bd873c7126f48c82c39e7ae64602ae74f#b16f5c7bd873c7126f48c82c39e7ae64602ae74f" dependencies = [ "blade-graphics", "bytemuck", @@ -15183,7 +15183,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index aaa4dc48a76645..825f423ad601ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -352,9 +352,9 @@ async-watch = "0.3.1" async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] } base64 = "0.22" bitflags = "2.6.0" -blade-graphics = { git = "https://github.com/kvark/blade", rev = "091a8401033847bb9b6ace3fcf70448d069621c5" } -blade-macros = { git = "https://github.com/kvark/blade", rev = "091a8401033847bb9b6ace3fcf70448d069621c5" } -blade-util = { git = "https://github.com/kvark/blade", rev = "091a8401033847bb9b6ace3fcf70448d069621c5" } +blade-graphics = { git = "https://github.com/kvark/blade", rev = "b16f5c7bd873c7126f48c82c39e7ae64602ae74f" } +blade-macros = { git = "https://github.com/kvark/blade", rev = "b16f5c7bd873c7126f48c82c39e7ae64602ae74f" } +blade-util = { git = "https://github.com/kvark/blade", rev = "b16f5c7bd873c7126f48c82c39e7ae64602ae74f" } blake3 = "1.5.3" bytes = "1.0" cargo_metadata = "0.19" diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 63aac122a8af28..55f2e561424f72 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -11,7 +11,7 @@ license = "Apache-2.0" workspace = true [features] -default = ["http_client", "font-kit", "wayland", "x11"] +default = ["http_client", "font-kit", "wayland", "x11", "macos-blade"] test-support = [ "backtrace", "collections/test-support", diff --git a/crates/gpui/src/platform/blade/blade_atlas.rs b/crates/gpui/src/platform/blade/blade_atlas.rs index e7c272f3f5c1fe..036d178f3e8204 100644 --- a/crates/gpui/src/platform/blade/blade_atlas.rs +++ b/crates/gpui/src/platform/blade/blade_atlas.rs @@ -27,7 +27,7 @@ struct BladeAtlasState { tiles_by_key: FxHashMap, initializations: Vec, uploads: Vec, - sample_count: u32, + path_sample_count: u32, } #[cfg(gles)] @@ -47,7 +47,7 @@ pub struct BladeTextureInfo { } impl BladeAtlas { - pub(crate) fn new(gpu: &Arc, sample_count: u32) -> Self { + pub(crate) fn new(gpu: &Arc, path_sample_count: u32) -> Self { BladeAtlas(Mutex::new(BladeAtlasState { gpu: Arc::clone(gpu), upload_belt: BufferBelt::new(BufferBeltDescriptor { @@ -59,7 +59,7 @@ impl BladeAtlas { tiles_by_key: Default::default(), initializations: Vec::new(), uploads: Vec::new(), - sample_count, + path_sample_count, })) } @@ -208,32 +208,10 @@ impl BladeAtlasState { } } - let raw = self.gpu.create_texture(gpu::TextureDesc { - name: "atlas", - format, - size: gpu::Extent { - width: size.width.into(), - height: size.height.into(), - depth: 1, - }, - array_layer_count: 1, - mip_level_count: 1, - sample_count: 1, - dimension: gpu::TextureDimension::D2, - usage, - }); - let raw_view = self.gpu.create_texture_view( - raw, - gpu::TextureViewDesc { - name: "", - format, - dimension: gpu::ViewDimension::D2, - subresources: &Default::default(), - }, - ); - let msaa_view = if self.sample_count > 1 { + // We currently only enable MSAA for path textures. + let msaa_view = if self.path_sample_count > 1 && kind == AtlasTextureKind::Path { let msaa = self.gpu.create_texture(gpu::TextureDesc { - name: "msaa texture", + name: "msaa path texture", format, size: gpu::Extent { width: size.width.into(), @@ -242,7 +220,7 @@ impl BladeAtlasState { }, array_layer_count: 1, mip_level_count: 1, - sample_count: self.sample_count, + sample_count: self.path_sample_count, dimension: gpu::TextureDimension::D2, usage: gpu::TextureUsage::TARGET, }); @@ -260,6 +238,30 @@ impl BladeAtlasState { None }; + let raw = self.gpu.create_texture(gpu::TextureDesc { + name: "atlas", + format, + size: gpu::Extent { + width: size.width.into(), + height: size.height.into(), + depth: 1, + }, + array_layer_count: 1, + mip_level_count: 1, + sample_count: 1, + dimension: gpu::TextureDimension::D2, + usage, + }); + let raw_view = self.gpu.create_texture_view( + raw, + gpu::TextureViewDesc { + name: "", + format, + dimension: gpu::ViewDimension::D2, + subresources: &Default::default(), + }, + ); + let texture_list = &mut self.storage[kind]; let index = texture_list.free_list.pop(); diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index c00f8b9cdf46f4..3738c3b9bd4f14 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -13,8 +13,6 @@ use bytemuck::{Pod, Zeroable}; use collections::HashMap; #[cfg(target_os = "macos")] use media::core_video::CVMetalTextureCache; -#[cfg(target_os = "macos")] -use objc2_metal::MTLDevice; use std::{mem, sync::Arc}; const MAX_FRAME_TIME_MS: u32 = 10000; @@ -129,7 +127,7 @@ struct BladePipelines { } impl BladePipelines { - fn new(gpu: &gpu::Context, surface_info: gpu::SurfaceInfo, sample_count: u32) -> Self { + fn new(gpu: &gpu::Context, surface_info: gpu::SurfaceInfo, path_sample_count: u32) -> Self { use gpu::ShaderData as _; log::info!( @@ -210,7 +208,7 @@ impl BladePipelines { write_mask: gpu::ColorWrites::default(), }], multisample_state: gpu::MultisampleState { - sample_count, + sample_count: path_sample_count, ..Default::default() }, }), @@ -343,21 +341,22 @@ impl BladeRenderer { .create_surface_configured(window, surface_config) .unwrap(); - // Determine the sample count based on the device's capabilities. + // macOS use 4x MSAA, all devices support it. + // https://developer.apple.com/documentation/metal/mtldevice/1433355-supportstexturesamplecount #[cfg(target_os = "macos")] + let sample_count = 4; + + // Determine on non-macOS platforms, until Blade supports querying sample counts. + #[cfg(not(target_os = "macos"))] let mut sample_count = 1; - #[cfg(target_os = "macos")] + #[cfg(not(target_os = "macos"))] for &n in &[4, 2] { - if context.gpu.metal_device().supportsTextureSampleCount(n) { + if context.gpu.supports_texture_sample_count(n) { sample_count = n as _; break; } } - // TODO: Determine on non-macOS platforms, until Blade supports querying sample counts. - #[cfg(not(target_os = "macos"))] - let sample_count = 4; - let command_encoder = context.gpu.create_command_encoder(gpu::CommandEncoderDesc { name: "main", buffer_count: 2, @@ -519,7 +518,7 @@ impl BladeRenderer { let vertex_buf = unsafe { self.instance_belt.alloc_typed(&vertices, &self.gpu) }; let frame_view = tex_info.raw_view; - let render_target = if let Some(msaa_view) = tex_info.msaa_view { + let color_target = if let Some(msaa_view) = tex_info.msaa_view { gpu::RenderTargetSet { colors: &[gpu::RenderTarget { view: msaa_view, @@ -539,7 +538,7 @@ impl BladeRenderer { } }; - if let mut pass = self.command_encoder.render("paths", render_target) { + if let mut pass = self.command_encoder.render("paths", color_target) { let mut encoder = pass.with(&self.pipelines.path_rasterization); encoder.bind( 0, diff --git a/crates/gpui/src/platform/mac/metal_atlas.rs b/crates/gpui/src/platform/mac/metal_atlas.rs index 52d08f068b6072..eef3ec5be5a8b0 100644 --- a/crates/gpui/src/platform/mac/metal_atlas.rs +++ b/crates/gpui/src/platform/mac/metal_atlas.rs @@ -13,14 +13,14 @@ use std::borrow::Cow; pub(crate) struct MetalAtlas(Mutex); impl MetalAtlas { - pub(crate) fn new(device: Device, sample_count: u32) -> Self { + pub(crate) fn new(device: Device, path_sample_count: u32) -> Self { MetalAtlas(Mutex::new(MetalAtlasState { device: AssertSend(device), monochrome_textures: Default::default(), polychrome_textures: Default::default(), path_textures: Default::default(), tiles_by_key: Default::default(), - sample_count, + path_sample_count, })) } @@ -59,7 +59,7 @@ struct MetalAtlasState { polychrome_textures: AtlasTextureList, path_textures: AtlasTextureList, tiles_by_key: FxHashMap, - sample_count: u32, + path_sample_count: u32, } impl PlatformAtlas for MetalAtlas { @@ -182,7 +182,8 @@ impl MetalAtlasState { texture_descriptor.set_usage(usage); let metal_texture = self.device.new_texture(&texture_descriptor); - let msaa_texture = if self.sample_count > 1 { + // We currently only enable MSAA for path textures. + let msaa_texture = if self.path_sample_count > 1 && kind == AtlasTextureKind::Path { let mut descriptor = texture_descriptor.clone(); descriptor.set_texture_type(metal::MTLTextureType::D2Multisample); descriptor.set_storage_mode(metal::MTLStorageMode::Private); diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 6cf2d02f1d9bfc..94c1bb70a6182f 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -107,6 +107,10 @@ pub(crate) struct MetalRenderer { core_video_texture_cache: CVMetalTextureCache, } +// macOS use 4x MSAA, all devices support it. +// https://developer.apple.com/documentation/metal/mtldevice/1433355-supportstexturesamplecount +const SAMPLE_COUNT: u32 = 4; + impl MetalRenderer { pub fn new(instance_buffer_pool: Arc>) -> Self { // Prefer low‐power integrated GPUs on Intel Mac. On Apple @@ -119,15 +123,6 @@ impl MetalRenderer { std::process::exit(1); }; - // Determine the sample count based on the device's capabilities. - let mut sample_count = 1; - for &n in &[4, 2] { - if device.supports_texture_sample_count(n) { - sample_count = n as _; - break; - } - } - let layer = metal::MetalLayer::new(); layer.set_device(&device); layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm); @@ -179,7 +174,7 @@ impl MetalRenderer { "path_rasterization_vertex", "path_rasterization_fragment", MTLPixelFormat::R16Float, - sample_count, + SAMPLE_COUNT, ); let path_sprites_pipeline_state = build_pipeline_state( &device, @@ -239,7 +234,7 @@ impl MetalRenderer { ); let command_queue = device.new_command_queue(); - let sprite_atlas = Arc::new(MetalAtlas::new(device.clone(), sample_count)); + let sprite_atlas = Arc::new(MetalAtlas::new(device.clone(), SAMPLE_COUNT)); let core_video_texture_cache = unsafe { CVMetalTextureCache::new(device.as_ptr()).unwrap() }; @@ -548,13 +543,13 @@ impl MetalRenderer { color_attachment.set_resolve_texture(Some(&texture)); color_attachment.set_load_action(metal::MTLLoadAction::Clear); color_attachment.set_store_action(metal::MTLStoreAction::MultisampleResolve); - color_attachment.set_resolve_level(0); } else { color_attachment.set_texture(Some(&texture)); color_attachment.set_load_action(metal::MTLLoadAction::Clear); color_attachment.set_store_action(metal::MTLStoreAction::Store); } color_attachment.set_clear_color(metal::MTLClearColor::new(0., 0., 0., 1.)); + let command_encoder = command_buffer.new_render_command_encoder(render_pass_descriptor); command_encoder.set_render_pipeline_state(&self.paths_rasterization_pipeline_state); command_encoder.set_vertex_buffer( From 26df026b7772829f331a36e85744033bb358655f Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 10 Jan 2025 14:10:14 +0800 Subject: [PATCH 11/16] . --- crates/gpui/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index 55f2e561424f72..63aac122a8af28 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -11,7 +11,7 @@ license = "Apache-2.0" workspace = true [features] -default = ["http_client", "font-kit", "wayland", "x11", "macos-blade"] +default = ["http_client", "font-kit", "wayland", "x11"] test-support = [ "backtrace", "collections/test-support", From b016e7bc839b937b180452b1a6061914d4f7549a Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Fri, 10 Jan 2025 14:11:19 +0800 Subject: [PATCH 12/16] . --- crates/gpui/src/platform/mac/metal_atlas.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/mac/metal_atlas.rs b/crates/gpui/src/platform/mac/metal_atlas.rs index eef3ec5be5a8b0..4662761a7d32a2 100644 --- a/crates/gpui/src/platform/mac/metal_atlas.rs +++ b/crates/gpui/src/platform/mac/metal_atlas.rs @@ -187,7 +187,7 @@ impl MetalAtlasState { let mut descriptor = texture_descriptor.clone(); descriptor.set_texture_type(metal::MTLTextureType::D2Multisample); descriptor.set_storage_mode(metal::MTLStorageMode::Private); - descriptor.set_sample_count(self.sample_count as _); + descriptor.set_sample_count(self.path_sample_count as _); let msaa_texture = self.device.new_texture(&descriptor); Some(msaa_texture) } else { From 3f96f24c1191d0bc4207e622b2deb93b81804c51 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Sat, 11 Jan 2025 23:43:50 +0800 Subject: [PATCH 13/16] Release msaa --- crates/gpui/src/platform/blade/blade_atlas.rs | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/crates/gpui/src/platform/blade/blade_atlas.rs b/crates/gpui/src/platform/blade/blade_atlas.rs index 036d178f3e8204..2783d57127e6c8 100644 --- a/crates/gpui/src/platform/blade/blade_atlas.rs +++ b/crates/gpui/src/platform/blade/blade_atlas.rs @@ -209,7 +209,7 @@ impl BladeAtlasState { } // We currently only enable MSAA for path textures. - let msaa_view = if self.path_sample_count > 1 && kind == AtlasTextureKind::Path { + let (msaa, msaa_view) = if self.path_sample_count > 1 && kind == AtlasTextureKind::Path { let msaa = self.gpu.create_texture(gpu::TextureDesc { name: "msaa path texture", format, @@ -225,17 +225,20 @@ impl BladeAtlasState { usage: gpu::TextureUsage::TARGET, }); - Some(self.gpu.create_texture_view( - msaa, - gpu::TextureViewDesc { - name: "msaa texture view", - format, - dimension: gpu::ViewDimension::D2, - subresources: &Default::default(), - }, - )) + ( + Some(msaa), + Some(self.gpu.create_texture_view( + msaa, + gpu::TextureViewDesc { + name: "msaa texture view", + format, + dimension: gpu::ViewDimension::D2, + subresources: &Default::default(), + }, + )), + ) } else { - None + (None, None) }; let raw = self.gpu.create_texture(gpu::TextureDesc { @@ -274,6 +277,7 @@ impl BladeAtlasState { format, raw, raw_view, + msaa, msaa_view, live_atlas_keys: 0, }; @@ -389,6 +393,7 @@ struct BladeAtlasTexture { allocator: BucketedAtlasAllocator, raw: gpu::Texture, raw_view: gpu::TextureView, + msaa: Option, msaa_view: Option, format: gpu::TextureFormat, live_atlas_keys: u32, @@ -417,6 +422,9 @@ impl BladeAtlasTexture { fn destroy(&mut self, gpu: &gpu::Context) { gpu.destroy_texture(self.raw); gpu.destroy_texture_view(self.raw_view); + if let Some(msaa) = self.msaa { + gpu.destroy_texture(msaa); + } if let Some(msaa_view) = self.msaa_view { gpu.destroy_texture_view(msaa_view); } From 35191e2bb2a45b7dc278fb9715c9a487e6ac159b Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Sat, 11 Jan 2025 23:47:26 +0800 Subject: [PATCH 14/16] rename sample_count to path_sample_count --- .../gpui/src/platform/blade/blade_renderer.rs | 17 +++++++++-------- crates/gpui/src/platform/mac/metal_renderer.rs | 12 ++++++------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index 3738c3b9bd4f14..259aeac5effa47 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -319,7 +319,7 @@ pub struct BladeRenderer { atlas_sampler: gpu::Sampler, #[cfg(target_os = "macos")] core_video_texture_cache: CVMetalTextureCache, - sample_count: u32, + path_sample_count: u32, } impl BladeRenderer { @@ -344,15 +344,15 @@ impl BladeRenderer { // macOS use 4x MSAA, all devices support it. // https://developer.apple.com/documentation/metal/mtldevice/1433355-supportstexturesamplecount #[cfg(target_os = "macos")] - let sample_count = 4; + let path_sample_count = 4; // Determine on non-macOS platforms, until Blade supports querying sample counts. #[cfg(not(target_os = "macos"))] - let mut sample_count = 1; + let mut path_sample_count = 1; #[cfg(not(target_os = "macos"))] for &n in &[4, 2] { if context.gpu.supports_texture_sample_count(n) { - sample_count = n as _; + path_sample_count = n as _; break; } } @@ -361,13 +361,13 @@ impl BladeRenderer { name: "main", buffer_count: 2, }); - let pipelines = BladePipelines::new(&context.gpu, surface.info(), sample_count); + let pipelines = BladePipelines::new(&context.gpu, surface.info(), path_sample_count); let instance_belt = BufferBelt::new(BufferBeltDescriptor { memory: gpu::Memory::Shared, min_chunk_size: 0x1000, alignment: 0x40, // Vulkan `minStorageBufferOffsetAlignment` on Intel Xe }); - let atlas = Arc::new(BladeAtlas::new(&context.gpu, sample_count)); + let atlas = Arc::new(BladeAtlas::new(&context.gpu, path_sample_count)); let atlas_sampler = context.gpu.create_sampler(gpu::SamplerDesc { name: "atlas", mag_filter: gpu::FilterMode::Linear, @@ -396,7 +396,7 @@ impl BladeRenderer { atlas_sampler, #[cfg(target_os = "macos")] core_video_texture_cache, - sample_count, + path_sample_count, }) } @@ -443,7 +443,8 @@ impl BladeRenderer { self.gpu .reconfigure_surface(&mut self.surface, self.surface_config); self.pipelines.destroy(&self.gpu); - self.pipelines = BladePipelines::new(&self.gpu, self.surface.info(), self.sample_count); + self.pipelines = + BladePipelines::new(&self.gpu, self.surface.info(), self.path_sample_count); } } diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 94c1bb70a6182f..640e5227157689 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -109,7 +109,7 @@ pub(crate) struct MetalRenderer { // macOS use 4x MSAA, all devices support it. // https://developer.apple.com/documentation/metal/mtldevice/1433355-supportstexturesamplecount -const SAMPLE_COUNT: u32 = 4; +const PATH_SAMPLE_COUNT: u32 = 4; impl MetalRenderer { pub fn new(instance_buffer_pool: Arc>) -> Self { @@ -174,7 +174,7 @@ impl MetalRenderer { "path_rasterization_vertex", "path_rasterization_fragment", MTLPixelFormat::R16Float, - SAMPLE_COUNT, + PATH_SAMPLE_COUNT, ); let path_sprites_pipeline_state = build_pipeline_state( &device, @@ -234,7 +234,7 @@ impl MetalRenderer { ); let command_queue = device.new_command_queue(); - let sprite_atlas = Arc::new(MetalAtlas::new(device.clone(), SAMPLE_COUNT)); + let sprite_atlas = Arc::new(MetalAtlas::new(device.clone(), PATH_SAMPLE_COUNT)); let core_video_texture_cache = unsafe { CVMetalTextureCache::new(device.as_ptr()).unwrap() }; @@ -1175,7 +1175,7 @@ fn build_path_rasterization_pipeline_state( vertex_fn_name: &str, fragment_fn_name: &str, pixel_format: metal::MTLPixelFormat, - sample_count: u32, + path_sample_count: u32, ) -> metal::RenderPipelineState { let vertex_fn = library .get_function(vertex_fn_name, None) @@ -1188,8 +1188,8 @@ fn build_path_rasterization_pipeline_state( descriptor.set_label(label); descriptor.set_vertex_function(Some(vertex_fn.as_ref())); descriptor.set_fragment_function(Some(fragment_fn.as_ref())); - if sample_count > 1 { - descriptor.set_raster_sample_count(sample_count as _); + if path_sample_count > 1 { + descriptor.set_raster_sample_count(path_sample_count as _); descriptor.set_alpha_to_coverage_enabled(true); } let color_attachment = descriptor.color_attachments().object_at(0).unwrap(); From 7eda9f3e2aabac661a8f90745f889e3771a151f1 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Sat, 11 Jan 2025 23:52:01 +0800 Subject: [PATCH 15/16] improve render_target_set init --- .../gpui/src/platform/blade/blade_renderer.rs | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index 259aeac5effa47..f5ff45f0fe19b9 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -520,26 +520,26 @@ impl BladeRenderer { let vertex_buf = unsafe { self.instance_belt.alloc_typed(&vertices, &self.gpu) }; let frame_view = tex_info.raw_view; let color_target = if let Some(msaa_view) = tex_info.msaa_view { - gpu::RenderTargetSet { - colors: &[gpu::RenderTarget { - view: msaa_view, - init_op: gpu::InitOp::Clear(gpu::TextureColor::OpaqueBlack), - finish_op: gpu::FinishOp::ResolveTo(frame_view), - }], - depth_stencil: None, + gpu::RenderTarget { + view: msaa_view, + init_op: gpu::InitOp::Clear(gpu::TextureColor::OpaqueBlack), + finish_op: gpu::FinishOp::ResolveTo(frame_view), } } else { - gpu::RenderTargetSet { - colors: &[gpu::RenderTarget { - view: frame_view, - init_op: gpu::InitOp::Clear(gpu::TextureColor::OpaqueBlack), - finish_op: gpu::FinishOp::Store, - }], - depth_stencil: None, + gpu::RenderTarget { + view: frame_view, + init_op: gpu::InitOp::Clear(gpu::TextureColor::OpaqueBlack), + finish_op: gpu::FinishOp::Store, } }; - if let mut pass = self.command_encoder.render("paths", color_target) { + if let mut pass = self.command_encoder.render( + "paths", + gpu::RenderTargetSet { + colors: &[color_target], + depth_stencil: None, + }, + ) { let mut encoder = pass.with(&self.pipelines.path_rasterization); encoder.bind( 0, From c0582204ce96c6f6643d1c58904dc278e5eb76a2 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 13 Jan 2025 15:12:01 +0800 Subject: [PATCH 16/16] Use PATH_SAMPLE_COUNT=4 for all platform. --- .../gpui/src/platform/blade/blade_renderer.rs | 32 +++++-------------- .../gpui/src/platform/mac/metal_renderer.rs | 7 ++-- 2 files changed, 11 insertions(+), 28 deletions(-) diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index f5ff45f0fe19b9..200ebaaf07fd2b 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -16,6 +16,9 @@ use media::core_video::CVMetalTextureCache; use std::{mem, sync::Arc}; const MAX_FRAME_TIME_MS: u32 = 10000; +// Use 4x MSAA, all devices support it. +// https://developer.apple.com/documentation/metal/mtldevice/1433355-supportstexturesamplecount +const PATH_SAMPLE_COUNT: u32 = 4; #[repr(C)] #[derive(Clone, Copy, Pod, Zeroable)] @@ -127,7 +130,7 @@ struct BladePipelines { } impl BladePipelines { - fn new(gpu: &gpu::Context, surface_info: gpu::SurfaceInfo, path_sample_count: u32) -> Self { + fn new(gpu: &gpu::Context, surface_info: gpu::SurfaceInfo) -> Self { use gpu::ShaderData as _; log::info!( @@ -208,7 +211,7 @@ impl BladePipelines { write_mask: gpu::ColorWrites::default(), }], multisample_state: gpu::MultisampleState { - sample_count: path_sample_count, + sample_count: PATH_SAMPLE_COUNT, ..Default::default() }, }), @@ -319,7 +322,6 @@ pub struct BladeRenderer { atlas_sampler: gpu::Sampler, #[cfg(target_os = "macos")] core_video_texture_cache: CVMetalTextureCache, - path_sample_count: u32, } impl BladeRenderer { @@ -341,33 +343,17 @@ impl BladeRenderer { .create_surface_configured(window, surface_config) .unwrap(); - // macOS use 4x MSAA, all devices support it. - // https://developer.apple.com/documentation/metal/mtldevice/1433355-supportstexturesamplecount - #[cfg(target_os = "macos")] - let path_sample_count = 4; - - // Determine on non-macOS platforms, until Blade supports querying sample counts. - #[cfg(not(target_os = "macos"))] - let mut path_sample_count = 1; - #[cfg(not(target_os = "macos"))] - for &n in &[4, 2] { - if context.gpu.supports_texture_sample_count(n) { - path_sample_count = n as _; - break; - } - } - let command_encoder = context.gpu.create_command_encoder(gpu::CommandEncoderDesc { name: "main", buffer_count: 2, }); - let pipelines = BladePipelines::new(&context.gpu, surface.info(), path_sample_count); + let pipelines = BladePipelines::new(&context.gpu, surface.info()); let instance_belt = BufferBelt::new(BufferBeltDescriptor { memory: gpu::Memory::Shared, min_chunk_size: 0x1000, alignment: 0x40, // Vulkan `minStorageBufferOffsetAlignment` on Intel Xe }); - let atlas = Arc::new(BladeAtlas::new(&context.gpu, path_sample_count)); + let atlas = Arc::new(BladeAtlas::new(&context.gpu, PATH_SAMPLE_COUNT)); let atlas_sampler = context.gpu.create_sampler(gpu::SamplerDesc { name: "atlas", mag_filter: gpu::FilterMode::Linear, @@ -396,7 +382,6 @@ impl BladeRenderer { atlas_sampler, #[cfg(target_os = "macos")] core_video_texture_cache, - path_sample_count, }) } @@ -443,8 +428,7 @@ impl BladeRenderer { self.gpu .reconfigure_surface(&mut self.surface, self.surface_config); self.pipelines.destroy(&self.gpu); - self.pipelines = - BladePipelines::new(&self.gpu, self.surface.info(), self.path_sample_count); + self.pipelines = BladePipelines::new(&self.gpu, self.surface.info()); } } diff --git a/crates/gpui/src/platform/mac/metal_renderer.rs b/crates/gpui/src/platform/mac/metal_renderer.rs index 640e5227157689..56109d2ff6e5cd 100644 --- a/crates/gpui/src/platform/mac/metal_renderer.rs +++ b/crates/gpui/src/platform/mac/metal_renderer.rs @@ -28,6 +28,9 @@ pub(crate) type PointF = crate::Point; const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); #[cfg(feature = "runtime_shaders")] const SHADERS_SOURCE_FILE: &str = include_str!(concat!(env!("OUT_DIR"), "/stitched_shaders.metal")); +// Use 4x MSAA, all devices support it. +// https://developer.apple.com/documentation/metal/mtldevice/1433355-supportstexturesamplecount +const PATH_SAMPLE_COUNT: u32 = 4; pub type Context = Arc>; pub type Renderer = MetalRenderer; @@ -107,10 +110,6 @@ pub(crate) struct MetalRenderer { core_video_texture_cache: CVMetalTextureCache, } -// macOS use 4x MSAA, all devices support it. -// https://developer.apple.com/documentation/metal/mtldevice/1433355-supportstexturesamplecount -const PATH_SAMPLE_COUNT: u32 = 4; - impl MetalRenderer { pub fn new(instance_buffer_pool: Arc>) -> Self { // Prefer low‐power integrated GPUs on Intel Mac. On Apple