mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 19:10:24 +00:00
linux: path rasterization shader
This commit is contained in:
parent
05c42211fe
commit
fdaffdbfff
4 changed files with 100 additions and 14 deletions
|
@ -41,6 +41,11 @@ impl BladeAtlasState {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct BladeTextureInfo {
|
||||
pub size: gpu::Extent,
|
||||
pub raw_view: Option<gpu::TextureView>,
|
||||
}
|
||||
|
||||
impl BladeAtlas {
|
||||
pub(crate) fn new(gpu: &Arc<gpu::Context>) -> Self {
|
||||
BladeAtlas(Mutex::new(BladeAtlasState {
|
||||
|
@ -94,14 +99,23 @@ impl BladeAtlas {
|
|||
sync_point
|
||||
}
|
||||
|
||||
pub fn get_texture_view(&self, id: AtlasTextureId) -> gpu::TextureView {
|
||||
pub fn get_texture_info(&self, id: AtlasTextureId) -> BladeTextureInfo {
|
||||
let lock = self.0.lock();
|
||||
let textures = match id.kind {
|
||||
crate::AtlasTextureKind::Monochrome => &lock.monochrome_textures,
|
||||
crate::AtlasTextureKind::Polychrome => &lock.polychrome_textures,
|
||||
crate::AtlasTextureKind::Path => &lock.path_textures,
|
||||
};
|
||||
textures[id.index as usize].raw_view.unwrap()
|
||||
let texture = &textures[id.index as usize];
|
||||
let size = texture.allocator.size();
|
||||
BladeTextureInfo {
|
||||
size: gpu::Extent {
|
||||
width: size.width as u32,
|
||||
height: size.height as u32,
|
||||
depth: 1,
|
||||
},
|
||||
raw_view: texture.raw_view,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ use bytemuck::{Pod, Zeroable};
|
|||
use collections::HashMap;
|
||||
|
||||
use blade_graphics as gpu;
|
||||
use std::sync::Arc;
|
||||
use std::{mem, sync::Arc};
|
||||
|
||||
const SURFACE_FRAME_COUNT: u32 = 3;
|
||||
const MAX_FRAME_TIME_MS: u32 = 1000;
|
||||
|
@ -34,6 +34,12 @@ struct ShaderShadowsData {
|
|||
b_shadows: gpu::BufferPiece,
|
||||
}
|
||||
|
||||
#[derive(blade_macros::ShaderData)]
|
||||
struct ShaderPathRasterizationData {
|
||||
globals: GlobalParams,
|
||||
b_path_vertices: gpu::BufferPiece,
|
||||
}
|
||||
|
||||
struct BladePipelines {
|
||||
quads: gpu::RenderPipeline,
|
||||
shadows: gpu::RenderPipeline,
|
||||
|
@ -47,8 +53,14 @@ impl BladePipelines {
|
|||
});
|
||||
shader.check_struct_size::<Quad>();
|
||||
shader.check_struct_size::<Shadow>();
|
||||
assert_eq!(
|
||||
mem::size_of::<PathVertex<ScaledPixels>>(),
|
||||
shader.get_struct_size("PathVertex") as usize,
|
||||
);
|
||||
let quads_layout = <ShaderQuadsData as gpu::ShaderData>::layout();
|
||||
let shadows_layout = <ShaderShadowsData as gpu::ShaderData>::layout();
|
||||
let path_rasterization_layout = <ShaderPathRasterizationData as gpu::ShaderData>::layout();
|
||||
|
||||
Self {
|
||||
quads: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "quads",
|
||||
|
@ -84,7 +96,7 @@ impl BladePipelines {
|
|||
}),
|
||||
path_rasterization: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "path_rasterization",
|
||||
data_layouts: &[&shadows_layout],
|
||||
data_layouts: &[&path_rasterization_layout],
|
||||
vertex: shader.at("vs_path_rasterization"),
|
||||
primitive: gpu::PrimitiveState {
|
||||
topology: gpu::PrimitiveTopology::TriangleStrip,
|
||||
|
@ -196,10 +208,16 @@ impl BladeRenderer {
|
|||
}
|
||||
|
||||
for (texture_id, vertices) in vertices_by_texture_id {
|
||||
let instances = self.instance_belt.alloc_data(&vertices, &self.gpu);
|
||||
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],
|
||||
};
|
||||
|
||||
let vertex_buf = self.instance_belt.alloc_data(&vertices, &self.gpu);
|
||||
let mut pass = self.command_encoder.render(gpu::RenderTargetSet {
|
||||
colors: &[gpu::RenderTarget {
|
||||
view: self.atlas.get_texture_view(texture_id),
|
||||
view: tex_info.raw_view.unwrap(),
|
||||
init_op: gpu::InitOp::Clear(gpu::TextureColor::OpaqueBlack),
|
||||
finish_op: gpu::FinishOp::Store,
|
||||
}],
|
||||
|
@ -207,6 +225,13 @@ impl BladeRenderer {
|
|||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -237,25 +262,25 @@ impl BladeRenderer {
|
|||
for batch in scene.batches() {
|
||||
match batch {
|
||||
PrimitiveBatch::Quads(quads) => {
|
||||
let instances = self.instance_belt.alloc_data(quads, &self.gpu);
|
||||
let instance_buf = self.instance_belt.alloc_data(quads, &self.gpu);
|
||||
let mut encoder = pass.with(&self.pipelines.quads);
|
||||
encoder.bind(
|
||||
0,
|
||||
&ShaderQuadsData {
|
||||
globals,
|
||||
b_quads: instances,
|
||||
b_quads: instance_buf,
|
||||
},
|
||||
);
|
||||
encoder.draw(0, 4, 0, quads.len() as u32);
|
||||
}
|
||||
PrimitiveBatch::Shadows(shadows) => {
|
||||
let instances = self.instance_belt.alloc_data(shadows, &self.gpu);
|
||||
let instance_buf = self.instance_belt.alloc_data(shadows, &self.gpu);
|
||||
let mut encoder = pass.with(&self.pipelines.shadows);
|
||||
encoder.bind(
|
||||
0,
|
||||
&ShaderShadowsData {
|
||||
globals,
|
||||
b_shadows: instances,
|
||||
b_shadows: instance_buf,
|
||||
},
|
||||
);
|
||||
encoder.draw(0, 4, 0, shadows.len() as u32);
|
||||
|
|
|
@ -35,19 +35,27 @@ struct Hsla {
|
|||
a: f32,
|
||||
}
|
||||
|
||||
fn to_device_position(unit_vertex: vec2<f32>, bounds: Bounds) -> vec4<f32> {
|
||||
let position = unit_vertex * vec2<f32>(bounds.size) + bounds.origin;
|
||||
fn to_device_position_impl(position: vec2<f32>) -> vec4<f32> {
|
||||
let device_position = position / globals.viewport_size * vec2<f32>(2.0, -2.0) + vec2<f32>(-1.0, 1.0);
|
||||
return vec4<f32>(device_position, 0.0, 1.0);
|
||||
}
|
||||
|
||||
fn distance_from_clip_rect(unit_vertex: vec2<f32>, bounds: Bounds, clip_bounds: Bounds) -> vec4<f32> {
|
||||
fn to_device_position(unit_vertex: vec2<f32>, bounds: Bounds) -> vec4<f32> {
|
||||
let position = unit_vertex * vec2<f32>(bounds.size) + bounds.origin;
|
||||
return to_device_position_impl(position);
|
||||
}
|
||||
|
||||
fn distance_from_clip_rect_impl(position: vec2<f32>, clip_bounds: Bounds) -> vec4<f32> {
|
||||
let tl = position - clip_bounds.origin;
|
||||
let br = clip_bounds.origin + clip_bounds.size - position;
|
||||
return vec4<f32>(tl.x, br.x, tl.y, br.y);
|
||||
}
|
||||
|
||||
fn distance_from_clip_rect(unit_vertex: vec2<f32>, bounds: Bounds, clip_bounds: Bounds) -> vec4<f32> {
|
||||
let position = unit_vertex * vec2<f32>(bounds.size) + bounds.origin;
|
||||
return distance_from_clip_rect_impl(position, clip_bounds);
|
||||
}
|
||||
|
||||
fn hsla_to_rgba(hsla: Hsla) -> vec4<f32> {
|
||||
let h = hsla.h * 6.0; // Now, it's an angle but scaled in [0, 6) range
|
||||
let s = hsla.s;
|
||||
|
@ -289,3 +297,42 @@ fn fs_shadow(input: ShadowVarying) -> @location(0) vec4<f32> {
|
|||
}
|
||||
|
||||
// --- path rasterization --- //
|
||||
|
||||
struct PathVertex {
|
||||
xy_position: vec2<f32>,
|
||||
st_position: vec2<f32>,
|
||||
content_mask: Bounds,
|
||||
}
|
||||
var<storage, read> b_path_vertices: array<PathVertex>;
|
||||
|
||||
struct PathRasterizationVarying {
|
||||
@builtin(position) position: vec4<f32>,
|
||||
@location(0) st_position: vec2<f32>,
|
||||
//TODO: use `clip_distance` once Naga supports it
|
||||
@location(3) clip_distances: vec4<f32>,
|
||||
}
|
||||
|
||||
@vertex
|
||||
fn vs_path_rasterization(@builtin(vertex_index) vertex_id: u32) -> PathRasterizationVarying {
|
||||
let v = b_path_vertices[vertex_id];
|
||||
|
||||
var out = PathRasterizationVarying();
|
||||
out.position = to_device_position_impl(v.xy_position);
|
||||
out.st_position = v.st_position;
|
||||
out.clip_distances = distance_from_clip_rect_impl(v.xy_position, v.content_mask);
|
||||
return out;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_path_rasterization(input: PathRasterizationVarying) -> @location(0) f32 {
|
||||
let dx = dpdx(input.st_position);
|
||||
let dy = dpdy(input.st_position);
|
||||
if (any(input.clip_distances < vec4<f32>(0.0))) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
let gradient = 2.0 * input.st_position * vec2<f32>(dx.x, dy.x) - vec2<f32>(dx.y, dy.y);
|
||||
let f = input.st_position.x * input.st_position.x - input.st_position.y;
|
||||
let distance = f / length(gradient);
|
||||
return saturate(0.5 - distance);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use font_kit::{
|
|||
};
|
||||
use parking_lot::RwLock;
|
||||
use smallvec::SmallVec;
|
||||
use std::{borrow::Cow};
|
||||
use std::borrow::Cow;
|
||||
|
||||
pub(crate) struct LinuxTextSystem(RwLock<LinuxTextSystemState>);
|
||||
|
||||
|
|
Loading…
Reference in a new issue