Skip to content

Commit

Permalink
Blade window transparency (#10973)
Browse files Browse the repository at this point in the history
Release Notes:

- N/A

Following up to #10880
TODO:
- [x] create window as transparent
  - [x] X11
  - [x] Wayland
  - [ ] Windows
  - [x] MacOS (when used with Blade)  
- [x] enable GPU surface transparency
- [x] adjust the pipeline blend modes
- [x] adjust shader outputs


![transparency2](https://github.com/zed-industries/zed/assets/107301/d554a41b-5d3f-4420-a857-c64c1747c2d5)

Blurred results from @jansol (on Wayland), who contributed to this work:


![zed-blur](https://github.com/zed-industries/zed/assets/107301/a6822171-2dcf-4109-be55-b75557c586de)

---------

Co-authored-by: Jan Solanti <jhs@psonet.com>
  • Loading branch information
kvark and jansol committed May 6, 2024
1 parent 056c785 commit e4f13dd
Show file tree
Hide file tree
Showing 11 changed files with 344 additions and 128 deletions.
18 changes: 16 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -254,8 +254,8 @@ async-recursion = "1.0.0"
async-tar = "0.4.2"
async-trait = "0.1"
bitflags = "2.4.2"
blade-graphics = { git = "https://github.com/kvark/blade", rev = "e82eec97691c3acdb43494484be60d661edfebf3" }
blade-macros = { git = "https://github.com/kvark/blade", rev = "e82eec97691c3acdb43494484be60d661edfebf3" }
blade-graphics = { git = "https://github.com/kvark/blade", rev = "f5766863de9dcc092e90fdbbc5e0007a99e7f9bf" }
blade-macros = { git = "https://github.com/kvark/blade", rev = "f5766863de9dcc092e90fdbbc5e0007a99e7f9bf" }
cap-std = "3.0"
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.4", features = ["derive"] }
Expand Down
1 change: 1 addition & 0 deletions crates/gpui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ wayland-protocols = { version = "0.31.2", features = [
"staging",
"unstable",
] }
wayland-protocols-plasma = { version = "0.2.0", features = ["client"] }
oo7 = "0.3.0"
open = "5.1.2"
filedescriptor = "0.8.2"
Expand Down
130 changes: 72 additions & 58 deletions crates/gpui/src/platform/blade/blade_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub unsafe fn new_renderer(
_native_window: *mut c_void,
native_view: *mut c_void,
bounds: crate::Size<f32>,
transparent: bool,
) -> Renderer {
use raw_window_handle as rwh;
struct RawWindow {
Expand Down Expand Up @@ -64,10 +65,13 @@ pub unsafe fn new_renderer(

BladeRenderer::new(
gpu,
gpu::Extent {
width: bounds.width as u32,
height: bounds.height as u32,
depth: 1,
BladeSurfaceConfig {
size: gpu::Extent {
width: bounds.width as u32,
height: bounds.height as u32,
depth: 1,
},
transparent,
},
)
}
Expand All @@ -76,7 +80,8 @@ pub unsafe fn new_renderer(
#[derive(Clone, Copy, Pod, Zeroable)]
struct GlobalParams {
viewport_size: [f32; 2],
pad: [u32; 2],
premultiplied_alpha: u32,
pad: u32,
}

//Note: we can't use `Bounds` directly here because
Expand Down Expand Up @@ -184,6 +189,10 @@ impl BladePipelines {
fn new(gpu: &gpu::Context, surface_info: gpu::SurfaceInfo) -> Self {
use gpu::ShaderData as _;

log::info!(
"Initializing Blade pipelines for surface {:?}",
surface_info
);
let shader = gpu.create_shader(gpu::ShaderDesc {
source: include_str!("shaders.wgsl"),
});
Expand All @@ -200,6 +209,18 @@ impl BladePipelines {
shader.check_struct_size::<MonochromeSprite>();
shader.check_struct_size::<PolychromeSprite>();

// See https://apoorvaj.io/alpha-compositing-opengl-blending-and-premultiplied-alpha/
let blend_mode = match surface_info.alpha {
gpu::AlphaMode::Ignored => gpu::BlendState::ALPHA_BLENDING,
gpu::AlphaMode::PreMultiplied => gpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING,
gpu::AlphaMode::PostMultiplied => gpu::BlendState::ALPHA_BLENDING,
};
let color_targets = &[gpu::ColorTargetState {
format: surface_info.format,
blend: Some(blend_mode),
write_mask: gpu::ColorWrites::default(),
}];

Self {
quads: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
name: "quads",
Expand All @@ -212,11 +233,7 @@ impl BladePipelines {
},
depth_stencil: None,
fragment: shader.at("fs_quad"),
color_targets: &[gpu::ColorTargetState {
format: surface_info.format,
blend: Some(gpu::BlendState::ALPHA_BLENDING),
write_mask: gpu::ColorWrites::default(),
}],
color_targets,
}),
shadows: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
name: "shadows",
Expand All @@ -229,11 +246,7 @@ impl BladePipelines {
},
depth_stencil: None,
fragment: shader.at("fs_shadow"),
color_targets: &[gpu::ColorTargetState {
format: surface_info.format,
blend: Some(gpu::BlendState::ALPHA_BLENDING),
write_mask: gpu::ColorWrites::default(),
}],
color_targets,
}),
path_rasterization: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
name: "path_rasterization",
Expand Down Expand Up @@ -263,11 +276,7 @@ impl BladePipelines {
},
depth_stencil: None,
fragment: shader.at("fs_path"),
color_targets: &[gpu::ColorTargetState {
format: surface_info.format,
blend: Some(gpu::BlendState::ALPHA_BLENDING),
write_mask: gpu::ColorWrites::default(),
}],
color_targets,
}),
underlines: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
name: "underlines",
Expand All @@ -280,11 +289,7 @@ impl BladePipelines {
},
depth_stencil: None,
fragment: shader.at("fs_underline"),
color_targets: &[gpu::ColorTargetState {
format: surface_info.format,
blend: Some(gpu::BlendState::ALPHA_BLENDING),
write_mask: gpu::ColorWrites::default(),
}],
color_targets,
}),
mono_sprites: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
name: "mono-sprites",
Expand All @@ -297,11 +302,7 @@ impl BladePipelines {
},
depth_stencil: None,
fragment: shader.at("fs_mono_sprite"),
color_targets: &[gpu::ColorTargetState {
format: surface_info.format,
blend: Some(gpu::BlendState::ALPHA_BLENDING),
write_mask: gpu::ColorWrites::default(),
}],
color_targets,
}),
poly_sprites: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
name: "poly-sprites",
Expand All @@ -314,11 +315,7 @@ impl BladePipelines {
},
depth_stencil: None,
fragment: shader.at("fs_poly_sprite"),
color_targets: &[gpu::ColorTargetState {
format: surface_info.format,
blend: Some(gpu::BlendState::ALPHA_BLENDING),
write_mask: gpu::ColorWrites::default(),
}],
color_targets,
}),
surfaces: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
name: "surfaces",
Expand All @@ -331,23 +328,25 @@ impl BladePipelines {
},
depth_stencil: None,
fragment: shader.at("fs_surface"),
color_targets: &[gpu::ColorTargetState {
format: surface_info.format,
blend: Some(gpu::BlendState::ALPHA_BLENDING),
write_mask: gpu::ColorWrites::default(),
}],
color_targets,
}),
}
}
}

