OGNLZ5CUNFD7X43S4VTMCCEMJA2R76O35XACIR7AUBHPGME27E3AC
EEO6C4YSWFW3JOZ3JH6K7X4TKAUTVJD53CQNYZHI2QY6REGEXUCAC
L6RIUKGLJZLAOKFGUDTZKBPP4HUBPEZAKHJEQHO34WFF62AB2ZIQC
X5EMQBC4BFNJOOHS2QMF4UB4QH6JKSALK6RXLK6B7SP6MNYSAP6QC
O5P6HCPWGMGJBFJEMC3SYQJ5OEW2AQV4KEJCMRVTTS3K6M45Z3BAC
GHIHJCWBCGFZI4AG66L7WG4WKJ467DXFBRBNLT4ZULSN7ZVBJI6AC
PAOLWMH7TLJLNAWBJBWP7KB7YGDFUPASMTFU33KZ3QW5JXJMPXCAC
HTDZ53HWD4X3DSFZX7MMC7DPFJNHQPGBVLJD2S325SQRRVIQ3CLAC
GROTV3H2V6BHU5CA7WSLVYDCWAR7GHUP5JV2QOGPLJ6N3553T4MAC
FPNW5ZHTGO2UDPGVOKZYX2BYZRMKAB3NEAFVSIXRVYNSWCUPBWFQC
6YVIIRYC6FQP7ET7AMJHG4XCIDI4KIJMOKUDAUMVBLYFEULRDQEAC
BYFMGWJ5ZPXZTCIFDHP66KK7JTEKT2NO7HR2XY7T5WRAAG3L5WYQC
DKGUNP6LG3DJ35VMHU42K3VJO5JJ5UVYI4PLM72HO5ZNAQ4P366AC
NS7EOR3SRISITX6SBHBOJIYTINDN2ZBL2QY64H6FNJJ3I2I3PYGQC
pub async fn new<S: assets_manager::source::Source>(
window: Window,
assets: &AssetCache<S>,
) -> color_eyre::Result<Self> {
let size = {
let actual_size = window.inner_size();
if actual_size.width == 0 || actual_size.height == 0 {
// Assume we are actually in-built height and notify
let assumed_size = PhysicalSize::new(WINDOW_WIDTH, WINDOW_HEIGHT);
window.set_min_inner_size(Some(assumed_size));
assumed_size
} else {
// It's fine
actual_size
}
};
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
..Default::default()
});
async fn acknoledge_surface(
&mut self,
surface: &wgpu::Surface<'static>,
) -> color_eyre::Result<()> {
if self
.adapter_state
.as_ref()
.is_some_and(|ads| ads.adapter.is_surface_supported(surface))
{
// Conserve work: we've already made a perfectly good adapter that supports the surface we want to draw to
return Ok(());
}
let surface_caps = surface.get_capabilities(&adapter);
pub async fn create_surface<S: assets_manager::source::Source>(
&mut self,
assets: &AssetCache<S>,
) -> color_eyre::Result<()> {
let surface = self.instance.create_surface(self.window.clone())?;
self.acknoledge_surface(&surface).await?;
let Some(adapter_state) = self.adapter_state.as_ref() else {
unreachable!("adapter_state should have been created by `Screen::acknowledge_surface`");
};
let surface_caps = surface.get_capabilities(&adapter_state.adapter);
let world_atlas = glyphon::TextAtlas::new(&device, &queue, world_texture_format);
let camera_atlas = glyphon::TextAtlas::new(&device, &queue, surface_format);
let world_renderer =
middleware::WorldRenderer::new(&device, config.format, world_texture_format, assets)?;
let world_atlas = glyphon::TextAtlas::new(
&adapter_state.device,
&adapter_state.queue,
world_texture_format,
);
let camera_atlas =
glyphon::TextAtlas::new(&adapter_state.device, &adapter_state.queue, surface_format);
let world_renderer = middleware::WorldRenderer::new(
&adapter_state.device,
config.format,
world_texture_format,
assets,
)?;
world_renderer,
});
Ok(())
}
pub async fn new(window: Window) -> color_eyre::Result<Self> {
let size = {
let actual_size = window.inner_size();
if actual_size.width == 0 || actual_size.height == 0 {
// Assume we are actually in-built height and notify
let assumed_size = PhysicalSize::new(WINDOW_WIDTH, WINDOW_HEIGHT);
window.set_min_inner_size(Some(assumed_size));
assumed_size
} else {
// It's fine
actual_size
}
};
let window = Arc::new(window);
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
backends: wgpu::Backends::all(),
..Default::default()
});
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
compatible_surface: None,
force_fallback_adapter: false,
})
.await;
let adapter_state = if let Some(adapter) = adapter {
let (device, queue) = adapter
.request_device(
&wgpu::DeviceDescriptor {
required_features: wgpu::Features::empty(), //wgpu::Features::all_webgpu_mask(),
required_limits: if cfg!(target_arch = "wasm32") {
if cfg!(feature = "webgpu") {
wgpu::Limits::downlevel_defaults()
} else if cfg!(feature = "webgl") {
wgpu::Limits::downlevel_webgl2_defaults()
} else {
unreachable!("for `web` feature, you must also enable a backend feature: `webgpu`, `webgl`")
}
} else {
wgpu::Limits::default()
},
label: None,
},
None,
)
.await?;
Some(AdapterState {
adapter,
device,
queue,
})
} else {
None
};
Ok(Self {
instance,
size,
window,
adapter_state,
surface_state: None,
self.size = new_size;
self.config.width = new_size.width;
self.config.height = new_size.height;
self.surface.configure(&self.device, &self.config);
if let Some((surface_state, adapter_state)) =
self.surface_state.as_mut().zip(self.adapter_state.as_ref())
{
self.size = new_size;
surface_state.config.width = new_size.width;
surface_state.config.height = new_size.height;
surface_state
.surface
.configure(&adapter_state.device, &surface_state.config);
}
match self.config.present_mode {
wgpu::PresentMode::AutoVsync => true,
wgpu::PresentMode::AutoNoVsync => false,
_ => unreachable!(),
if let Some(state) = self.surface_state.as_ref() {
match state.config.present_mode {
wgpu::PresentMode::AutoVsync => true,
wgpu::PresentMode::AutoNoVsync => false,
_ => unreachable!(),
}
} else {
false
let pm = if vsync {
wgpu::PresentMode::AutoVsync
} else {
wgpu::PresentMode::AutoNoVsync
};
self.config.present_mode = pm;
self.surface.configure(&self.device, &self.config);
if let Some((surface_state, adapter_state)) =
self.surface_state.as_mut().zip(self.adapter_state.as_ref())
{
let pm = if vsync {
wgpu::PresentMode::AutoVsync
} else {
wgpu::PresentMode::AutoNoVsync
};
surface_state.config.present_mode = pm;
surface_state
.surface
.configure(&adapter_state.device, &surface_state.config);
}
let output = self.surface.get_current_texture()?;
let Some((surface_state, adapter_state)) =
self.surface_state.as_mut().zip(self.adapter_state.as_ref())
else {
// Return early, as surface has not been initialized
return Ok(());
};
let output = surface_state.surface.get_current_texture()?;
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
let mut encoder =
adapter_state
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
}
// Poor man's executor for winit's poor man's async
type TaskId = usize;
struct PollTask(TaskId);
struct WinitExecutor<E> {
// a better implementation should use a vec of options here.
tasks: HashMap<TaskId, Pin<Box<dyn Future<Output = Result<(), E>>>>>,
event_loop_proxy: EventLoopProxy<PollTask>,
impl<E> WinitExecutor<E> {
/// Create a new `WinitExecutor`, driven by the given event loop.
pub fn new(event_loop_proxy: EventLoopProxy<PollTask>) -> Self {
Self {
tasks: HashMap::new(),
event_loop_proxy,
}
}
fn next_task_id(&self) -> TaskId {
static NEXT_TASK_ID: std::sync::atomic::AtomicUsize =
std::sync::atomic::AtomicUsize::new(0);
NEXT_TASK_ID.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
}
/// Spawn a task.
///
/// This immediately pools the task once, and then schedules it to be
/// polled again if needed, using a `UserEvent::PollTask` event.
pub fn spawn(&mut self, task: impl Future<Output = Result<(), E>> + 'static) {
let task = Box::pin(task);
let task_id = self.next_task_id();
self.tasks.insert(task_id, task);
self.poll(task_id);
}
/// Poll a task.
///
/// Should be called when the event loop receives a `UserEvent::PollTask`.
pub fn poll(&mut self, task_id: TaskId) -> Option<Result<(), E>> {
// this wake only need to work once, I believe, so we could use some type of "oneshot box"
// instead of a mutex?
let winit_proxy = Mutex::new(self.event_loop_proxy.clone());
let waker = waker_fn::waker_fn(move || {
let _ = winit_proxy.lock().unwrap().send_event(PollTask(task_id));
});
let task = self.tasks.get_mut(&task_id).unwrap().as_mut();
match task.poll(&mut Context::from_waker(&waker)) {
Poll::Ready(res) => {
_ = self.tasks.remove(&task_id);
Some(res)
}
Poll::Pending => None,
}
}
}
Event::Resumed => {
// Actually create the surface (and panic if we fail...)
winit_executor.spawn({
let game = game.clone();
async move { game.lock().unwrap().create_surface().await }
});
}
Event::UserEvent(PollTask(tid)) => {
if let Some(res) = winit_executor.poll(tid) {
// the stuff here shouldn't fail
res.unwrap();
}
}
desktop = ["egui-winit/clipboard", "egui-winit/links", "egui-winit/wayland",
"egui-winit/x11", "wgpu/dx12", "wgpu/metal", "wgpu/webgpu", "wgpu/wgsl",
"tracing-subscriber/env-filter", "dep:pollster"]
desktop = ["egui-winit/default", "wgpu/default", "tracing-subscriber/env-filter", "dep:pollster"]
name = "loom"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5"
dependencies = [
"cfg-if",
"generator",
"pin-utils",
"scoped-tls",
"tracing",
"tracing-subscriber",
]
[[package]]