Add first test for lyon tesselation

This commit is contained in:
Maximilian Ammann 2021-11-30 13:03:09 +01:00
parent 3838725c4f
commit 742d510ed4
9 changed files with 1237 additions and 1 deletions

378
Cargo.lock generated
View File

@ -41,6 +41,15 @@ dependencies = [
"xml-rs",
]
[[package]]
name = "approx"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f2a05fd1bd10b2527e20a2cd32d8873d115b8b39fe219ee25f42a8aca6ba278"
dependencies = [
"num-traits",
]
[[package]]
name = "arrayvec"
version = "0.5.2"
@ -53,6 +62,18 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
[[package]]
name = "as-slice"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45403b49e3954a4b8428a0ac21a4b7afadccf92bfd96273f1a58cd4812496ae0"
dependencies = [
"generic-array 0.12.4",
"generic-array 0.13.3",
"generic-array 0.14.4",
"stable_deref_trait",
]
[[package]]
name = "ash"
version = "0.33.3+1.2.191"
@ -124,6 +145,12 @@ version = "3.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
[[package]]
name = "bytemuck"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72957246c41db82b8ef88a5486143830adeb8227ef9837740bdec67724cf2c5b"
[[package]]
name = "byteorder"
version = "1.4.3"
@ -584,6 +611,30 @@ dependencies = [
"termcolor",
]
[[package]]
name = "euclid"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da96828553a086d7b18dcebfc579bd9628b016f86590d7453c115e490fa74b80"
dependencies = [
"num-traits",
]
[[package]]
name = "float-cmp"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75224bec9bfe1a65e2d34132933f2de7fe79900c96a0174307554244ece8150e"
[[package]]
name = "float_next_after"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fc612c5837986b7104a87a0df74a5460931f1c5274be12f8d0f40aa2f30d632"
dependencies = [
"num-traits",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -605,6 +656,95 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "futures"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27"
dependencies = [
"futures-core",
"futures-sink",
]
[[package]]
name = "futures-core"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445"
[[package]]
name = "futures-executor"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11"
[[package]]
name = "futures-macro"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-sink"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af"
[[package]]
name = "futures-task"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12"
[[package]]
name = "futures-util"
version = "0.3.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "fxhash"
version = "0.2.1"
@ -614,6 +754,68 @@ dependencies = [
"byteorder",
]
[[package]]
name = "generic-array"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f797e67af32588215eaaab8327027ee8e71b9dd0b2b26996aedf20c030fce309"
dependencies = [
"typenum",
]
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "geo"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02bf7fb342abefefb0abbb8d033f37233e6f857a1a970805d15f96560834d699"
dependencies = [
"geo-types",
"geographiclib-rs",
"log",
"num-traits",
"robust",
"rstar",
]
[[package]]
name = "geo-types"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8bd2e95dd9f5c8ff74159ed9205ad7fd239a9569173a550863976421b45d2bb"
dependencies = [
"approx",
"num-traits",
"rstar",
]
[[package]]
name = "geographiclib-rs"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b78e20d5d868fa2c4182a8170cb4df261e781a605810e3c1500269c1907da461"
dependencies = [
"lazy_static",
]
[[package]]
name = "getrandom"
version = "0.2.3"
@ -682,6 +884,15 @@ version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
[[package]]
name = "hash32"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc"
dependencies = [
"byteorder",
]
[[package]]
name = "hashbrown"
version = "0.11.2"
@ -691,6 +902,18 @@ dependencies = [
"ahash",
]
[[package]]
name = "heapless"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "634bd4d29cbf24424d0a4bfcbf80c6960129dc24424752a7d1d1390607023422"
dependencies = [
"as-slice",
"generic-array 0.14.4",
"hash32",
"stable_deref_trait",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
@ -852,6 +1075,77 @@ dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "lyon"
version = "0.17.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf0510ed5e3e2fb80f3db2061ef5ca92d87bfda1a624bb1eacf3bd50226e4cbb"
dependencies = [
"lyon_algorithms",
"lyon_extra",
"lyon_tessellation",
]
[[package]]
name = "lyon_algorithms"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8037f716541ba0d84d3de05c0069f8068baf73990d55980558b84d944c8a244a"
dependencies = [
"lyon_path",
"sid",
]
[[package]]
name = "lyon_extra"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0729bc681ea3d88df18cbe65cf6495790424c78d361bf8c517898a11081c882"
dependencies = [
"lyon_path",
"lyon_svg",
]
[[package]]
name = "lyon_geom"
version = "0.17.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce99ce77c22bfd8f39a95b9c749dffbfc3e2491ea30c874764c801a8b1485489"
dependencies = [
"arrayvec 0.5.2",
"euclid",
"num-traits",
]
[[package]]
name = "lyon_path"
version = "0.17.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0a59fdf767ca0d887aa61d1b48d4bbf6a124c1a45503593f7d38ab945bfbc0"
dependencies = [
"lyon_geom",
]
[[package]]
name = "lyon_svg"
version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d48d6de2455c678fc9f41c14d05555b0585ee4a12aca0447ce73fbe1334363a"
dependencies = [
"lyon_path",
"svgtypes",
]
[[package]]
name = "lyon_tessellation"
version = "0.17.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7230e08dd0638048e46f387f255dbe7a7344a3e6705beab53242b5af25635760"
dependencies = [
"float_next_after",
"lyon_path",
]
[[package]]
name = "malloc_buf"
version = "0.0.6"
@ -865,11 +1159,16 @@ dependencies = [
name = "mapr"
version = "0.1.0"
dependencies = [
"bytemuck",
"criterion",
"env_logger 0.8.4",
"env_logger 0.9.0",
"futures",
"geo",
"geo-types",
"hexdump",
"log",
"lyon",
"mvt",
"pollster",
"serde",
@ -1182,12 +1481,30 @@ dependencies = [
"winapi",
]
[[package]]
name = "pdqselect"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec91767ecc0a0bbe558ce8c9da33c068066c57ecc8bb8477ef8c1ad3ef77c27"
[[package]]
name = "percent-encoding"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pin-project-lite"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.22"
@ -1403,6 +1720,24 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157"
[[package]]
name = "robust"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5864e7ef1a6b7bcf1d6ca3f655e65e724ed3b52546a0d0a663c991522f552ea"
[[package]]
name = "rstar"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a45c0e8804d37e4d97e55c6f258bc9ad9c5ee7b07437009dd152d764949a27c"
dependencies = [
"heapless",
"num-traits",
"pdqselect",
"smallvec",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
@ -1496,6 +1831,27 @@ dependencies = [
"serde",
]
[[package]]
name = "sid"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd5ac56c121948b4879bba9e519852c211bcdd8f014efff766441deff0b91bdb"
dependencies = [
"num-traits",
]
[[package]]
name = "siphasher"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
[[package]]
name = "slab"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5"
[[package]]
name = "slotmap"
version = "1.0.6"
@ -1540,12 +1896,28 @@ dependencies = [
"num-traits",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "strsim"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
[[package]]
name = "svgtypes"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c536faaff1a10837cfe373142583f6e27d81e96beba339147e77b67c9f260ff"
dependencies = [
"float-cmp",
"siphasher",
]
[[package]]
name = "syn"
version = "1.0.82"
@ -1631,6 +2003,12 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc"
[[package]]
name = "typenum"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
[[package]]
name = "unicode-width"
version = "0.1.9"

View File

@ -9,14 +9,21 @@ resolver = "2"
[dependencies]
# Wanted by lyon experiment
futures = "0.3.5"
bytemuck = "1.2.0"
# Vector riles
mvt = { path = "libs/mvt" }
vector-tile = { path = "libs/vector_tile" }
geo = "0.18.0"
geo-types = "0.7"
# Rendering
winit = "0.25"
wgpu = "0.11"
pollster = "0.2"
lyon = { version = "0.17", features = ["extra"] }
# https://docs.rs/euclid/0.22.6/euclid/index.html
# Logging
@ -39,4 +46,9 @@ env_logger = "0.8" # Used for test-env-log
[[bin]]
name = "mapr"
path = "src/main.rs"
path = "src/main.rs"
[[bin]]
name = "lyon_test"
path = "src/lyon_test/main.rs"

489
src/lyon_test/main.rs Normal file
View File

@ -0,0 +1,489 @@
use std::ops::Rem;
use std::time::{Duration, Instant};
use futures::executor::block_on;
use lyon::extra::rust_logo::build_logo_path;
use lyon::math::*;
use lyon::path::Path;
use lyon::tessellation;
use lyon::tessellation::geometry_builder::*;
use lyon::tessellation::{FillOptions, FillTessellator};
use lyon::tessellation::{StrokeOptions, StrokeTessellator};
use wgpu::util::DeviceExt;
use winit::event_loop::EventLoop;
use winit::window::Window;
use crate::piplines::create_map_render_pipeline_description;
use crate::scene::SceneParams;
use crate::shader::{
create_fragment_module_descriptor, create_map_fragment_state, create_map_vertex_state,
create_vertex_module_descriptor,
};
use crate::shader_ffi::*;
mod piplines;
mod scene;
mod shader;
mod shader_ffi;
const PRIM_BUFFER_LEN: usize = 256;
const DEFAULT_WINDOW_WIDTH: f32 = 800.0;
const DEFAULT_WINDOW_HEIGHT: f32 = 800.0;
/// Creates a texture that uses MSAA and fits a given swap chain
fn create_multisampled_framebuffer(
device: &wgpu::Device,
desc: &wgpu::SurfaceConfiguration,
sample_count: u32,
) -> wgpu::TextureView {
let multisampled_frame_descriptor = &wgpu::TextureDescriptor {
label: Some("Multisampled frame descriptor"),
size: wgpu::Extent3d {
width: desc.width,
height: desc.height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count,
dimension: wgpu::TextureDimension::D2,
format: desc.format,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
};
device
.create_texture(multisampled_frame_descriptor)
.create_view(&wgpu::TextureViewDescriptor::default())
}
fn main() {
env_logger::init();
println!("== wgpu example ==");
println!("Controls:");
println!(" Arrow keys: scrolling");
println!(" PgUp/PgDown: zoom in/out");
println!(" a/z: increase/decrease the stroke width");
// Number of samples for anti-aliasing
// Set to 1 to disable
let sample_count = 4;
let num_instances: u32 = 1;
let tolerance = 0.02;
let stroke_prim_id = 0;
let fill_prim_id = 1;
let arrows_prim_id = num_instances + 1;
let mut geometry: VertexBuffers<GpuVertex, u16> = VertexBuffers::new();
let mut fill_tess = FillTessellator::new();
let mut stroke_tess = StrokeTessellator::new();
// Build a Path for the rust logo.
let mut builder = Path::builder().with_svg();
build_logo_path(&mut builder);
let path = builder.build();
// Build a Path for the arrow.
let mut builder = Path::builder();
builder.begin(point(-1.0, -0.3));
builder.line_to(point(0.0, -0.3));
builder.line_to(point(0.0, -1.0));
builder.line_to(point(1.5, 0.0));
builder.line_to(point(0.0, 1.0));
builder.line_to(point(0.0, 0.3));
builder.line_to(point(-1.0, 0.3));
builder.close();
let arrow_path = builder.build();
fill_tess
.tessellate_path(
&path,
&FillOptions::tolerance(tolerance).with_fill_rule(tessellation::FillRule::NonZero),
&mut BuffersBuilder::new(&mut geometry, WithId(fill_prim_id as u32)),
)
.unwrap();
let fill_range = 0..(geometry.indices.len() as u32);
stroke_tess
.tessellate_path(
&path,
&StrokeOptions::tolerance(tolerance),
&mut BuffersBuilder::new(&mut geometry, WithId(stroke_prim_id as u32)),
)
.unwrap();
let stroke_range = fill_range.end..(geometry.indices.len() as u32);
fill_tess
.tessellate_path(
&arrow_path,
&FillOptions::tolerance(tolerance),
&mut BuffersBuilder::new(&mut geometry, WithId(arrows_prim_id as u32)),
)
.unwrap();
let mut cpu_primitives = Vec::with_capacity(PRIM_BUFFER_LEN);
for _ in 0..PRIM_BUFFER_LEN {
cpu_primitives.push(Primitive {
color: [1.0, 0.0, 0.0, 1.0],
z_index: 0,
width: 0.0,
translate: [0.0, 0.0],
angle: 0.0,
..Primitive::DEFAULT
});
}
// Stroke primitive
cpu_primitives[stroke_prim_id] = Primitive {
color: [0.0, 0.0, 0.0, 1.0],
z_index: num_instances as i32 + 2,
width: 1.0,
..Primitive::DEFAULT
};
// Main fill primitive
cpu_primitives[fill_prim_id] = Primitive {
color: [1.0, 1.0, 1.0, 1.0],
z_index: num_instances as i32 + 1,
..Primitive::DEFAULT
};
// Instance primitives
for (idx, cpu_prim) in cpu_primitives
.iter_mut()
.enumerate()
.skip(fill_prim_id + 1)
.take(num_instances as usize - 1)
{
cpu_prim.z_index = (idx as u32 + 1) as i32;
cpu_prim.color = [
(0.1 * idx as f32).rem(1.0),
(0.5 * idx as f32).rem(1.0),
(0.9 * idx as f32).rem(1.0),
1.0,
];
}
let mut scene = SceneParams::DEFAULT;
let event_loop = EventLoop::new();
let window = Window::new(&event_loop).unwrap();
// create an instance
let instance = wgpu::Instance::new(wgpu::Backends::all());
// create an surface
let surface = unsafe { instance.create_surface(&window) };
// create an adapter
let adapter = block_on(instance.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::LowPower,
compatible_surface: Some(&surface),
force_fallback_adapter: false,
}))
.unwrap();
// create a device and a queue
let (device, queue) = block_on(adapter.request_device(
&wgpu::DeviceDescriptor {
label: None,
features: wgpu::Features::default(),
limits: wgpu::Limits::default(),
},
None,
))
.unwrap();
let vbo = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&geometry.vertices),
usage: wgpu::BufferUsages::VERTEX,
});
let ibo = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: None,
contents: bytemuck::cast_slice(&geometry.indices),
usage: wgpu::BufferUsages::INDEX,
});
let prim_buffer_byte_size = (PRIM_BUFFER_LEN * std::mem::size_of::<Primitive>()) as u64;
let globals_buffer_byte_size = std::mem::size_of::<Globals>() as u64;
let prims_ubo = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Prims ubo"),
size: prim_buffer_byte_size,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let globals_ubo = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Globals ubo"),
size: globals_buffer_byte_size,
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
mapped_at_creation: false,
});
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
label: Some("Bind group layout"),
entries: &[
wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: wgpu::BufferSize::new(globals_buffer_byte_size),
},
count: None,
},
wgpu::BindGroupLayoutEntry {
binding: 1,
visibility: wgpu::ShaderStages::VERTEX,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: wgpu::BufferSize::new(prim_buffer_byte_size),
},
count: None,
},
],
});
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("Bind group"),
layout: &bind_group_layout,
entries: &[
wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::Buffer(globals_ubo.as_entire_buffer_binding()),
},
wgpu::BindGroupEntry {
binding: 1,
resource: wgpu::BindingResource::Buffer(prims_ubo.as_entire_buffer_binding()),
},
],
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
bind_group_layouts: &[&bind_group_layout],
push_constant_ranges: &[],
label: None,
});
let vertex_module = device.create_shader_module(&create_vertex_module_descriptor());
let fragment_module = device.create_shader_module(&create_fragment_module_descriptor());
let mut render_pipeline_descriptor = create_map_render_pipeline_description(
&pipeline_layout,
create_map_vertex_state(&vertex_module),
create_map_fragment_state(&fragment_module),
sample_count,
);
let render_pipeline = device.create_render_pipeline(&render_pipeline_descriptor);
// TODO: this isn't what we want: we'd need the equivalent of VK_POLYGON_MODE_LINE,
// but it doesn't seem to be exposed by wgpu?
render_pipeline_descriptor.primitive.topology = wgpu::PrimitiveTopology::LineList;
let size = window.inner_size();
let mut surface_desc = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: wgpu::TextureFormat::Bgra8UnormSrgb,
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::Mailbox,
};
let mut multisampled_render_target = None;
surface.configure(&device, &surface_desc);
let mut depth_texture_view = None;
let start = Instant::now();
let mut next_report = start + Duration::from_secs(1);
let mut frame_count: u32 = 0;
let mut time_secs: f32 = 0.0;
window.request_redraw();
event_loop.run(move |event, _, control_flow| {
if !scene.update_inputs(event, &window, control_flow) {
// keep polling inputs.
return;
}
if scene.size_changed {
scene.size_changed = false;
let physical = scene.window_size;
surface_desc.width = physical.width;
surface_desc.height = physical.height;
surface.configure(&device, &surface_desc);
let depth_texture = device.create_texture(&wgpu::TextureDescriptor {
label: Some("Depth texture"),
size: wgpu::Extent3d {
width: surface_desc.width,
height: surface_desc.height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count,
dimension: wgpu::TextureDimension::D2,
format: wgpu::TextureFormat::Depth32Float,
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
});
depth_texture_view =
Some(depth_texture.create_view(&wgpu::TextureViewDescriptor::default()));
multisampled_render_target = if sample_count > 1 {
Some(create_multisampled_framebuffer(
&device,
&surface_desc,
sample_count,
))
} else {
None
};
}
// TODO: Without this we are not able to close the window
if !scene.render {
return;
}
scene.render = false;
let frame = match surface.get_current_texture() {
Ok(texture) => texture,
Err(e) => {
println!("Swap-chain error: {:?}", e);
return;
}
};
let frame_view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Encoder"),
});
cpu_primitives[stroke_prim_id as usize].width = scene.stroke_width;
cpu_primitives[stroke_prim_id as usize].color = [
(time_secs * 0.8 - 1.6).sin() * 0.1 + 0.1,
(time_secs * 0.5 - 1.6).sin() * 0.1 + 0.1,
(time_secs - 1.6).sin() * 0.1 + 0.1,
1.0,
];
for idx in 2..(num_instances + 1) {
cpu_primitives[idx as usize].translate = [
(time_secs * 0.05 * idx as f32).sin() * (100.0 + idx as f32 * 10.0),
(time_secs * 0.1 * idx as f32).sin() * (100.0 + idx as f32 * 10.0),
];
}
queue.write_buffer(
&globals_ubo,
0,
bytemuck::cast_slice(&[Globals {
resolution: [
scene.window_size.width as f32,
scene.window_size.height as f32,
],
zoom: scene.zoom,
scroll_offset: scene.scroll.to_array(),
_pad: 0.0,
}]),
);
queue.write_buffer(&prims_ubo, 0, bytemuck::cast_slice(&cpu_primitives));
{
// A resolve target is only supported if the attachment actually uses anti-aliasing
// So if sample_count == 1 then we must render directly to the surface's buffer
let color_attachment = if let Some(msaa_target) = &multisampled_render_target {
wgpu::RenderPassColorAttachment {
view: msaa_target,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
store: true,
},
resolve_target: Some(&frame_view),
}
} else {
wgpu::RenderPassColorAttachment {
view: &frame_view,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::WHITE),
store: true,
},
resolve_target: None,
}
};
let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[color_attachment],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: depth_texture_view.as_ref().unwrap(),
depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(0.0),
store: true,
}),
stencil_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Clear(0),
store: true,
}),
}),
});
pass.set_pipeline(&render_pipeline);
pass.set_bind_group(0, &bind_group, &[]);
pass.set_index_buffer(ibo.slice(..), wgpu::IndexFormat::Uint16);
pass.set_vertex_buffer(0, vbo.slice(..));
pass.draw_indexed(fill_range.clone(), 0, 0..(num_instances as u32));
pass.draw_indexed(stroke_range.clone(), 0, 0..1);
}
queue.submit(Some(encoder.finish()));
frame.present();
frame_count += 1;
let now = Instant::now();
time_secs = (now - start).as_secs_f32();
if now >= next_report {
println!("{} FPS", frame_count);
frame_count = 0;
next_report = now + Duration::from_secs(1);
}
});
}
/// This vertex constructor forwards the positions and normals provided by the
/// tessellators and add a shape id.
pub struct WithId(pub u32);
impl FillVertexConstructor<GpuVertex> for WithId {
fn new_vertex(&mut self, vertex: tessellation::FillVertex) -> GpuVertex {
GpuVertex {
position: vertex.position().to_array(),
normal: [0.0, 0.0],
prim_id: self.0,
}
}
}
impl StrokeVertexConstructor<GpuVertex> for WithId {
fn new_vertex(&mut self, vertex: tessellation::StrokeVertex) -> GpuVertex {
GpuVertex {
position: vertex.position_on_path().to_array(),
normal: vertex.normal().to_array(),
prim_id: self.0,
}
}
}

