Skip to content

Instantly share code, notes, and snippets.

@FredrikNoren
Created August 9, 2021 12:31
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save FredrikNoren/7c3535b11e99e8fcd8dd3d55f9a934a2 to your computer and use it in GitHub Desktop.
Save FredrikNoren/7c3535b11e99e8fcd8dd3d55f9a934a2 to your computer and use it in GitHub Desktop.
use tokio::{runtime::Builder, sync::{mpsc}};
use winit::{event::{Event, WindowEvent}, event_loop::{ControlFlow, EventLoop}, window::{Window, WindowBuilder}};
pub struct Gpu {
pub surface: wgpu::Surface,
pub device: wgpu::Device,
pub queue: wgpu::Queue,
pub sc_desc: wgpu::SwapChainDescriptor,
pub swap_chain: wgpu::SwapChain,
pub swapchain_format: wgpu::TextureFormat,
pub adapter: wgpu::Adapter,
}
impl Gpu {
pub async fn new(window: &Window) -> Self {
let size = window.inner_size();
let swapchain_format = wgpu::TextureFormat::Bgra8UnormSrgb;
let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY);
let surface = unsafe { instance.create_surface(window) };
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
compatible_surface: Some(&surface),
})
.await
.expect("Failed to find an appropiate adapter");
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
label: None,
features: wgpu::Features::NON_FILL_POLYGON_MODE,
limits: wgpu::Limits::default(),
},
None,
)
.await
.expect("Failed to create device");
let sc_desc = wgpu::SwapChainDescriptor {
usage: wgpu::TextureUsage::RENDER_ATTACHMENT,
format: swapchain_format,
width: size.width,
height: size.height,
present_mode: wgpu::PresentMode::Immediate,
};
let swap_chain = device.create_swap_chain(&surface, &sc_desc);
Self {
sc_desc,
swap_chain,
device,
surface,
queue,
swapchain_format,
adapter,
}
}
fn clear(&self) {
let frame = self.swap_chain
.get_current_frame()
.expect("Failed to acquire next swap chain texture")
.output;
let mut encoder = self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{
encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: None,
color_attachments: &[wgpu::RenderPassColorAttachment {
view: &frame.view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
store: true,
},
}],
depth_stencil_attachment: None,
});
}
self.queue.submit(Some(encoder.finish()));
}
}
fn main() {
let runtime = Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
let (event_tx, mut event_rx) = mpsc::unbounded_channel();
let event_loop = EventLoop::new();
let window = WindowBuilder::new().build(&event_loop).unwrap();
runtime.block_on(async {
let gpu = Gpu::new(&window).await;
runtime.spawn(async move {
loop {
let event = event_rx.recv().await.unwrap();
println!("{:?} {:?}", event, std::thread::current().id());
gpu.clear();
}
});
});
event_loop.run(move |event, _, control_flow| {
*control_flow = ControlFlow::Wait;
match &event {
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } => *control_flow = ControlFlow::Exit,
_ => (),
}
event_tx.send(event.to_static()).unwrap();
});
}
@FredrikNoren
Copy link
Author

@LukasBombach Np! One additional problem I ran into; you can't do set_title on the window on any other thread than the main thread on some OS (can't remember if it was win or osx), so you might need to send stuff over to the main thread to do that (i.e. inside the event_loop.run thing)

@LukasBombach
Copy link

I see. I also think you cannot create new windows from another thread as you needs ownership of the event loop, do you happen to know if that is correct?

@FredrikNoren
Copy link
Author

FredrikNoren commented Oct 25, 2021 via email

@LukasBombach
Copy link

👌

@FredrikNoren
Copy link
Author

Quick note; I ended up moving away from this and just running the game loop on the main thread (like normal) instead, and integrating tokio by just creating a runtime and passing around Handle's to it, which can be used to spawn.

@LukasBombach
Copy link

integrating tokio by just creating a runtime and passing around Handle's to it, which can be used to spawn

@FredrikNoren can you elaborate what you mean by this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment