Merge swap chain into surface

This commit is contained in:
Dzmitry Malyshau 2021-08-09 10:47:33 -04:00 committed by Dzmitry Malyshau
parent 3afab9c5aa
commit f78061bcef
34 changed files with 643 additions and 699 deletions

View File

@ -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.

View File

@ -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);
}

View File

@ -149,8 +149,8 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
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::<A>(device).unwrap();
@ -202,9 +202,9 @@ impl GlobalPlay for wgc::hub::Global<IdentityPassThroughFactory> {
Action::DestroySampler(id) => {
self.sampler_drop::<A>(id);
}
Action::GetSwapChainTexture { id, parent_id } => {
Action::GetSurfaceTexture { id, parent_id } => {
self.device_maintain_ids::<A>(device).unwrap();
self.swap_chain_get_current_texture_view::<A>(parent_id, id)
self.surface_get_current_texture_view::<A>(parent_id, id)
.unwrap()
.view_id
.unwrap();

View File

@ -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(

View File

@ -141,7 +141,7 @@ pub struct CommandBuffer<A: hal::Api> {
status: CommandEncoderStatus,
pub(crate) device_id: Stored<id::DeviceId>,
pub(crate) trackers: TrackerSet,
pub(crate) used_swap_chains: SmallVec<[Stored<id::SwapChainId>; 1]>,
pub(crate) used_surfaces: SmallVec<[id::Valid<id::SurfaceId>; 1]>,
buffer_memory_init_actions: Vec<MemoryInitTrackerAction<id::BufferId>>,
limits: wgt::Limits,
support_fill_buffer_texture: bool,
@ -169,7 +169,7 @@ impl<A: HalApi> CommandBuffer<A> {
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),

View File

@ -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<RenderAttachment<'a>>,
used_swap_chain: Option<Stored<id::SwapChainId>>,
used_surface: Option<id::Valid<id::SurfaceId>>,
is_ds_read_only: bool,
extent: wgt::Extent3d,
_phantom: PhantomData<A>,
@ -535,7 +533,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
depth_stencil_attachment: Option<&RenderPassDepthStencilAttachment>,
cmd_buf: &mut CommandBuffer<A>,
view_guard: &'a Storage<TextureView<A>, id::TextureViewId>,
swap_chain_guard: &'a Storage<SwapChain<A>, id::SwapChainId>,
surface_guard: &'a Storage<Surface, id::SurfaceId>,
) -> Result<Self, RenderPassErrorInner> {
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<id::SwapChainId>, hal::TextureUses)>;
let mut used_surface = None::<(id::Valid<id::SurfaceId>, hal::TextureUses)>;
let mut add_view = |view: &TextureView<A>, 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<Texture<A>, id::TextureId>,
swap_chain_guard: &Storage<SwapChain<A>, id::SwapChainId>,
) -> Result<(StatefulTrackerSubset, Option<Stored<id::SwapChainId>>), RenderPassErrorInner>
surface_guard: &Storage<Surface, id::SurfaceId>,
) -> Result<(StatefulTrackerSubset, Option<id::Valid<id::SurfaceId>>), 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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
depth_stencil_attachment,
cmd_buf,
&*view_guard,
&*swap_chain_guard,
&*surface_guard,
)
.map_pass_err(scope)?;
@ -1762,8 +1756,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
}
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<G: GlobalIdentityHandlerFactory> Global<G> {
.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)
};

View File

@ -391,7 +391,7 @@ impl<A: HalApi> LifetimeTracker<A> {
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);
}

View File

@ -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<A: HalApi> Device<A> {
.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<A: HalApi> Device<A> {
.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<A: hal::Api> Device<A> {
}
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<A: HalApi>(
pub fn surface_get_preferred_format<A: HalApi>(
&self,
adapter_id: id::AdapterId,
surface_id: id::SurfaceId,
) -> Result<TextureFormat, instance::GetSwapChainPreferredFormatError> {
adapter_id: id::AdapterId,
) -> Result<TextureFormat, instance::GetSurfacePreferredFormatError> {
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<A: HalApi>(
@ -3260,8 +3264,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
.push(layout_id);
}
pub fn device_create_swap_chain<A: HalApi>(
pub fn surface_configure<A: HalApi>(
&self,
device_id: id::DeviceId,
surface_id: id::SurfaceId,
desc: &wgt::SwapChainDescriptor,
) -> (id::SwapChainId, Option<swap_chain::CreateSwapChainError>) {
device_id: id::DeviceId,
config: &wgt::SurfaceConfiguration,
) -> Option<present::ConfigureSurfaceError> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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("<SwapChain>"),
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")]

View File

@ -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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
// 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),
}
}

View File

@ -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>,

View File

@ -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<T, I: id::TypedId> ops::IndexMut<id::Valid<I>> for Storage<T, I> {
}
impl<T, I: id::TypedId> Storage<T, I> {
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<T, I: id::TypedId> Storage<T, I> {
}
// Prevents panic on out of range access, allows Vacant elements.
pub(crate) fn try_remove(&mut self, id: I) -> Option<T> {
pub(crate) fn _try_remove(&mut self, id: I) -> Option<T> {
let (index, epoch, _) = id.unzip();
if index as usize >= self.map.len() {
None
@ -264,8 +263,6 @@ impl<A: hal::Api> Access<Adapter<A>> for Surface {}
impl<A: hal::Api> Access<Device<A>> for Root {}
impl<A: hal::Api> Access<Device<A>> for Surface {}
impl<A: hal::Api> Access<Device<A>> for Adapter<A> {}
impl<A: hal::Api> Access<SwapChain<A>> for Root {}
impl<A: hal::Api> Access<SwapChain<A>> for Device<A> {}
impl<A: hal::Api> Access<PipelineLayout<A>> for Root {}
impl<A: hal::Api> Access<PipelineLayout<A>> for Device<A> {}
impl<A: hal::Api> Access<PipelineLayout<A>> for RenderBundle {}
@ -279,7 +276,6 @@ impl<A: hal::Api> Access<BindGroup<A>> for PipelineLayout<A> {}
impl<A: hal::Api> Access<BindGroup<A>> for CommandBuffer<A> {}
impl<A: hal::Api> Access<CommandBuffer<A>> for Root {}
impl<A: hal::Api> Access<CommandBuffer<A>> for Device<A> {}
impl<A: hal::Api> Access<CommandBuffer<A>> for SwapChain<A> {} //TODO: remove this (only used in `submit()`)
impl<A: hal::Api> Access<RenderBundle> for Device<A> {}
impl<A: hal::Api> Access<RenderBundle> for CommandBuffer<A> {}
impl<A: hal::Api> Access<ComputePipeline<A>> for Device<A> {}
@ -307,7 +303,6 @@ impl<A: hal::Api> Access<Texture<A>> for Root {}
impl<A: hal::Api> Access<Texture<A>> for Device<A> {}
impl<A: hal::Api> Access<Texture<A>> for Buffer<A> {}
impl<A: hal::Api> Access<TextureView<A>> for Root {}
impl<A: hal::Api> Access<TextureView<A>> for SwapChain<A> {} //TODO: remove this (only used in `get_next_texture()`)
impl<A: hal::Api> Access<TextureView<A>> for Device<A> {}
impl<A: hal::Api> Access<TextureView<A>> for Texture<A> {}
impl<A: hal::Api> Access<Sampler<A>> for Root {}
@ -395,7 +390,6 @@ impl<I: id::TypedId + Debug> IdentityHandlerFactory<I> for IdentityManagerFactor
pub trait GlobalIdentityHandlerFactory:
IdentityHandlerFactory<id::AdapterId>
+ IdentityHandlerFactory<id::DeviceId>
+ IdentityHandlerFactory<id::SwapChainId>
+ IdentityHandlerFactory<id::PipelineLayoutId>
+ IdentityHandlerFactory<id::ShaderModuleId>
+ IdentityHandlerFactory<id::BindGroupLayoutId>
@ -559,7 +553,6 @@ impl<T: Resource, I: id::TypedId + Copy, F: IdentityHandlerFactory<I>> 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<A: hal::Api, F: GlobalIdentityHandlerFactory> {
pub adapters: Registry<Adapter<A>, id::AdapterId, F>,
pub devices: Registry<Device<A>, id::DeviceId, F>,
pub swap_chains: Registry<SwapChain<A>, id::SwapChainId, F>,
pub pipeline_layouts: Registry<PipelineLayout<A>, id::PipelineLayoutId, F>,
pub shader_modules: Registry<ShaderModule<A>, id::ShaderModuleId, F>,
pub bind_group_layouts: Registry<BindGroupLayout<A>, id::BindGroupLayoutId, F>,
@ -605,7 +597,6 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
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<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
device.raw.destroy_texture_view(texture_view.raw);
}
}
TextureViewSource::SwapChain(_) => {} //TODO
TextureViewSource::Surface(_) => {} //TODO
}
}
}
@ -731,16 +722,13 @@ impl<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
}
}
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<A: HalApi, F: GlobalIdentityHandlerFactory> Hub<A, F> {
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<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G>;
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface;
fn get_surface(surface: &Surface) -> &HalSurface<Self>;
fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface<Self>;
}
#[cfg(vulkan)]
@ -967,7 +955,10 @@ impl HalApi for hal::api::Vulkan {
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.vulkan
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
fn get_surface(surface: &Surface) -> &HalSurface<Self> {
surface.vulkan.as_ref().unwrap()
}
fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface<Self> {
surface.vulkan.as_mut().unwrap()
}
}
@ -984,7 +975,10 @@ impl HalApi for hal::api::Metal {
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.metal
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
fn get_surface(surface: &Surface) -> &HalSurface<Self> {
surface.metal.as_ref().unwrap()
}
fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface<Self> {
surface.metal.as_mut().unwrap()
}
}
@ -1002,7 +996,10 @@ impl HalApi for hal::api::Dx12 {
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.dx12
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
fn get_surface(surface: &Surface) -> &HalSurface<Self> {
surface.dx12.as_ref().unwrap()
}
fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface<Self> {
surface.dx12.as_mut().unwrap()
}
}
@ -1014,7 +1011,10 @@ impl HalApi for hal::api::Dx11 {
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.dx11
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
fn get_surface(surface: &Surface) -> &HalSurface<Self> {
surface.dx11.as_ref().unwrap()
}
fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface<Self> {
surface.dx11.as_mut().unwrap()
}
}
@ -1033,7 +1033,10 @@ impl HalApi for hal::api::Gles {
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self, G> {
&global.hubs.gl
}
fn get_surface_mut(surface: &mut Surface) -> &mut Self::Surface {
fn get_surface(surface: &Surface) -> &HalSurface<Self> {
surface.gl.as_ref().unwrap()
}
fn get_surface_mut(surface: &mut Surface) -> &mut HalSurface<Self> {
surface.gl.as_mut().unwrap()
}
}

View File

@ -161,21 +161,6 @@ pub type ComputePassEncoderId = *mut crate::command::ComputePass;
pub type RenderBundleEncoderId = *mut crate::command::RenderBundleEncoder;
pub type RenderBundleId = Id<crate::command::RenderBundle>;
pub type QuerySetId = Id<crate::resource::QuerySet<Dummy>>;
// Swap chain
pub type SwapChainId = Id<crate::swap_chain::SwapChain<Dummy>>;
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() {

View File

@ -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<SurfaceId>;
type HalInstance<A> = <A as hal::Api>::Instance;
type HalSurface<A> = <A as hal::Api>::Surface;
pub struct HalSurface<A: hal::Api> {
pub raw: A::Surface,
pub acquired_texture: Option<A::SurfaceTexture>,
}
#[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<Presentation>,
#[cfg(vulkan)]
pub vulkan: Option<HalSurface<hal::api::Vulkan>>,
#[cfg(metal)]
@ -168,6 +173,38 @@ impl crate::hub::Resource for Surface {
}
}
impl Surface {
pub fn get_preferred_format<A: HalApi>(
&self,
adapter: &Adapter<A>,
) -> Result<wgt::TextureFormat, GetSurfacePreferredFormatError> {
// 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<A: hal::Api> {
pub(crate) raw: hal::ExposedAdapter<A>,
life_guard: LifeGuard,
@ -181,41 +218,9 @@ impl<A: HalApi> Adapter<A> {
}
}
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<wgt::TextureFormat, GetSwapChainPreferredFormatError> {
// 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<G: GlobalIdentityHandlerFactory> Global<G> {
) -> 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: hal::Api>(
_: A,
inst: &Option<A::Instance>,
handle: &impl raw_window_handle::HasRawWindowHandle,
) -> Option<HalSurface<A>> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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));

View File

@ -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;

View File

@ -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,
}
};