44
src/lyon_test/piplines.rs Normal file
View File

@ -0,0 +1,44 @@
use wgpu::{FragmentState, PipelineLayout, RenderPipelineDescriptor, VertexState};
pub fn create_map_render_pipeline_description<'a>(
pipeline_layout: &'a PipelineLayout,
vertex_state: VertexState<'a>,
fragment_state: FragmentState<'a>,
sample_count: u32,
) -> RenderPipelineDescriptor<'a> {
let depth_stencil_state = wgpu::DepthStencilState {
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: true,
depth_compare: wgpu::CompareFunction::Greater,
stencil: wgpu::StencilState {
front: wgpu::StencilFaceState::IGNORE,
back: wgpu::StencilFaceState::IGNORE,
read_mask: 0,
write_mask: 0,
},
bias: wgpu::DepthBiasState::default(),
};
let descriptor = wgpu::RenderPipelineDescriptor {
label: None,
layout: Some(&pipeline_layout),
vertex: vertex_state,
fragment: Some(fragment_state),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
polygon_mode: wgpu::PolygonMode::Fill,
front_face: wgpu::FrontFace::Ccw,
strip_index_format: None,
cull_mode: Some(wgpu::Face::Back),
clamp_depth: false,
conservative: false,
},
depth_stencil: Some(depth_stencil_state),
multisample: wgpu::MultisampleState {
count: sample_count,
mask: !0,
alpha_to_coverage_enabled: false,
},
};
descriptor
}

