wgpu basics part 2
This commit is contained in:
parent
6d003d2c98
commit
cbcaab8a10
|
@ -22,7 +22,10 @@ wasm-logger = "0.2"
|
||||||
serde-wasm-bindgen = "0.6"
|
serde-wasm-bindgen = "0.6"
|
||||||
chrono = "0.4"
|
chrono = "0.4"
|
||||||
itertools = "0.11"
|
itertools = "0.11"
|
||||||
winit = "0.29"
|
winit = { version = "0.29", features = ["rwh_05"], default-features = false }
|
||||||
|
wgpu = { version = "0.18", features = ["webgl"] }
|
||||||
|
raw-window-handle = "0.5"
|
||||||
|
wasm-bindgen-futures = "0.4"
|
||||||
|
|
||||||
[dependencies.js-sys]
|
[dependencies.js-sys]
|
||||||
version = "0.3"
|
version = "0.3"
|
||||||
|
|
|
@ -10,9 +10,10 @@ pub mod colors;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
use js_sys::Uint8Array;
|
use js_sys::Uint8Array;
|
||||||
use log::{debug, info};
|
use log::{debug, error, info};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
|
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement};
|
||||||
|
use wgpu::SurfaceError;
|
||||||
use winit::dpi::PhysicalSize;
|
use winit::dpi::PhysicalSize;
|
||||||
use winit::event::{ElementState, Event, WindowEvent};
|
use winit::event::{ElementState, Event, WindowEvent};
|
||||||
use winit::event::WindowEvent::KeyboardInput;
|
use winit::event::WindowEvent::KeyboardInput;
|
||||||
|
@ -23,7 +24,8 @@ use winit::platform::web::{WindowExtWebSys, EventLoopExtWebSys};
|
||||||
use crate::command::{exec, should_newline};
|
use crate::command::{exec, should_newline};
|
||||||
use crate::mode::Mode;
|
use crate::mode::Mode;
|
||||||
use crate::mode::Mode::Reflectivity;
|
use crate::mode::Mode::Reflectivity;
|
||||||
use crate::scope::{Preferences, RenderState, ScopeState};
|
use crate::scope::{Preferences, ScopeState, WgpuState};
|
||||||
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -35,7 +37,7 @@ extern "C" {
|
||||||
pub struct AbiScopeState(ScopeState);
|
pub struct AbiScopeState(ScopeState);
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub fn __nxrd_browser_init() -> AbiScopeState {
|
pub async fn __nxrd_browser_init(w: u32, h: u32) -> AbiScopeState {
|
||||||
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
|
||||||
utils::set_panic_hook();
|
utils::set_panic_hook();
|
||||||
|
|
||||||
|
@ -44,7 +46,8 @@ pub fn __nxrd_browser_init() -> AbiScopeState {
|
||||||
let event_loop = EventLoop::new().expect("event loop creation failed");
|
let event_loop = EventLoop::new().expect("event loop creation failed");
|
||||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||||
|
|
||||||
window.set_min_inner_size(Some(PhysicalSize::new(450, 400)));
|
window.set_min_inner_size(Some(PhysicalSize::new(w, h)));
|
||||||
|
|
||||||
|
|
||||||
web_sys::window()
|
web_sys::window()
|
||||||
.and_then(|win| win.document())
|
.and_then(|win| win.document())
|
||||||
|
@ -57,6 +60,9 @@ pub fn __nxrd_browser_init() -> AbiScopeState {
|
||||||
})
|
})
|
||||||
.expect("Couldn't append canvas to document body.");
|
.expect("Couldn't append canvas to document body.");
|
||||||
|
|
||||||
|
let mut render_state = WgpuState::new(window, PhysicalSize::new(w, h)).await;
|
||||||
|
|
||||||
|
|
||||||
// If you see an error here, your IDE is not compiling for webassembly
|
// If you see an error here, your IDE is not compiling for webassembly
|
||||||
event_loop.spawn(move |event: Event<_>, window: &EventLoopWindowTarget<_>| {
|
event_loop.spawn(move |event: Event<_>, window: &EventLoopWindowTarget<_>| {
|
||||||
match event {
|
match event {
|
||||||
|
@ -64,14 +70,29 @@ pub fn __nxrd_browser_init() -> AbiScopeState {
|
||||||
match event {
|
match event {
|
||||||
KeyboardInput { event, .. } => {
|
KeyboardInput { event, .. } => {
|
||||||
debug!("{:?}", event.physical_key);
|
debug!("{:?}", event.physical_key);
|
||||||
if event.physical_key == KeyCode::Escape {
|
|
||||||
window.exit();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
WindowEvent::CloseRequested => { window.exit(); },
|
WindowEvent::CloseRequested => { window.exit(); },
|
||||||
|
WindowEvent::Resized(physical_size) => {
|
||||||
|
render_state.reconfigure(*physical_size);
|
||||||
|
},
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
render_state.update();
|
||||||
|
match render_state.render() {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(SurfaceError::Lost) => render_state.reconfigure(render_state.size),
|
||||||
|
Err(SurfaceError::OutOfMemory) => {
|
||||||
|
error!("out of memory!");
|
||||||
|
window.exit();
|
||||||
|
},
|
||||||
|
Err(e) => error!("transient rendering error: {}", e),
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Event::AboutToWait => {
|
||||||
|
render_state.window().request_redraw();
|
||||||
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
|
use std::iter;
|
||||||
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, HtmlInputElement};
|
use web_sys::{CanvasRenderingContext2d, HtmlCanvasElement, HtmlInputElement};
|
||||||
|
use wgpu::{Backends, Color, CommandEncoderDescriptor, Device, Features, Instance, InstanceDescriptor, Limits, LoadOp, Operations, Queue, RenderPassColorAttachment, RenderPassDescriptor, StoreOp, Surface, SurfaceConfiguration, SurfaceError, TextureUsages, TextureViewDescriptor};
|
||||||
|
use winit::dpi::PhysicalSize;
|
||||||
|
use winit::event::WindowEvent;
|
||||||
|
use raw_window_handle::HasRawDisplayHandle;
|
||||||
|
use winit::window::Window;
|
||||||
use nexrad2::Nexrad2Chunk;
|
use nexrad2::Nexrad2Chunk;
|
||||||
use crate::mode::Mode;
|
use crate::mode::Mode;
|
||||||
|
use wgpu::DeviceDescriptor;
|
||||||
|
|
||||||
pub struct ScopeState {
|
pub struct ScopeState {
|
||||||
pub ar2: Option<Nexrad2Chunk>,
|
pub ar2: Option<Nexrad2Chunk>,
|
||||||
|
@ -16,11 +23,132 @@ pub struct ScopeState {
|
||||||
pub show_ui: bool
|
pub show_ui: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RenderState {
|
pub struct WgpuState {
|
||||||
pub canvas: HtmlCanvasElement,
|
pub surface: Surface,
|
||||||
pub context: CanvasRenderingContext2d
|
pub device: Device,
|
||||||
|
pub queue: Queue,
|
||||||
|
pub surface_config: SurfaceConfiguration,
|
||||||
|
pub size: PhysicalSize<u32>,
|
||||||
|
pub window: Window
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl WgpuState {
|
||||||
|
pub async fn new(window: Window, size: PhysicalSize<u32>) -> Self {
|
||||||
|
let instance = Instance::new(InstanceDescriptor {
|
||||||
|
backends: Backends::all(),
|
||||||
|
flags: Default::default(),
|
||||||
|
dx12_shader_compiler: Default::default(),
|
||||||
|
gles_minor_version: Default::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(
|
||||||
|
&DeviceDescriptor {
|
||||||
|
features: Features::empty(),
|
||||||
|
limits: Limits::downlevel_webgl2_defaults(),
|
||||||
|
label: None,
|
||||||
|
},
|
||||||
|
None, // Trace path
|
||||||
|
).await.unwrap();
|
||||||
|
|
||||||
|
let surface_capabilities = surface.get_capabilities(&adapter);
|
||||||
|
|
||||||
|
let surface_format = surface_capabilities.formats.iter()
|
||||||
|
.copied()
|
||||||
|
.find(|f| f.is_srgb())
|
||||||
|
.unwrap_or(surface_capabilities.formats[0]);
|
||||||
|
|
||||||
|
let surface_config = SurfaceConfiguration {
|
||||||
|
usage: TextureUsages::RENDER_ATTACHMENT,
|
||||||
|
format: surface_format,
|
||||||
|
width: size.width,
|
||||||
|
height: size.height,
|
||||||
|
present_mode: surface_capabilities.present_modes[0],
|
||||||
|
alpha_mode: surface_capabilities.alpha_modes[0],
|
||||||
|
view_formats: vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
surface.configure(&device, &surface_config);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
window,
|
||||||
|
surface,
|
||||||
|
device,
|
||||||
|
queue,
|
||||||
|
surface_config,
|
||||||
|
size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn window(&self) -> &Window {
|
||||||
|
&self.window
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reconfigure(&mut self, new_size: PhysicalSize<u32>) {
|
||||||
|
if new_size.width > 0 && new_size.height > 0 {
|
||||||
|
self.size = new_size;
|
||||||
|
self.surface_config.width = new_size.width;
|
||||||
|
self.surface_config.height = new_size.height;
|
||||||
|
self.surface.configure(&self.device, &self.surface_config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input(&mut self, event: &WindowEvent) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn render(&mut self) -> Result<(), SurfaceError> {
|
||||||
|
let output = self.surface.get_current_texture()?;
|
||||||
|
let view = output.texture.create_view(&TextureViewDescriptor::default());
|
||||||
|
let mut encoder = self.device.create_command_encoder(&CommandEncoderDescriptor {
|
||||||
|
label: Some("Render Encoder"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// LOCK BLOCK
|
||||||
|
{
|
||||||
|
let render_pass = encoder.begin_render_pass(&RenderPassDescriptor {
|
||||||
|
label: Some("Render Pass"),
|
||||||
|
color_attachments: &[Some(RenderPassColorAttachment {
|
||||||
|
view: &view,
|
||||||
|
resolve_target: None,
|
||||||
|
ops: Operations {
|
||||||
|
load: LoadOp::Clear(Color {
|
||||||
|
r: 0.1,
|
||||||
|
g: 0.2,
|
||||||
|
b: 0.3,
|
||||||
|
a: 1.0,
|
||||||
|
}),
|
||||||
|
store: StoreOp::Store,
|
||||||
|
},
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
self.queue.submit(iter::once(encoder.finish()));
|
||||||
|
output.present();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pub struct Preferences {
|
pub struct Preferences {
|
||||||
pub fcs: usize
|
pub fcs: usize
|
||||||
}
|
}
|
|
@ -14,9 +14,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
image-rendering: pixelated;
|
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import * as wasm from "./wasm/nexrad_browser.js";
|
import * as wasm from "./wasm/nexrad_browser.js";
|
||||||
await wasm.default();
|
await wasm.default();
|
||||||
let global_context = wasm.__nxrd_browser_init();
|
let global_context = wasm.__nxrd_browser_init(window.innerWidth, window.innerHeight);
|
||||||
/*
|
/*
|
||||||
function rescaleCanvas(canvas, ctx) {
|
function rescaleCanvas(canvas, ctx) {
|
||||||
var dpr = window.devicePixelRatio || 1;
|
var dpr = window.devicePixelRatio || 1;
|
||||||
|
|
Loading…
Reference in New Issue