View File

@ -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<A: hal::Api> {
pub(crate) life_guard: LifeGuard,
pub(crate) struct Presentation {
pub(crate) device_id: Stored<DeviceId>,
pub(crate) desc: wgt::SwapChainDescriptor,
pub(crate) config: wgt::SurfaceConfiguration,
pub(crate) num_frames: u32,
pub(crate) acquired_texture: Option<(Stored<TextureViewId>, A::SurfaceTexture)>,
pub(crate) acquired_texture: Option<Stored<TextureViewId>>,
pub(crate) active_submission_index: SubmissionIndex,
pub(crate) marker: PhantomData<A>,
}
impl<A: hal::Api> crate::hub::Resource for SwapChain<A> {
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<TextureViewId>,
}
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn swap_chain_get_current_texture_view<A: HalApi>(
pub fn surface_get_current_texture_view<A: HalApi>(
&self,
swap_chain_id: SwapChainId,
surface_id: SurfaceId,
view_id_in: Input<G, TextureViewId>,
) -> Result<SwapChainOutput, SwapChainError> {
) -> Result<SurfaceOutput, SurfaceError> {
profiling::scope!("get_next_texture", "SwapChain");
let hub = A::hub(self);
@ -122,25 +92,26 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
};
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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<A: HalApi>(
pub fn surface_present<A: HalApi>(
&self,
swap_chain_id: SwapChainId,
) -> Result<Status, SwapChainError> {
surface_id: SurfaceId,
) -> Result<Status, SurfaceError> {
profiling::scope!("present", "SwapChain");
let hub = A::hub(self);
@ -246,40 +213,40 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
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<G: GlobalIdentityHandlerFactory> Global<G> {
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)
}
},
}

View File

@ -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<TextureId>),
SwapChain(Stored<SwapChainId>),
Surface(Valid<SurfaceId>),
}
#[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<A: hal::Api> Resource for TextureView<A> {

