Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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();
});
}
@LukasBombach

This comment has been minimized.

Copy link

@LukasBombach LukasBombach commented Oct 18, 2021

This is great, thanks!

@FredrikNoren

This comment has been minimized.

Copy link
Owner Author

@FredrikNoren FredrikNoren commented Oct 18, 2021

@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

This comment has been minimized.

Copy link

@LukasBombach LukasBombach commented Oct 25, 2021

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

This comment has been minimized.

Copy link
Owner Author

@FredrikNoren FredrikNoren commented Oct 25, 2021

@LukasBombach

This comment has been minimized.

Copy link

@LukasBombach LukasBombach commented Oct 26, 2021

👌

@FredrikNoren

This comment has been minimized.

Copy link
Owner Author

@FredrikNoren FredrikNoren commented Nov 16, 2021

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.

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