logwise::declare_logging_domain!();
mod gpu {
use app_window::window::Window;
use some_executor::hint::Hint;
use some_executor::observer::Observer;
use some_executor::task::Configuration;
use some_executor::{Priority, SomeExecutor};
use std::borrow::Cow;
use std::sync::{Arc, Mutex};
use app_window::{WGPU_SURFACE_STRATEGY, WGPUStrategy};
use wgpu::{Device, Queue, SurfaceTargetUnsafe};
#[cfg(not(target_arch = "wasm32"))]
async fn use_strategy<C, R>(strategy: WGPUStrategy, for_closure: C) -> R
where
C: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
match strategy {
WGPUStrategy::Relaxed => for_closure(),
WGPUStrategy::MainThread => {
let f = app_window::application::on_main_thread(
"use_strategy".to_string(),
move || for_closure(),
)
.await;
f
}
WGPUStrategy::NotMainThread => {
if app_window::application::is_main_thread() {
todo!()
} else {
for_closure()
}
}
_ => todo!("Unsupported WGPU strategy: {:?}", strategy),
}
}
#[cfg(target_arch = "wasm32")]
async fn use_strategy<C, R>(strategy: WGPUStrategy, for_closure: C) -> R
where
C: FnOnce() -> R,
{
match strategy {
WGPUStrategy::Relaxed => for_closure(),
WGPUStrategy::MainThread => {
assert!(app_window::application::is_main_thread());
for_closure()
}
WGPUStrategy::NotMainThread => {
if app_window::application::is_main_thread() {
todo!()
} else {
for_closure()
}
}
_ => todo!("Unsupported WGPU strategy: {:?}", strategy),
}
}
enum Message {
SizeChanged,
}
struct State<'window> {
surface: wgpu::Surface<'window>,
device: Device,
queue: Queue,
render_pipeline: wgpu::RenderPipeline,
}
fn render(state: &State) {
let frame = state
.surface
.get_current_texture()
.expect("Failed to acquire next swap chain texture");
let view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
let mut encoder = state
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
depth_slice: None,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
store: wgpu::StoreOp::Store,
},
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});
rpass.set_pipeline(&state.render_pipeline);
rpass.draw(0..3, 0..1);
}
state.queue.submit(Some(encoder.finish()));
frame.present();
}
async fn wgpu_run(mut window: Window) {
logwise::warn_sync!("main_run");
let mut app_surface = window.surface().await;
let (sender, mut receiver) = ampsc::channel();
let (size, _scale) = app_surface.size_scale().await;
let latest_size = Arc::new(Mutex::new(size));
let move_latest_size = latest_size.clone();
app_surface.size_update(move |size| {
let mut update_sender = sender.clone();
let mut some_executor = some_executor::current_executor::current_executor();
*move_latest_size.lock().unwrap() = size;
println!("got size update {:?}", size);
let task = some_executor::task::Task::new_objsafe(
"resize".into(),
Box::new(async move {
update_sender.send(Message::SizeChanged).await.unwrap();
update_sender.async_drop().await;
Box::new(()) as Box<dyn std::any::Any + Send>
}),
Configuration::new(
Hint::CPU,
Priority::UserInteractive,
some_executor::Instant::now(),
),
None,
);
some_executor.spawn_objsafe(task).detach();
});
let app_surface = Arc::new(app_surface);
let move_surface = app_surface.clone();
let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::from_env_or_default());
let move_instance = instance.clone();
let surface = use_strategy(WGPU_SURFACE_STRATEGY, move || unsafe {
move_instance
.create_surface_unsafe(SurfaceTargetUnsafe::RawHandle {
raw_display_handle: move_surface.raw_display_handle(),
raw_window_handle: move_surface.raw_window_handle(),
})
.expect("Can't create surface")
})
.await;
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
force_fallback_adapter: false,
compatible_surface: Some(&surface),
})
.await
.expect("Can't create adapter");
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor {
label: None,
required_features: wgpu::Features::empty(),
required_limits: wgpu::Limits::downlevel_webgl2_defaults()
.using_resolution(adapter.limits()),
memory_hints: wgpu::MemoryHints::MemoryUsage,
trace: wgpu::Trace::default(),
experimental_features: wgpu::ExperimentalFeatures::default(),
})
.await
.expect("Failed to create device");
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: None,
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &[],
immediate_size: 0,
});
let swapchain_capabilities = surface.get_capabilities(&adapter);
let swapchain_format = swapchain_capabilities.formats[0];
let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: None,
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
buffers: &[],
compilation_options: Default::default(),
},
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
compilation_options: Default::default(),
targets: &[Some(swapchain_format.into())],
}),
primitive: wgpu::PrimitiveState::default(),
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview_mask: None,
cache: None,
});
let mut config = surface
.get_default_config(&adapter, size.width() as u32, size.height() as u32)
.expect("Can't configure");
surface.configure(&device, &config);
let state = State {
surface,
device,
queue,
render_pipeline,
};
render(&state);
loop {
let msg = receiver.receive().await;
match msg {
Ok(Message::SizeChanged) => {
let new_size = *latest_size.lock().unwrap();
config.width = new_size.width() as u32;
config.height = new_size.height() as u32;
state.surface.configure(&state.device, &config);
render(&state);
}
Err(e) => {
panic!("Error receiving message: {:?}", e);
}
}
}
}
pub fn main() {
app_window::application::main(|| match app_window::WGPU_STRATEGY {
WGPUStrategy::MainThread => {
app_window::application::submit_to_main_thread("gpu".to_owned(), || {
some_executor::task::Task::without_notifications(
"gpu_main".to_string(),
Configuration::default(),
async {
wgpu_run(Window::default().await).await;
},
)
.spawn_static_current()
});
}
WGPUStrategy::NotMainThread => {
std::thread::Builder::new()
.name("gpu_main".to_string())
.spawn(|| {
some_executor::task::Task::without_notifications(
"gpu_main".to_string(),
Configuration::default(),
async {
wgpu_run(Window::default().await).await;
},
)
.spawn_static_current()
})
.unwrap();
}
WGPUStrategy::Relaxed => some_executor::task::Task::without_notifications(
"gpu_main".to_string(),
Configuration::default(),
async {
wgpu_run(Window::default().await).await;
},
)
.spawn_static_current(),
_ => {
panic!("Unsupported WGPU strategy: {:?}", app_window::WGPU_STRATEGY);
}
});
}
}
pub fn main() {
#[cfg(target_arch = "wasm32")]
{
console_error_panic_hook::set_once();
}
gpu::main();
}