128
src/lyon_test/scene.rs Normal file
View File

@ -0,0 +1,128 @@
use lyon::math::Vector;
use winit::dpi::PhysicalSize;
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::ControlFlow;
use winit::window::Window;
use crate::{DEFAULT_WINDOW_HEIGHT, DEFAULT_WINDOW_WIDTH};
pub struct SceneParams {
pub target_zoom: f32,
pub zoom: f32,
pub target_scroll: Vector,
pub scroll: Vector,
pub show_points: bool,
pub stroke_width: f32,
pub target_stroke_width: f32,
pub window_size: PhysicalSize<u32>,
pub size_changed: bool,
pub render: bool,
}
impl SceneParams {
pub const DEFAULT: SceneParams = SceneParams {
target_zoom: 5.0,
zoom: 5.0,
target_scroll: Vector::new(70.0, 70.0),
scroll: Vector::new(70.0, 70.0),
show_points: false,
stroke_width: 1.0,
target_stroke_width: 1.0,
window_size: PhysicalSize::new(DEFAULT_WINDOW_WIDTH as u32, DEFAULT_WINDOW_HEIGHT as u32),
size_changed: true,
render: false,
};
pub fn update_inputs(
self: &mut SceneParams,
event: Event<()>,
window: &Window,
control_flow: &mut ControlFlow,
) -> bool {
match event {
Event::RedrawRequested(_) => {
self.render = true;
}
Event::RedrawEventsCleared => {
window.request_redraw();
}
Event::WindowEvent {
event: WindowEvent::Destroyed,
..
}
| Event::WindowEvent {
event: WindowEvent::CloseRequested,
..
} => {
*control_flow = ControlFlow::Exit;
return false;
}
Event::WindowEvent {
event: WindowEvent::Resized(size),
..
} => {
self.window_size = size;
self.size_changed = true
}
Event::WindowEvent {
event:
WindowEvent::KeyboardInput {
input:
KeyboardInput {
state: ElementState::Pressed,
virtual_keycode: Some(key),
..
},
..
},
..
} => match key {
VirtualKeyCode::Escape => {
*control_flow = ControlFlow::Exit;
return false;
}
VirtualKeyCode::PageDown => {
self.target_zoom *= 0.8;
}
VirtualKeyCode::PageUp => {
self.target_zoom *= 1.25;
}
VirtualKeyCode::Left => {
self.target_scroll.x -= 50.0 / self.target_zoom;
}
VirtualKeyCode::Right => {
self.target_scroll.x += 50.0 / self.target_zoom;
}
VirtualKeyCode::Up => {
self.target_scroll.y -= 50.0 / self.target_zoom;
}
VirtualKeyCode::Down => {
self.target_scroll.y += 50.0 / self.target_zoom;
}
VirtualKeyCode::P => {
self.show_points = !self.show_points;
}
VirtualKeyCode::A => {
self.target_stroke_width /= 0.8;
}
VirtualKeyCode::Z => {
self.target_stroke_width *= 0.8;
}
_key => {}
},
_evt => {
//println!("{:?}", _evt);
}
}
//println!(" -- zoom: {}, scroll: {:?}", self.target_zoom, self.target_scroll);
self.zoom += (self.target_zoom - self.zoom) / 3.0;
self.scroll = self.scroll + (self.target_scroll - self.scroll) / 3.0;
self.stroke_width =
self.stroke_width + (self.target_stroke_width - self.stroke_width) / 5.0;
*control_flow = ControlFlow::Poll;
true
}
}

