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 parking_lot::Mutex;
|
||||||
use std::{borrow::Cow, sync::Arc};
|
use std::{borrow::Cow, sync::Arc};
|
||||||
|
|
||||||
|
pub(crate) const PATH_TEXTURE_FORMAT: gpu::TextureFormat = gpu::TextureFormat::R16Float;
|
||||||
|
|
||||||
pub(crate) struct BladeAtlas(Mutex<BladeAtlasState>);
|
pub(crate) struct BladeAtlas(Mutex<BladeAtlasState>);
|
||||||
|
|
||||||
struct BladeAtlasState {
|
struct BladeAtlasState {
|
||||||
|
@ -32,6 +34,7 @@ impl BladeAtlasState {
|
||||||
}
|
}
|
||||||
for texture in self.path_textures.drain(..) {
|
for texture in self.path_textures.drain(..) {
|
||||||
self.gpu.destroy_texture(texture.raw);
|
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.gpu.destroy_command_encoder(&mut self.gpu_encoder);
|
||||||
self.upload_belt.destroy(&self.gpu);
|
self.upload_belt.destroy(&self.gpu);
|
||||||
|
@ -78,6 +81,11 @@ impl BladeAtlas {
|
||||||
lock.gpu_encoder.start();
|
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 {
|
pub fn finish_frame(&self) -> gpu::SyncPoint {
|
||||||
let mut lock = self.0.lock();
|
let mut lock = self.0.lock();
|
||||||
let gpu = lock.gpu.clone();
|
let gpu = lock.gpu.clone();
|
||||||
|
@ -85,6 +93,16 @@ impl BladeAtlas {
|
||||||
lock.upload_belt.flush(&sync_point);
|
lock.upload_belt.flush(&sync_point);
|
||||||
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 {
|
impl PlatformAtlas for BladeAtlas {
|
||||||
|
@ -146,7 +164,7 @@ impl BladeAtlasState {
|
||||||
usage = gpu::TextureUsage::COPY | gpu::TextureUsage::RESOURCE;
|
usage = gpu::TextureUsage::COPY | gpu::TextureUsage::RESOURCE;
|
||||||
}
|
}
|
||||||
AtlasTextureKind::Path => {
|
AtlasTextureKind::Path => {
|
||||||
format = gpu::TextureFormat::R16Float;
|
format = PATH_TEXTURE_FORMAT;
|
||||||
usage = gpu::TextureUsage::COPY
|
usage = gpu::TextureUsage::COPY
|
||||||
| gpu::TextureUsage::RESOURCE
|
| gpu::TextureUsage::RESOURCE
|
||||||
| gpu::TextureUsage::TARGET;
|
| gpu::TextureUsage::TARGET;
|
||||||
|
@ -166,6 +184,17 @@ impl BladeAtlasState {
|
||||||
dimension: gpu::TextureDimension::D2,
|
dimension: gpu::TextureDimension::D2,
|
||||||
usage,
|
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 {
|
let textures = match kind {
|
||||||
AtlasTextureKind::Monochrome => &mut self.monochrome_textures,
|
AtlasTextureKind::Monochrome => &mut self.monochrome_textures,
|
||||||
|
@ -180,6 +209,7 @@ impl BladeAtlasState {
|
||||||
allocator: etagere::BucketedAtlasAllocator::new(size.into()),
|
allocator: etagere::BucketedAtlasAllocator::new(size.into()),
|
||||||
format,
|
format,
|
||||||
raw,
|
raw,
|
||||||
|
raw_view,
|
||||||
};
|
};
|
||||||
textures.push(atlas_texture);
|
textures.push(atlas_texture);
|
||||||
textures.last_mut().unwrap()
|
textures.last_mut().unwrap()
|
||||||
|
@ -218,6 +248,7 @@ struct BladeAtlasTexture {
|
||||||
id: AtlasTextureId,
|
id: AtlasTextureId,
|
||||||
allocator: BucketedAtlasAllocator,
|
allocator: BucketedAtlasAllocator,
|
||||||
raw: gpu::Texture,
|
raw: gpu::Texture,
|
||||||
|
raw_view: Option<gpu::TextureView>,
|
||||||
format: gpu::TextureFormat,
|
format: gpu::TextureFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,12 @@
|
||||||
#![allow(irrefutable_let_patterns)]
|
#![allow(irrefutable_let_patterns)]
|
||||||
|
|
||||||
use super::{BladeBelt, BladeBeltDescriptor};
|
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 bytemuck::{Pod, Zeroable};
|
||||||
|
use collections::HashMap;
|
||||||
|
|
||||||
use blade_graphics as gpu;
|
use blade_graphics as gpu;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
@ -33,6 +37,7 @@ struct ShaderShadowsData {
|
||||||
struct BladePipelines {
|
struct BladePipelines {
|
||||||
quads: gpu::RenderPipeline,
|
quads: gpu::RenderPipeline,
|
||||||
shadows: gpu::RenderPipeline,
|
shadows: gpu::RenderPipeline,
|
||||||
|
path_rasterization: gpu::RenderPipeline,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BladePipelines {
|
impl BladePipelines {
|
||||||
|
@ -77,6 +82,22 @@ impl BladePipelines {
|
||||||
write_mask: gpu::ColorWrites::default(),
|
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,
|
pipelines: BladePipelines,
|
||||||
instance_belt: BladeBelt,
|
instance_belt: BladeBelt,
|
||||||
viewport_size: gpu::Extent,
|
viewport_size: gpu::Extent,
|
||||||
|
path_tiles: HashMap<PathId, AtlasTile>,
|
||||||
|
atlas: Arc<BladeAtlas>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BladeRenderer {
|
impl BladeRenderer {
|
||||||
|
@ -106,6 +129,8 @@ impl BladeRenderer {
|
||||||
memory: gpu::Memory::Shared,
|
memory: gpu::Memory::Shared,
|
||||||
min_chunk_size: 0x1000,
|
min_chunk_size: 0x1000,
|
||||||
});
|
});
|
||||||
|
let atlas = Arc::new(BladeAtlas::new(&gpu));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
gpu,
|
gpu,
|
||||||
command_encoder,
|
command_encoder,
|
||||||
|
@ -113,6 +138,8 @@ impl BladeRenderer {
|
||||||
pipelines,
|
pipelines,
|
||||||
instance_belt,
|
instance_belt,
|
||||||
viewport_size: size,
|
viewport_size: size,
|
||||||
|
path_tiles: HashMap::default(),
|
||||||
|
atlas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +153,7 @@ impl BladeRenderer {
|
||||||
|
|
||||||
pub fn destroy(&mut self) {
|
pub fn destroy(&mut self) {
|
||||||
self.wait_for_gpu();
|
self.wait_for_gpu();
|
||||||
|
self.atlas.destroy();
|
||||||
self.instance_belt.destroy(&self.gpu);
|
self.instance_belt.destroy(&self.gpu);
|
||||||
self.gpu.destroy_command_encoder(&mut self.command_encoder);
|
self.gpu.destroy_command_encoder(&mut self.command_encoder);
|
||||||
}
|
}
|
||||||
|
@ -140,11 +168,56 @@ impl BladeRenderer {
|
||||||
self.viewport_size = size;
|
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) {
|
pub fn draw(&mut self, scene: &Scene) {
|
||||||
let frame = self.gpu.acquire_frame();
|
let frame = self.gpu.acquire_frame();
|
||||||
self.command_encoder.start();
|
self.command_encoder.start();
|
||||||
self.command_encoder.init_texture(frame.texture());
|
self.command_encoder.init_texture(frame.texture());
|
||||||
|
|
||||||
|
self.rasterize_paths(scene.paths());
|
||||||
|
|
||||||
let globals = GlobalParams {
|
let globals = GlobalParams {
|
||||||
viewport_size: [
|
viewport_size: [
|
||||||
self.viewport_size.width as f32,
|
self.viewport_size.width as f32,
|
||||||
|
@ -187,6 +260,7 @@ impl BladeRenderer {
|
||||||
);
|
);
|
||||||
encoder.draw(0, 4, 0, shadows.len() as u32);
|
encoder.draw(0, 4, 0, shadows.len() as u32);
|
||||||
}
|
}
|
||||||
|
PrimitiveBatch::Paths(paths) => {}
|
||||||
_ => continue,
|
_ => 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);
|
return input.color * vec4<f32>(1.0, 1.0, 1.0, alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- path rasterization --- //
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::BladeRenderer;
|
use super::BladeRenderer;
|
||||||
use crate::{
|
use crate::{
|
||||||
BladeAtlas, Bounds, GlobalPixels, LinuxDisplay, Pixels, PlatformDisplay, PlatformInputHandler,
|
Bounds, GlobalPixels, LinuxDisplay, Pixels, PlatformDisplay, PlatformInputHandler,
|
||||||
PlatformWindow, Point, Size, WindowAppearance, WindowBounds, WindowOptions, XcbAtoms,
|
PlatformWindow, Point, Size, WindowAppearance, WindowBounds, WindowOptions, XcbAtoms,
|
||||||
};
|
};
|
||||||
use blade_graphics as gpu;
|
use blade_graphics as gpu;
|
||||||
|
@ -57,7 +57,6 @@ pub(crate) struct LinuxWindowState {
|
||||||
x_window: x::Window,
|
x_window: x::Window,
|
||||||
callbacks: Mutex<Callbacks>,
|
callbacks: Mutex<Callbacks>,
|
||||||
inner: Mutex<LinuxWindowInner>,
|
inner: Mutex<LinuxWindowInner>,
|
||||||
sprite_atlas: Arc<BladeAtlas>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -186,7 +185,6 @@ impl LinuxWindowState {
|
||||||
height: bounds.size.height as u32,
|
height: bounds.size.height as u32,
|
||||||
depth: 1,
|
depth: 1,
|
||||||
};
|
};
|
||||||
let sprite_atlas = Arc::new(BladeAtlas::new(&gpu));
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
xcb_connection: Arc::clone(xcb_connection),
|
xcb_connection: Arc::clone(xcb_connection),
|
||||||
|
@ -200,16 +198,11 @@ impl LinuxWindowState {
|
||||||
scale_factor: 1.0,
|
scale_factor: 1.0,
|
||||||
renderer: BladeRenderer::new(gpu, gpu_extent),
|
renderer: BladeRenderer::new(gpu, gpu_extent),
|
||||||
}),
|
}),
|
||||||
sprite_atlas,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(&self) {
|
pub fn destroy(&self) {
|
||||||
self.sprite_atlas.destroy();
|
self.inner.lock().renderer.destroy();
|
||||||
{
|
|
||||||
let mut inner = self.inner.lock();
|
|
||||||
inner.renderer.destroy();
|
|
||||||
}
|
|
||||||
self.xcb_connection.send_request(&x::UnmapWindow {
|
self.xcb_connection.send_request(&x::UnmapWindow {
|
||||||
window: self.x_window,
|
window: self.x_window,
|
||||||
});
|
});
|
||||||
|
@ -379,6 +372,7 @@ impl PlatformWindow for LinuxWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sprite_atlas(&self) -> sync::Arc<dyn crate::PlatformAtlas> {
|
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