Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a wgpu backend #63

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
502 changes: 499 additions & 3 deletions Cargo.lock

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ thread_profiler = "0.3.0"
log = "0.4.14"
fern = "0.6.0"
sha3 = "0.9.1"
wgpu = { version = "0.8.0", optional = true }
pollster = { version = "0.2.3", optional = true }
bytemuck = { version = "1.5.1", features = ["derive"], optional = true }

[target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.24.0"
Expand All @@ -54,5 +57,6 @@ foreign-types-shared = "0.1.1"
debug = true

[features]
default = [ "profiler"]
default = ["profiler", "wgpu-backend"]
profiler = ["thread_profiler/thread_profiler"]
wgpu-backend = ["wgpu", "pollster", "bytemuck"]
72 changes: 46 additions & 26 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ extern crate cocoa;
#[cfg(target_os = "macos")]
use cocoa::foundation::NSAutoreleasePool;

#[cfg(feature = "wgpu-backend")]
mod render_wgpu;

mod errors {
error_chain! {
links {
Expand Down Expand Up @@ -243,6 +246,9 @@ fn download(
));
}

#[cfg(feature = "wgpu-backend")]
let header_source = include_str!("shadertoy_header_wgpu.glsl");
#[cfg(not(feature = "wgpu-backend"))]
let header_source = include_str!("shadertoy_header.glsl");
let image_footer_source = include_str!("shadertoy_image_footer.glsl");
let sound_footer_source = include_str!("shadertoy_sound_footer.glsl");
Expand Down Expand Up @@ -270,7 +276,19 @@ fn download(
{
// these shaders get stuck in forever compilation, so let's skip them for now
// TODO should make compilation more robust and be able to timeout and then remove this
#[cfg(not(feature = "wgpu-backend"))]
let skip_shaders = ["XllSWf", "ll2BWz", "4sG3Wy", "XdsBzj", "4td3z4"];
#[cfg(feature = "wgpu-backend")]
let skip_shaders = [
// Vulkan
"4sjBDG", "MlyGWh", "4ll3RS", "WdX3zl", "wsjXz1",
// Vulkan stack overflows
"MsBcRG", "wsyGzt",
// Metal
"3sfGDS", "tssfW2",
// DirectX 12
"WsjBW1",
];

if skip_shaders.contains(&shader.info.id.as_str()) {
continue;
Expand Down Expand Up @@ -545,9 +563,9 @@ fn run() -> Result<()> {

// setup renderer

let render_backend: Option<Box<dyn RenderBackend>>;
let mut render_backend: Option<Box<dyn RenderBackend>> = None;

#[cfg(target_os = "macos")]
#[cfg(all(target_os = "macos", not(feature = "wgpu-backend")))]
{
match MetalRenderBackend::new() {
Ok(rb) => render_backend = Some(Box::new(rb)),
Expand All @@ -558,13 +576,37 @@ fn run() -> Result<()> {
}
}

#[cfg(not(target_os = "macos"))]
#[cfg(feature = "wgpu-backend")]
{
render_backend = None;
render_backend = Some(Box::new(render_wgpu::WgpuRenderBackend::new()));
}

thread_profiler::register_thread_with_profiler();

// set up rendering window

let event_loop = winit::event_loop::EventLoop::new();
let window = winit::window::WindowBuilder::new()
.with_inner_size(winit::dpi::LogicalSize::new(
matches
.value_of("res_width")
.unwrap()
.parse::<f64>()
.unwrap(),
matches
.value_of("res_height")
.unwrap()
.parse::<f64>()
.unwrap(),
))
.with_title("Shadertoy Browser".to_string())
.build(&event_loop)
.chain_err(|| "error creating window")?;

if let Some(render_backend) = render_backend.as_mut() {
render_backend.init_window(&window);
}

// download and process assets

let mut built_shadertoy_shaders =
Expand All @@ -589,28 +631,6 @@ fn run() -> Result<()> {
let mut render_backend =
render_backend.chain_err(|| "skipping rendering, as have no renderer available")?;

// set up rendering window

let event_loop = winit::event_loop::EventLoop::new();
let window = winit::window::WindowBuilder::new()
.with_inner_size(winit::dpi::LogicalSize::new(
matches
.value_of("res_width")
.unwrap()
.parse::<f64>()
.unwrap(),
matches
.value_of("res_height")
.unwrap()
.parse::<f64>()
.unwrap(),
))
.with_title("Shadertoy Browser".to_string())
.build(&event_loop)
.chain_err(|| "error creating window")?;

render_backend.init_window(&window);

#[cfg(target_os = "macos")]
let mut pool = unsafe { NSAutoreleasePool::new(cocoa::base::nil) };

Expand Down
12 changes: 8 additions & 4 deletions src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ use std::any::Any;
use crate::errors::*;

#[repr(C)]
#[cfg_attr(
feature = "wgpu-backend",
derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)
)]
#[allow(non_snake_case)]
pub struct ShadertoyConstants {
// The viewport resolution (z is pixel aspect ratio, usually 1.0).
pub iResolution: (f32, f32, f32),
pub iResolution: [f32; 3],
pub pad1: f32,
/// xy contain the current pixel coords (if LMB is down). zw contain the click pixel.
pub iMouse: (f32, f32, f32, f32),
pub iMouse: [f32; 4],
/// Current time in seconds.
pub iTime: f32,
/// Delta time since last frame.
Expand All @@ -22,11 +26,11 @@ pub struct ShadertoyConstants {
pub iFrame: i32,
pub pad2: [i32; 3],
/// Year, month, day, time in seconds in .xyzw
pub iDate: (f32, f32, f32, f32),
pub iDate: [f32; 4],
/// Time for channel (if video or sound), in seconds.
pub iChannelTime: [f32; 4],
/// Input texture resolution for each channel.
pub iChannelResolution: [(f32, f32, f32, f32); 4],
pub iChannelResolution: [[f32; 4]; 4],
pub iBlockOffset: f32,
pub pad3: [f32; 3],
}
Expand Down
29 changes: 12 additions & 17 deletions src/render_metal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,46 +218,41 @@ impl RenderBackend for MetalRenderBackend {

let dt: DateTime<Local> = Local::now();

let mut mouse = (
let mut mouse = [
(params.mouse_pos.0 as f32) / self.dpi_factor,
(params.mouse_pos.1 as f32) / self.dpi_factor,
(params.mouse_click_pos.0 as f32) / self.dpi_factor,
(params.mouse_click_pos.1 as f32) / self.dpi_factor,
);
];

// flip y
if mouse.1 > 0.0 {
mouse.1 = h - mouse.1;
if mouse[1] > 0.0 {
mouse[1] = h - mouse[1];
}
if mouse.3 > 0.0 {
mouse.3 = h - mouse.3;
if mouse[3] > 0.0 {
mouse[3] = h - mouse[3];
}

ShadertoyConstants {
iResolution: ((quad.size.0 * w), (quad.size.1 * h), w / h),
iResolution: [(quad.size.0 * w), (quad.size.1 * h), w / h],
pad1: 0.0,
iMouse: mouse,
iTime: time,
iTimeDelta: delta_time,
iFrameRate: 1.0 / delta_time,
iSampleRate: 44100.0,
iFrame: self.frame_index as i32,
pad2: [0, 0, 0],
iDate: (
pad2: [0; 3],
iDate: [
dt.year() as f32,
dt.month() as f32,
dt.day() as f32,
dt.second() as f32, // TODO unclear what seconds should be here?
),
iChannelTime: [time, time, time, time], // TODO not correct
iChannelResolution: [
(0.0, 0.0, 0.0, 0.0),
(0.0, 0.0, 0.0, 0.0),
(0.0, 0.0, 0.0, 0.0),
(0.0, 0.0, 0.0, 0.0),
],
iChannelTime: [time; 4], // TODO not correct
iChannelResolution: [[0.0; 4], [0.0; 4], [0.0; 4], [0.0; 4]],
iBlockOffset: 0.0,
pad3: [0.0, 0.0, 0.0],
pad3: [0.0; 3],
}
};

Expand Down
Loading