63
src/lyon_test/shader.rs Normal file
View File

@ -0,0 +1,63 @@
use wgpu::{ColorTargetState, FragmentState, ShaderModule, ShaderModuleDescriptor, VertexAttribute, VertexBufferLayout, VertexState};
use crate::GpuVertex;
const MAP_VERTEX_SHADER_ARGUMENTS: [VertexAttribute; 3] = [
wgpu::VertexAttribute {
offset: 0,
format: wgpu::VertexFormat::Float32x2,
shader_location: 0,
},
wgpu::VertexAttribute {
offset: wgpu::VertexFormat::Float32x2.size(),
format: wgpu::VertexFormat::Float32x2,
shader_location: 1,
},
wgpu::VertexAttribute {
offset: 2 * wgpu::VertexFormat::Float32x2.size(),
format: wgpu::VertexFormat::Uint32,
shader_location: 2,
},
];
const MAP_VERTEX_SHADER_BUFFERS: [VertexBufferLayout; 1] = [wgpu::VertexBufferLayout {
array_stride: std::mem::size_of::<GpuVertex>() as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &MAP_VERTEX_SHADER_ARGUMENTS,
}];
const MAP_VERTEX_COLOR_TARGETS: [ColorTargetState; 1] = [wgpu::ColorTargetState {
format: wgpu::TextureFormat::Bgra8UnormSrgb,
blend: None,
write_mask: wgpu::ColorWrites::ALL,
}];
pub fn create_vertex_module_descriptor<'a>() -> ShaderModuleDescriptor<'a> {
wgpu::ShaderModuleDescriptor {
label: Some("Geometry vs"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/vertex.wgsl").into()),
}
}
pub fn create_fragment_module_descriptor<'a>() -> ShaderModuleDescriptor<'a> {
wgpu::ShaderModuleDescriptor {
label: Some("Geometry fs"),
source: wgpu::ShaderSource::Wgsl(include_str!("shaders/fragment.wgsl").into()),
}
}
pub fn create_map_vertex_state(vertex_shader_module: &ShaderModule) -> VertexState {
wgpu::VertexState {
module: vertex_shader_module,
entry_point: "main",
buffers: &MAP_VERTEX_SHADER_BUFFERS,
}
}
pub fn create_map_fragment_state(fragment_shader_module: &ShaderModule) -> FragmentState {
wgpu::FragmentState {
module: fragment_shader_module,
entry_point: "main",
targets: &MAP_VERTEX_COLOR_TARGETS,
}
}

View File

@ -0,0 +1,58 @@
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Globals {
pub resolution: [f32; 2],
pub scroll_offset: [f32; 2],
pub zoom: f32,
pub _pad: f32,
}
unsafe impl bytemuck::Pod for Globals {}
unsafe impl bytemuck::Zeroable for Globals {}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct GpuVertex {
pub position: [f32; 2],
pub normal: [f32; 2],
pub prim_id: u32,
}
unsafe impl bytemuck::Pod for GpuVertex {}
unsafe impl bytemuck::Zeroable for GpuVertex {}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct Primitive {
pub color: [f32; 4],
pub translate: [f32; 2],
pub z_index: i32,
pub width: f32,
pub angle: f32,
pub scale: f32,
pub _pad1: i32,
pub _pad2: i32,
}
impl Primitive {
pub const DEFAULT: Self = Primitive {
color: [0.0; 4],
translate: [0.0; 2],
z_index: 0,
width: 0.0,
angle: 0.0,
scale: 1.0,
_pad1: 0,
_pad2: 0,
};
}
unsafe impl bytemuck::Pod for Primitive {}
unsafe impl bytemuck::Zeroable for Primitive {}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct BgPoint {
pub point: [f32; 2],
}
unsafe impl bytemuck::Pod for BgPoint {}
unsafe impl bytemuck::Zeroable for BgPoint {}

View File

@ -0,0 +1,8 @@
struct Output {
[[location(0)]] out_color: vec4<f32>;
};
[[stage(fragment)]]
fn main([[location(0)]] v_color: vec4<f32>) -> Output {
return Output(v_color);
}

View File

@ -0,0 +1,56 @@
[[block]]
struct Globals {
resolution: vec2<f32>;
scroll_offset: vec2<f32>;
zoom: f32;
};
struct Primitive {
color: vec4<f32>;
translate: vec2<f32>;
z_index: i32;
width: f32;
angle: f32;
scale: f32;
pad1: i32;
pad2: i32;
};
[[block]]
struct Primitives {
primitives: [[stride(48)]] array<Primitive, 256>;
};
[[group(0), binding(0)]] var<uniform> globals: Globals;
[[group(0), binding(1)]] var<uniform> u_primitives: Primitives;
struct VertexOutput {
[[location(0)]] v_color: vec4<f32>;
[[builtin(position)]] position: vec4<f32>;
};
[[stage(vertex)]]
fn main(
[[location(0)]] a_position: vec2<f32>,
[[location(1)]] a_normal: vec2<f32>,
[[location(2)]] a_prim_id: u32,
[[builtin(instance_index)]] instance_idx: u32
) -> VertexOutput {
var prim: Primitive = u_primitives.primitives[a_prim_id + instance_idx];
var invert_y = vec2<f32>(1.0, -1.0);
var rotation = mat2x2<f32>(
vec2<f32>(cos(prim.angle), -sin(prim.angle)),
vec2<f32>(sin(prim.angle), cos(prim.angle))
);
var local_pos = (a_position * prim.scale + a_normal * prim.width) * rotation;
var world_pos = local_pos - globals.scroll_offset + prim.translate;
var transformed_pos = world_pos * globals.zoom / (0.5 * globals.resolution) * invert_y;
var z = f32(prim.z_index) / 4096.0;
var position = vec4<f32>(transformed_pos.x, transformed_pos.y, z, 1.0);
return VertexOutput(prim.color, position);
}