Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ members = [
"layout21raw",
"layout21tetris",
"layout21utils",
"layout21wgpu",
"lef21",
]
resolver = "2"

# Inherited Package Attributes
# Thanks https://doc.rust-lang.org/cargo/reference/workspaces.html#the-package-table!
Expand Down
54 changes: 31 additions & 23 deletions layout21raw/src/geom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,32 @@ pub struct Path {
pub points: Vec<Point>,
pub width: usize,
}
impl Path {
/// Convert a Manhattan path into a vector of rectangles.
/// Returns `None` if the path is not Manhattan.
pub fn rects(&self) -> Option<Vec<Rect>> {
let (points, width) = (&self.points, self.width);
let width = Int::try_from(width).unwrap(); // FIXME: probably store these signed, check them on creation
let mut rects: Vec<Rect> = Vec::with_capacity(self.points.len());
for k in 0..points.len() - 1 {
let rect = if points[k].x == points[k + 1].x {
Rect {
p0: Point::new(points[k].x - width / 2, points[k].y),
p1: Point::new(points[k].x + width / 2, points[k + 1].y),
}
} else if points[k].y == points[k + 1].y {
Rect {
p0: Point::new(points[k].x, points[k].y - width / 2),
p1: Point::new(points[k + 1].x, points[k].y + width / 2),
}
} else {
return None; // Non-Manhattan Path
};
rects.push(rect);
}
Some(rects)
}
}
/// # Polygon
///
/// Closed n-sided polygon with arbitrary number of vertices.
Expand Down Expand Up @@ -314,33 +340,15 @@ impl ShapeTrait for Path {
/// Boolean indication of whether the [Shape] contains [Point] `pt`.
/// Containment is *inclusive* for all [Shape] types.
/// [Point]s on their boundary, which generally include all points specifying the shape itself, are regarded throughout as "inside" the shape.
///
/// Note checks for [`Path`] are valid solely for Manhattan paths, i.e. those with segments solely running vertically or horizontally.
fn contains(&self, pt: &Point) -> bool {
// Break into segments, and check for intersection with each
// Probably not the most efficient way to do this, but a start.
// Only "Manhattan paths", i.e. those with segments solely running vertically or horizontally, are supported.
// FIXME: even with this method, there are some small pieces at corners which we'll miss.
// Whether these are relevant in real life, tbd.
let (points, width) = (&self.points, self.width);
let width = Int::try_from(width).unwrap(); // FIXME: probably store these signed, check them on creation
for k in 0..points.len() - 1 {
let rect = if points[k].x == points[k + 1].x {
Rect {
p0: Point::new(points[k].x - width / 2, points[k].y),
p1: Point::new(points[k].x + width / 2, points[k + 1].y),
}
} else if points[k].y == points[k + 1].y {
Rect {
p0: Point::new(points[k].x, points[k].y - width / 2),
p1: Point::new(points[k + 1].x, points[k].y + width / 2),
}
} else {
unimplemented!("Unsupported Non-Manhattan Path")
};
if rect.contains(pt) {
return true;
}
match self.rects() {
None => false, // FIXME! non-Manhattan paths
Some(rects) => rects.iter().any(|r| r.contains(pt)),
}
false
}
fn to_poly(&self) -> Polygon {
unimplemented!("Path::to_poly")
Expand Down
41 changes: 41 additions & 0 deletions layout21wgpu/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[package]
description = "Layout21 WGPU"
name = "layout21wgpu"

# Shared layout21 attributes
authors.workspace = true
categories.workspace = true
documentation.workspace = true
edition.workspace = true
exclude.workspace = true
homepage.workspace = true
include.workspace = true
keywords.workspace = true
license.workspace = true
readme.workspace = true
repository.workspace = true
version.workspace = true
workspace = "../"

[dependencies]
# Local workspace dependencies
layout21protos = {path = "../layout21protos", version = "3.0.0-pre.3"}
layout21raw = {path = "../layout21raw", version = "3.0.0-pre.3"}
layout21utils = {path = "../layout21utils", version = "3.0.0-pre.3"}

# Crates.io
wgpu = "0.15"
derive_builder = "0.9"
derive_more = "0.99.16"
num-integer = "0.1"
num-traits = "0.2"
serde = {version = "1.0", features = ["derive"]}
serde_derive = "1.0.88"
slotmap = {version = "1.0", features = ["serde"]}
winit = "0.27.5"
rand = "0.8.5"
log = "0.4.17"
bytemuck = { version = "1.4", features = ["derive"] }
env_logger = "0.10.0"
pollster = "0.2.5"
lyon = "1.0.1"
5 changes: 5 additions & 0 deletions layout21wgpu/src/buffers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

use lyon::tessellation::geometry_builder::VertexBuffers;
use crate::Vertex;

pub type Buffers = VertexBuffers<Vertex, u16>;
29 changes: 29 additions & 0 deletions layout21wgpu/src/color.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use bytemuck::{Pod, Zeroable};

#[repr(C)]
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
pub struct Color(pub [f32; 3]);

pub const COLORS: [Color; 7] = [
Color([1.0, 0.0, 0.0]), // red
Color([0.0, 1.0, 0.0]), // green
Color([0.0, 0.0, 1.0]), // blue
Color([1.0, 1.0, 0.0]), //
Color([1.0, 0.0, 1.0]), //
Color([0.0, 1.0, 1.0]), //
Color([1.0, 1.0, 1.0]), // white
];
#[derive(Debug)]
pub(crate) struct ColorWheel {
index: usize,
}
impl ColorWheel {
pub fn new() -> Self {
Self { index: 0 }
}
pub fn next(&mut self) -> Color {
let color = COLORS[self.index];
self.index = (self.index + 1) % COLORS.len();
color
}
}
194 changes: 194 additions & 0 deletions layout21wgpu/src/gpu.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
//!
//! # GPU Stuff
//!
//! All the WGPU machinery lives here.
//! Many, many terms of art fly around GPU world; get used to it.
//!

use wgpu::util::DeviceExt;
use winit::window::Window;

// Local Imports
use crate::{Buffers, Vertex};

/// # GPU Stuff
///
/// *Microooo-processors*. Idunno what they are, you dunno what they are, CASH.
///
pub struct GpuStuff {
pub surface: wgpu::Surface,
pub device: wgpu::Device,
pub queue: wgpu::Queue,
pub config: wgpu::SurfaceConfiguration,
pub size: winit::dpi::PhysicalSize<u32>,
pub pipeline: wgpu::RenderPipeline,
pub vertex_buffer: wgpu::Buffer,
pub index_buffer: wgpu::Buffer,
}
impl GpuStuff {
/// Create new [`GpuStuff`].
///
/// Much of the machinery and terminology lives here in the configuration phase.
/// Once this gets done, things really do calm down to just the vertex and index buffers,
/// and writing triangles to them.
///
pub async fn new(window: &Window, buffers: &Buffers) -> Self {
let size = window.inner_size();
let backends = wgpu::util::backend_bits_from_env().unwrap_or_else(wgpu::Backends::all);
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends,
dx12_shader_compiler: wgpu::Dx12Compiler::default(),
});
let surface = unsafe { instance.create_surface(window) }.unwrap();
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
compatible_surface: Some(&surface),
force_fallback_adapter: false,
})
.await
.unwrap();

let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
features: wgpu::Features::empty(),
limits: wgpu::Limits::default(),
},
None, // Trace path
)
.await
.unwrap();
let swapchain_capabilities = surface.get_capabilities(&adapter);
let swapchain_format = swapchain_capabilities.formats[0];

let config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: swapchain_format,
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::Fifo,
alpha_mode: wgpu::CompositeAlphaMode::Auto,
view_formats: Vec::new(),
};
surface.configure(&device, &config);

let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()),
});

let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});

let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: "vs_main",
buffers: &[Vertex::desc()],
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: "fs_main",
targets: &[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
strip_index_format: None,
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
});

let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(&buffers.vertices),
usage: wgpu::BufferUsages::VERTEX,
});
let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Index Buffer"),
contents: bytemuck::cast_slice(&buffers.indices),
usage: wgpu::BufferUsages::INDEX,
});

Self {
surface,
device,
queue,
config,
size,
pipeline,
vertex_buffer,
index_buffer,
}
}

pub fn resize(&mut self, new_size: winit::dpi::PhysicalSize<u32>) {
if new_size.width > 0 && new_size.height > 0 {
self.size = new_size;
self.config.width = new_size.width;
self.config.height = new_size.height;
self.surface.configure(&self.device, &self.config);
}
}

/// Render the current frame
pub fn render(&self, buffers: &Buffers) -> Result<(), wgpu::SurfaceError> {
let output = self.surface.get_current_texture()?;
let view = output
.texture
.create_view(&wgpu::TextureViewDescriptor::default());

let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});

{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color {
r: 0.2,
g: 0.247,
b: 0.314,
a: 1.0,
}),
store: true,
},
})],
depth_stencil_attachment: None,
});

render_pass.set_pipeline(&self.pipeline);
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
render_pass.set_index_buffer(self.index_buffer.slice(..), wgpu::IndexFormat::Uint16);
render_pass.draw_indexed(
0..buffers.indices.len() as u32, // indices
0, // base_vertex
0..1, // instances
);
}

self.queue.submit(std::iter::once(encoder.finish()));
output.present();

Ok(())
}
}
Loading