pub struct BladeSurfaceConfig {
pub size: gpu::Extent,
pub transparent: bool,
}

pub struct BladeRenderer {
gpu: Arc<gpu::Context>,
surface_config: gpu::SurfaceConfig,
alpha_mode: gpu::AlphaMode,
command_encoder: gpu::CommandEncoder,
last_sync_point: Option<gpu::SyncPoint>,
pipelines: BladePipelines,
instance_belt: BladeBelt,
viewport_size: gpu::Extent,
path_tiles: HashMap<PathId, AtlasTile>,
atlas: Arc<BladeAtlas>,
atlas_sampler: gpu::Sampler,
Expand All @@ -356,21 +355,19 @@ pub struct BladeRenderer {
}

impl BladeRenderer {
fn make_surface_config(size: gpu::Extent) -> gpu::SurfaceConfig {
gpu::SurfaceConfig {
size,
pub fn new(gpu: Arc<gpu::Context>, config: BladeSurfaceConfig) -> Self {
let surface_config = gpu::SurfaceConfig {
size: config.size,
usage: gpu::TextureUsage::TARGET,
display_sync: gpu::DisplaySync::Recent,
//Note: this matches the original logic of the Metal backend,
// but ultimaterly we need to switch to `Linear`.
color_space: gpu::ColorSpace::Srgb,
allow_exclusive_full_screen: false,
transparent: false,
}
}
transparent: config.transparent,
};
let surface_info = gpu.resize(surface_config);

pub fn new(gpu: Arc<gpu::Context>, size: gpu::Extent) -> Self {
let surface_info = gpu.resize(Self::make_surface_config(size));
let command_encoder = gpu.create_command_encoder(gpu::CommandEncoderDesc {
name: "main",
buffer_count: 2,
Expand All @@ -397,11 +394,12 @@ impl BladeRenderer {

Self {
gpu,
surface_config,
alpha_mode: surface_info.alpha,
command_encoder,
last_sync_point: None,
pipelines,
instance_belt,
viewport_size: size,
path_tiles: HashMap::default(),
atlas,
atlas_sampler,
Expand All @@ -425,15 +423,26 @@ impl BladeRenderer {
depth: 1,
};

if gpu_size != self.viewport_size() {
if gpu_size != self.surface_config.size {
self.wait_for_gpu();
self.gpu.resize(Self::make_surface_config(gpu_size));
self.viewport_size = gpu_size;
self.surface_config.size = gpu_size;
self.gpu.resize(self.surface_config);
}
}

pub fn update_transparency(&mut self, transparent: bool) {
if transparent != self.surface_config.transparent {
self.wait_for_gpu();
self.surface_config.transparent = transparent;
let surface_info = self.gpu.resize(self.surface_config);
self.pipelines = BladePipelines::new(&self.gpu, surface_info);
self.alpha_mode = surface_info.alpha;
}
}

#[cfg_attr(target_os = "macos", allow(dead_code))]
pub fn viewport_size(&self) -> gpu::Extent {
self.viewport_size
self.surface_config.size
}

pub fn sprite_atlas(&self) -> &Arc<BladeAtlas> {
Expand Down Expand Up @@ -481,7 +490,8 @@ impl BladeRenderer {
let tex_info = self.atlas.get_texture_info(texture_id);
let globals = GlobalParams {
viewport_size: [tex_info.size.width as f32, tex_info.size.height as f32],
pad: [0; 2],
premultiplied_alpha: 0,
pad: 0,
};

let vertex_buf = unsafe { self.instance_belt.alloc_data(&vertices, &self.gpu) };
Expand Down Expand Up @@ -526,10 +536,14 @@ impl BladeRenderer {

let globals = GlobalParams {
viewport_size: [
self.viewport_size.width as f32,
self.viewport_size.height as f32,
self.surface_config.size.width as f32,
self.surface_config.size.height as f32,
],
pad: [0; 2],
premultiplied_alpha: match self.alpha_mode {
gpu::AlphaMode::Ignored | gpu::AlphaMode::PostMultiplied => 0,
gpu::AlphaMode::PreMultiplied => 1,
},
pad: 0,
};

if let mut pass = self.command_encoder.render(gpu::RenderTargetSet {
Expand Down

0 comments on commit e4f13dd

Please sign in to comment.