diff --git a/CHANGELOG.md b/CHANGELOG.md index 81230b2d11..b1f4c7604f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - processing SPIR-V inputs for later translation now requires `spirv` compile feature enabled - new `Features::SPIRV_SHADER_PASSTHROUGH` run-time feature allows providing pass-through SPIR-V (orthogonal to the compile feature) - several bitflag names are renamed to plural: `TextureUsage`, `BufferUsage`, `ColorWrite`. + - the `SwapChain` is merged into `Surface`. - renamed `TextureUsage` bits: `SAMPLED` -> `TEXTURE_BINDING`, `STORAGE` -> `STORAGE_BINDING`. - renamed `InputStepMode` to `VertexStepMode` - Implemented `Rgb9e5Ufloat` format. diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index 41e454fd79..2eac675d1b 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -103,7 +103,7 @@ fn main() { event_loop::ControlFlow, }; - let mut resize_desc = None; + let mut resize_config = None; let mut frame_count = 0; let mut done = false; event_loop.run(move |event, _, control_flow| { @@ -112,31 +112,30 @@ fn main() { Event::MainEventsCleared => { window.request_redraw(); } - Event::RedrawRequested(_) if resize_desc.is_none() => loop { + Event::RedrawRequested(_) if resize_config.is_none() => loop { match actions.pop() { - Some(trace::Action::CreateSwapChain(id, desc)) => { - log::info!("Initializing the swapchain"); - assert_eq!(id.to_surface_id(), surface); + Some(trace::Action::ConfigureSurface(_device_id, config)) => { + log::info!("Configuring the surface"); let current_size: (u32, u32) = window.inner_size().into(); - let size = (desc.width, desc.height); + let size = (config.width, config.height); if current_size != size { window.set_inner_size(winit::dpi::PhysicalSize::new( - desc.width, - desc.height, + config.width, + config.height, )); - resize_desc = Some(desc); + resize_config = Some(config); break; } else { - let (_, error) = gfx_select!(device => global.device_create_swap_chain(device, surface, &desc)); + let error = gfx_select!(device => global.surface_configure(surface, device, &config)); if let Some(e) = error { panic!("{:?}", e); } } } - Some(trace::Action::PresentSwapChain(id)) => { + Some(trace::Action::Present(id)) => { frame_count += 1; log::debug!("Presenting frame {}", frame_count); - gfx_select!(device => global.swap_chain_present(id)).unwrap(); + gfx_select!(device => global.surface_present(id)).unwrap(); break; } Some(action) => { @@ -153,8 +152,8 @@ fn main() { }, Event::WindowEvent { event, .. } => match event { WindowEvent::Resized(_) => { - if let Some(desc) = resize_desc.take() { - let (_, error) = gfx_select!(device => global.device_create_swap_chain(device, surface, &desc)); + if let Some(config) = resize_config.take() { + let error = gfx_select!(device => global.surface_configure(surface, device, &config)); if let Some(e) = error { panic!("{:?}", e); } diff --git a/player/src/lib.rs b/player/src/lib.rs index c84393ea7c..87c21e2f64 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -149,8 +149,8 @@ impl GlobalPlay for wgc::hub::Global { Action::Init { .. } => { panic!("Unexpected Action::Init: has to be the first action only") } - Action::CreateSwapChain { .. } | Action::PresentSwapChain(_) => { - panic!("Unexpected SwapChain action: winit feature is not enabled") + Action::ConfigureSurface { .. } | Action::Present(_) => { + panic!("Unexpected Surface action: winit feature is not enabled") } Action::CreateBuffer(id, desc) => { self.device_maintain_ids::(device).unwrap(); @@ -202,9 +202,9 @@ impl GlobalPlay for wgc::hub::Global { Action::DestroySampler(id) => { self.sampler_drop::(id); } - Action::GetSwapChainTexture { id, parent_id } => { + Action::GetSurfaceTexture { id, parent_id } => { self.device_maintain_ids::(device).unwrap(); - self.swap_chain_get_current_texture_view::(parent_id, id) + self.surface_get_current_texture_view::(parent_id, id) .unwrap() .view_id .unwrap(); diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 3c1b507e11..ab932e50d1 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -91,8 +91,8 @@ pub enum CreateBindGroupError { MissingTextureUsage(#[from] MissingTextureUsageError), #[error("binding declared as a single item, but bind group is using it as an array")] SingleBindingExpected, - #[error("unable to create a bind group with a swap chain image")] - SwapChainImage, + #[error("unable to create a bind group with a surface image")] + SurfaceImage, #[error("buffer offset {0} does not respect `BIND_BUFFER_ALIGNMENT`")] UnalignedBufferOffset(wgt::BufferAddress), #[error( diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 610a547a5b..7236b8b3af 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -141,7 +141,7 @@ pub struct CommandBuffer { status: CommandEncoderStatus, pub(crate) device_id: Stored, pub(crate) trackers: TrackerSet, - pub(crate) used_swap_chains: SmallVec<[Stored; 1]>, + pub(crate) used_surfaces: SmallVec<[id::Valid; 1]>, buffer_memory_init_actions: Vec>, limits: wgt::Limits, support_fill_buffer_texture: bool, @@ -169,7 +169,7 @@ impl CommandBuffer { status: CommandEncoderStatus::Recording, device_id, trackers: TrackerSet::new(A::VARIANT), - used_swap_chains: Default::default(), + used_surfaces: Default::default(), buffer_memory_init_actions: Default::default(), limits, support_fill_buffer_texture: features.contains(wgt::Features::CLEAR_COMMANDS), diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 9d5c9e1ee3..f748407790 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -13,10 +13,10 @@ use crate::{ error::{ErrorFormatter, PrettyError}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id, + instance::Surface, memory_init_tracker::{MemoryInitKind, MemoryInitTrackerAction}, pipeline::PipelineFlags, resource::{Texture, TextureView, TextureViewSource}, - swap_chain::SwapChain, track::{StatefulTrackerSubset, TextureSelector, UsageConflict}, validation::{ check_buffer_usage, check_texture_usage, MissingBufferUsageError, MissingTextureUsageError, @@ -414,8 +414,6 @@ pub enum RenderPassErrorInner { InvalidResolveTargetSampleCount, #[error("not enough memory left")] OutOfMemory, - #[error("attempted to use a swap chain image as a depth/stencil attachment")] - SwapChainImageAsDepthStencil, #[error("unable to clear non-present/read-only depth")] InvalidDepthOps, #[error("unable to clear non-present/read-only stencil")] @@ -522,7 +520,7 @@ struct RenderPassInfo<'a, A: hal::Api> { context: RenderPassContext, trackers: StatefulTrackerSubset, render_attachments: AttachmentDataVec>, - used_swap_chain: Option>, + used_surface: Option>, is_ds_read_only: bool, extent: wgt::Extent3d, _phantom: PhantomData, @@ -535,7 +533,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>, cmd_buf: &mut CommandBuffer, view_guard: &'a Storage, id::TextureViewId>, - swap_chain_guard: &'a Storage, id::SwapChainId>, + surface_guard: &'a Storage, ) -> Result { profiling::scope!("start", "RenderPassInfo"); @@ -549,7 +547,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { let mut attachment_type_name = ""; let mut extent = None; let mut sample_count = 0; - let mut used_swap_chain = None::<(Stored, hal::TextureUses)>; + let mut used_surface = None::<(id::Valid, hal::TextureUses)>; let mut add_view = |view: &TextureView, type_name| { if let Some(ex) = extent { @@ -594,9 +592,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { let source_id = match view.source { TextureViewSource::Native(ref source_id) => source_id, - TextureViewSource::SwapChain(_) => { - return Err(RenderPassErrorInner::SwapChainImageAsDepthStencil); - } + TextureViewSource::Surface(_) => unreachable!(), }; let usage = if at.is_read_only(ds_aspects)? { @@ -648,14 +644,14 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { usage: hal::TextureUses::COLOR_TARGET, }); } - TextureViewSource::SwapChain(ref source_id) => { + TextureViewSource::Surface(source_id) => { //HACK: guess the start usage based on the load op let start_usage = match at.channel.load_op { LoadOp::Load => hal::TextureUses::empty(), LoadOp::Clear => hal::TextureUses::UNINITIALIZED, }; - assert!(used_swap_chain.is_none()); - used_swap_chain = Some((source_id.clone(), start_usage)); + assert!(used_surface.is_none()); + used_surface = Some((source_id, start_usage)); } }; @@ -687,11 +683,11 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { usage: hal::TextureUses::COLOR_TARGET, }); } - TextureViewSource::SwapChain(ref source_id) => { + TextureViewSource::Surface(source_id) => { //HACK: guess the start usage let start_usage = hal::TextureUses::UNINITIALIZED; - assert!(used_swap_chain.is_none()); - used_swap_chain = Some((source_id.clone(), start_usage)); + assert!(used_surface.is_none()); + used_surface = Some((source_id, start_usage)); } }; @@ -716,8 +712,8 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { return Err(RenderPassErrorInner::InvalidSampleCount(sample_count)); } - if let Some((ref sc_id, start_usage)) = used_swap_chain { - let &(_, ref suf_texture) = swap_chain_guard[sc_id.value] + if let Some((surface_id, start_usage)) = used_surface { + let suf_texture = A::get_surface(&surface_guard[surface_id]) .acquired_texture .as_ref() .unwrap(); @@ -764,7 +760,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { context, trackers: StatefulTrackerSubset::new(A::VARIANT), render_attachments, - used_swap_chain: used_swap_chain.map(|(sc_id, _)| sc_id), + used_surface: used_surface.map(|(sc_id, _)| sc_id), is_ds_read_only, extent, _phantom: PhantomData, @@ -775,19 +771,17 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { mut self, raw: &mut A::CommandEncoder, texture_guard: &Storage, id::TextureId>, - swap_chain_guard: &Storage, id::SwapChainId>, - ) -> Result<(StatefulTrackerSubset, Option>), RenderPassErrorInner> + surface_guard: &Storage, + ) -> Result<(StatefulTrackerSubset, Option>), RenderPassErrorInner> { profiling::scope!("finish", "RenderPassInfo"); unsafe { raw.end_render_pass(); } - if let Some(ref sc_id) = self.used_swap_chain { - let &(_, ref suf_texture) = swap_chain_guard[sc_id.value] - .acquired_texture - .as_ref() - .unwrap(); + if let Some(surface_id) = self.used_surface { + let suf = A::get_surface(&surface_guard[surface_id]); + let suf_texture = suf.acquired_texture.as_ref().unwrap(); let barrier = hal::TextureBarrier { texture: std::borrow::Borrow::borrow(suf_texture), usage: hal::TextureUses::COLOR_TARGET..hal::TextureUses::empty(), @@ -814,7 +808,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { .map_err(UsageConflict::from)?; } - Ok((self.trackers, self.used_swap_chain)) + Ok((self.trackers, self.used_surface)) } } @@ -848,10 +842,10 @@ impl Global { let hub = A::hub(self); let mut token = Token::root(); + let (surface_guard, mut token) = self.surfaces.read(&mut token); let (device_guard, mut token) = hub.devices.read(&mut token); let (pass_raw, trackers, query_reset_state) = { - let (swap_chain_guard, mut token) = hub.swap_chains.read(&mut token); let (mut cmb_guard, mut token) = hub.command_buffers.write(&mut token); let cmd_buf = @@ -895,7 +889,7 @@ impl Global { depth_stencil_attachment, cmd_buf, &*view_guard, - &*swap_chain_guard, + &*surface_guard, ) .map_pass_err(scope)?; @@ -1762,8 +1756,8 @@ impl Global { } log::trace!("Merging {:?} with the render pass", encoder_id); - let (trackers, used_swapchain) = info - .finish(raw, &*texture_guard, &*swap_chain_guard) + let (trackers, used_surface) = info + .finish(raw, &*texture_guard, &*surface_guard) .map_pass_err(scope)?; let raw_cmd_buf = unsafe { @@ -1772,7 +1766,7 @@ impl Global { .map_pass_err(scope)? }; cmd_buf.status = CommandEncoderStatus::Recording; - cmd_buf.used_swap_chains.extend(used_swapchain); + cmd_buf.used_surfaces.extend(used_surface); (raw_cmd_buf, trackers, query_reset_state) }; diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index 63270106af..99b70a2daf 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -391,7 +391,7 @@ impl LifetimeTracker { resource::TextureViewSource::Native(ref source_id) => { self.suspected_resources.textures.push(source_id.value); } - resource::TextureViewSource::SwapChain { .. } => {} + resource::TextureViewSource::Surface { .. } => {} }; self.schedule_texture_view_for_destruction(id, res); } diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index a42acc015d..a0ba25dac0 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -4,7 +4,7 @@ use crate::{ hub::{Global, GlobalIdentityHandlerFactory, HalApi, Hub, Input, InvalidId, Storage, Token}, id, instance, memory_init_tracker::{MemoryInitKind, MemoryInitTracker, MemoryInitTrackerAction}, - pipeline, resource, swap_chain, + pipeline, present, resource, track::{BufferState, TextureSelector, TextureState, TrackerSet, UsageConflict}, validation::{self, check_buffer_usage, check_texture_usage}, FastHashMap, Label, LabelHelpers as _, LifeGuard, MultiRefCount, Stored, SubmissionIndex, @@ -1448,8 +1448,8 @@ impl Device { .map_err(UsageConflict::from)?; check_texture_usage(texture.desc.usage, pub_usage)?; } - resource::TextureViewSource::SwapChain(_) => { - return Err(Error::SwapChainImage); + resource::TextureViewSource::Surface(_) => { + return Err(Error::SurfaceImage); } } @@ -1500,8 +1500,8 @@ impl Device { .map_err(UsageConflict::from)?; check_texture_usage(texture.desc.usage, pub_usage)?; } - resource::TextureViewSource::SwapChain(_) => { - return Err(Error::SwapChainImage); + resource::TextureViewSource::Surface(_) => { + return Err(Error::SurfaceImage); } } @@ -2478,6 +2478,10 @@ impl Device { } life_tracker.triage_submissions(current_index, &self.command_allocator); life_tracker.cleanup(&self.raw); + #[cfg(feature = "trace")] + { + self.trace = None; + } } pub(crate) fn dispose(self) { @@ -2567,34 +2571,34 @@ impl Global { let hub = A::hub(self); let mut token = Token::root(); - let (mut surface_guard, mut token) = self.surfaces.write(&mut token); + let (surface_guard, mut token) = self.surfaces.read(&mut token); let (adapter_guard, mut _token) = hub.adapters.read(&mut token); let adapter = adapter_guard .get(adapter_id) .map_err(|_| instance::IsSurfaceSupportedError::InvalidAdapter)?; let surface = surface_guard - .get_mut(surface_id) + .get(surface_id) .map_err(|_| instance::IsSurfaceSupportedError::InvalidSurface)?; Ok(adapter.is_surface_supported(surface)) } - pub fn adapter_get_swap_chain_preferred_format( + pub fn surface_get_preferred_format( &self, - adapter_id: id::AdapterId, surface_id: id::SurfaceId, - ) -> Result { + adapter_id: id::AdapterId, + ) -> Result { let hub = A::hub(self); let mut token = Token::root(); - let (mut surface_guard, mut token) = self.surfaces.write(&mut token); + let (surface_guard, mut token) = self.surfaces.read(&mut token); let (adapter_guard, mut _token) = hub.adapters.read(&mut token); let adapter = adapter_guard .get(adapter_id) - .map_err(|_| instance::GetSwapChainPreferredFormatError::InvalidAdapter)?; + .map_err(|_| instance::GetSurfacePreferredFormatError::InvalidAdapter)?; let surface = surface_guard - .get_mut(surface_id) - .map_err(|_| instance::GetSwapChainPreferredFormatError::InvalidSurface)?; + .get(surface_id) + .map_err(|_| instance::GetSurfacePreferredFormatError::InvalidSurface)?; - adapter.get_swap_chain_preferred_format(surface) + surface.get_preferred_format(adapter) } pub fn device_features( @@ -3260,8 +3264,8 @@ impl Global { resource::TextureViewSource::Native(ref source_id) => { texture_guard[source_id.value].device_id.value } - resource::TextureViewSource::SwapChain(_) => { - return Err(resource::TextureViewDestroyError::SwapChainImage) + resource::TextureViewSource::Surface(_) => { + return Err(resource::TextureViewDestroyError::SurfaceImage) } }; (last_submit_index, device_id) @@ -4289,19 +4293,20 @@ impl Global { .push(layout_id); } - pub fn device_create_swap_chain( + pub fn surface_configure( &self, - device_id: id::DeviceId, surface_id: id::SurfaceId, - desc: &wgt::SwapChainDescriptor, - ) -> (id::SwapChainId, Option) { + device_id: id::DeviceId, + config: &wgt::SurfaceConfiguration, + ) -> Option { use hal::{Adapter as _, Surface as _}; - profiling::scope!("create_swap_chain", "Device"); + use present::ConfigureSurfaceError as E; + profiling::scope!("surface_configure"); - fn validate_swap_chain_descriptor( + fn validate_surface_configuraiton( config: &mut hal::SurfaceConfiguration, caps: &hal::SurfaceCapabilities, - ) -> Result<(), swap_chain::CreateSwapChainError> { + ) -> Result<(), E> { let width = config.extent.width; let height = config.extent.height; if width < caps.extents.start().width @@ -4324,29 +4329,27 @@ impl Global { config.present_mode = wgt::PresentMode::Fifo; } if !caps.formats.contains(&config.format) { - return Err(swap_chain::CreateSwapChainError::UnsupportedFormat { + return Err(E::UnsupportedFormat { requested: config.format, available: caps.formats.clone(), }); } if !caps.usage.contains(config.usage) { - return Err(swap_chain::CreateSwapChainError::UnsupportedUsage); + return Err(E::UnsupportedUsage); } if width == 0 || height == 0 { - return Err(swap_chain::CreateSwapChainError::ZeroArea); + return Err(E::ZeroArea); } Ok(()) } - log::info!("creating swap chain {:?}", desc); - let sc_id = surface_id.to_swap_chain_id(A::VARIANT); + log::info!("configuring surface with {:?}", config); let hub = A::hub(self); let mut token = Token::root(); let (mut surface_guard, mut token) = self.surfaces.write(&mut token); let (adapter_guard, mut token) = hub.adapters.read(&mut token); - let (device_guard, mut token) = hub.devices.read(&mut token); - let (mut swap_chain_guard, _) = hub.swap_chains.write(&mut token); + let (device_guard, _token) = hub.devices.read(&mut token); let error = loop { let device = match device_guard.get(device_id) { @@ -4357,86 +4360,82 @@ impl Global { if let Some(ref trace) = device.trace { trace .lock() - .add(trace::Action::CreateSwapChain(sc_id, desc.clone())); + .add(trace::Action::ConfigureSurface(surface_id, config.clone())); } let surface = match surface_guard.get_mut(surface_id) { Ok(surface) => surface, - Err(_) => break swap_chain::CreateSwapChainError::InvalidSurface, + Err(_) => break E::InvalidSurface, }; let caps = unsafe { - let surface = A::get_surface_mut(surface); + let suf = A::get_surface(surface); let adapter = &adapter_guard[device.adapter_id.value]; - match adapter.raw.adapter.surface_capabilities(surface) { + match adapter.raw.adapter.surface_capabilities(&suf.raw) { Some(caps) => caps, - None => break swap_chain::CreateSwapChainError::UnsupportedQueueFamily, + None => break E::UnsupportedQueueFamily, } }; - let num_frames = swap_chain::DESIRED_NUM_FRAMES + let num_frames = present::DESIRED_NUM_FRAMES .max(*caps.swap_chain_sizes.start()) .min(*caps.swap_chain_sizes.end()); - let mut config = hal::SurfaceConfiguration { + let mut hal_config = hal::SurfaceConfiguration { swap_chain_size: num_frames, - present_mode: desc.present_mode, + present_mode: config.present_mode, composite_alpha_mode: hal::CompositeAlphaMode::Opaque, - format: desc.format, + format: config.format, extent: wgt::Extent3d { - width: desc.width, - height: desc.height, + width: config.width, + height: config.height, depth_or_array_layers: 1, }, - usage: conv::map_texture_usage(desc.usage, hal::FormatAspects::COLOR), + usage: conv::map_texture_usage(config.usage, hal::FormatAspects::COLOR), }; - if let Err(error) = validate_swap_chain_descriptor(&mut config, &caps) { + if let Err(error) = validate_surface_configuraiton(&mut hal_config, &caps) { break error; } - match unsafe { A::get_surface_mut(surface).configure(&device.raw, &config) } { + match unsafe { + A::get_surface_mut(surface) + .raw + .configure(&device.raw, &hal_config) + } { Ok(()) => (), Err(error) => { break match error { - hal::SurfaceError::Outdated | hal::SurfaceError::Lost => { - swap_chain::CreateSwapChainError::InvalidSurface - } - hal::SurfaceError::Device(error) => { - swap_chain::CreateSwapChainError::Device(error.into()) - } + hal::SurfaceError::Outdated | hal::SurfaceError::Lost => E::InvalidSurface, + hal::SurfaceError::Device(error) => E::Device(error.into()), hal::SurfaceError::Other(message) => { log::error!("surface configuration failed: {}", message); - swap_chain::CreateSwapChainError::InvalidSurface + E::InvalidSurface } } } } - if let Some(sc) = swap_chain_guard.try_remove(sc_id) { - if sc.acquired_texture.is_some() { - break swap_chain::CreateSwapChainError::SwapChainOutputExists; + if let Some(present) = surface.presentation.take() { + if present.acquired_texture.is_some() { + break E::PreviousOutputExists; } } - let swap_chain = swap_chain::SwapChain { - life_guard: LifeGuard::new(""), + surface.presentation = Some(present::Presentation { device_id: Stored { value: id::Valid(device_id), ref_count: device.life_guard.add_ref(), }, - desc: desc.clone(), + config: config.clone(), num_frames, acquired_texture: None, active_submission_index: 0, - marker: PhantomData, - }; - swap_chain_guard.insert(sc_id, swap_chain); + }); - return (sc_id, None); + return None; }; - swap_chain_guard.insert_error(sc_id, ""); - (sc_id, Some(error)) + Some(error) } #[cfg(feature = "replay")] diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 8c25456782..e90ad2981a 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -15,7 +15,6 @@ use crate::{ use hal::{CommandEncoder as _, Device as _, Queue as _}; use parking_lot::Mutex; -use smallvec::SmallVec; use std::{iter, mem, num::NonZeroU32, ptr}; use thiserror::Error; @@ -212,8 +211,10 @@ pub enum QueueSubmitError { DestroyedTexture(id::TextureId), #[error(transparent)] Unmap(#[from] BufferAccessError), - #[error("swap chain output was dropped before the command buffer got submitted")] - SwapChainOutputDropped, + #[error("surface output was dropped before the command buffer got submitted")] + SurfaceOutputDropped, + #[error("surface was unconfigured before the command buffer got submitted")] + SurfaceUnconfigured, #[error("GPU got stuck :(")] StuckGpu, } @@ -510,6 +511,7 @@ impl Global { let mut token = Token::root(); let callbacks = { + let (mut surface_guard, mut token) = self.surfaces.write(&mut token); let (mut device_guard, mut token) = hub.devices.write(&mut token); let device = device_guard .get_mut(queue_id) @@ -520,8 +522,6 @@ impl Global { let mut active_executions = Vec::new(); { - let mut signal_swapchain_semaphores = SmallVec::<[_; 1]>::new(); - let (mut swap_chain_guard, mut token) = hub.swap_chains.write(&mut token); let (mut command_buffer_guard, mut token) = hub.command_buffers.write(&mut token); if !command_buffer_ids.is_empty() { @@ -569,16 +569,17 @@ impl Global { // optimize the tracked states cmdbuf.trackers.optimize(); - for sc_id in cmdbuf.used_swap_chains.drain(..) { - let sc = &mut swap_chain_guard[sc_id.value]; - if sc.acquired_texture.is_none() { - return Err(QueueSubmitError::SwapChainOutputDropped); + for surface_id in cmdbuf.used_surfaces.drain(..) { + let surface = &mut surface_guard[surface_id]; + let suf = A::get_surface_mut(surface); + if suf.acquired_texture.is_none() { + return Err(QueueSubmitError::SurfaceOutputDropped); } - if sc.active_submission_index != submit_index { - sc.active_submission_index = submit_index; - // Only add a signal if this is the first time for this swapchain - // to be used in the submission. - signal_swapchain_semaphores.push(sc_id.value); + match surface.presentation { + Some(ref mut present) => { + present.active_submission_index = submit_index; + } + None => return Err(QueueSubmitError::SurfaceUnconfigured), } } diff --git a/wgpu-core/src/device/trace.rs b/wgpu-core/src/device/trace.rs index 7fdd48f27a..417b43e463 100644 --- a/wgpu-core/src/device/trace.rs +++ b/wgpu-core/src/device/trace.rs @@ -39,6 +39,7 @@ pub enum Action<'a> { desc: crate::device::DeviceDescriptor<'a>, backend: wgt::Backend, }, + ConfigureSurface(id::SurfaceId, wgt::SurfaceConfiguration), CreateBuffer(id::BufferId, crate::resource::BufferDescriptor<'a>), FreeBuffer(id::BufferId), DestroyBuffer(id::BufferId), @@ -53,12 +54,11 @@ pub enum Action<'a> { DestroyTextureView(id::TextureViewId), CreateSampler(id::SamplerId, crate::resource::SamplerDescriptor<'a>), DestroySampler(id::SamplerId), - CreateSwapChain(id::SwapChainId, wgt::SwapChainDescriptor), - GetSwapChainTexture { + GetSurfaceTexture { id: id::TextureViewId, - parent_id: id::SwapChainId, + parent_id: id::SurfaceId, }, - PresentSwapChain(id::SwapChainId), + Present(id::SurfaceId), CreateBindGroupLayout( id::BindGroupLayoutId, crate::binding_model::BindGroupLayoutDescriptor<'a>, diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 9cea16114d..ba748fe7a7 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -3,10 +3,9 @@ use crate::{ command::{CommandBuffer, RenderBundle}, device::Device, id, - instance::{Adapter, Instance, Surface}, + instance::{Adapter, HalSurface, Instance, Surface}, pipeline::{ComputePipeline, RenderPipeline, ShaderModule}, resource::{Buffer, QuerySet, Sampler, Texture, TextureView}, - swap_chain::SwapChain, Epoch, Index, }; @@ -111,7 +110,7 @@ impl ops::IndexMut> for Storage { } impl Storage { - pub(crate) fn contains(&self, id: I) -> bool { + pub(crate) fn _contains(&self, id: I) -> bool { let (index, epoch, _) = id.unzip(); match self.map[index as usize] { Element::Vacant => false, @@ -201,7 +200,7 @@ impl Storage { } // Prevents panic on out of range access, allows Vacant elements. - pub(crate) fn try_remove(&mut self, id: I) -> Option { + pub(crate) fn _try_remove(&mut self, id: I) -> Option { let (index, epoch, _) = id.unzip(); if index as usize >= self.map.len() { None @@ -264,8 +263,6 @@ impl Access> for Surface {} impl Access> for Root {} impl Access> for Surface {} impl Access> for Adapter {} -impl Access> for Root {} -impl Access> for Device {} impl Access> for Root {} impl Access> for Device {} impl Access> for RenderBundle {} @@ -279,7 +276,6 @@ impl Access> for PipelineLayout {} impl Access> for CommandBuffer {} impl Access> for Root {} impl Access> for Device {} -impl Access> for SwapChain {} //TODO: remove this (only used in `submit()`) impl Access for Device {} impl Access for CommandBuffer {} impl Access> for Device {} @@ -307,7 +303,6 @@ impl Access> for Root {} impl Access> for Device {} impl Access> for Buffer {} impl Access> for Root {} -impl Access> for SwapChain {} //TODO: remove this (only used in `get_next_texture()`) impl Access> for Device {} impl Access> for Texture {} impl Access> for Root {} @@ -395,7 +390,6 @@ impl IdentityHandlerFactory for IdentityManagerFactor pub trait GlobalIdentityHandlerFactory: IdentityHandlerFactory + IdentityHandlerFactory - + IdentityHandlerFactory + IdentityHandlerFactory + IdentityHandlerFactory + IdentityHandlerFactory @@ -559,7 +553,6 @@ impl> Registry< pub struct HubReport { pub adapters: StorageReport, pub devices: StorageReport, - pub swap_chains: StorageReport, pub pipeline_layouts: StorageReport, pub shader_modules: StorageReport, pub bind_group_layouts: StorageReport, @@ -584,7 +577,6 @@ impl HubReport { pub struct Hub { pub adapters: Registry, id::AdapterId, F>, pub devices: Registry, id::DeviceId, F>, - pub swap_chains: Registry, id::SwapChainId, F>, pub pipeline_layouts: Registry, id::PipelineLayoutId, F>, pub shader_modules: Registry, id::ShaderModuleId, F>, pub bind_group_layouts: Registry, id::BindGroupLayoutId, F>, @@ -605,7 +597,6 @@ impl Hub { Self { adapters: Registry::new(A::VARIANT, factory), devices: Registry::new(A::VARIANT, factory), - swap_chains: Registry::new(A::VARIANT, factory), pipeline_layouts: Registry::new(A::VARIANT, factory), shader_modules: Registry::new(A::VARIANT, factory), bind_group_layouts: Registry::new(A::VARIANT, factory), @@ -664,7 +655,7 @@ impl Hub { device.raw.destroy_texture_view(texture_view.raw); } } - TextureViewSource::SwapChain(_) => {} //TODO + TextureViewSource::Surface(_) => {} //TODO } } } @@ -731,16 +722,13 @@ impl Hub { } } - for (index, element) in self.swap_chains.data.write().map.drain(..).enumerate() { - if let Element::Occupied(swap_chain, epoch) = element { - let device = &devices[swap_chain.device_id.value]; - let suf_id = id::TypedId::zip(index as Index, epoch, A::VARIANT); - //TODO: hold the surface alive by the swapchain - if surface_guard.contains(suf_id) { - let surface = surface_guard.get_mut(suf_id).unwrap(); - let suf = A::get_surface_mut(surface); + for element in surface_guard.map.drain(..) { + if let Element::Occupied(mut surface, _epoch) = element { + if let Some(present) = surface.presentation.take() { + let device = &devices[present.device_id.value]; + let suf = A::get_surface_mut(&mut surface); unsafe { - suf.unconfigure(&device.raw); + suf.raw.unconfigure(&device.raw); } } } @@ -771,7 +759,6 @@ impl Hub { HubReport { adapters: self.adapters.data.read().generate_report(), devices: self.devices.data.read().generate_report(), - swap_chains: self.swap_chains.data.read().generate_report(), pipeline_layouts: self.pipeline_layouts.data.read().generate_report(), shader_modules: self.shader_modules.data.read().generate_report(), bind_group_layouts: self.bind_group_layouts.data.read().generate_report(), @@ -951,7 +938,8 @@ pub trait HalApi: hal::Api { const VARIANT: Backend; fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance; fn hub(global: &Global) -> &Hub; - fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface; + fn get_surface(surface: &Surface) -> &HalSurface; + fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface; } #[cfg(vulkan)] @@ -967,7 +955,10 @@ impl HalApi for hal::api::Vulkan { fn hub(global: &Global) -> &Hub { &global.hubs.vulkan } - fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface { + fn get_surface(surface: &Surface) -> &HalSurface { + surface.vulkan.as_ref().unwrap() + } + fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { surface.vulkan.as_mut().unwrap() } } @@ -984,7 +975,10 @@ impl HalApi for hal::api::Metal { fn hub(global: &Global) -> &Hub { &global.hubs.metal } - fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface { + fn get_surface(surface: &Surface) -> &HalSurface { + surface.metal.as_ref().unwrap() + } + fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { surface.metal.as_mut().unwrap() } } @@ -1002,7 +996,10 @@ impl HalApi for hal::api::Dx12 { fn hub(global: &Global) -> &Hub { &global.hubs.dx12 } - fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface { + fn get_surface(surface: &Surface) -> &HalSurface { + surface.dx12.as_ref().unwrap() + } + fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { surface.dx12.as_mut().unwrap() } } @@ -1014,7 +1011,10 @@ impl HalApi for hal::api::Dx11 { fn hub(global: &Global) -> &Hub { &global.hubs.dx11 } - fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface { + fn get_surface(surface: &Surface) -> &HalSurface { + surface.dx11.as_ref().unwrap() + } + fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { surface.dx11.as_mut().unwrap() } } @@ -1033,7 +1033,10 @@ impl HalApi for hal::api::Gles { fn hub(global: &Global) -> &Hub { &global.hubs.gl } - fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface { + fn get_surface(surface: &Surface) -> &HalSurface { + surface.gl.as_ref().unwrap() + } + fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface { surface.gl.as_mut().unwrap() } } diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index 4d26e11618..d102eb6183 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -161,21 +161,6 @@ pub type ComputePassEncoderId = *mut crate::command::ComputePass; pub type RenderBundleEncoderId = *mut crate::command::RenderBundleEncoder; pub type RenderBundleId = Id; pub type QuerySetId = Id>; -// Swap chain -pub type SwapChainId = Id>; - -impl SurfaceId { - pub(crate) fn to_swap_chain_id(self, backend: Backend) -> SwapChainId { - let (index, epoch, _) = self.unzip(); - Id::zip(index, epoch, backend) - } -} -impl SwapChainId { - pub fn to_surface_id(self) -> SurfaceId { - let (index, epoch, _) = self.unzip(); - Id::zip(index, epoch, Backend::Empty) - } -} #[test] fn test_id_backend() { diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 63bc7cfa6d..d821bcc125 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -2,6 +2,7 @@ use crate::{ device::{Device, DeviceDescriptor}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Input, Token}, id::{AdapterId, DeviceId, SurfaceId, Valid}, + present::Presentation, LabelHelpers, LifeGuard, Stored, DOWNLEVEL_WARNING_MESSAGE, }; @@ -12,7 +13,10 @@ use thiserror::Error; pub type RequestAdapterOptions = wgt::RequestAdapterOptions; type HalInstance = ::Instance; -type HalSurface = ::Surface; +pub struct HalSurface { + pub raw: A::Surface, + pub acquired_texture: Option, +} #[derive(Clone, Debug, Error)] #[error("Limit '{name}' value {requested} is better than allowed {allowed}")] @@ -124,7 +128,7 @@ impl Instance { let map = |(surface_backend, self_backend)| { unsafe { if let Some(suf) = surface_backend { - self_backend.as_ref().unwrap().destroy_surface(suf); + self_backend.as_ref().unwrap().destroy_surface(suf.raw); } } }; @@ -144,6 +148,7 @@ impl Instance { } pub struct Surface { + pub(crate) presentation: Option, #[cfg(vulkan)] pub vulkan: Option>, #[cfg(metal)] @@ -168,6 +173,38 @@ impl crate::hub::Resource for Surface { } } +impl Surface { + pub fn get_preferred_format( + &self, + adapter: &Adapter, + ) -> Result { + // Check the four formats mentioned in the WebGPU spec. + // Also, prefer sRGB over linear as it is better in + // representing perceived colors. + let preferred_formats = [ + wgt::TextureFormat::Bgra8UnormSrgb, + wgt::TextureFormat::Rgba8UnormSrgb, + wgt::TextureFormat::Bgra8Unorm, + wgt::TextureFormat::Rgba8Unorm, + ]; + + let suf = A::get_surface(self); + let caps = unsafe { + adapter + .raw + .adapter + .surface_capabilities(&suf.raw) + .ok_or(GetSurfacePreferredFormatError::UnsupportedQueueFamily)? + }; + + preferred_formats + .iter() + .cloned() + .find(|preferred| caps.formats.contains(preferred)) + .ok_or(GetSurfacePreferredFormatError::NotFound) + } +} + pub struct Adapter { pub(crate) raw: hal::ExposedAdapter, life_guard: LifeGuard, @@ -181,41 +218,9 @@ impl Adapter { } } - pub fn is_surface_supported(&self, surface: &mut Surface) -> bool { - unsafe { - self.raw - .adapter - .surface_capabilities(A::get_surface_mut(surface)) - } - .is_some() - } - - pub fn get_swap_chain_preferred_format( - &self, - surface: &mut Surface, - ) -> Result { - // Check the four formats mentioned in the WebGPU spec. - // Also, prefer sRGB over linear as it is better in - // representing perceived colors. - let preferred_formats = [ - wgt::TextureFormat::Bgra8UnormSrgb, - wgt::TextureFormat::Rgba8UnormSrgb, - wgt::TextureFormat::Bgra8Unorm, - wgt::TextureFormat::Rgba8Unorm, - ]; - - let caps = unsafe { - self.raw - .adapter - .surface_capabilities(A::get_surface_mut(surface)) - .ok_or(GetSwapChainPreferredFormatError::UnsupportedQueueFamily)? - }; - - preferred_formats - .iter() - .cloned() - .find(|preferred| caps.formats.contains(preferred)) - .ok_or(GetSwapChainPreferredFormatError::NotFound) + pub fn is_surface_supported(&self, surface: &Surface) -> bool { + let suf = A::get_surface(surface); + unsafe { self.raw.adapter.surface_capabilities(&suf.raw) }.is_some() } pub(crate) fn get_texture_format_features( @@ -362,7 +367,7 @@ pub enum IsSurfaceSupportedError { } #[derive(Clone, Debug, Error)] -pub enum GetSwapChainPreferredFormatError { +pub enum GetSurfacePreferredFormatError { #[error("no suitable format found")] NotFound, #[error("invalid adapter")] @@ -433,29 +438,39 @@ impl Global { ) -> SurfaceId { profiling::scope!("create_surface", "Instance"); - let surface = unsafe { - backends_map! { - let map = |inst| { - inst - .as_ref() - .and_then(|inst| inst.create_surface(handle).map_err(|e| { + //Note: using adummy argument to work around the following error: + //> cannot provide explicit generic arguments when `impl Trait` is used in argument position + fn init( + _: A, + inst: &Option, + handle: &impl raw_window_handle::HasRawWindowHandle, + ) -> Option> { + inst.as_ref().and_then(|inst| unsafe { + match inst.create_surface(handle) { + Ok(raw) => Some(HalSurface { + raw, + acquired_texture: None, + }), + Err(e) => { log::warn!("Error: {:?}", e); - }).ok()) - }; - - Surface { - #[cfg(vulkan)] - vulkan: map(&self.instance.vulkan), - #[cfg(metal)] - metal: map(&self.instance.metal), - #[cfg(dx12)] - dx12: map(&self.instance.dx12), - #[cfg(dx11)] - dx11: map(&self.instance.dx11), - #[cfg(gl)] - gl: map(&self.instance.gl), + None + } } - } + }) + } + + let surface = Surface { + presentation: None, + #[cfg(vulkan)] + vulkan: init(hal::api::Vulkan, &self.instance.vulkan, handle), + #[cfg(metal)] + metal: init(hal::api::Metal, &self.instance.metal, handle), + #[cfg(dx12)] + dx12: init(hal::api::Dx12, &self.instance.dx12, handle), + #[cfg(dx11)] + dx11: init(hal::api::Dx11, &self.instance.dx11, handle), + #[cfg(gl)] + gl: init(hal::api::Gles, &self.instance.gl, handle), }; let mut token = Token::root(); @@ -472,10 +487,14 @@ impl Global { profiling::scope!("create_surface_metal", "Instance"); let surface = Surface { - metal: self.instance.metal.as_ref().map(|inst| { - // we don't want to link to metal-rs for this - #[allow(clippy::transmute_ptr_to_ref)] - inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) }) + presentation: None, + metal: self.instance.metal.as_ref().map(|inst| HalSurface { + raw: { + // we don't want to link to metal-rs for this + #[allow(clippy::transmute_ptr_to_ref)] + inst.create_surface_from_layer(unsafe { std::mem::transmute(layer) }) + }, + acquired_texture: None, }), }; @@ -563,7 +582,7 @@ impl Global { let mut adapters = unsafe { inst.enumerate_adapters() }; if let Some(surface_backend) = compatible_surface.and_then(surface_backend) { adapters.retain(|exposed| unsafe { - exposed.adapter.surface_capabilities(surface_backend).is_some() + exposed.adapter.surface_capabilities(&surface_backend.raw).is_some() }); } device_types.extend(adapters.iter().map(|ad| ad.info.device_type)); diff --git a/wgpu-core/src/lib.rs b/wgpu-core/src/lib.rs index 37bc00f8e8..a56840efaa 100644 --- a/wgpu-core/src/lib.rs +++ b/wgpu-core/src/lib.rs @@ -40,8 +40,8 @@ pub mod id; pub mod instance; mod memory_init_tracker; pub mod pipeline; +pub mod present; pub mod resource; -pub mod swap_chain; mod track; mod validation; diff --git a/wgpu-core/src/macros.rs b/wgpu-core/src/macros.rs index 8b662ddc4f..a8b6cd0eb0 100644 --- a/wgpu-core/src/macros.rs +++ b/wgpu-core/src/macros.rs @@ -30,26 +30,6 @@ macro_rules! backends_map { } )* }; - - // a struct constructor with one field per backend with mapped data - ( - let map = |$backend:pat| $map:block; - $Struct:ident { - $( - #[cfg($backend_cfg:meta)] $ident:ident : map($expr:expr), - )* - } - ) => { - $Struct { - $( - #[cfg($backend_cfg)] - $ident: { - let $backend = $expr; - $map - }, - )* - } - }; } #[test] @@ -69,13 +49,16 @@ fn test_backend_macro() { } // test struct construction - let test_foo: Foo = backends_map! { - let map = |init| { init - 100 }; + let test_foo: Foo = { Foo { - #[cfg(vulkan)] vulkan: map(101), - #[cfg(metal)] metal: map(102), - #[cfg(dx12)] dx12: map(103), - #[cfg(dx11)] dx11: map(104), + #[cfg(vulkan)] + vulkan: 101, + #[cfg(metal)] + metal: 102, + #[cfg(dx12)] + dx12: 103, + #[cfg(dx11)] + dx11: 104, } }; diff --git a/wgpu-core/src/swap_chain.rs b/wgpu-core/src/present.rs similarity index 57% rename from wgpu-core/src/swap_chain.rs rename to wgpu-core/src/present.rs index 7919247d7f..61bd630e77 100644 --- a/wgpu-core/src/swap_chain.rs +++ b/wgpu-core/src/present.rs @@ -1,31 +1,11 @@ -/*! Swap chain management. +/*! Presentation. ## Lifecycle - At the low level, the swap chain is using the new simplified model of gfx-rs. - - A swap chain is a separate object that is backend-dependent but shares the index with - the parent surface, which is backend-independent. This ensures a 1:1 correspondence - between them. - - `get_next_image()` requests a new image from the surface. It becomes a part of - `TextureViewInner::SwapChain` of the resulted view. The view is registered in the HUB - but not in the device tracker. - - The only operation allowed on the view is to be either a color or a resolve attachment. - It can only be used in one command buffer, which needs to be submitted before presenting. - Command buffer tracker knows about the view, but only for the duration of recording. - The view ID is erased from it at the end, so that it's not merged into the device tracker. - When a swapchain view is used in `begin_render_pass()`, we assume the start and end image layouts purely based on whether or not this view was used in this command buffer before. It always starts with `Uninitialized` and ends with `Present`, so that no barriers are needed when we need to actually present it. - - In `queue_submit()` we make sure to signal the semaphore whenever we render to a swap - chain view. - - In `present()` we return the swap chain image back and wait on the semaphore. !*/ #[cfg(feature = "trace")] @@ -33,62 +13,52 @@ use crate::device::trace::Action; use crate::{ device::DeviceError, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Input, Token}, - id::{DeviceId, SwapChainId, TextureViewId, Valid}, + id::{DeviceId, SurfaceId, TextureViewId, Valid}, resource, track::TextureSelector, LifeGuard, Stored, SubmissionIndex, }; use hal::{Device as _, Queue as _, Surface as _}; -use std::{borrow::Borrow, marker::PhantomData}; +use std::borrow::Borrow; use thiserror::Error; -use wgt::SwapChainStatus as Status; +use wgt::SurfaceStatus as Status; const FRAME_TIMEOUT_MS: u32 = 1000; pub const DESIRED_NUM_FRAMES: u32 = 3; #[derive(Debug)] -pub struct SwapChain { - pub(crate) life_guard: LifeGuard, +pub(crate) struct Presentation { pub(crate) device_id: Stored, - pub(crate) desc: wgt::SwapChainDescriptor, + pub(crate) config: wgt::SurfaceConfiguration, pub(crate) num_frames: u32, - pub(crate) acquired_texture: Option<(Stored, A::SurfaceTexture)>, + pub(crate) acquired_texture: Option>, pub(crate) active_submission_index: SubmissionIndex, - pub(crate) marker: PhantomData, -} - -impl crate::hub::Resource for SwapChain { - const TYPE: &'static str = "SwapChain"; - - fn life_guard(&self) -> &LifeGuard { - &self.life_guard - } } #[derive(Clone, Debug, Error)] -pub enum SwapChainError { - #[error("swap chain is invalid")] +pub enum SurfaceError { + #[error("surface is invalid")] Invalid, - #[error("parent surface is invalid")] - InvalidSurface, + #[error("surface is not configured for presentation")] + NotConfigured, #[error(transparent)] Device(#[from] DeviceError), - #[error("swap chain image is already acquired")] + #[error("surface image is already acquired")] AlreadyAcquired, #[error("acquired frame is still referenced")] StillReferenced, } #[derive(Clone, Debug, Error)] -pub enum CreateSwapChainError { +pub enum ConfigureSurfaceError { #[error(transparent)] Device(#[from] DeviceError), #[error("invalid surface")] InvalidSurface, - #[error("`SwapChainOutput` must be dropped before a new `SwapChain` is made")] - SwapChainOutputExists, - #[error("Both `SwapChain` width and height must be non-zero. Wait to recreate the `SwapChain` until the window has non-zero area.")] + #[error("`SurfaceOutput` must be dropped before a new `Surface` is made")] + PreviousOutputExists, + #[error("Both `Surface` width and height must be non-zero. Wait to recreate the `Surface` until the window has non-zero area.")] ZeroArea, #[error("surface does not support the adapter's queue family")] UnsupportedQueueFamily, @@ -103,17 +73,17 @@ pub enum CreateSwapChainError { #[repr(C)] #[derive(Debug)] -pub struct SwapChainOutput { +pub struct SurfaceOutput { pub status: Status, pub view_id: Option, } impl Global { - pub fn swap_chain_get_current_texture_view( + pub fn surface_get_current_texture_view( &self, - swap_chain_id: SwapChainId, + surface_id: SurfaceId, view_id_in: Input, - ) -> Result { + ) -> Result { profiling::scope!("get_next_texture", "SwapChain"); let hub = A::hub(self); @@ -122,25 +92,26 @@ impl Global { let (mut surface_guard, mut token) = self.surfaces.write(&mut token); let surface = surface_guard - .get_mut(swap_chain_id.to_surface_id()) - .map_err(|_| SwapChainError::InvalidSurface)?; + .get_mut(surface_id) + .map_err(|_| SurfaceError::Invalid)?; let (device_guard, mut token) = hub.devices.read(&mut token); - let (mut swap_chain_guard, mut token) = hub.swap_chains.write(&mut token); - let sc = swap_chain_guard - .get_mut(swap_chain_id) - .map_err(|_| SwapChainError::Invalid)?; - let device = &device_guard[sc.device_id.value]; + let device = match surface.presentation { + Some(ref present) => &device_guard[present.device_id.value], + None => return Err(SurfaceError::NotConfigured), + }; + #[cfg(feature = "trace")] if let Some(ref trace) = device.trace { - trace.lock().add(Action::GetSwapChainTexture { + trace.lock().add(Action::GetSurfaceTexture { id: fid.id(), - parent_id: swap_chain_id, + parent_id: surface_id, }); } + let config = surface.presentation.as_ref().unwrap().config.clone(); let suf = A::get_surface_mut(surface); - let (texture, status) = match unsafe { suf.acquire_texture(FRAME_TIMEOUT_MS) } { + let (texture, status) = match unsafe { suf.raw.acquire_texture(FRAME_TIMEOUT_MS) } { Ok(Some(ast)) => { let status = if ast.suboptimal { Status::Suboptimal @@ -168,7 +139,7 @@ impl Global { let hal_desc = hal::TextureViewDescriptor { label: Some("_Frame"), - format: sc.desc.format, + format: config.format, dimension: wgt::TextureViewDimension::D2, usage: hal::TextureUses::COLOR_TARGET, range: wgt::ImageSubresourceRange::default(), @@ -184,12 +155,9 @@ impl Global { }; let view = resource::TextureView { raw, - source: resource::TextureViewSource::SwapChain(Stored { - value: Valid(swap_chain_id), - ref_count: sc.life_guard.add_ref(), - }), + source: resource::TextureViewSource::Surface(Valid(surface_id)), desc: resource::HalTextureViewDescriptor { - format: sc.desc.format, + format: config.format, dimension: wgt::TextureViewDimension::D2, range: wgt::ImageSubresourceRange::default(), }, @@ -199,8 +167,8 @@ impl Global { filterable: false, }, extent: wgt::Extent3d { - width: sc.desc.width, - height: sc.desc.height, + width: config.width, + height: config.height, depth_or_array_layers: 1, }, samples: 1, @@ -215,30 +183,29 @@ impl Global { let ref_count = view.life_guard.add_ref(); let id = fid.assign(view, &mut token); - if sc.acquired_texture.is_some() { - return Err(SwapChainError::AlreadyAcquired); - } + suf.acquired_texture = Some(suf_texture); - sc.acquired_texture = Some(( - Stored { - value: id, - ref_count, - }, - suf_texture, - )); + let present = surface.presentation.as_mut().unwrap(); + if present.acquired_texture.is_some() { + return Err(SurfaceError::AlreadyAcquired); + } + present.acquired_texture = Some(Stored { + value: id, + ref_count, + }); Some(id.0) } None => None, }; - Ok(SwapChainOutput { status, view_id }) + Ok(SurfaceOutput { status, view_id }) } - pub fn swap_chain_present( + pub fn surface_present( &self, - swap_chain_id: SwapChainId, - ) -> Result { + surface_id: SurfaceId, + ) -> Result { profiling::scope!("present", "SwapChain"); let hub = A::hub(self); @@ -246,40 +213,40 @@ impl Global { let (mut surface_guard, mut token) = self.surfaces.write(&mut token); let surface = surface_guard - .get_mut(swap_chain_id.to_surface_id()) - .map_err(|_| SwapChainError::InvalidSurface)?; + .get_mut(surface_id) + .map_err(|_| SurfaceError::Invalid)?; let (mut device_guard, mut token) = hub.devices.write(&mut token); - let (mut swap_chain_guard, _) = hub.swap_chains.write(&mut token); - let sc = swap_chain_guard - .get_mut(swap_chain_id) - .map_err(|_| SwapChainError::Invalid)?; - let device = &mut device_guard[sc.device_id.value]; + + let present = match surface.presentation { + Some(ref mut present) => present, + None => return Err(SurfaceError::NotConfigured), + }; + + let device = &mut device_guard[present.device_id.value]; #[cfg(feature = "trace")] if let Some(ref trace) = device.trace { - trace.lock().add(Action::PresentSwapChain(swap_chain_id)); + trace.lock().add(Action::Present(surface_id)); } - let suf_texture = { - let (view_id, suf_texture) = sc + let result = { + let view_id = present .acquired_texture .take() - .ok_or(SwapChainError::AlreadyAcquired)?; + .ok_or(SurfaceError::AlreadyAcquired)?; + let suf = A::get_surface_mut(surface); + let suf_texture = suf.acquired_texture.take().unwrap(); - drop(swap_chain_guard); + let result = unsafe { device.queue.present(&mut suf.raw, suf_texture) }; + + drop(surface_guard); let (view, _) = hub.texture_views.unregister(view_id.value.0, &mut token); if let Some(view) = view { device.schedule_rogue_texture_view_for_destruction(view_id.value, view, &mut token); } - suf_texture - }; - - let result = unsafe { - device - .queue - .present(A::get_surface_mut(surface), suf_texture) + result }; log::debug!("Presented. End of Frame"); @@ -288,11 +255,11 @@ impl Global { Ok(()) => Ok(Status::Good), Err(err) => match err { hal::SurfaceError::Lost => Ok(Status::Lost), - hal::SurfaceError::Device(err) => Err(SwapChainError::from(DeviceError::from(err))), + hal::SurfaceError::Device(err) => Err(SurfaceError::from(DeviceError::from(err))), hal::SurfaceError::Outdated => Ok(Status::Outdated), hal::SurfaceError::Other(msg) => { log::error!("acquire error: {}", msg); - Err(SwapChainError::InvalidSurface) + Err(SurfaceError::Invalid) } }, } diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index c3bb29fec0..4cc92b4453 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -1,7 +1,7 @@ use crate::{ device::{DeviceError, HostMap, MissingFeatures}, hub::Resource, - id::{DeviceId, SwapChainId, TextureId}, + id::{DeviceId, SurfaceId, TextureId, Valid}, memory_init_tracker::MemoryInitTracker, track::{TextureSelector, DUMMY_SELECTOR}, validation::MissingBufferUsageError, @@ -240,7 +240,7 @@ pub struct TextureViewDescriptor<'a> { #[derive(Debug)] pub(crate) enum TextureViewSource { Native(Stored), - SwapChain(Stored), + Surface(Valid), } #[derive(Debug)] @@ -311,8 +311,8 @@ pub enum CreateTextureViewError { #[derive(Clone, Debug, Error)] pub enum TextureViewDestroyError { - #[error("cannot destroy swap chain image")] - SwapChainImage, + #[error("cannot destroy a surface image")] + SurfaceImage, } impl Resource for TextureView { diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 871d3ca0b6..5d6376c9de 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2366,12 +2366,12 @@ bitflags::bitflags! { } } -/// Describes a [`SwapChain`]. +/// Configures a [`Surface`] for presentation. #[repr(C)] #[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] -pub struct SwapChainDescriptor { +pub struct SurfaceConfiguration { /// The usage of the swap chain. The only supported usage is `RENDER_ATTACHMENT`. pub usage: TextureUsages, /// The texture format of the swap chain. The only formats that are guaranteed are @@ -2386,10 +2386,10 @@ pub struct SwapChainDescriptor { pub present_mode: PresentMode, } -/// Status of the recieved swapchain image. +/// Status of the recieved surface image. #[repr(C)] #[derive(Debug)] -pub enum SwapChainStatus { +pub enum SurfaceStatus { /// No issues. Good, /// The swap chain is operational, but it does no longer perfectly diff --git a/wgpu/examples/boids/main.rs b/wgpu/examples/boids/main.rs index f90a453b81..331e63c819 100644 --- a/wgpu/examples/boids/main.rs +++ b/wgpu/examples/boids/main.rs @@ -33,7 +33,7 @@ struct Example { impl framework::Example for Example { /// constructs initial instance of Example struct fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, _queue: &wgpu::Queue, @@ -143,7 +143,7 @@ impl framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &draw_shader, entry_point: "main", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState::default(), depth_stencil: None, @@ -246,7 +246,7 @@ impl framework::Example for Example { /// resize is called on WindowEvent::Resized events fn resize( &mut self, - _sc_desc: &wgpu::SwapChainDescriptor, + _sc_desc: &wgpu::SurfaceConfiguration, _device: &wgpu::Device, _queue: &wgpu::Queue, ) { diff --git a/wgpu/examples/bunnymark/main.rs b/wgpu/examples/bunnymark/main.rs index ddc346b7fe..2677c88d5b 100644 --- a/wgpu/examples/bunnymark/main.rs +++ b/wgpu/examples/bunnymark/main.rs @@ -39,7 +39,7 @@ struct Example { impl framework::Example for Example { fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, queue: &wgpu::Queue, @@ -118,7 +118,7 @@ impl framework::Example for Example { module: &shader, entry_point: "fs_main", targets: &[wgpu::ColorTargetState { - format: sc_desc.format, + format: config.format, blend: Some(wgpu::BlendState::ALPHA_BLENDING), write_mask: wgpu::ColorWrites::default(), }], @@ -179,9 +179,9 @@ impl framework::Example for Example { let globals = Globals { mvp: cgmath::ortho( 0.0, - sc_desc.width as f32, + config.width as f32, 0.0, - sc_desc.height as f32, + config.height as f32, -1.0, 1.0, ) @@ -239,7 +239,7 @@ impl framework::Example for Example { local_group, bunnies: Vec::new(), local_buffer, - extent: [sc_desc.width, sc_desc.height], + extent: [config.width, config.height], } } @@ -275,7 +275,7 @@ impl framework::Example for Example { fn resize( &mut self, - _sc_desc: &wgpu::SwapChainDescriptor, + _sc_desc: &wgpu::SurfaceConfiguration, _device: &wgpu::Device, _queue: &wgpu::Queue, ) { diff --git a/wgpu/examples/conservative-raster/main.rs b/wgpu/examples/conservative-raster/main.rs index 82ea118837..09773bdc6f 100644 --- a/wgpu/examples/conservative-raster/main.rs +++ b/wgpu/examples/conservative-raster/main.rs @@ -18,7 +18,7 @@ struct Example { impl Example { fn create_low_res_target( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, bind_group_layout_upscale: &wgpu::BindGroupLayout, ) -> (wgpu::TextureView, wgpu::BindGroup) { @@ -26,8 +26,8 @@ impl Example { .create_texture(&wgpu::TextureDescriptor { label: Some("Low Resolution Target"), size: wgpu::Extent3d { - width: sc_desc.width / 16, - height: sc_desc.width / 16, + width: config.width / 16, + height: config.width / 16, depth_or_array_layers: 1, }, mip_level_count: 1, @@ -73,7 +73,7 @@ impl framework::Example for Example { wgpu::Features::NON_FILL_POLYGON_MODE } fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, _queue: &wgpu::Queue, @@ -150,7 +150,7 @@ impl framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &shader_triangle_and_lines, entry_point: "fs_main_white", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState { polygon_mode: wgpu::PolygonMode::Line, @@ -213,7 +213,7 @@ impl framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState::default(), depth_stencil: None, @@ -224,7 +224,7 @@ impl framework::Example for Example { }; let (low_res_target, bind_group_upscale) = - Self::create_low_res_target(sc_desc, device, &bind_group_layout_upscale); + Self::create_low_res_target(config, device, &bind_group_layout_upscale); Self { low_res_target, @@ -240,12 +240,12 @@ impl framework::Example for Example { fn resize( &mut self, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, _queue: &wgpu::Queue, ) { let (low_res_target, bind_group_upscale) = - Self::create_low_res_target(sc_desc, device, &self.bind_group_layout_upscale); + Self::create_low_res_target(config, device, &self.bind_group_layout_upscale); self.low_res_target = low_res_target; self.bind_group_upscale = bind_group_upscale; } diff --git a/wgpu/examples/cube/main.rs b/wgpu/examples/cube/main.rs index e15dd44e63..a04df18d6b 100644 --- a/wgpu/examples/cube/main.rs +++ b/wgpu/examples/cube/main.rs @@ -112,7 +112,7 @@ impl framework::Example for Example { } fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, queue: &wgpu::Queue, @@ -195,7 +195,7 @@ impl framework::Example for Example { ); // Create other resources - let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); + let mx_total = Self::generate_matrix(config.width as f32 / config.height as f32); let mx_ref: &[f32; 16] = mx_total.as_ref(); let uniform_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Uniform Buffer"), @@ -252,7 +252,7 @@ impl framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState { cull_mode: Some(wgpu::Face::Back), @@ -278,7 +278,7 @@ impl framework::Example for Example { module: &shader, entry_point: "fs_wire", targets: &[wgpu::ColorTargetState { - format: sc_desc.format, + format: config.format, blend: Some(wgpu::BlendState { color: wgpu::BlendComponent { operation: wgpu::BlendOperation::Add, @@ -322,11 +322,11 @@ impl framework::Example for Example { fn resize( &mut self, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _device: &wgpu::Device, queue: &wgpu::Queue, ) { - let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); + let mx_total = Self::generate_matrix(config.width as f32 / config.height as f32); let mx_ref: &[f32; 16] = mx_total.as_ref(); queue.write_buffer(&self.uniform_buf, 0, bytemuck::cast_slice(mx_ref)); } diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index a45308ebbd..a2c01dc4a7 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -44,14 +44,14 @@ pub trait Example: 'static + Sized { wgpu::Limits::downlevel_defaults() // These downlevel limits will allow the code to run on all possible hardware } fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, adapter: &wgpu::Adapter, device: &wgpu::Device, queue: &wgpu::Queue, ) -> Self; fn resize( &mut self, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, queue: &wgpu::Queue, ); @@ -137,7 +137,7 @@ async fn setup(title: &str) -> Setup { required_features - adapter_features ); - // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain. + // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the surface. let needed_limits = E::required_limits().using_resolution(adapter.limits()); let trace_dir = std::env::var("WGPU_TRACE"); @@ -178,17 +178,17 @@ fn start( }: Setup, ) { let spawner = Spawner::new(); - let mut sc_desc = wgpu::SwapChainDescriptor { + let mut config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: adapter.get_swap_chain_preferred_format(&surface).unwrap(), + format: surface.get_preferred_format(&adapter).unwrap(), width: size.width, height: size.height, present_mode: wgpu::PresentMode::Mailbox, }; - let mut swap_chain = device.create_swap_chain(&surface, &sc_desc); + surface.configure(&device, &config); log::info!("Initializing the example..."); - let mut example = E::init(&sc_desc, &adapter, &device, &queue); + let mut example = E::init(&config, &adapter, &device, &queue); #[cfg(not(target_arch = "wasm32"))] let mut last_update_inst = Instant::now(); @@ -237,10 +237,10 @@ fn start( .. } => { log::info!("Resizing to {:?}", size); - sc_desc.width = size.width.max(1); - sc_desc.height = size.height.max(1); - example.resize(&sc_desc, &device, &queue); - swap_chain = device.create_swap_chain(&surface, &sc_desc); + config.width = size.width.max(1); + config.height = size.height.max(1); + example.resize(&config, &device, &queue); + surface.configure(&device, &config); } event::Event::WindowEvent { event, .. } => match event { WindowEvent::KeyboardInput { @@ -287,13 +287,13 @@ fn start( } } - let frame = match swap_chain.get_current_frame() { + let frame = match surface.get_current_frame() { Ok(frame) => frame, Err(_) => { - swap_chain = device.create_swap_chain(&surface, &sc_desc); - swap_chain + surface.configure(&device, &config); + surface .get_current_frame() - .expect("Failed to acquire next swap chain texture!") + .expect("Failed to acquire next surface texture!") } }; @@ -430,7 +430,7 @@ pub fn test(mut params: FrameworkRefTest) { }); let mut example = E::init( - &wgpu::SwapChainDescriptor { + &wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: wgpu::TextureFormat::Rgba8UnormSrgb, width: params.width, diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs index cbd20f508c..bfc20da981 100644 --- a/wgpu/examples/hello-triangle/main.rs +++ b/wgpu/examples/hello-triangle/main.rs @@ -44,7 +44,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) { push_constant_ranges: &[], }); - let swapchain_format = adapter.get_swap_chain_preferred_format(&surface).unwrap(); + let swapchain_format = surface.get_preferred_format(&adapter).unwrap(); let render_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: None, @@ -64,7 +64,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) { multisample: wgpu::MultisampleState::default(), }); - let mut sc_desc = wgpu::SwapChainDescriptor { + let mut config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, format: swapchain_format, width: size.width, @@ -72,7 +72,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) { present_mode: wgpu::PresentMode::Mailbox, }; - let mut swap_chain = device.create_swap_chain(&surface, &sc_desc); + surface.configure(&device, &config); event_loop.run(move |event, _, control_flow| { // Have the closure take ownership of the resources. @@ -86,13 +86,13 @@ async fn run(event_loop: EventLoop<()>, window: Window) { event: WindowEvent::Resized(size), .. } => { - // Recreate the swap chain with the new size - sc_desc.width = size.width; - sc_desc.height = size.height; - swap_chain = device.create_swap_chain(&surface, &sc_desc); + // Reconfigure the surface with the new size + config.width = size.width; + config.height = size.height; + surface.configure(&device, &config); } Event::RedrawRequested(_) => { - let frame = swap_chain + let frame = surface .get_current_frame() .expect("Failed to acquire next swap chain texture") .output; diff --git a/wgpu/examples/hello-windows/main.rs b/wgpu/examples/hello-windows/main.rs index 116cdd44de..ad10c5b5d7 100644 --- a/wgpu/examples/hello-windows/main.rs +++ b/wgpu/examples/hello-windows/main.rs @@ -13,8 +13,7 @@ struct ViewportDesc { struct Viewport { desc: ViewportDesc, - sc_desc: wgpu::SwapChainDescriptor, - swap_chain: wgpu::SwapChain, + config: wgpu::SurfaceConfiguration, } impl ViewportDesc { @@ -30,34 +29,29 @@ impl ViewportDesc { fn build(self, adapter: &wgpu::Adapter, device: &wgpu::Device) -> Viewport { let size = self.window.inner_size(); - let sc_desc = wgpu::SwapChainDescriptor { + let config = wgpu::SurfaceConfiguration { usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - format: adapter - .get_swap_chain_preferred_format(&self.surface) - .unwrap(), + format: self.surface.get_preferred_format(adapter).unwrap(), width: size.width, height: size.height, present_mode: wgpu::PresentMode::Fifo, }; - let swap_chain = device.create_swap_chain(&self.surface, &sc_desc); + self.surface.configure(device, &config); - Viewport { - desc: self, - sc_desc, - swap_chain, - } + Viewport { desc: self, config } } } impl Viewport { fn resize(&mut self, device: &wgpu::Device, size: winit::dpi::PhysicalSize) { - self.sc_desc.width = size.width; - self.sc_desc.height = size.height; - self.swap_chain = device.create_swap_chain(&self.desc.surface, &self.sc_desc); + self.config.width = size.width; + self.config.height = size.height; + self.desc.surface.configure(device, &self.config); } - fn get_current_frame(&mut self) -> wgpu::SwapChainTexture { - self.swap_chain + fn get_current_frame(&mut self) -> wgpu::SurfaceTexture { + self.desc + .surface .get_current_frame() .expect("Failed to acquire next swap chain texture") .output diff --git a/wgpu/examples/mipmap/main.rs b/wgpu/examples/mipmap/main.rs index ed3416915d..476f210ac0 100644 --- a/wgpu/examples/mipmap/main.rs +++ b/wgpu/examples/mipmap/main.rs @@ -203,7 +203,7 @@ impl framework::Example for Example { } fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, queue: &wgpu::Queue, @@ -262,7 +262,7 @@ impl framework::Example for Example { mipmap_filter: wgpu::FilterMode::Linear, ..Default::default() }); - let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); + let mx_total = Self::generate_matrix(config.width as f32 / config.height as f32); let mx_ref: &[f32; 16] = mx_total.as_ref(); let uniform_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Uniform Buffer"), @@ -287,7 +287,7 @@ impl framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::TriangleStrip, @@ -425,11 +425,11 @@ impl framework::Example for Example { fn resize( &mut self, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _device: &wgpu::Device, queue: &wgpu::Queue, ) { - let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); + let mx_total = Self::generate_matrix(config.width as f32 / config.height as f32); let mx_ref: &[f32; 16] = mx_total.as_ref(); queue.write_buffer(&self.uniform_buf, 0, bytemuck::cast_slice(mx_ref)); } diff --git a/wgpu/examples/msaa-line/main.rs b/wgpu/examples/msaa-line/main.rs index c629d2d2d3..9d95bcedd1 100644 --- a/wgpu/examples/msaa-line/main.rs +++ b/wgpu/examples/msaa-line/main.rs @@ -31,13 +31,13 @@ struct Example { vertex_count: u32, sample_count: u32, rebuild_bundle: bool, - sc_desc: wgpu::SwapChainDescriptor, + config: wgpu::SurfaceConfiguration, } impl Example { fn create_bundle( device: &wgpu::Device, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, shader: &wgpu::ShaderModule, pipeline_layout: &wgpu::PipelineLayout, sample_count: u32, @@ -60,7 +60,7 @@ impl Example { fragment: Some(wgpu::FragmentState { module: shader, entry_point: "fs_main", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState { topology: wgpu::PrimitiveTopology::LineList, @@ -76,7 +76,7 @@ impl Example { let mut encoder = device.create_render_bundle_encoder(&wgpu::RenderBundleEncoderDescriptor { label: None, - color_formats: &[sc_desc.format], + color_formats: &[config.format], depth_stencil: None, sample_count, }); @@ -90,12 +90,12 @@ impl Example { fn create_multisampled_framebuffer( device: &wgpu::Device, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, sample_count: u32, ) -> wgpu::TextureView { let multisampled_texture_extent = wgpu::Extent3d { - width: sc_desc.width, - height: sc_desc.height, + width: config.width, + height: config.height, depth_or_array_layers: 1, }; let multisampled_frame_descriptor = &wgpu::TextureDescriptor { @@ -103,7 +103,7 @@ impl Example { mip_level_count: 1, sample_count, dimension: wgpu::TextureDimension::D2, - format: sc_desc.format, + format: config.format, usage: wgpu::TextureUsages::RENDER_ATTACHMENT, label: None, }; @@ -116,7 +116,7 @@ impl Example { impl framework::Example for Example { fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, _queue: &wgpu::Queue, @@ -136,7 +136,7 @@ impl framework::Example for Example { }); let multisampled_framebuffer = - Example::create_multisampled_framebuffer(device, sc_desc, sample_count); + Example::create_multisampled_framebuffer(device, config, sample_count); let mut vertex_data = vec![]; @@ -163,7 +163,7 @@ impl framework::Example for Example { let bundle = Example::create_bundle( device, - sc_desc, + config, &shader, &pipeline_layout, sample_count, @@ -180,7 +180,7 @@ impl framework::Example for Example { vertex_count, sample_count, rebuild_bundle: false, - sc_desc: sc_desc.clone(), + config: config.clone(), } } @@ -214,13 +214,13 @@ impl framework::Example for Example { fn resize( &mut self, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, _queue: &wgpu::Queue, ) { - self.sc_desc = sc_desc.clone(); + self.config = config.clone(); self.multisampled_framebuffer = - Example::create_multisampled_framebuffer(device, sc_desc, self.sample_count); + Example::create_multisampled_framebuffer(device, config, self.sample_count); } fn render( @@ -233,7 +233,7 @@ impl framework::Example for Example { if self.rebuild_bundle { self.bundle = Example::create_bundle( device, - &self.sc_desc, + &self.config, &self.shader, &self.pipeline_layout, self.sample_count, @@ -241,7 +241,7 @@ impl framework::Example for Example { self.vertex_count, ); self.multisampled_framebuffer = - Example::create_multisampled_framebuffer(device, &self.sc_desc, self.sample_count); + Example::create_multisampled_framebuffer(device, &self.config, self.sample_count); self.rebuild_bundle = false; } diff --git a/wgpu/examples/shadow/main.rs b/wgpu/examples/shadow/main.rs index 7896d6a433..ecbae99d0f 100644 --- a/wgpu/examples/shadow/main.rs +++ b/wgpu/examples/shadow/main.rs @@ -187,13 +187,13 @@ impl Example { } fn create_depth_texture( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, ) -> wgpu::TextureView { let depth_texture = device.create_texture(&wgpu::TextureDescriptor { size: wgpu::Extent3d { - width: sc_desc.width, - height: sc_desc.height, + width: config.width, + height: config.height, depth_or_array_layers: 1, }, mip_level_count: 1, @@ -214,7 +214,7 @@ impl framework::Example for Example { } fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, _queue: &wgpu::Queue, @@ -578,7 +578,7 @@ impl framework::Example for Example { push_constant_ranges: &[], }); - let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); + let mx_total = Self::generate_matrix(config.width as f32 / config.height as f32); let forward_uniforms = GlobalUniforms { proj: *mx_total.as_ref(), num_lights: [lights.len() as u32, 0, 0, 0], @@ -625,7 +625,7 @@ impl framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_main", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState { front_face: wgpu::FrontFace::Ccw, @@ -649,7 +649,7 @@ impl framework::Example for Example { } }; - let forward_depth = Self::create_depth_texture(sc_desc, device); + let forward_depth = Self::create_depth_texture(config, device); Example { entities, @@ -670,12 +670,12 @@ impl framework::Example for Example { fn resize( &mut self, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, queue: &wgpu::Queue, ) { // update view-projection matrix - let mx_total = Self::generate_matrix(sc_desc.width as f32 / sc_desc.height as f32); + let mx_total = Self::generate_matrix(config.width as f32 / config.height as f32); let mx_ref: &[f32; 16] = mx_total.as_ref(); queue.write_buffer( &self.forward_pass.uniform_buf, @@ -683,7 +683,7 @@ impl framework::Example for Example { bytemuck::cast_slice(mx_ref), ); - self.forward_depth = Self::create_depth_texture(sc_desc, device); + self.forward_depth = Self::create_depth_texture(config, device); } fn render( diff --git a/wgpu/examples/skybox/main.rs b/wgpu/examples/skybox/main.rs index d8e7e9377d..d4ff775313 100644 --- a/wgpu/examples/skybox/main.rs +++ b/wgpu/examples/skybox/main.rs @@ -73,13 +73,13 @@ impl Skybox { const DEPTH_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Depth24Plus; fn create_depth_texture( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, ) -> wgpu::TextureView { let depth_texture = device.create_texture(&wgpu::TextureDescriptor { size: wgpu::Extent3d { - width: sc_desc.width, - height: sc_desc.height, + width: config.width, + height: config.height, depth_or_array_layers: 1, }, mip_level_count: 1, @@ -102,7 +102,7 @@ impl framework::Example for Skybox { } fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, queue: &wgpu::Queue, @@ -182,7 +182,7 @@ impl framework::Example for Skybox { }); let camera = Camera { - screen_size: (sc_desc.width, sc_desc.height), + screen_size: (config.width, config.height), angle_xz: 0.2, angle_y: 0.2, dist: 30.0, @@ -212,7 +212,7 @@ impl framework::Example for Skybox { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_sky", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState { front_face: wgpu::FrontFace::Cw, @@ -242,7 +242,7 @@ impl framework::Example for Skybox { fragment: Some(wgpu::FragmentState { module: &shader, entry_point: "fs_entity", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState { front_face: wgpu::FrontFace::Cw, @@ -354,7 +354,7 @@ impl framework::Example for Skybox { label: None, }); - let depth_view = Self::create_depth_texture(sc_desc, device); + let depth_view = Self::create_depth_texture(config, device); Skybox { camera, @@ -383,12 +383,12 @@ impl framework::Example for Skybox { fn resize( &mut self, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, _queue: &wgpu::Queue, ) { - self.depth_view = Self::create_depth_texture(sc_desc, device); - self.camera.screen_size = (sc_desc.width, sc_desc.height); + self.depth_view = Self::create_depth_texture(config, device); + self.camera.screen_size = (config.width, config.height); } fn render( diff --git a/wgpu/examples/texture-arrays/main.rs b/wgpu/examples/texture-arrays/main.rs index dd86e6cf3f..b126b7a8ad 100644 --- a/wgpu/examples/texture-arrays/main.rs +++ b/wgpu/examples/texture-arrays/main.rs @@ -85,7 +85,7 @@ impl framework::Example for Example { } } fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, queue: &wgpu::Queue, @@ -245,7 +245,7 @@ impl framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &fs_module, entry_point: "main", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState { front_face: wgpu::FrontFace::Ccw, @@ -266,7 +266,7 @@ impl framework::Example for Example { } fn resize( &mut self, - _sc_desc: &wgpu::SwapChainDescriptor, + _sc_desc: &wgpu::SurfaceConfiguration, _device: &wgpu::Device, _queue: &wgpu::Queue, ) { diff --git a/wgpu/examples/water/main.rs b/wgpu/examples/water/main.rs index 997d13cb2b..81fc24497c 100644 --- a/wgpu/examples/water/main.rs +++ b/wgpu/examples/water/main.rs @@ -156,7 +156,7 @@ impl Example { /// Initializes Uniforms and textures. /// fn initialize_resources( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, queue: &wgpu::Queue, water_uniforms: &wgpu::Buffer, @@ -170,7 +170,7 @@ impl Example { terrain_normal, terrain_flipped, water, - } = Self::generate_uniforms(sc_desc.width, sc_desc.height); + } = Self::generate_uniforms(config.width, config.height); // Put the uniforms into buffers on the GPU queue.write_buffer( @@ -186,8 +186,8 @@ impl Example { queue.write_buffer(water_uniforms, 0, bytemuck::cast_slice(&[water])); let texture_extent = wgpu::Extent3d { - width: sc_desc.width, - height: sc_desc.height, + width: config.width, + height: config.height, depth_or_array_layers: 1, }; @@ -197,7 +197,7 @@ impl Example { mip_level_count: 1, sample_count: 1, dimension: wgpu::TextureDimension::D2, - format: sc_desc.format, + format: config.format, usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST | wgpu::TextureUsages::RENDER_ATTACHMENT, @@ -263,7 +263,7 @@ impl Example { impl framework::Example for Example { fn init( - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, _adapter: &wgpu::Adapter, device: &wgpu::Device, queue: &wgpu::Queue, @@ -460,7 +460,7 @@ impl framework::Example for Example { // This puts values behind what was laid out in the bind group layout. let (reflect_view, depth_buffer, water_bind_group) = Self::initialize_resources( - sc_desc, + config, device, queue, &water_uniform_buf, @@ -524,7 +524,7 @@ impl framework::Example for Example { // Describes how the colour will be interpolated // and assigned to the output attachment. targets: &[wgpu::ColorTargetState { - format: sc_desc.format, + format: config.format, blend: Some(wgpu::BlendState { color: wgpu::BlendComponent { src_factor: wgpu::BlendFactor::SrcAlpha, @@ -583,7 +583,7 @@ impl framework::Example for Example { fragment: Some(wgpu::FragmentState { module: &terrain_module, entry_point: "fs_main", - targets: &[sc_desc.format.into()], + targets: &[config.format.into()], }), primitive: wgpu::PrimitiveState { front_face: wgpu::FrontFace::Ccw, @@ -633,11 +633,11 @@ impl framework::Example for Example { fn resize( &mut self, - sc_desc: &wgpu::SwapChainDescriptor, + config: &wgpu::SurfaceConfiguration, device: &wgpu::Device, queue: &wgpu::Queue, ) { - if sc_desc.width == 0 && sc_desc.height == 0 { + if config.width == 0 && config.height == 0 { // Stop rendering altogether. self.active = None; return; @@ -647,7 +647,7 @@ impl framework::Example for Example { // Regenerate all of the buffers and textures. let (reflect_view, depth_buffer, water_bind_group) = Self::initialize_resources( - sc_desc, + config, device, queue, &self.water_uniform_buf, diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 8cf7784892..aa1ca12c3f 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -4,7 +4,7 @@ use crate::{ ComputePipelineDescriptor, DownlevelCapabilities, Features, Label, Limits, LoadOp, MapMode, Operations, PipelineLayoutDescriptor, RenderBundleEncoderDescriptor, RenderPipelineDescriptor, SamplerDescriptor, ShaderModuleDescriptor, ShaderModuleDescriptorSpirV, ShaderSource, - SwapChainStatus, TextureDescriptor, TextureFormat, TextureViewDescriptor, + SurfaceStatus, TextureDescriptor, TextureFormat, TextureViewDescriptor, }; use arrayvec::ArrayVec; @@ -675,6 +675,14 @@ fn map_pass_channel( } } +#[derive(Debug)] +pub struct Surface { + id: wgc::id::SurfaceId, + /// Configured device is needed to know which backend + /// code to execute when acquiring a new frame. + configured_device: Mutex>, +} + #[derive(Debug)] pub struct Device { id: wgc::id::DeviceId, @@ -722,10 +730,9 @@ impl crate::Context for Context { type CommandBufferId = wgc::id::CommandBufferId; type RenderBundleEncoderId = wgc::command::RenderBundleEncoder; type RenderBundleId = wgc::id::RenderBundleId; - type SurfaceId = wgc::id::SurfaceId; - type SwapChainId = wgc::id::SwapChainId; + type SurfaceId = Surface; - type SwapChainOutputDetail = SwapChainOutputDetail; + type SurfaceOutputDetail = SurfaceOutputDetail; type RequestAdapterFuture = Ready>; #[allow(clippy::type_complexity)] @@ -745,7 +752,10 @@ impl crate::Context for Context { &self, handle: &impl raw_window_handle::HasRawWindowHandle, ) -> Self::SurfaceId { - self.0.instance_create_surface(handle, PhantomData) + Surface { + id: self.0.instance_create_surface(handle, PhantomData), + configured_device: Mutex::new(None), + } } fn instance_request_adapter( @@ -755,7 +765,7 @@ impl crate::Context for Context { let id = self.0.request_adapter( &wgc::instance::RequestAdapterOptions { power_preference: options.power_preference, - compatible_surface: options.compatible_surface.map(|surface| surface.id), + compatible_surface: options.compatible_surface.map(|surface| surface.id.id), }, wgc::instance::AdapterInputs::Mask(wgt::Backends::all(), |_| PhantomData), ); @@ -801,26 +811,13 @@ impl crate::Context for Context { surface: &Self::SurfaceId, ) -> bool { let global = &self.0; - match wgc::gfx_select!(adapter => global.adapter_is_surface_supported(*adapter, *surface)) { + match wgc::gfx_select!(adapter => global.adapter_is_surface_supported(*adapter, surface.id)) + { Ok(result) => result, Err(err) => self.handle_error_fatal(err, "Adapter::is_surface_supported"), } } - fn adapter_get_swap_chain_preferred_format( - &self, - adapter: &Self::AdapterId, - surface: &Self::SurfaceId, - ) -> Option { - let global = &self.0; - match wgc::gfx_select!(adapter => global.adapter_get_swap_chain_preferred_format(*adapter, *surface)) - { - Ok(swap_chain_preferred_format) => Some(swap_chain_preferred_format), - Err(wgc::instance::GetSwapChainPreferredFormatError::UnsupportedQueueFamily) => None, - Err(err) => self.handle_error_fatal(err, "Adapter::get_swap_chain_preferred_format"), - } - } - fn adapter_features(&self, adapter: &Self::AdapterId) -> Features { let global = &self.0; match wgc::gfx_select!(*adapter => global.adapter_features(*adapter)) { @@ -866,6 +863,71 @@ impl crate::Context for Context { } } + fn surface_get_preferred_format( + &self, + surface: &Self::SurfaceId, + adapter: &Self::AdapterId, + ) -> Option { + let global = &self.0; + match wgc::gfx_select!(adapter => global.surface_get_preferred_format(surface.id, *adapter)) + { + Ok(format) => Some(format), + Err(wgc::instance::GetSurfacePreferredFormatError::UnsupportedQueueFamily) => None, + Err(err) => self.handle_error_fatal(err, "Surface::get_preferred_format"), + } + } + + fn surface_configure( + &self, + surface: &Self::SurfaceId, + device: &Self::DeviceId, + config: &wgt::SurfaceConfiguration, + ) { + let global = &self.0; + let error = + wgc::gfx_select!(device.id => global.surface_configure(surface.id, device.id, config)); + if let Some(e) = error { + self.handle_error_fatal(e, "Surface::configure"); + } else { + *surface.configured_device.lock() = Some(device.id); + } + } + + fn surface_get_current_texture_view( + &self, + surface: &Self::SurfaceId, + ) -> ( + Option, + SurfaceStatus, + Self::SurfaceOutputDetail, + ) { + let global = &self.0; + let device_id = surface + .configured_device + .lock() + .expect("Surface was not configured?"); + match wgc::gfx_select!( + device_id => global.surface_get_current_texture_view(surface.id, PhantomData) + ) { + Ok(wgc::present::SurfaceOutput { status, view_id }) => ( + view_id, + status, + SurfaceOutputDetail { + surface_id: surface.id, + }, + ), + Err(err) => self.handle_error_fatal(err, "Surface::get_current_texture_view"), + } + } + + fn surface_present(&self, view: &Self::TextureViewId, detail: &Self::SurfaceOutputDetail) { + let global = &self.0; + match wgc::gfx_select!(*view => global.surface_present(detail.surface_id)) { + Ok(_status) => (), + Err(err) => self.handle_error_fatal(err, "Surface::present"), + } + } + fn device_features(&self, device: &Self::DeviceId) -> Features { let global = &self.0; match wgc::gfx_select!(device.id => global.device_features(device.id)) { @@ -890,20 +952,6 @@ impl crate::Context for Context { } } - fn device_create_swap_chain( - &self, - device: &Self::DeviceId, - surface: &Self::SurfaceId, - desc: &wgt::SwapChainDescriptor, - ) -> Self::SwapChainId { - let global = &self.0; - let (sc, error) = wgc::gfx_select!(device.id => global.device_create_swap_chain(device.id, *surface, desc)); - match error { - Some(e) => self.handle_error_fatal(e, "Device::create_swap_chain"), - None => sc, - } - } - fn device_create_shader_module( &self, device: &Self::DeviceId, @@ -1507,37 +1555,6 @@ impl crate::Context for Context { } } - fn swap_chain_get_current_texture_view( - &self, - swap_chain: &Self::SwapChainId, - ) -> ( - Option, - SwapChainStatus, - Self::SwapChainOutputDetail, - ) { - let global = &self.0; - match wgc::gfx_select!( - *swap_chain => global.swap_chain_get_current_texture_view(*swap_chain, PhantomData) - ) { - Ok(wgc::swap_chain::SwapChainOutput { status, view_id }) => ( - view_id, - status, - SwapChainOutputDetail { - swap_chain_id: *swap_chain, - }, - ), - Err(err) => self.handle_error_fatal(err, "SwapChain::get_current_texture_view"), - } - } - - fn swap_chain_present(&self, view: &Self::TextureViewId, detail: &Self::SwapChainOutputDetail) { - let global = &self.0; - match wgc::gfx_select!(*view => global.swap_chain_present(detail.swap_chain_id)) { - Ok(_status) => (), - Err(err) => self.handle_error_fatal(err, "SwapChain::present"), - } - } - fn texture_create_view( &self, texture: &Self::TextureId, @@ -2079,8 +2096,8 @@ impl crate::Context for Context { } #[derive(Debug)] -pub(crate) struct SwapChainOutputDetail { - swap_chain_id: wgc::id::SwapChainId, +pub(crate) struct SurfaceOutputDetail { + surface_id: wgc::id::SurfaceId, } type ErrorSink = Arc>; diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 0505b19d34..42be6c8759 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -909,9 +909,8 @@ impl crate::Context for Context { type RenderBundleEncoderId = RenderBundleEncoder; type RenderBundleId = Sendable; type SurfaceId = Sendable; - type SwapChainId = Sendable; - type SwapChainOutputDetail = SwapChainOutputDetail; + type SurfaceOutputDetail = SurfaceOutputDetail; type RequestAdapterFuture = MakeSendFuture< wasm_bindgen_futures::JsFuture, @@ -1043,16 +1042,6 @@ impl crate::Context for Context { ) } - fn adapter_get_swap_chain_preferred_format( - &self, - adapter: &Self::AdapterId, - surface: &Self::SurfaceId, - ) -> Option { - let format = - map_texture_format_from_web_sys(surface.0.get_swap_chain_preferred_format(&adapter.0)); - Some(format) - } - fn adapter_features(&self, adapter: &Self::AdapterId) -> wgt::Features { // TODO let _features = adapter.0.features(); @@ -1112,6 +1101,49 @@ impl crate::Context for Context { format.describe().guaranteed_format_features } + fn surface_get_preferred_format( + &self, + surface: &Self::SurfaceId, + adapter: &Self::AdapterId, + ) -> Option { + let format = + map_texture_format_from_web_sys(surface.0.get_swap_chain_preferred_format(&adapter.0)); + Some(format) + } + + fn surface_configure( + &self, + surface: &Self::SurfaceId, + device: &Self::DeviceId, + config: &wgt::SurfaceConfiguration, + ) { + let mut mapped = + web_sys::GpuSwapChainDescriptor::new(&device.0, map_texture_format(config.format)); + mapped.usage(config.usage.bits()); + surface.0.configure_swap_chain(&mapped); + } + + fn surface_get_current_texture_view( + &self, + _surface: &Self::SurfaceId, + ) -> ( + Option, + wgt::SurfaceStatus, + Self::SurfaceOutputDetail, + ) { + // TODO: Should we pass a descriptor here? + // Or is the default view always correct? + ( + None, //TODO: surface.0.get_current_texture().create_view() + wgt::SurfaceStatus::Good, + (), + ) + } + + fn surface_present(&self, _view: &Self::TextureViewId, _detail: &Self::SurfaceOutputDetail) { + // Swapchain is presented automatically + } + fn device_features(&self, _device: &Self::DeviceId) -> wgt::Features { // TODO wgt::Features::empty() @@ -1127,18 +1159,6 @@ impl crate::Context for Context { wgt::DownlevelCapabilities::default() } - fn device_create_swap_chain( - &self, - device: &Self::DeviceId, - surface: &Self::SurfaceId, - desc: &wgt::SwapChainDescriptor, - ) -> Self::SwapChainId { - let mut mapped = - web_sys::GpuSwapChainDescriptor::new(&device.0, map_texture_format(desc.format)); - mapped.usage(desc.usage.bits()); - Sendable(surface.0.configure_swap_chain(&mapped)) - } - fn device_create_shader_module( &self, device: &Self::DeviceId, @@ -1582,31 +1602,6 @@ impl crate::Context for Context { buffer.0.unmap(); } - fn swap_chain_get_current_texture_view( - &self, - swap_chain: &Self::SwapChainId, - ) -> ( - Option, - wgt::SwapChainStatus, - Self::SwapChainOutputDetail, - ) { - // TODO: Should we pass a descriptor here? - // Or is the default view always correct? - ( - Some(Sendable(swap_chain.0.get_current_texture().create_view())), - wgt::SwapChainStatus::Good, - (), - ) - } - - fn swap_chain_present( - &self, - _view: &Self::TextureViewId, - _detail: &Self::SwapChainOutputDetail, - ) { - // Swapchain is presented automatically - } - fn texture_create_view( &self, texture: &Self::TextureId, @@ -2047,7 +2042,7 @@ impl crate::Context for Context { fn device_stop_capture(&self, _device: &Self::DeviceId) {} } -pub(crate) type SwapChainOutputDetail = (); +pub(crate) type SurfaceOutputDetail = (); #[derive(Debug)] pub struct BufferMappedRange { diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index b371442ce2..e104416d63 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -34,7 +34,7 @@ pub use wgt::{ PipelineStatisticsTypes, PolygonMode, PowerPreference, PresentMode, PrimitiveState, PrimitiveTopology, PushConstantRange, QueryType, RenderBundleDepthStencil, SamplerBorderColor, ShaderLocation, ShaderModel, ShaderStages, StencilFaceState, StencilOperation, StencilState, - StorageTextureAccess, SwapChainDescriptor, SwapChainStatus, TextureAspect, TextureDimension, + StorageTextureAccess, SurfaceConfiguration, SurfaceStatus, TextureAspect, TextureDimension, TextureFormat, TextureFormatFeatureFlags, TextureFormatFeatures, TextureSampleType, TextureUsages, TextureViewDimension, VertexAttribute, VertexFormat, VertexStepMode, BIND_BUFFER_ALIGNMENT, COPY_BUFFER_ALIGNMENT, COPY_BYTES_PER_ROW_ALIGNMENT, MAP_ALIGNMENT, @@ -174,9 +174,8 @@ trait Context: Debug + Send + Sized + Sync { type RenderBundleEncoderId: Debug + RenderInner; type RenderBundleId: Debug + Send + Sync + 'static; type SurfaceId: Debug + Send + Sync + 'static; - type SwapChainId: Debug + Send + Sync + 'static; - type SwapChainOutputDetail: Send; + type SurfaceOutputDetail: Send; type RequestAdapterFuture: Future> + Send; type RequestDeviceFuture: Future> @@ -204,11 +203,6 @@ trait Context: Debug + Send + Sized + Sync { adapter: &Self::AdapterId, surface: &Self::SurfaceId, ) -> bool; - fn adapter_get_swap_chain_preferred_format( - &self, - adapter: &Self::AdapterId, - surface: &Self::SurfaceId, - ) -> Option; fn adapter_features(&self, adapter: &Self::AdapterId) -> Features; fn adapter_limits(&self, adapter: &Self::AdapterId) -> Limits; fn adapter_downlevel_properties(&self, adapter: &Self::AdapterId) -> DownlevelCapabilities; @@ -219,15 +213,30 @@ trait Context: Debug + Send + Sized + Sync { format: TextureFormat, ) -> TextureFormatFeatures; + fn surface_get_preferred_format( + &self, + surface: &Self::SurfaceId, + adapter: &Self::AdapterId, + ) -> Option; + fn surface_configure( + &self, + surface: &Self::SurfaceId, + device: &Self::DeviceId, + config: &SurfaceConfiguration, + ); + fn surface_get_current_texture_view( + &self, + surface: &Self::SurfaceId, + ) -> ( + Option, + SurfaceStatus, + Self::SurfaceOutputDetail, + ); + fn surface_present(&self, view: &Self::TextureViewId, detail: &Self::SurfaceOutputDetail); + fn device_features(&self, device: &Self::DeviceId) -> Features; fn device_limits(&self, device: &Self::DeviceId) -> Limits; fn device_downlevel_properties(&self, device: &Self::DeviceId) -> DownlevelCapabilities; - fn device_create_swap_chain( - &self, - device: &Self::DeviceId, - surface: &Self::SurfaceId, - desc: &SwapChainDescriptor, - ) -> Self::SwapChainId; fn device_create_shader_module( &self, device: &Self::DeviceId, @@ -313,15 +322,6 @@ trait Context: Debug + Send + Sized + Sync { sub_range: Range, ) -> BufferMappedRange; fn buffer_unmap(&self, buffer: &Self::BufferId); - fn swap_chain_get_current_texture_view( - &self, - swap_chain: &Self::SwapChainId, - ) -> ( - Option, - SwapChainStatus, - Self::SwapChainOutputDetail, - ); - fn swap_chain_present(&self, view: &Self::TextureViewId, detail: &Self::SwapChainOutputDetail); fn texture_create_view( &self, texture: &Self::TextureId, @@ -670,16 +670,6 @@ impl Drop for Surface { } } -/// Handle to a swap chain. -/// -/// A `SwapChain` represents the image or series of images that will be presented to a [`Surface`]. -/// A `SwapChain` may be created with [`Device::create_swap_chain`]. -#[derive(Debug)] -pub struct SwapChain { - context: Arc, - id: ::SwapChainId, -} - /// Handle to a binding group layout. /// /// A `BindGroupLayout` is a handle to the GPU-side layout of a binding group. It can be used to @@ -1337,27 +1327,27 @@ pub struct RenderBundleEncoderDescriptor<'a> { pub sample_count: u32, } -/// Swap chain image that can be rendered to. +/// Surface texture that can be rendered to. #[derive(Debug)] -pub struct SwapChainTexture { +pub struct SurfaceTexture { /// Accessible view of the frame. pub view: TextureView, - detail: ::SwapChainOutputDetail, + detail: ::SurfaceOutputDetail, } -/// Result of a successful call to [`SwapChain::get_current_frame`]. +/// Result of a successful call to [`Surface::get_current_frame`]. #[derive(Debug)] -pub struct SwapChainFrame { +pub struct SurfaceFrame { /// The texture into which the next frame should be rendered. - pub output: SwapChainTexture, + pub output: SurfaceTexture, /// `true` if the acquired buffer can still be used for rendering, /// but should be recreated for maximum performance. pub suboptimal: bool, } -/// Result of an unsuccessful call to [`SwapChain::get_current_frame`]. +/// Result of an unsuccessful call to [`Surface::get_current_frame`]. #[derive(Clone, PartialEq, Eq, Debug)] -pub enum SwapChainError { +pub enum SurfaceError { /// A timeout was encountered while trying to acquire the next frame. Timeout, /// The underlying surface has changed, and therefore the swap chain must be updated. @@ -1368,7 +1358,7 @@ pub enum SwapChainError { OutOfMemory, } -impl Display for SwapChainError { +impl Display for SurfaceError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", match self { Self::Timeout => "A timeout was encountered while trying to acquire the next frame", @@ -1379,7 +1369,7 @@ impl Display for SwapChainError { } } -impl error::Error for SwapChainError {} +impl error::Error for SurfaceError {} impl Instance { /// Create an new instance of wgpu. @@ -1574,13 +1564,6 @@ impl Adapter { Context::adapter_is_surface_supported(&*self.context, &self.id, &surface.id) } - /// Returns an optimal texture format to use for the [`SwapChain`] with this adapter. - /// - /// Returns None if the surface is incompatible with the adapter. - pub fn get_swap_chain_preferred_format(&self, surface: &Surface) -> Option { - Context::adapter_get_swap_chain_preferred_format(&*self.context, &self.id, &surface.id) - } - /// List all features that are supported with this adapter. /// /// Features must be explicitly requested in [`Adapter::request_device`] in order @@ -1794,19 +1777,6 @@ impl Device { } } - /// Create a new [`SwapChain`] which targets `surface`. - /// - /// # Panics - /// - /// - A old [`SwapChainFrame`] is still alive referencing an old swapchain. - /// - Texture format requested is unsupported on the swap chain. - pub fn create_swap_chain(&self, surface: &Surface, desc: &SwapChainDescriptor) -> SwapChain { - SwapChain { - context: Arc::clone(&self.context), - id: Context::device_create_swap_chain(&*self.context, &self.id, &surface.id, desc), - } - } - /// Set a callback for errors that are not handled in error scopes. pub fn on_uncaptured_error(&self, handler: impl UncapturedErrorHandler) { self.context.device_on_uncaptured_error(&self.id, handler); @@ -3083,26 +3053,43 @@ impl Queue { } } -impl Drop for SwapChainTexture { +impl Drop for SurfaceTexture { fn drop(&mut self) { if !thread::panicking() { - Context::swap_chain_present(&*self.view.context, &self.view.id, &self.detail); + Context::surface_present(&*self.view.context, &self.view.id, &self.detail); } } } -impl SwapChain { +impl Surface { + /// Returns an optimal texture format to use for the [`Surface`] with this adapter. + /// + /// Returns None if the surface is incompatible with the adapter. + pub fn get_preferred_format(&self, adapter: &Adapter) -> Option { + Context::surface_get_preferred_format(&*self.context, &self.id, &adapter.id) + } + + /// Initializes [`Surface`] for presentation. + /// + /// # Panics + /// + /// - A old [`SurfaceFrame`] is still alive referencing an old surface. + /// - Texture format requested is unsupported on the surface. + pub fn configure(&self, device: &Device, config: &SurfaceConfiguration) { + Context::surface_configure(&*self.context, &self.id, &device.id, config) + } + /// Returns the next texture to be presented by the swapchain for drawing. /// - /// When the [`SwapChainFrame`] returned by this method is dropped, the swapchain will present + /// When the [`SurfaceFrame`] returned by this method is dropped, the swapchain will present /// the texture to the associated [`Surface`]. /// - /// If a SwapChainFrame referencing this surface is alive when the swapchain is recreated, + /// If a SurfaceFrame referencing this surface is alive when the swapchain is recreated, /// recreating the swapchain will panic. - pub fn get_current_frame(&self) -> Result { + pub fn get_current_frame(&self) -> Result { let (view_id, status, detail) = - Context::swap_chain_get_current_texture_view(&*self.context, &self.id); - let output = view_id.map(|id| SwapChainTexture { + Context::surface_get_current_texture_view(&*self.context, &self.id); + let output = view_id.map(|id| SurfaceTexture { view: TextureView { context: Arc::clone(&self.context), id, @@ -3112,17 +3099,17 @@ impl SwapChain { }); match status { - SwapChainStatus::Good => Ok(SwapChainFrame { + SurfaceStatus::Good => Ok(SurfaceFrame { output: output.unwrap(), suboptimal: false, }), - SwapChainStatus::Suboptimal => Ok(SwapChainFrame { + SurfaceStatus::Suboptimal => Ok(SurfaceFrame { output: output.unwrap(), suboptimal: true, }), - SwapChainStatus::Timeout => Err(SwapChainError::Timeout), - SwapChainStatus::Outdated => Err(SwapChainError::Outdated), - SwapChainStatus::Lost => Err(SwapChainError::Lost), + SurfaceStatus::Timeout => Err(SurfaceError::Timeout), + SurfaceStatus::Outdated => Err(SurfaceError::Outdated), + SurfaceStatus::Lost => Err(SurfaceError::Lost), } } }