Merge branch 'xMAC94x/fix_1165' into 'master'

remove futures_executor from renderer and rather pass tokio runtime to it...

See merge request veloren/veloren!2755
This commit is contained in:
Marcel
2021-08-11 15:26:08 +00:00
9 changed files with 102 additions and 114 deletions

1
Cargo.lock generated
View File

@ -6161,7 +6161,6 @@ dependencies = [
"egui_winit_platform", "egui_winit_platform",
"enum-iterator", "enum-iterator",
"euc", "euc",
"futures-executor",
"gilrs", "gilrs",
"glyph_brush", "glyph_brush",
"guillotiere", "guillotiere",

View File

@ -98,7 +98,6 @@ crossbeam-channel = "0.5"
directories-next = "2.0" directories-next = "2.0"
dot_vox = "4.0" dot_vox = "4.0"
enum-iterator = "0.6" enum-iterator = "0.6"
futures-executor = "0.3"
guillotiere = "0.6" guillotiere = "0.6"
hashbrown = {version = "0.11", features = ["rayon", "serde", "nightly"]} hashbrown = {version = "0.11", features = ["rayon", "serde", "nightly"]}
image = {version = "0.23.12", default-features = false, features = ["ico", "png"]} image = {version = "0.23.12", default-features = false, features = ["ico", "png"]}

View File

@ -51,6 +51,9 @@ use common_base::span;
use i18n::LocalizationHandle; use i18n::LocalizationHandle;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc;
use tokio::runtime::Runtime;
/// A type used to store state that is shared between all play states. /// A type used to store state that is shared between all play states.
pub struct GlobalState { pub struct GlobalState {
pub userdata_dir: PathBuf, pub userdata_dir: PathBuf,
@ -58,6 +61,7 @@ pub struct GlobalState {
pub settings: Settings, pub settings: Settings,
pub profile: Profile, pub profile: Profile,
pub window: Window, pub window: Window,
pub tokio_runtime: Arc<Runtime>,
#[cfg(feature = "egui-ui")] #[cfg(feature = "egui-ui")]
pub egui_state: EguiState, pub egui_state: EguiState,
pub lazy_init: scene::terrain::SpriteRenderContextLazy, pub lazy_init: scene::terrain::SpriteRenderContextLazy,

View File

@ -165,6 +165,29 @@ fn main() {
default_hook(panic_info); default_hook(panic_info);
})); }));
// Setup tokio runtime
use common::consts::MIN_RECOMMENDED_TOKIO_THREADS;
use std::sync::{
atomic::{AtomicUsize, Ordering},
Arc,
};
use tokio::runtime::Builder;
// TODO: evaluate std::thread::available_concurrency as a num_cpus replacement
let cores = num_cpus::get();
let tokio_runtime = Arc::new(
Builder::new_multi_thread()
.enable_all()
.worker_threads((cores / 4).max(MIN_RECOMMENDED_TOKIO_THREADS))
.thread_name_fn(|| {
static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
format!("tokio-voxygen-{}", id)
})
.build()
.unwrap(),
);
#[cfg(feature = "hot-reloading")] #[cfg(feature = "hot-reloading")]
assets::start_hot_reloading(); assets::start_hot_reloading();
@ -210,7 +233,7 @@ fn main() {
// Create window // Create window
use veloren_voxygen::{error::Error, render::RenderError}; use veloren_voxygen::{error::Error, render::RenderError};
let (mut window, event_loop) = match Window::new(&settings) { let (mut window, event_loop) = match Window::new(&settings, &tokio_runtime) {
Ok(ok) => ok, Ok(ok) => ok,
// Custom panic message when a graphics backend could not be found // Custom panic message when a graphics backend could not be found
Err(Error::RenderError(RenderError::CouldNotFindAdapter)) => { Err(Error::RenderError(RenderError::CouldNotFindAdapter)) => {
@ -247,6 +270,7 @@ fn main() {
audio, audio,
profile, profile,
window, window,
tokio_runtime,
#[cfg(feature = "egui-ui")] #[cfg(feature = "egui-ui")]
egui_state, egui_state,
lazy_init, lazy_init,

View File

@ -3,11 +3,10 @@ use client::{
error::{Error as ClientError, NetworkConnectError, NetworkError}, error::{Error as ClientError, NetworkConnectError, NetworkError},
Client, ServerInfo, Client, ServerInfo,
}; };
use common::consts::MIN_RECOMMENDED_TOKIO_THREADS;
use crossbeam_channel::{unbounded, Receiver, Sender, TryRecvError}; use crossbeam_channel::{unbounded, Receiver, Sender, TryRecvError};
use std::{ use std::{
sync::{ sync::{
atomic::{AtomicBool, AtomicUsize, Ordering}, atomic::{AtomicBool, Ordering},
Arc, Arc,
}, },
time::Duration, time::Duration,
@ -47,29 +46,13 @@ impl ClientInit {
connection_args: ConnectionArgs, connection_args: ConnectionArgs,
username: String, username: String,
password: String, password: String,
runtime: Option<Arc<runtime::Runtime>>, runtime: Arc<runtime::Runtime>,
) -> Self { ) -> Self {
let (tx, rx) = unbounded(); let (tx, rx) = unbounded();
let (trust_tx, trust_rx) = unbounded(); let (trust_tx, trust_rx) = unbounded();
let cancel = Arc::new(AtomicBool::new(false)); let cancel = Arc::new(AtomicBool::new(false));
let cancel2 = Arc::clone(&cancel); let cancel2 = Arc::clone(&cancel);
let runtime = runtime.unwrap_or_else(|| {
// TODO: evaluate std::thread::available_concurrency as a num_cpus replacement
let cores = num_cpus::get();
Arc::new(
runtime::Builder::new_multi_thread()
.enable_all()
.worker_threads((cores / 4).max(MIN_RECOMMENDED_TOKIO_THREADS))
.thread_name_fn(|| {
static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
format!("tokio-voxygen-{}", id)
})
.build()
.unwrap(),
)
});
let runtime2 = Arc::clone(&runtime); let runtime2 = Arc::clone(&runtime);
runtime.spawn(async move { runtime.spawn(async move {

View File

@ -93,7 +93,7 @@ impl PlayState for MainMenuState {
{ {
if let Some(singleplayer) = &global_state.singleplayer { if let Some(singleplayer) = &global_state.singleplayer {
match singleplayer.receiver.try_recv() { match singleplayer.receiver.try_recv() {
Ok(Ok(runtime)) => { Ok(Ok(())) => {
// Attempt login after the server is finished initializing // Attempt login after the server is finished initializing
attempt_login( attempt_login(
&mut global_state.info_message, &mut global_state.info_message,
@ -101,7 +101,7 @@ impl PlayState for MainMenuState {
"".to_owned(), "".to_owned(),
ConnectionArgs::Mpsc(14004), ConnectionArgs::Mpsc(14004),
&mut self.init, &mut self.init,
Some(runtime), &global_state.tokio_runtime,
); );
}, },
Ok(Err(e)) => { Ok(Err(e)) => {
@ -261,7 +261,7 @@ impl PlayState for MainMenuState {
password, password,
connection_args, connection_args,
&mut self.init, &mut self.init,
None, &global_state.tokio_runtime,
); );
}, },
MainMenuEvent::CancelLoginAttempt => { MainMenuEvent::CancelLoginAttempt => {
@ -290,7 +290,7 @@ impl PlayState for MainMenuState {
}, },
#[cfg(feature = "singleplayer")] #[cfg(feature = "singleplayer")]
MainMenuEvent::StartSingleplayer => { MainMenuEvent::StartSingleplayer => {
let singleplayer = Singleplayer::new(); let singleplayer = Singleplayer::new(&global_state.tokio_runtime);
global_state.singleplayer = Some(singleplayer); global_state.singleplayer = Some(singleplayer);
}, },
@ -450,7 +450,7 @@ fn attempt_login(
password: String, password: String,
connection_args: ConnectionArgs, connection_args: ConnectionArgs,
init: &mut InitState, init: &mut InitState,
runtime: Option<Arc<runtime::Runtime>>, runtime: &Arc<runtime::Runtime>,
) { ) {
if let Err(err) = comp::Player::alias_validate(&username) { if let Err(err) = comp::Player::alias_validate(&username) {
*info_message = Some(err.to_string()); *info_message = Some(err.to_string());
@ -463,7 +463,7 @@ fn attempt_login(
connection_args, connection_args,
username, username,
password, password,
runtime, Arc::clone(runtime),
)); ));
} }
} }

View File

@ -183,7 +183,11 @@ pub struct Renderer {
impl Renderer { impl Renderer {
/// Create a new `Renderer` from a variety of backend-specific components /// Create a new `Renderer` from a variety of backend-specific components
/// and the window targets. /// and the window targets.
pub fn new(window: &winit::window::Window, mode: RenderMode) -> Result<Self, RenderError> { pub fn new(
window: &winit::window::Window,
mode: RenderMode,
runtime: &tokio::runtime::Runtime,
) -> Result<Self, RenderError> {
let (pipeline_modes, mut other_modes) = mode.split(); let (pipeline_modes, mut other_modes) = mode.split();
// Enable seamless cubemaps globally, where available--they are essentially a // Enable seamless cubemaps globally, where available--they are essentially a
// strict improvement on regular cube maps. // strict improvement on regular cube maps.
@ -220,13 +224,12 @@ impl Renderer {
#[allow(unsafe_code)] #[allow(unsafe_code)]
let surface = unsafe { instance.create_surface(window) }; let surface = unsafe { instance.create_surface(window) };
let adapter = futures_executor::block_on(instance.request_adapter( let adapter = runtime
&wgpu::RequestAdapterOptionsBase { .block_on(instance.request_adapter(&wgpu::RequestAdapterOptionsBase {
power_preference: wgpu::PowerPreference::HighPerformance, power_preference: wgpu::PowerPreference::HighPerformance,
compatible_surface: Some(&surface), compatible_surface: Some(&surface),
}, }))
)) .ok_or(RenderError::CouldNotFindAdapter)?;
.ok_or(RenderError::CouldNotFindAdapter)?;
let info = adapter.get_info(); let info = adapter.get_info();
info!( info!(
@ -244,7 +247,33 @@ impl Renderer {
..Default::default() ..Default::default()
}; };
let (device, queue) = futures_executor::block_on(adapter.request_device( let trace_env = std::env::var_os("WGPU_TRACE_DIR");
let trace_path = trace_env.as_ref().map(|v| {
let path = std::path::Path::new(v);
// We don't want to continue if we can't actually collect the api trace
assert!(
path.exists(),
"WGPU_TRACE_DIR is set to the path \"{}\" which doesn't exist",
path.display()
);
assert!(
path.is_dir(),
"WGPU_TRACE_DIR is set to the path \"{}\" which is not a directory",
path.display()
);
assert!(
path.read_dir()
.expect("Could not read the directory that is specified by WGPU_TRACE_DIR")
.next()
.is_some(),
"WGPU_TRACE_DIR is set to the path \"{}\" which already contains other files",
path.display()
);
path
});
let (device, queue) = runtime.block_on(adapter.request_device(
&wgpu::DeviceDescriptor { &wgpu::DeviceDescriptor {
// TODO // TODO
label: None, label: None,
@ -254,36 +283,7 @@ impl Renderer {
| (adapter.features() & wgpu_profiler::GpuProfiler::REQUIRED_WGPU_FEATURES), | (adapter.features() & wgpu_profiler::GpuProfiler::REQUIRED_WGPU_FEATURES),
limits, limits,
}, },
std::env::var_os("WGPU_TRACE_DIR").as_ref().map(|v| { trace_path.as_deref(),
let path = std::path::Path::new(v);
// We don't want to continue if we can't actually collect the api trace
if !path.exists() {
panic!(
"WGPU_TRACE_DIR is set to the path \"{}\" which doesn't exist",
path.display()
);
}
if !path.is_dir() {
panic!(
"WGPU_TRACE_DIR is set to the path \"{}\" which is not a directory",
path.display()
);
}
if path
.read_dir()
.expect("Could not read the directory that is specified by WGPU_TRACE_DIR")
.next()
.is_some()
{
panic!(
"WGPU_TRACE_DIR is set to the path \"{}\" which already contains other \
files",
path.display()
);
}
path
}),
))?; ))?;
// Set error handler for wgpu errors // Set error handler for wgpu errors

View File

@ -1,4 +1,4 @@
use common::{clock::Clock, consts::MIN_RECOMMENDED_TOKIO_THREADS}; use common::clock::Clock;
use crossbeam_channel::{bounded, unbounded, Receiver, Sender, TryRecvError}; use crossbeam_channel::{bounded, unbounded, Receiver, Sender, TryRecvError};
use server::{ use server::{
persistence::{DatabaseSettings, SqlLogMode}, persistence::{DatabaseSettings, SqlLogMode},
@ -6,14 +6,14 @@ use server::{
}; };
use std::{ use std::{
sync::{ sync::{
atomic::{AtomicBool, AtomicUsize, Ordering}, atomic::{AtomicBool, Ordering},
Arc, Arc,
}, },
thread::{self, JoinHandle}, thread::{self, JoinHandle},
time::Duration, time::Duration,
}; };
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
use tracing::{debug, error, info, trace, warn}; use tracing::{error, info, trace, warn};
const TPS: u64 = 30; const TPS: u64 = 30;
@ -22,7 +22,7 @@ const TPS: u64 = 30;
pub struct Singleplayer { pub struct Singleplayer {
_server_thread: JoinHandle<()>, _server_thread: JoinHandle<()>,
stop_server_s: Sender<()>, stop_server_s: Sender<()>,
pub receiver: Receiver<Result<Arc<Runtime>, ServerError>>, pub receiver: Receiver<Result<(), ServerError>>,
// Wether the server is stopped or not // Wether the server is stopped or not
paused: Arc<AtomicBool>, paused: Arc<AtomicBool>,
// Settings that the server was started with // Settings that the server was started with
@ -30,8 +30,7 @@ pub struct Singleplayer {
} }
impl Singleplayer { impl Singleplayer {
#[allow(clippy::new_without_default)] pub fn new(runtime: &Arc<Runtime>) -> Self {
pub fn new() -> Self {
let (stop_server_s, stop_server_r) = unbounded(); let (stop_server_s, stop_server_r) = unbounded();
// Determine folder to save server data in // Determine folder to save server data in
@ -82,22 +81,6 @@ impl Singleplayer {
let settings = server::Settings::singleplayer(&server_data_dir); let settings = server::Settings::singleplayer(&server_data_dir);
let editable_settings = server::EditableSettings::singleplayer(&server_data_dir); let editable_settings = server::EditableSettings::singleplayer(&server_data_dir);
// TODO: evaluate std::thread::available_concurrency as a num_cpus replacement
let cores = num_cpus::get();
debug!("Creating a new runtime for server");
let runtime = Arc::new(
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.worker_threads((cores / 4).max(MIN_RECOMMENDED_TOKIO_THREADS))
.thread_name_fn(|| {
static ATOMIC_ID: AtomicUsize = AtomicUsize::new(0);
let id = ATOMIC_ID.fetch_add(1, Ordering::SeqCst);
format!("tokio-sp-{}", id)
})
.build()
.unwrap(),
);
let settings2 = settings.clone(); let settings2 = settings.clone();
// Relative to data_dir // Relative to data_dir
@ -117,39 +100,32 @@ impl Singleplayer {
let (result_sender, result_receiver) = bounded(1); let (result_sender, result_receiver) = bounded(1);
let builder = thread::Builder::new().name("singleplayer-server-thread".into()); let builder = thread::Builder::new().name("singleplayer-server-thread".into());
let runtime = Arc::clone(runtime);
let thread = builder let thread = builder
.spawn(move || { .spawn(move || {
trace!("starting singleplayer server thread"); trace!("starting singleplayer server thread");
let mut server = None;
if let Err(e) = result_sender.send( let (server, init_result) = match Server::new(
match Server::new( settings2,
settings2, editable_settings,
editable_settings, database_settings,
database_settings, &server_data_dir,
&server_data_dir, runtime,
Arc::clone(&runtime),
) {
Ok(s) => {
server = Some(s);
Ok(runtime)
},
Err(e) => Err(e),
},
) { ) {
warn!( Ok(server) => (Some(server), Ok(())),
Err(err) => (None, Err(err)),
};
match (result_sender.send(init_result), server) {
(Err(e), _) => warn!(
?e, ?e,
"Failed to send singleplayer server initialization result. Most likely \ "Failed to send singleplayer server initialization result. Most likely \
the channel was closed by cancelling server creation. Stopping Server" the channel was closed by cancelling server creation. Stopping Server"
); ),
return; (Ok(()), None) => (),
}; (Ok(()), Some(server)) => run_server(server, stop_server_r, paused1),
}
let server = match server {
Some(s) => s,
None => return,
};
run_server(server, stop_server_r, paused1);
trace!("ending singleplayer server thread"); trace!("ending singleplayer server thread");
}) })
.unwrap(); .unwrap();

View File

@ -398,7 +398,10 @@ pub struct Window {
} }
impl Window { impl Window {
pub fn new(settings: &Settings) -> Result<(Window, EventLoop), Error> { pub fn new(
settings: &Settings,
runtime: &tokio::runtime::Runtime,
) -> Result<(Window, EventLoop), Error> {
let event_loop = EventLoop::new(); let event_loop = EventLoop::new();
let size = settings.graphics.window_size; let size = settings.graphics.window_size;
@ -418,7 +421,7 @@ impl Window {
let window = win_builder.build(&event_loop).unwrap(); let window = win_builder.build(&event_loop).unwrap();
let renderer = Renderer::new(&window, settings.graphics.render_mode.clone())?; let renderer = Renderer::new(&window, settings.graphics.render_mode.clone(), runtime)?;
let keypress_map = HashMap::new(); let keypress_map = HashMap::new();