View File

@ -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

View File

@ -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,
) {

View File

@ -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,
) {

View File

@ -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;
}

View File

@ -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));
}

View File

@ -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<E: Example>(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<E: Example>(
}: 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<E: Example>(
..
} => {
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<E: Example>(
}
}
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<E: Example>(mut params: FrameworkRefTest) {
});
let mut example = E::init(
&wgpu::SwapChainDescriptor {
&wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: wgpu::TextureFormat::Rgba8UnormSrgb,
width: params.width,

View File

@ -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;

View File

@ -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<u32>) {
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

View File

@ -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));
}

View File

@ -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;
}

View File

@ -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(

View File

@ -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(

View File

@ -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,
) {

View File

@ -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,

View File

@ -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<V: Copy + Default>(
}
}
#[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<Option<wgc::id::DeviceId>>,
}
#[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<Option<Self::AdapterId>>;
#[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<TextureFormat> {
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<TextureFormat> {
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<Self::TextureViewId>,
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<Self::TextureViewId>,
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<Mutex<ErrorSinkRaw>>;

View File

@ -909,9 +909,8 @@ impl crate::Context for Context {
type RenderBundleEncoderId = RenderBundleEncoder;
type RenderBundleId = Sendable<web_sys::GpuRenderBundle>;
type SurfaceId = Sendable<web_sys::GpuCanvasContext>;
type SwapChainId = Sendable<web_sys::GpuSwapChain>;
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<wgt::TextureFormat> {
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<wgt::TextureFormat> {
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<Self::TextureViewId>,
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<Self::TextureViewId>,
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 {

View File

@ -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<Self>;
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<Output = Option<Self::AdapterId>> + Send;
type RequestDeviceFuture: Future<Output = Result<(Self::DeviceId, Self::QueueId), RequestDeviceError>>
@ -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<TextureFormat>;
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<TextureFormat>;
fn surface_configure(
&self,
surface: &Self::SurfaceId,
device: &Self::DeviceId,
config: &SurfaceConfiguration,
);
fn surface_get_current_texture_view(
&self,
surface: &Self::SurfaceId,
) -> (
Option<Self::TextureViewId>,
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<BufferAddress>,
) -> BufferMappedRange;
fn buffer_unmap(&self, buffer: &Self::BufferId);
fn swap_chain_get_current_texture_view(
&self,
swap_chain: &Self::SwapChainId,
) -> (
Option<Self::TextureViewId>,
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<C>,
id: <C as Context>::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: <C as Context>::SwapChainOutputDetail,
detail: <C as Context>::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<TextureFormat> {
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<TextureFormat> {
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<SwapChainFrame, SwapChainError> {
pub fn get_current_frame(&self) -> Result<SurfaceFrame, SurfaceError> {
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),
}
}
}