Rename SwapChain::get_next_texture to SwapChain::get_next_frame, and have it return errors to the user.

This commit is contained in:
AlphaModder
2020-05-24 19:35:48 -07:00
parent e371a2e1b7
commit 91d46ecc2b
14 changed files with 138 additions and 117 deletions

View File

@@ -28,14 +28,14 @@ vulkan = ["wgc/gfx-backend-vulkan"]
package = "wgpu-core"
version = "0.5"
git = "https://github.com/gfx-rs/wgpu"
rev = "4e1d76013c0b272383400beba48dc306e1a350f6"
rev = "a6d468086dc48683d0c97b9e3b63264ad67660da"
features = ["raw-window-handle"]
[dependencies.wgt]
package = "wgpu-types"
version = "0.5"
git = "https://github.com/gfx-rs/wgpu"
rev = "4e1d76013c0b272383400beba48dc306e1a350f6"
rev = "a6d468086dc48683d0c97b9e3b63264ad67660da"
[dependencies]
arrayvec = "0.5"

View File

@@ -259,7 +259,7 @@ impl framework::Example for Example {
/// a TriangleList draw call for all NUM_PARTICLES at 3 vertices each
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
frame: &wgpu::SwapChainTexture,
device: &wgpu::Device,
_queue: &wgpu::Queue,
) -> wgpu::CommandBuffer {

View File

@@ -95,7 +95,7 @@ async fn run() {
queue.submit(Some(command_buffer));
// Note that we're not calling `.await` here.
let buffer_future = output_buffer.map_read(0, (size * size) as u64 * size_of::<u32>() as u64);
let buffer_future = output_buffer.map_read(0, wgt::BufferSize::WHOLE);
// Poll the device in a blocking manner so that our future resolves.
// In an actual application, `device.poll(...)` should

View File

@@ -319,7 +319,7 @@ impl framework::Example for Example {
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
frame: &wgpu::SwapChainTexture,
device: &wgpu::Device,
_queue: &wgpu::Queue,
) -> wgpu::CommandBuffer {

View File

@@ -44,7 +44,7 @@ pub trait Example: 'static + Sized {
fn update(&mut self, event: WindowEvent);
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
frame: &wgpu::SwapChainTexture,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> wgpu::CommandBuffer;
@@ -143,7 +143,6 @@ async fn run_async<E: Example>(event_loop: EventLoop<()>, window: Window) {
log::info!("Resizing to {:?}", size);
sc_desc.width = size.width;
sc_desc.height = size.height;
swap_chain = device.create_swap_chain(&surface, &sc_desc);
example.resize(&sc_desc, &device, &queue);
}
event::Event::WindowEvent { event, .. } => match event {
@@ -164,10 +163,17 @@ async fn run_async<E: Example>(event_loop: EventLoop<()>, window: Window) {
}
},
event::Event::RedrawRequested(_) => {
let frame = swap_chain
.get_next_texture()
.expect("Timeout when acquiring next swap chain texture");
let command_buf = example.render(&frame, &device, &queue);
let frame = match swap_chain.get_next_frame() {
Ok(frame) => frame,
Err(_) => {
swap_chain = device.create_swap_chain(&surface, &sc_desc);
swap_chain
.get_next_frame()
.expect("Failed to acquire next swap chain texture!")
}
};
let command_buf = example.render(&frame.output, &device, &queue);
queue.submit(Some(command_buf));
}
_ => {}

View File

@@ -111,7 +111,7 @@ async fn execute_gpu(numbers: Vec<u32>) -> Vec<u32> {
queue.submit(Some(encoder.finish()));
// Note that we're not calling `.await` here.
let buffer_future = staging_buffer.map_read(0, size);
let buffer_future = staging_buffer.map_read(0, wgt::BufferSize::WHOLE);
// Poll the device in a blocking manner so that our future resolves.
// In an actual application, `device.poll(...)` should

View File

@@ -110,8 +110,9 @@ async fn run(event_loop: EventLoop<()>, window: Window, swapchain_format: wgpu::
}
Event::RedrawRequested(_) => {
let frame = swap_chain
.get_next_texture()
.expect("Timeout when acquiring next swap chain texture");
.get_next_frame()
.expect("Failed to acquire next swap chain texture")
.output;
let mut encoder =
device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
{

View File

@@ -412,7 +412,7 @@ impl framework::Example for Example {
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
frame: &wgpu::SwapChainTexture,
device: &wgpu::Device,
_queue: &wgpu::Queue,
) -> wgpu::CommandBuffer {

View File

@@ -218,7 +218,7 @@ impl framework::Example for Example {
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
frame: &wgpu::SwapChainTexture,
device: &wgpu::Device,
_queue: &wgpu::Queue,
) -> wgpu::CommandBuffer {

View File

@@ -698,7 +698,7 @@ impl framework::Example for Example {
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
frame: &wgpu::SwapChainTexture,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> wgpu::CommandBuffer {

View File

@@ -261,7 +261,7 @@ impl framework::Example for Skybox {
fn render(
&mut self,
frame: &wgpu::SwapChainOutput,
frame: &wgpu::SwapChainTexture,
device: &wgpu::Device,
queue: &wgpu::Queue,
) -> wgpu::CommandBuffer {

View File

@@ -1,14 +1,14 @@
use crate::{
backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource,
BindingType, BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor,
PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor, TextureDescriptor,
TextureViewDescriptor, TextureViewDimension,
PipelineLayoutDescriptor, RenderPipelineDescriptor, SamplerDescriptor, SwapChainStatus,
TextureDescriptor, TextureViewDescriptor, TextureViewDimension,
};
use arrayvec::ArrayVec;
use futures::future::{ready, Ready};
use smallvec::SmallVec;
use std::{ffi::CString, marker::PhantomData, ptr, slice};
use std::{ffi::CString, marker::PhantomData, ops::Range, ptr, slice};
macro_rules! gfx_select {
($id:expr => $global:ident.$method:ident( $($param:expr),+ )) => {
@@ -89,7 +89,7 @@ mod pass_impl {
&mut self,
buffer: &wgc::id::BufferId,
offset: wgt::BufferAddress,
size: wgt::BufferAddress,
size: wgt::BufferSize,
) {
unsafe { wgpu_render_pass_set_index_buffer(self, *buffer, offset, size) }
}
@@ -98,7 +98,7 @@ mod pass_impl {
slot: u32,
buffer: &wgc::id::BufferId,
offset: wgt::BufferAddress,
size: wgt::BufferAddress,
size: wgt::BufferSize,
) {
unsafe { wgpu_render_pass_set_vertex_buffer(self, slot, *buffer, offset, size) }
}
@@ -358,7 +358,7 @@ impl crate::Context for Context {
bm::BindingResource::Buffer(bm::BufferBinding {
buffer: buffer_slice.buffer.id,
offset: buffer_slice.offset,
size: buffer_slice.size_or_0(),
size: buffer_slice.size,
})
}
BindingResource::Sampler(ref sampler) => {
@@ -590,10 +590,10 @@ impl crate::Context for Context {
fn buffer_map_read(
&self,
buffer: &Self::BufferId,
start: wgt::BufferAddress,
size: wgt::BufferAddress,
range: Range<wgt::BufferAddress>,
) -> Self::MapReadFuture {
let (future, completion) = native_gpu_future::new_gpu_future(*buffer, size);
let (future, completion) =
native_gpu_future::new_gpu_future(*buffer, range.end - range.start);
extern "C" fn buffer_map_read_future_wrapper(
status: wgc::resource::BufferMapAsyncStatus,
@@ -619,7 +619,7 @@ impl crate::Context for Context {
callback: buffer_map_read_future_wrapper,
userdata: completion.to_raw() as _,
};
gfx_select!(*buffer => self.buffer_map_async(*buffer, start .. start + size, operation));
gfx_select!(*buffer => self.buffer_map_async(*buffer, range, operation));
future
}
@@ -627,10 +627,10 @@ impl crate::Context for Context {
fn buffer_map_write(
&self,
buffer: &Self::BufferId,
start: wgt::BufferAddress,
size: wgt::BufferAddress,
range: Range<wgt::BufferAddress>,
) -> Self::MapWriteFuture {
let (future, completion) = native_gpu_future::new_gpu_future(*buffer, size);
let (future, completion) =
native_gpu_future::new_gpu_future(*buffer, range.end - range.start);
extern "C" fn buffer_map_write_future_wrapper(
status: wgc::resource::BufferMapAsyncStatus,
@@ -656,7 +656,7 @@ impl crate::Context for Context {
callback: buffer_map_write_future_wrapper,
userdata: completion.to_raw() as _,
};
gfx_select!(*buffer => self.buffer_map_async(*buffer, start .. start + size, operation));
gfx_select!(*buffer => self.buffer_map_async(*buffer, range, operation));
future
}
@@ -668,17 +668,11 @@ impl crate::Context for Context {
fn swap_chain_get_next_texture(
&self,
swap_chain: &Self::SwapChainId,
) -> Result<(Self::TextureViewId, Self::SwapChainOutputDetail), crate::TimeOut> {
gfx_select!(*swap_chain => self.swap_chain_get_next_texture(*swap_chain, PhantomData))
.map(|output| {
(
output.view_id.unwrap(),
SwapChainOutputDetail {
swap_chain_id: *swap_chain,
},
)
})
.map_err(|_| crate::TimeOut)
) -> (Option<Self::TextureViewId>, SwapChainStatus, Self::SwapChainOutputDetail) {
let wgc::swap_chain::SwapChainOutput { status, view_id } =
gfx_select!(*swap_chain => self.swap_chain_get_next_texture(*swap_chain, PhantomData));
(view_id, status, SwapChainOutputDetail { swap_chain_id: *swap_chain })
}
fn swap_chain_present(&self, view: &Self::TextureViewId, detail: &Self::SwapChainOutputDetail) {

View File

@@ -1,8 +1,8 @@
use crate::{
BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, BindingType, BufferDescriptor,
CommandEncoderDescriptor, ComputePipelineDescriptor, PipelineLayoutDescriptor,
ProgrammableStageDescriptor, RenderPipelineDescriptor, SamplerDescriptor, TextureDescriptor,
TextureViewDescriptor, TextureViewDimension,
ProgrammableStageDescriptor, RenderPipelineDescriptor, SamplerDescriptor, SwapChainStatus,
TextureDescriptor, TextureViewDescriptor, TextureViewDimension,
};
use futures::FutureExt;
@@ -107,20 +107,22 @@ impl crate::RenderPassInner<Context> for RenderPass {
&mut self,
buffer: &Sendable<web_sys::GpuBuffer>,
offset: wgt::BufferAddress,
size: wgt::BufferAddress,
size: wgt::BufferSize,
) {
assert_ne!(size, wgt::BufferSize::WHOLE); //TODO
self.0
.set_index_buffer_with_f64_and_f64(&buffer.0, offset as f64, size as f64);
.set_index_buffer_with_f64_and_f64(&buffer.0, offset as f64, size.0 as f64);
}
fn set_vertex_buffer(
&mut self,
slot: u32,
buffer: &Sendable<web_sys::GpuBuffer>,
offset: wgt::BufferAddress,
size: wgt::BufferAddress,
size: wgt::BufferSize,
) {
assert_ne!(size, wgt::BufferSize::WHOLE); //TODO
self.0
.set_vertex_buffer_with_f64_and_f64(slot, &buffer.0, offset as f64, size as f64);
.set_vertex_buffer_with_f64_and_f64(slot, &buffer.0, offset as f64, size.0 as f64);
}
fn set_blend_color(&mut self, color: wgt::Color) {
self.0
@@ -830,7 +832,9 @@ impl crate::Context for Context {
let mut mapped_buffer_binding =
web_sys::GpuBufferBinding::new(&buffer_slice.buffer.id.0);
mapped_buffer_binding.offset(buffer_slice.offset as f64);
mapped_buffer_binding.size(buffer_slice.size_or_0() as f64);
if buffer_slice.size != wgt::BufferSize::WHOLE {
mapped_buffer_binding.size(buffer_slice.size.0 as f64);
}
JsValue::from(mapped_buffer_binding.clone())
}
BindingResource::Sampler(ref sampler) => JsValue::from(sampler.id.0.clone()),
@@ -1046,8 +1050,7 @@ impl crate::Context for Context {
fn buffer_map_read(
&self,
buffer: &Self::BufferId,
_start: wgt::BufferAddress,
_size: wgt::BufferAddress,
_range: Range<wgt::BufferAddress>,
) -> Self::MapReadFuture {
MakeSendFuture(MapFuture {
child: wasm_bindgen_futures::JsFuture::from(buffer.0.map_read_async()),
@@ -1059,8 +1062,7 @@ impl crate::Context for Context {
fn buffer_map_write(
&self,
buffer: &Self::BufferId,
_start: wgt::BufferAddress,
_size: wgt::BufferAddress,
_range: Range<wgt::BufferAddress>,
) -> Self::MapWriteFuture {
MakeSendFuture(MapFuture {
child: wasm_bindgen_futures::JsFuture::from(buffer.0.map_write_async()),
@@ -1076,13 +1078,10 @@ impl crate::Context for Context {
fn swap_chain_get_next_texture(
&self,
swap_chain: &Self::SwapChainId,
) -> Result<(Self::TextureViewId, Self::SwapChainOutputDetail), crate::TimeOut> {
) -> (Option<Self::TextureViewId>, SwapChainStatus, Self::SwapChainOutputDetail) {
// TODO: Should we pass a descriptor here?
// Or is the default view always correct?
Ok((
Sendable(swap_chain.0.get_current_texture().create_view()),
(),
))
(Some(Sendable(swap_chain.0.get_current_texture().create_view())), SwapChainStatus::Good, ())
}
fn swap_chain_present(

View File

@@ -18,14 +18,14 @@ use std::{
pub use wgc::instance::{AdapterInfo, DeviceType};
pub use wgt::{
read_spirv, AddressMode, Backend, BackendBit, BlendDescriptor, BlendFactor, BlendOperation,
BufferAddress, BufferUsage, Color, ColorStateDescriptor, ColorWrite, CommandBufferDescriptor,
CompareFunction, CullMode, DepthStencilStateDescriptor, DeviceDescriptor, DynamicOffset,
Extensions, Extent3d, FilterMode, FrontFace, IndexFormat, InputStepMode, Limits, LoadOp,
Origin3d, PowerPreference, PresentMode, PrimitiveTopology, RasterizationStateDescriptor,
ShaderLocation, ShaderStage, StencilOperation, StencilStateFaceDescriptor, StoreOp,
SwapChainDescriptor, TextureAspect, TextureComponentType, TextureDataLayout, TextureDimension,
TextureFormat, TextureUsage, TextureViewDimension, VertexAttributeDescriptor, VertexFormat,
BIND_BUFFER_ALIGNMENT, MAX_BIND_GROUPS,
BufferAddress, BufferSize, BufferUsage, Color, ColorStateDescriptor, ColorWrite,
CommandBufferDescriptor, CompareFunction, CullMode, DepthStencilStateDescriptor,
DeviceDescriptor, DynamicOffset, Extensions, Extent3d, FilterMode, FrontFace, IndexFormat,
InputStepMode, Limits, LoadOp, Origin3d, PowerPreference, PresentMode, PrimitiveTopology,
RasterizationStateDescriptor, ShaderLocation, ShaderStage, StencilOperation,
StencilStateFaceDescriptor, StoreOp, SwapChainDescriptor, SwapChainStatus, TextureAspect,
TextureComponentType, TextureDataLayout, TextureDimension, TextureFormat, TextureUsage,
TextureViewDimension, VertexAttributeDescriptor, VertexFormat, BIND_BUFFER_ALIGNMENT,
};
use backend::Context as C;
@@ -54,18 +54,13 @@ trait RenderPassInner<Ctx: Context> {
bind_group: &Ctx::BindGroupId,
offsets: &[DynamicOffset],
);
fn set_index_buffer(
&mut self,
buffer: &Ctx::BufferId,
offset: BufferAddress,
size: BufferAddress,
);
fn set_index_buffer(&mut self, buffer: &Ctx::BufferId, offset: BufferAddress, size: BufferSize);
fn set_vertex_buffer(
&mut self,
slot: u32,
buffer: &Ctx::BufferId,
offset: BufferAddress,
size: BufferAddress,
size: BufferSize,
);
fn set_blend_color(&mut self, color: wgt::Color);
fn set_scissor_rect(&mut self, x: u32, y: u32, width: u32, height: u32);
@@ -207,20 +202,18 @@ trait Context: Sized {
fn buffer_map_read(
&self,
buffer: &Self::BufferId,
start: BufferAddress,
size: BufferAddress,
range: Range<BufferAddress>,
) -> Self::MapReadFuture;
fn buffer_map_write(
&self,
buffer: &Self::BufferId,
start: BufferAddress,
size: BufferAddress,
range: Range<BufferAddress>,
) -> Self::MapWriteFuture;
fn buffer_unmap(&self, buffer: &Self::BufferId);
fn swap_chain_get_next_texture(
&self,
swap_chain: &Self::SwapChainId,
) -> Result<(Self::TextureViewId, Self::SwapChainOutputDetail), TimeOut>;
) -> (Option<Self::TextureViewId>, SwapChainStatus, Self::SwapChainOutputDetail);
fn swap_chain_present(&self, view: &Self::TextureViewId, detail: &Self::SwapChainOutputDetail);
fn texture_create_view(
&self,
@@ -357,22 +350,14 @@ pub enum Maintain {
pub struct Buffer {
context: Arc<C>,
id: <C as Context>::BufferId,
//detail: <C as Context>::BufferDetail,
size: BufferAddress,
}
/// A description of what portion of a buffer to use
pub struct BufferSlice<'a> {
buffer: &'a Buffer,
offset: BufferAddress,
size: Option<BufferAddress>,
}
impl<'a> BufferSlice<'a> {
/// This fn can be used for calling lower-level APIs where `0` denotes that the slice should
/// extend to the end of the buffer.
fn size_or_0(&self) -> BufferAddress {
self.size.unwrap_or(0)
}
size: BufferSize,
}
/// A handle to a texture on the GPU.
@@ -835,11 +820,26 @@ pub type TextureViewDescriptor<'a> = wgt::TextureViewDescriptor<Option<&'a str>>
pub type SamplerDescriptor<'a> = wgt::SamplerDescriptor<Option<&'a str>>;
/// A swap chain image that can be rendered to.
pub struct SwapChainOutput {
pub struct SwapChainTexture {
pub view: TextureView,
detail: <C as Context>::SwapChainOutputDetail,
}
/// The result of a successful call to `SwapChain::get_next_frame`.
pub struct SwapChainFrame {
pub output: SwapChainTexture,
pub suboptimal: bool,
}
/// The result of an unsuccessful call to `SwapChain::get_next_frame`.
#[derive(Debug)]
pub enum SwapChainError {
Timeout,
Outdated,
Lost,
OutOfMemory,
}
/// A view of a buffer which can be used to copy to or from a texture.
#[derive(Clone)]
pub struct BufferCopyView<'a> {
@@ -887,7 +887,7 @@ impl CreateBufferMapped<'_> {
Buffer {
context: self.context,
id: self.id,
//detail: self.detail,
size: self.mapped_data.len() as BufferAddress,
}
}
}
@@ -1074,6 +1074,7 @@ impl Device {
Buffer {
context: Arc::clone(&self.context),
id: Context::device_create_buffer(&*self.context, &self.id, desc),
size: desc.size,
}
}
@@ -1197,9 +1198,9 @@ impl Buffer {
Bound::Unbounded => 0,
};
let size = match bounds.end_bound() {
Bound::Included(&bound) => Some(bound + 1 - offset),
Bound::Excluded(&bound) => Some(bound - offset),
Bound::Unbounded => None,
Bound::Included(&bound) => BufferSize(bound + 1 - offset),
Bound::Excluded(&bound) => BufferSize(bound - offset),
Bound::Unbounded => BufferSize::WHOLE,
};
BufferSlice {
buffer: self,
@@ -1219,11 +1220,16 @@ impl Buffer {
pub fn map_read(
&self,
start: BufferAddress,
size: BufferAddress,
size: BufferSize,
) -> impl Future<Output = Result<BufferReadMapping, BufferAsyncError>> + Send {
let context = Arc::clone(&self.context);
let end = if size == BufferSize::WHOLE {
self.size
} else {
start + size.0
};
self.context
.buffer_map_read(&self.id, start, size)
.buffer_map_read(&self.id, start..end)
.map(|result| result.map(|detail| BufferReadMapping { context, detail }))
}
@@ -1234,11 +1240,16 @@ impl Buffer {
pub fn map_write(
&self,
start: BufferAddress,
size: BufferAddress,
size: BufferSize,
) -> impl Future<Output = Result<BufferWriteMapping, BufferAsyncError>> + Send {
let context = Arc::clone(&self.context);
let end = if size == BufferSize::WHOLE {
self.size
} else {
start + size.0
};
self.context
.buffer_map_write(&self.id, start, size)
.buffer_map_write(&self.id, start..end)
.map(|result| result.map(|detail| BufferWriteMapping { context, detail }))
}
@@ -1422,7 +1433,7 @@ impl<'a> RenderPass<'a> {
&mut self.id,
&buffer_slice.buffer.id,
buffer_slice.offset,
buffer_slice.size_or_0(),
buffer_slice.size,
)
}
@@ -1444,7 +1455,7 @@ impl<'a> RenderPass<'a> {
slot,
&buffer_slice.buffer.id,
buffer_slice.offset,
buffer_slice.size_or_0(),
buffer_slice.size,
)
}
@@ -1613,7 +1624,7 @@ impl Queue {
}
}
impl Drop for SwapChainOutput {
impl Drop for SwapChainTexture {
fn drop(&mut self) {
if !thread::panicking() {
Context::swap_chain_present(&*self.view.context, &self.view.id, &self.detail);
@@ -1621,26 +1632,36 @@ impl Drop for SwapChainOutput {
}
}
/// The GPU timed out when attempting to acquire the next texture or if a
/// previous output is still alive.
#[derive(Clone, Debug)]
pub struct TimeOut;
impl SwapChain {
/// Returns the next texture to be presented by the swapchain for drawing.
///
/// When the [`SwapChainOutput`] returned by this method is dropped, the swapchain will present
/// the texture to the associated [`Surface`].
pub fn get_next_texture(&mut self) -> Result<SwapChainOutput, TimeOut> {
Context::swap_chain_get_next_texture(&*self.context, &self.id).map(|(id, detail)| {
SwapChainOutput {
view: TextureView {
context: Arc::clone(&self.context),
id,
owned: false,
},
detail,
}
})
pub fn get_next_frame(&mut self) -> Result<SwapChainFrame, SwapChainError> {
let (view_id, status, detail) =
Context::swap_chain_get_next_texture(&*self.context, &self.id);
let output = view_id.map(|id| SwapChainTexture {
view: TextureView {
context: Arc::clone(&self.context),
id: id,
owned: false,
},
detail,
});
match status {
SwapChainStatus::Good => Ok(SwapChainFrame {
output: output.unwrap(),
suboptimal: false,
}),
SwapChainStatus::Suboptimal => Ok(SwapChainFrame {
output: output.unwrap(),
suboptimal: true,
}),
SwapChainStatus::Timeout => Err(SwapChainError::Timeout),
SwapChainStatus::Outdated => Err(SwapChainError::Outdated),
SwapChainStatus::Lost => Err(SwapChainError::Lost),
SwapChainStatus::OutOfMemory => Err(SwapChainError::OutOfMemory),
}
}
}