WIP path rasterization
This commit is contained in:
parent
ce84a2a671
commit
ed679c9347
4 changed files with 113 additions and 12 deletions
|
@ -10,6 +10,8 @@ use etagere::BucketedAtlasAllocator;
|
|||
use parking_lot::Mutex;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
pub(crate) const PATH_TEXTURE_FORMAT: gpu::TextureFormat = gpu::TextureFormat::R16Float;
|
||||
|
||||
pub(crate) struct BladeAtlas(Mutex<BladeAtlasState>);
|
||||
|
||||
struct BladeAtlasState {
|
||||
|
@ -32,6 +34,7 @@ impl BladeAtlasState {
|
|||
}
|
||||
for texture in self.path_textures.drain(..) {
|
||||
self.gpu.destroy_texture(texture.raw);
|
||||
self.gpu.destroy_texture_view(texture.raw_view.unwrap());
|
||||
}
|
||||
self.gpu.destroy_command_encoder(&mut self.gpu_encoder);
|
||||
self.upload_belt.destroy(&self.gpu);
|
||||
|
@ -78,6 +81,11 @@ impl BladeAtlas {
|
|||
lock.gpu_encoder.start();
|
||||
}
|
||||
|
||||
pub fn allocate(&self, size: Size<DevicePixels>, texture_kind: AtlasTextureKind) -> AtlasTile {
|
||||
let mut lock = self.0.lock();
|
||||
lock.allocate(size, texture_kind)
|
||||
}
|
||||
|
||||
pub fn finish_frame(&self) -> gpu::SyncPoint {
|
||||
let mut lock = self.0.lock();
|
||||
let gpu = lock.gpu.clone();
|
||||
|
@ -85,6 +93,16 @@ impl BladeAtlas {
|
|||
lock.upload_belt.flush(&sync_point);
|
||||
sync_point
|
||||
}
|
||||
|
||||
pub fn get_texture_view(&self, id: AtlasTextureId) -> gpu::TextureView {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformAtlas for BladeAtlas {
|
||||
|
@ -146,7 +164,7 @@ impl BladeAtlasState {
|
|||
usage = gpu::TextureUsage::COPY | gpu::TextureUsage::RESOURCE;
|
||||
}
|
||||
AtlasTextureKind::Path => {
|
||||
format = gpu::TextureFormat::R16Float;
|
||||
format = PATH_TEXTURE_FORMAT;
|
||||
usage = gpu::TextureUsage::COPY
|
||||
| gpu::TextureUsage::RESOURCE
|
||||
| gpu::TextureUsage::TARGET;
|
||||
|
@ -166,6 +184,17 @@ impl BladeAtlasState {
|
|||
dimension: gpu::TextureDimension::D2,
|
||||
usage,
|
||||
});
|
||||
let raw_view = if usage.contains(gpu::TextureUsage::TARGET) {
|
||||
Some(self.gpu.create_texture_view(gpu::TextureViewDesc {
|
||||
name: "",
|
||||
texture: raw,
|
||||
format,
|
||||
dimension: gpu::ViewDimension::D2,
|
||||
subresources: &Default::default(),
|
||||
}))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let textures = match kind {
|
||||
AtlasTextureKind::Monochrome => &mut self.monochrome_textures,
|
||||
|
@ -180,6 +209,7 @@ impl BladeAtlasState {
|
|||
allocator: etagere::BucketedAtlasAllocator::new(size.into()),
|
||||
format,
|
||||
raw,
|
||||
raw_view,
|
||||
};
|
||||
textures.push(atlas_texture);
|
||||
textures.last_mut().unwrap()
|
||||
|
@ -218,6 +248,7 @@ struct BladeAtlasTexture {
|
|||
id: AtlasTextureId,
|
||||
allocator: BucketedAtlasAllocator,
|
||||
raw: gpu::Texture,
|
||||
raw_view: Option<gpu::TextureView>,
|
||||
format: gpu::TextureFormat,
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,12 @@
|
|||
#![allow(irrefutable_let_patterns)]
|
||||
|
||||
use super::{BladeBelt, BladeBeltDescriptor};
|
||||
use crate::{PrimitiveBatch, Quad, Scene, Shadow};
|
||||
use crate::{
|
||||
AtlasTextureKind, AtlasTile, BladeAtlas, ContentMask, Path, PathId, PathVertex, PrimitiveBatch,
|
||||
Quad, ScaledPixels, Scene, Shadow, PATH_TEXTURE_FORMAT,
|
||||
};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use collections::HashMap;
|
||||
|
||||
use blade_graphics as gpu;
|
||||
use std::sync::Arc;
|
||||
|
@ -33,6 +37,7 @@ struct ShaderShadowsData {
|
|||
struct BladePipelines {
|
||||
quads: gpu::RenderPipeline,
|
||||
shadows: gpu::RenderPipeline,
|
||||
path_rasterization: gpu::RenderPipeline,
|
||||
}
|
||||
|
||||
impl BladePipelines {
|
||||
|
@ -77,6 +82,22 @@ impl BladePipelines {
|
|||
write_mask: gpu::ColorWrites::default(),
|
||||
}],
|
||||
}),
|
||||
path_rasterization: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "path_rasterization",
|
||||
data_layouts: &[&shadows_layout],
|
||||
vertex: shader.at("vs_path_rasterization"),
|
||||
primitive: gpu::PrimitiveState {
|
||||
topology: gpu::PrimitiveTopology::TriangleStrip,
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
fragment: shader.at("fs_path_rasterization"),
|
||||
color_targets: &[gpu::ColorTargetState {
|
||||
format: PATH_TEXTURE_FORMAT,
|
||||
blend: Some(gpu::BlendState::ALPHA_BLENDING),
|
||||
write_mask: gpu::ColorWrites::default(),
|
||||
}],
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +109,8 @@ pub struct BladeRenderer {
|
|||
pipelines: BladePipelines,
|
||||
instance_belt: BladeBelt,
|
||||
viewport_size: gpu::Extent,
|
||||
path_tiles: HashMap<PathId, AtlasTile>,
|
||||
atlas: Arc<BladeAtlas>,
|
||||
}
|
||||
|
||||
impl BladeRenderer {
|
||||
|
@ -106,6 +129,8 @@ impl BladeRenderer {
|
|||
memory: gpu::Memory::Shared,
|
||||
min_chunk_size: 0x1000,
|
||||
});
|
||||
let atlas = Arc::new(BladeAtlas::new(&gpu));
|
||||
|
||||
Self {
|
||||
gpu,
|
||||
command_encoder,
|
||||
|
@ -113,6 +138,8 @@ impl BladeRenderer {
|
|||
pipelines,
|
||||
instance_belt,
|
||||
viewport_size: size,
|
||||
path_tiles: HashMap::default(),
|
||||
atlas,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,6 +153,7 @@ impl BladeRenderer {
|
|||
|
||||
pub fn destroy(&mut self) {
|
||||
self.wait_for_gpu();
|
||||
self.atlas.destroy();
|
||||
self.instance_belt.destroy(&self.gpu);
|
||||
self.gpu.destroy_command_encoder(&mut self.command_encoder);
|
||||
}
|
||||
|
@ -140,11 +168,56 @@ impl BladeRenderer {
|
|||
self.viewport_size = size;
|
||||
}
|
||||
|
||||
pub fn atlas(&self) -> &Arc<BladeAtlas> {
|
||||
&self.atlas
|
||||
}
|
||||
|
||||
fn rasterize_paths(&mut self, paths: &[Path<ScaledPixels>]) {
|
||||
self.path_tiles.clear();
|
||||
let mut vertices_by_texture_id = HashMap::default();
|
||||
|
||||
for path in paths {
|
||||
let clipped_bounds = path.bounds.intersect(&path.content_mask.bounds);
|
||||
let tile = self
|
||||
.atlas
|
||||
.allocate(clipped_bounds.size.map(Into::into), AtlasTextureKind::Path);
|
||||
vertices_by_texture_id
|
||||
.entry(tile.texture_id)
|
||||
.or_insert(Vec::new())
|
||||
.extend(path.vertices.iter().map(|vertex| PathVertex {
|
||||
xy_position: vertex.xy_position - clipped_bounds.origin
|
||||
+ tile.bounds.origin.map(Into::into),
|
||||
st_position: vertex.st_position,
|
||||
content_mask: ContentMask {
|
||||
bounds: tile.bounds.map(Into::into),
|
||||
},
|
||||
}));
|
||||
self.path_tiles.insert(path.id, tile);
|
||||
}
|
||||
|
||||
for (texture_id, vertices) in vertices_by_texture_id {
|
||||
let instances = 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),
|
||||
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.draw(0, vertices.len() as u32, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, scene: &Scene) {
|
||||
let frame = self.gpu.acquire_frame();
|
||||
self.command_encoder.start();
|
||||
self.command_encoder.init_texture(frame.texture());
|
||||
|
||||
self.rasterize_paths(scene.paths());
|
||||
|
||||
let globals = GlobalParams {
|
||||
viewport_size: [
|
||||
self.viewport_size.width as f32,
|
||||
|
@ -187,6 +260,7 @@ impl BladeRenderer {
|
|||
);
|
||||
encoder.draw(0, 4, 0, shadows.len() as u32);
|
||||
}
|
||||
PrimitiveBatch::Paths(paths) => {}
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -287,3 +287,5 @@ fn fs_shadow(input: ShadowVarying) -> @location(0) vec4<f32> {
|
|||
|
||||
return input.color * vec4<f32>(1.0, 1.0, 1.0, alpha);
|
||||
}
|
||||
|
||||
// --- path rasterization --- //
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::BladeRenderer;
|
||||
use crate::{
|
||||
BladeAtlas, Bounds, GlobalPixels, LinuxDisplay, Pixels, PlatformDisplay, PlatformInputHandler,
|
||||
Bounds, GlobalPixels, LinuxDisplay, Pixels, PlatformDisplay, PlatformInputHandler,
|
||||
PlatformWindow, Point, Size, WindowAppearance, WindowBounds, WindowOptions, XcbAtoms,
|
||||
};
|
||||
use blade_graphics as gpu;
|
||||
|
@ -57,7 +57,6 @@ pub(crate) struct LinuxWindowState {
|
|||
x_window: x::Window,
|
||||
callbacks: Mutex<Callbacks>,
|
||||
inner: Mutex<LinuxWindowInner>,
|
||||
sprite_atlas: Arc<BladeAtlas>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -186,7 +185,6 @@ impl LinuxWindowState {
|
|||
height: bounds.size.height as u32,
|
||||
depth: 1,
|
||||
};
|
||||
let sprite_atlas = Arc::new(BladeAtlas::new(&gpu));
|
||||
|
||||
Self {
|
||||
xcb_connection: Arc::clone(xcb_connection),
|
||||
|
@ -200,16 +198,11 @@ impl LinuxWindowState {
|
|||
scale_factor: 1.0,
|
||||
renderer: BladeRenderer::new(gpu, gpu_extent),
|
||||
}),
|
||||
sprite_atlas,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(&self) {
|
||||
self.sprite_atlas.destroy();
|
||||
{
|
||||
let mut inner = self.inner.lock();
|
||||
inner.renderer.destroy();
|
||||
}
|
||||
self.inner.lock().renderer.destroy();
|
||||
self.xcb_connection.send_request(&x::UnmapWindow {
|
||||
window: self.x_window,
|
||||
});
|
||||
|
@ -379,6 +372,7 @@ impl PlatformWindow for LinuxWindow {
|
|||
}
|
||||
|
||||
fn sprite_atlas(&self) -> sync::Arc<dyn crate::PlatformAtlas> {
|
||||
self.0.sprite_atlas.clone()
|
||||
let mut inner = self.0.inner.lock();
|
||||
inner.renderer.atlas().clone()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue