Skip to content

Commit

Permalink
Merge pull request #15 from jonmmease/jonmmease/png_scale
Browse files Browse the repository at this point in the history
Add scale support
  • Loading branch information
jonmmease authored Jan 9, 2024
2 parents 62dede3 + f526aa9 commit 7bba362
Show file tree
Hide file tree
Showing 35 changed files with 84 additions and 38 deletions.
2 changes: 1 addition & 1 deletion sg2d-vega-test-data/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fn main() {
let png = pollster::block_on(converter.vega_to_png(
vg_spec.clone(),
Default::default(),
None,
Some(2.0),
None,
))
.unwrap();
Expand Down
Binary file modified sg2d-vega-test-data/vega-scenegraphs/rect/heatmap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified sg2d-vega-test-data/vega-scenegraphs/rect/stacked_bar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified sg2d-vega-test-data/vega-scenegraphs/rule/wide_rule_axes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified sg2d-vega-test-data/vega-scenegraphs/symbol/wedge_angle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified sg2d-vega-test-data/vega-scenegraphs/symbol/wind_vector.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified sg2d-vega-test-data/vega-scenegraphs/text/bar_axis_labels.png
70 changes: 55 additions & 15 deletions sg2d-wgpu/src/canvas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use wgpu::{
TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureUsages, TextureView,
TextureViewDescriptor,
};
use winit::dpi::{PhysicalSize, Size};
use winit::event::WindowEvent;
use winit::window::Window;

Expand All @@ -26,7 +27,8 @@ use sg2d::{
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
pub struct CanvasUniform {
pub size: [f32; 2],
filler: [f32; 2], // Pad to 16 bytes
pub scale: f32,
_pad: [f32; 1], // Pad to 16 bytes
}

pub enum MarkRenderer {
Expand All @@ -40,6 +42,7 @@ pub trait Canvas {
fn device(&self) -> &Device;
fn queue(&self) -> &Queue;
fn uniform(&self) -> &CanvasUniform;
fn scale(&self) -> f32;

fn set_uniform(&mut self, uniform: CanvasUniform);

Expand Down Expand Up @@ -130,7 +133,8 @@ pub trait Canvas {
// Set uniforms
self.set_uniform(CanvasUniform {
size: [scene_graph.width, scene_graph.height],
filler: [0.0, 0.0],
scale: self.scale(),
_pad: [0.0],
});

// Clear existing marks
Expand Down Expand Up @@ -270,12 +274,23 @@ pub struct WindowCanvas {
sample_count: u32,
config: SurfaceConfiguration,
size: winit::dpi::PhysicalSize<u32>,
scale: f32,
marks: Vec<MarkRenderer>,
uniform: CanvasUniform,
}

impl WindowCanvas {
pub async fn new(window: Window) -> Result<Self, Sg2dWgpuError> {
pub async fn new(
window: Window,
width: f32,
height: f32,
scale: f32,
) -> Result<Self, Sg2dWgpuError> {
window.set_inner_size(Size::Physical(PhysicalSize::new(
(width * scale) as u32,
(height * scale) as u32,
)));

let size = window.inner_size();

let instance = make_wgpu_instance();
Expand Down Expand Up @@ -316,7 +331,8 @@ impl WindowCanvas {

let uniform = CanvasUniform {
size: [size.width as f32, size.height as f32],
filler: [0.0, 0.0],
scale,
_pad: [0.0],
};

Ok(Self {
Expand All @@ -327,6 +343,7 @@ impl WindowCanvas {
sample_count,
config,
size,
scale,
window,
uniform,
marks: Vec::new(),
Expand Down Expand Up @@ -424,6 +441,10 @@ impl Canvas for WindowCanvas {
&self.uniform
}

fn scale(&self) -> f32 {
self.scale
}

fn set_uniform(&mut self, uniform: CanvasUniform) {
self.uniform = uniform;
}
Expand All @@ -444,29 +465,34 @@ pub struct PngCanvas {
sample_count: u32,
marks: Vec<MarkRenderer>,
uniform: CanvasUniform,
width: f32,
height: f32,
pub width: f32,
pub height: f32,
pub scale: f32,
pub texture_view: TextureView,
pub output_buffer: Buffer,
pub texture: Texture,
pub texture_size: Extent3d,
pub padded_width: u32,
pub padded_height: u32,
pub physical_width: f32,
pub physical_height: f32,
}

impl PngCanvas {
pub async fn new(width: f32, height: f32) -> Result<Self, Sg2dWgpuError> {
pub async fn new(width: f32, height: f32, scale: f32) -> Result<Self, Sg2dWgpuError> {
let instance = make_wgpu_instance();
let adapter = make_wgpu_adapter(&instance, None).await?;
let (device, queue) = request_wgpu_device(&adapter).await?;
let texture_format = TextureFormat::Rgba8Unorm;
let format_flags = adapter.get_texture_format_features(texture_format).flags;
let sample_count = get_supported_sample_count(format_flags);

let physical_width = width * scale;
let physical_height = height * scale;
let texture_desc = TextureDescriptor {
size: Extent3d {
width: width as u32,
height: height as u32,
width: physical_width as u32,
height: physical_height as u32,
depth_or_array_layers: 1,
},
mip_level_count: 1,
Expand All @@ -486,8 +512,8 @@ impl PngCanvas {

// Width and height must be padded to multiple of 256 for copying image buffer
// from/to GPU texture
let padded_width = (256.0 * (width / 256.0).ceil()) as u32;
let padded_height = (256.0 * (width / 256.0).ceil()) as u32;
let padded_width = (256.0 * (physical_width / 256.0).ceil()) as u32;
let padded_height = (256.0 * (physical_height / 256.0).ceil()) as u32;

let output_buffer_size = (u32_size * padded_width * padded_height) as BufferAddress;
let output_buffer_desc = BufferDescriptor {
Expand All @@ -502,13 +528,14 @@ impl PngCanvas {

let uniform = CanvasUniform {
size: [width, height],
filler: [0.0, 0.0],
scale,
_pad: [0.0],
};

let multisampled_framebuffer = create_multisampled_framebuffer(
&device,
width as u32,
height as u32,
physical_width as u32,
physical_height as u32,
texture_format,
sample_count,
);
Expand All @@ -520,6 +547,9 @@ impl PngCanvas {
sample_count,
width,
height,
scale,
physical_width,
physical_height,
uniform,
texture,
texture_view,
Expand Down Expand Up @@ -626,7 +656,13 @@ impl PngCanvas {
image::RgbaImage::from_vec(self.padded_width, self.padded_height, data.to_vec())
.unwrap();

let cropped_img = crop_imm(&img_buf, 0, 0, self.width as u32, self.height as u32);
let cropped_img = crop_imm(
&img_buf,
0,
0,
self.physical_width as u32,
self.physical_height as u32,
);
cropped_img.to_image()
};

Expand Down Expand Up @@ -656,6 +692,10 @@ impl Canvas for PngCanvas {
&self.uniform
}

fn scale(&self) -> f32 {
self.scale
}

fn set_uniform(&mut self, uniform: CanvasUniform) {
self.uniform = uniform;
}
Expand Down
14 changes: 6 additions & 8 deletions sg2d-wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use crate::canvas::{Canvas, WindowCanvas};
use sg2d::scene_graph::SceneGraph;
use sg2d_vega::dims::VegaSceneGraphDims;
use sg2d_vega::scene_graph::VegaSceneGraph;
use winit::dpi::{PhysicalSize, Size};
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::WindowBuilder;
Expand Down Expand Up @@ -48,31 +47,30 @@ pub async fn run() {
}
// Load scene graph
let scene_spec: VegaSceneGraph = serde_json::from_str(include_str!(
"../../sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_diamonds.sg.json"
"../../sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_cross_stroke.sg.json"
))
.unwrap();

// Load dims
let scene_dims: VegaSceneGraphDims = serde_json::from_str(include_str!(
"../../sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_diamonds.dims.json"
"../../sg2d-vega-test-data/vega-scenegraphs/symbol/binned_scatter_cross_stroke.dims.json"
))
.unwrap();

// Extract dims and set window size
let origin = [scene_dims.origin_x, scene_dims.origin_y];
let width = scene_dims.width;
let height = scene_dims.height;
window.set_inner_size(Size::Physical(PhysicalSize::new(
width as u32,
height as u32,
)));
let scale = 3.0;

let scene_graph: SceneGraph = scene_spec
.to_scene_graph(origin, width, height)
.expect("Failed to parse scene graph");

// Save to png
let mut canvas = WindowCanvas::new(window).await.unwrap();
let mut canvas = WindowCanvas::new(window, width, height, scale)
.await
.unwrap();

canvas.set_scene(&scene_graph).unwrap();

Expand Down
16 changes: 9 additions & 7 deletions sg2d-wgpu/src/marks/circle.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

struct ChartUniform {
size: vec2<f32>,
filler: vec2<f32>, // for 16 byte alignment
scale: f32,
_pad: f32, // for 16 byte alignment
};

@group(0) @binding(0)
var<uniform> chart_uniforms: ChartUniform;

Expand Down Expand Up @@ -52,12 +54,12 @@ fn vs_main(

// Compute circle center in fragment shader coordinates
out.center = vec2<f32>(
instance.position[0],
instance.position[1]
instance.position[0] * chart_uniforms.scale,
instance.position[1] * chart_uniforms.scale,
);

// Compute radius in fragment shader coordinates
out.radius = size_scale / 2.0;
out.radius = size_scale * chart_uniforms.scale / 2.0;
return out;
}

Expand All @@ -66,12 +68,12 @@ fn vs_main(
fn fs_main(
in: VertexOutput,
) -> @location(0) vec4<f32> {
let buffer = 0.5;
let buffer = 0.5 * chart_uniforms.scale;
let dist = length(in.center - vec2<f32>(in.clip_position[0], in.clip_position[1]));

if (in.stroke_width > 0.0) {
let inner_radius = in.radius - in.stroke_width / 2.0;
let outer_radius = in.radius + in.stroke_width / 2.0;
let inner_radius = in.radius - in.stroke_width * chart_uniforms.scale / 2.0;
let outer_radius = in.radius + in.stroke_width * chart_uniforms.scale / 2.0;
if (dist > outer_radius + buffer * 2.0) {
discard;
} else {
Expand Down
2 changes: 1 addition & 1 deletion sg2d-wgpu/src/marks/mark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl GeomMarkRenderer {
let uniform_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[wgpu::BindGroupLayoutEntry {
binding: 0,
visibility: wgpu::ShaderStages::VERTEX,
visibility: wgpu::ShaderStages::VERTEX | wgpu::ShaderStages::FRAGMENT,
ty: wgpu::BindingType::Buffer {
ty: wgpu::BufferBindingType::Uniform,
has_dynamic_offset: false,
Expand Down
4 changes: 3 additions & 1 deletion sg2d-wgpu/src/marks/polygon_symbol.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

struct ChartUniform {
size: vec2<f32>,
filler: vec2<f32>, // for 16 byte alignment
scale: f32,
_pad: f32, // for 16 byte alignment
};

@group(0) @binding(0)
var<uniform> chart_uniforms: ChartUniform;

Expand Down
4 changes: 3 additions & 1 deletion sg2d-wgpu/src/marks/rect.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

struct ChartUniform {
size: vec2<f32>,
filler: vec2<f32>,
scale: f32,
_pad: f32, // for 16 byte alignment
};

@group(0) @binding(0)
var<uniform> chart_uniforms: ChartUniform;

Expand Down
4 changes: 3 additions & 1 deletion sg2d-wgpu/src/marks/rule.wgsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

struct ChartUniform {
size: vec2<f32>,
filler: vec2<f32>,
scale: f32,
_pad: f32, // for 16 byte alignment
};

@group(0) @binding(0)
var<uniform> chart_uniforms: ChartUniform;

Expand Down
6 changes: 3 additions & 3 deletions sg2d-wgpu/tests/test_image_baselines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ mod test_image_baselines {
case("symbol", "binned_scatter_circle_stroke_no_fill", 0.001),
case("symbol", "binned_scatter_path_star_stroke_no_fill", 0.001),
case("symbol", "scatter_transparent_stroke", 0.001),
case("symbol", "scatter_transparent_stroke_star", 0.005),
case("symbol", "scatter_transparent_stroke_star", 0.006),
case("symbol", "wind_vector", 0.0015),
case("symbol", "wedge_angle", 0.001),
case("symbol", "wedge_stroke_angle", 0.001),
case("rule", "wide_rule_axes", 0.0001),
case("text", "bar_axis_labels", 0.01)
case("text", "bar_axis_labels", 0.025)
)]
fn test_image_baseline(category: &str, spec_name: &str, tolerance: f64) {
let specs_dir = format!(
Expand Down Expand Up @@ -74,7 +74,7 @@ mod test_image_baselines {
.to_scene_graph(origin, width, height)
.expect("Failed to parse scene graph");

let mut png_canvas = pollster::block_on(PngCanvas::new(width, height)).unwrap();
let mut png_canvas = pollster::block_on(PngCanvas::new(width, height, 2.0)).unwrap();
png_canvas.set_scene(&scene_graph).unwrap();
let img = pollster::block_on(png_canvas.render()).expect("Failed to render PNG image");
let result_path = format!("{output_dir}/{category}-{spec_name}.png");
Expand Down

0 comments on commit 7bba362

Please sign in to comment.