-
Couldn't load subscription status.
- Fork 1.1k
Fix warnings for unrecognized Vulkan present mode #7850
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix warnings for unrecognized Vulkan present mode #7850
Conversation
2c1ff1b to
8b453b1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice
### Related * #10286 * leaving it open until proper fix arrives * proper upstream fix in gfx-rs/wgpu#7850 ### What Fixes annoying warning spam on Windows (some systems? also Linux?). --------- Co-authored-by: Emil Ernerfeldt <[email protected]>
|
The only present mode I am using is fn resize(&mut self, new_size: PhysicalSize<u32>) {
let Some(internal_fields) = self.internal_fields.as_mut() else { return; };
internal_fields.surface_config.width = new_size.width;
internal_fields.surface_config.height = new_size.height;
internal_fields.surface.configure(&internal_fields.device, &internal_fields.surface_config);
}Am I doing anything wrong? Or is this purely a wgpu bug, and I don't have to fix anything? |
|
@palapapa what is the exact warning you're getting and are you sure you're using the wgpu's trunk version? The change in this PR hasn't been release in any stable version yet |
|
Something like: wgpu version is 25.0.2. I only want to confirm if there is any error on my part. I know this PR hasn't been released. My code is the following, but I don't think it's relevant:
mod application_handler;
use std::process::*;
use application_handler::*;
use env_logger::*;
use log::*;
use winit::event_loop::*;
#[tokio::main]
async fn main() -> ExitCode {
init_env_logger();
info!("App started.");
let event_loop = match EventLoop::new() {
Ok(event_loop) => event_loop,
Err(err) => {
error!("Could not create the event loop. Error: {err:#?}");
return ExitCode::FAILURE;
}
};
event_loop.set_control_flow(ControlFlow::Poll);
let mut app = App::default();
match event_loop.run_app(&mut app) {
Ok(()) => (),
Err(err) => {
error!("The event loop terminated abnormally. Error: {err:#?}");
return ExitCode::FAILURE;
}
}
info!("Exiting.");
ExitCode::SUCCESS
}
fn init_env_logger() {
let env = Env::new().filter_or("RUST_LOG", "info");
Builder::from_env(env).format_timestamp_millis().init();
}
use std::fmt::Debug;
use std::iter::*;
use std::sync::*;
use futures::executor::*;
use log::*;
use tokio::task::block_in_place;
use winit::application::*;
use winit::dpi::*;
use winit::error::*;
use winit::event_loop::*;
use winit::window::*;
use winit::event::WindowEvent::{self, *};
use wgpu::*;
use wgpu::PowerPreference::HighPerformance;
/// An implementation of [`ApplicationHandler`] that manages the states of the app and the GPU.
#[derive(Default)]
pub struct App<'a> {
/// Because if these fields were placed in [`App`] directly, they would all have
/// to be [`Option`]s, and all either be [`Some`] of [`None`] at the same time.
/// So [`Option<AppInternalFields<'a>>`] is used in it instead.
internal_fields: Option<AppInternalFields<'a>>
}
impl App<'_> {
/// Initializes the fields inside [`Self::internal_fields`]. Does nothing if
/// called multiple times after succeeding.
///
/// * `event_loop`: The [`ActiveEventLoop`] provided by
/// [`ApplicationHandler::resumed`] used to create a [`Window`] to store
/// inside [`Self::internal_fields`].
#[expect(clippy::future_not_send, reason = "This function is currently only called using block_on.")]
async fn initialize(&mut self, event_loop: &ActiveEventLoop) -> Result<(), AppInitializationError> {
if self.internal_fields.is_some() {
return Ok(());
}
let window_attributes = Window::default_attributes().with_title("Mycraft");
let window = match event_loop.create_window(window_attributes) {
Ok(window) => {
info!("The window with ID {} has been created.", u64::from(window.id()));
Arc::new(window)
},
Err(err) => {
error!("Could not create the window. {err:#?}");
return Err(AppInitializationError::Os(err));
}
};
let wgpu_instance = Instance::new(&InstanceDescriptor {
backends: Backends::PRIMARY,
flags: InstanceFlags::from_env_or_default(),
..Default::default()
});
let surface = match wgpu_instance.create_surface(Arc::clone(&window)) {
Ok(surface) => {
info!("The surface has been created. {surface:#?}");
surface
},
Err(err) => {
error!("Could not create the surface. {err:#?}");
return Err(AppInitializationError::CreateSurface(err));
}
};
let adapter = match wgpu_instance.request_adapter(&RequestAdapterOptions {
power_preference: HighPerformance,
compatible_surface: Some(&surface),
force_fallback_adapter: false
}).await {
Ok(adapter) => {
info!("The adapter has been created. {adapter:#?}");
adapter
}
Err(err) => {
error!("The adapter could not be created. {err:#?}");
return Err(AppInitializationError::RequestAdapter(err));
}
};
let (device, command_queue) = match adapter.request_device(&DeviceDescriptor {
label: Some("default-device"),
..Default::default()
}).await {
Ok(val) => {
info!("The device and command queue has been created. {:#?}, {:#?}", val.0, val.1);
val
},
Err(err) => {
error!("The device and command queue could not be created. {err:#?}");
return Err(AppInitializationError::RequestDevice(err));
}
};
let surface_capabilities = surface.get_capabilities(&adapter);
if surface_capabilities.formats.is_empty() {
error!("The surface format could not be determined because the surface is incompatible with the adapter.");
return Err(AppInitializationError::CreateSurfaceTextureFormat);
}
#[expect(clippy::indexing_slicing, reason = "The Vec has already been checked to not be empty.")]
let surface_format = surface_capabilities.formats
.iter()
.find(|format| format.is_srgb())
.copied()
.unwrap_or(surface_capabilities.formats[0]);
info!("Supported surface formats: {:#?}", surface_capabilities.formats);
info!("The surface format {surface_format:#?} has been chosen.");
let present_mode = PresentMode::Fifo;
info!("Supported present modes: {:#?}", surface_capabilities.present_modes);
info!("The present mode {present_mode:#?} has been chosen.");
let alpha_mode = CompositeAlphaMode::Auto;
info!("Supported alpha modes: {:#?}", surface_capabilities.alpha_modes);
info!("The alpha mode {alpha_mode:#?} has been chosen.");
let surface_usages = TextureUsages::RENDER_ATTACHMENT;
info!("Supported surface usages: {:#?}", surface_capabilities.usages);
info!("The surface usages {surface_usages:#?} have been chosen.");
let surface_config = SurfaceConfiguration {
alpha_mode,
desired_maximum_frame_latency: 2,
format: surface_format,
height: window.inner_size().height,
width: window.inner_size().width,
present_mode,
usage: surface_usages,
view_formats: vec![]
};
self.internal_fields = Some(AppInternalFields {
command_queue,
device,
surface,
surface_config,
window
});
Ok(())
}
fn resize(&mut self, new_size: PhysicalSize<u32>) {
let Some(internal_fields) = self.internal_fields.as_mut() else { return; };
internal_fields.surface_config.width = new_size.width;
internal_fields.surface_config.height = new_size.height;
internal_fields.surface.configure(&internal_fields.device, &internal_fields.surface_config);
}
fn render(&self) -> Result<(), SurfaceError> {
let Some(internal_fields) = self.internal_fields.as_ref() else { return Ok(()); };
let output_surface_texture = match internal_fields.surface.get_current_texture() {
Ok(output_surface_texture) => output_surface_texture,
Err(err) => {
error!("`get_current_texture` failed when rendering. {err:#?}");
return Err(err)
}
};
let output_surface_texture_view = output_surface_texture.texture.create_view(&TextureViewDescriptor {
label: Some("main-surface-texture-view"),
..Default::default()
});
let mut command_encoder = internal_fields.device.create_command_encoder(&CommandEncoderDescriptor {
label: Some("main-command-encoder")
});
command_encoder.begin_render_pass(&RenderPassDescriptor {
label: Some("main-render-pass"),
color_attachments: &[Some(RenderPassColorAttachment {
view: &output_surface_texture_view,
resolve_target: None,
ops: Operations {
load: LoadOp::Clear(Color::default()),
store: StoreOp::Store
}
})],
..Default::default()
});
internal_fields.command_queue.submit(once(command_encoder.finish()));
output_surface_texture.present();
Ok(())
}
}
impl ApplicationHandler for App<'_> {
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
if let Some(internal_fields) = self.internal_fields.as_ref() {
info!("The window with ID {} is resuming.", u64::from(internal_fields.window.id()));
return;
}
// If `resumed` is called for the first time.
match block_in_place(|| block_on(self.initialize(event_loop))) {
Ok(()) => {
info!("The window has been initialized.");
},
Err(err) => {
error!("Failed to initialize the window. {err:#?}");
}
}
}
fn window_event(
&mut self,
event_loop: &ActiveEventLoop,
window_id: WindowId,
event: WindowEvent,
) {
match event {
Resized(new_size) => {
self.resize(new_size);
},
RedrawRequested => {
_ = self.render();
}
CloseRequested => {
info!("The window with ID {} is exiting.", u64::from(window_id));
event_loop.exit();
}
_ => {}
}
}
}
/// Because if these fields were placed in [`App`] directly, they would all have
/// to be [`Option`]s, and all either be [`Some`] of [`None`] at the same time.
/// So [`Option<AppInternalFields<'a>>`] is used in it instead.
struct AppInternalFields<'a> {
/// This has to be declared before [`Self::window`] so that it is dropped
/// before it in order to not cause a segfault. See
/// <https://github.com/gfx-rs/wgpu/pull/1792>.
surface: Surface<'a>,
/// <https://www.reddit.com/r/rust/comments/1csjakb/comment/l45os9v>
///
/// This also cannot be a owned [`Window`], because [`Self::surface`] holds
/// a reference to this, but is created in the same scope as this. If this
/// were a owned [`Window`] you would get a "borrowed data escapes outside
/// of ..." error.
window: Arc<Window>,
surface_config: SurfaceConfiguration,
device: Device,
command_queue: Queue
}
#[derive(Debug)]
#[expect(dead_code, reason = "The tuple variants are currectly unused.")]
enum AppInitializationError {
Os(OsError),
CreateSurface(CreateSurfaceError),
RequestDevice(RequestDeviceError),
CreateSurfaceTextureFormat,
RequestAdapter(RequestAdapterError)
} |
well that's literally the warning that this PR fixes as pointed out in the description and you're not using a wgpu version that has the fix yet, so not sure what you expected 🤷. You can safely ignore this warning |
Connections
wgpu_hal::vulkan::conv] Unrecognized present mode 1000361000warning spam on Windows rerun-io/rerun#10286Description
Got a lot of log spam on windows
Encountering a present mode we don't support isn't worth a warning in the first place imho (surprise there's feature that aren't covere!), but also we should explicitly handle the present modes we can know. PR does both!
Testing
ran example with logs enabled before/after
Squash or Rebase?
Squash
Checklist
cargo fmt.taplo format.cargo clippy --tests. If applicable, add:--target wasm32-unknown-unknowncargo xtask testto run tests.CHANGELOG.mdentry.