Skip to content

Commit

Permalink
Breaking: Change type of create_surface() functions to expose canva…
Browse files Browse the repository at this point in the history
…s errors.

Part of fixing gfx-rs#3017.
  • Loading branch information
kpreid committed Sep 27, 2022
1 parent a02af02 commit 952035b
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 30 deletions.
5 changes: 3 additions & 2 deletions wgpu/examples/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ async fn setup<E: Example>(title: &str) -> Setup {
let size = window.inner_size();

#[cfg(not(target_arch = "wasm32"))]
let surface = instance.create_surface(&window);
let surface = instance.create_surface(&window).unwrap();
#[cfg(target_arch = "wasm32")]
let surface = {
if let Some(offscreen_canvas_setup) = &offscreen_canvas_setup {
Expand All @@ -174,7 +174,8 @@ async fn setup<E: Example>(title: &str) -> Setup {
} else {
instance.create_surface(&window)
}
};
}
.unwrap();

(size, surface)
};
Expand Down
2 changes: 1 addition & 1 deletion wgpu/examples/hello-triangle/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use winit::{
async fn run(event_loop: EventLoop<()>, window: Window) {
let size = window.inner_size();
let instance = wgpu::Instance::new(wgpu::Backends::all());
let surface = unsafe { instance.create_surface(&window) };
let surface = unsafe { instance.create_surface(&window) }.unwrap();
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions {
power_preference: wgpu::PowerPreference::default(),
Expand Down
2 changes: 1 addition & 1 deletion wgpu/examples/hello-windows/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct Viewport {

impl ViewportDesc {
fn new(window: Window, background: wgpu::Color, instance: &wgpu::Instance) -> Self {
let surface = unsafe { instance.create_surface(&window) };
let surface = unsafe { instance.create_surface(&window) }.unwrap();
Self {
window,
background,
Expand Down
6 changes: 3 additions & 3 deletions wgpu/src/backend/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,13 +845,13 @@ impl crate::Context for Context {
&self,
display_handle: raw_window_handle::RawDisplayHandle,
window_handle: raw_window_handle::RawWindowHandle,
) -> Self::SurfaceId {
Surface {
) -> Result<Self::SurfaceId, crate::CreateSurfaceError> {
Ok(Surface {
id: self
.0
.instance_create_surface(display_handle, window_handle, ()),
configured_device: Mutex::new(None),
}
})
}

fn instance_request_adapter(
Expand Down
12 changes: 5 additions & 7 deletions wgpu/src/backend/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -962,17 +962,15 @@ impl Context {
pub fn instance_create_surface_from_canvas(
&self,
canvas: &web_sys::HtmlCanvasElement,
) -> <Self as crate::Context>::SurfaceId {
) -> Result<<Self as crate::Context>::SurfaceId, crate::CreateSurfaceError> {
self.create_surface_from_context(canvas.get_context("webgpu"))
.unwrap()
}

pub fn instance_create_surface_from_offscreen_canvas(
&self,
canvas: &web_sys::OffscreenCanvas,
) -> <Self as crate::Context>::SurfaceId {
) -> Result<<Self as crate::Context>::SurfaceId, crate::CreateSurfaceError> {
self.create_surface_from_context(canvas.get_context("webgpu"))
.unwrap()
}

/// Common portion of public `instance_create_surface_from_*` functions.
Expand All @@ -982,7 +980,7 @@ impl Context {
fn create_surface_from_context(
&self,
context_result: Result<Option<js_sys::Object>, wasm_bindgen::JsValue>,
) -> Result<<Self as crate::Context>::SurfaceId, ()> {
) -> Result<<Self as crate::Context>::SurfaceId, crate::CreateSurfaceError> {
let context: js_sys::Object = match context_result {
Ok(Some(context)) => context,
Ok(None) => {
Expand All @@ -992,7 +990,7 @@ impl Context {
// “not supported” could include “insufficient GPU resources” or “the GPU process
// previously crashed”. So, we must return it as an `Err` since it could occur
// for circumstances outside the application author's control.
return Err(());
return Err(crate::CreateSurfaceError {});
}
Err(js_error) => {
// <https://html.spec.whatwg.org/multipage/canvas.html#dom-canvas-getcontext>
Expand Down Expand Up @@ -1063,7 +1061,7 @@ impl crate::Context for Context {
&self,
_display_handle: raw_window_handle::RawDisplayHandle,
window_handle: raw_window_handle::RawWindowHandle,
) -> Self::SurfaceId {
) -> Result<Self::SurfaceId, crate::CreateSurfaceError> {
let canvas_attribute = match window_handle {
raw_window_handle::RawWindowHandle::Web(web_handle) => web_handle.id,
_ => panic!("expected valid handle for canvas"),
Expand Down
72 changes: 56 additions & 16 deletions wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ trait Context: Debug + Send + Sized + Sync {
&self,
display_handle: raw_window_handle::RawDisplayHandle,
window_handle: raw_window_handle::RawWindowHandle,
) -> Self::SurfaceId;
) -> Result<Self::SurfaceId, crate::CreateSurfaceError>;
fn instance_request_adapter(
&self,
options: &RequestAdapterOptions<'_>,
Expand Down Expand Up @@ -1815,23 +1815,34 @@ impl Instance {
///
/// # Safety
///
/// - Raw Window Handle must be a valid object to create a surface upon and
/// must remain valid for the lifetime of the returned surface.
/// - If not called on the main thread, metal backend will panic.
/// - `raw_window_handle` must be a valid object to create a surface upon.
/// - `raw_window_handle` must remain valid until after the returned [`Surface`] is
/// dropped.
///
/// # Errors
///
/// - On WebGL 2: Will return an error if the browser does not support WebGL 2,
/// or declines to provide GPU access (such as due to a resource shortage).
///
/// # Panics
///
/// - On macOS/Metal: will panic if not called on the main thread.
/// - On web: will panic if the `raw_window_handle` does not properly refer to a
/// canvas element.
pub unsafe fn create_surface<
W: raw_window_handle::HasRawWindowHandle + raw_window_handle::HasRawDisplayHandle,
>(
&self,
window: &W,
) -> Surface {
Surface {
) -> Result<Surface, CreateSurfaceError> {
Ok(Surface {
context: Arc::clone(&self.context),
id: Context::instance_create_surface(
&*self.context,
raw_window_handle::HasRawDisplayHandle::raw_display_handle(window),
raw_window_handle::HasRawWindowHandle::raw_window_handle(window),
),
}
)?,
})
}

/// Creates a surface from `CoreAnimationLayer`.
Expand Down Expand Up @@ -1861,29 +1872,42 @@ impl Instance {
///
/// The `canvas` argument must be a valid `<canvas>` element to
/// create a surface upon.
///
/// # Errors
///
/// - On WebGL 2: Will return an error if the browser does not support WebGL 2,
/// or declines to provide GPU access (such as due to a resource shortage).
#[cfg(all(target_arch = "wasm32", not(feature = "emscripten")))]
pub fn create_surface_from_canvas(&self, canvas: &web_sys::HtmlCanvasElement) -> Surface {
Surface {
pub fn create_surface_from_canvas(
&self,
canvas: &web_sys::HtmlCanvasElement,
) -> Result<Surface, CreateSurfaceError> {
Ok(Surface {
context: Arc::clone(&self.context),
id: self.context.instance_create_surface_from_canvas(canvas),
}
id: self.context.instance_create_surface_from_canvas(canvas)?,
})
}

/// Creates a surface from a `web_sys::OffscreenCanvas`.
///
/// The `canvas` argument must be a valid `OffscreenCanvas` object
/// to create a surface upon.
///
/// # Errors
///
/// - On WebGL 2: Will return an error if the browser does not support WebGL 2,
/// or declines to provide GPU access (such as due to a resource shortage).
#[cfg(all(target_arch = "wasm32", not(feature = "emscripten")))]
pub fn create_surface_from_offscreen_canvas(
&self,
canvas: &web_sys::OffscreenCanvas,
) -> Surface {
Surface {
) -> Result<Surface, CreateSurfaceError> {
Ok(Surface {
context: Arc::clone(&self.context),
id: self
.context
.instance_create_surface_from_offscreen_canvas(canvas),
}
.instance_create_surface_from_offscreen_canvas(canvas)?,
})
}

/// Polls all devices.
Expand Down Expand Up @@ -2341,6 +2365,22 @@ impl Display for RequestDeviceError {

impl error::Error for RequestDeviceError {}

/// [`Instance::create_surface()`] or a related function failed.
#[derive(Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub struct CreateSurfaceError {
// TODO: Report diagnostic clues
}
static_assertions::assert_impl_all!(CreateSurfaceError: Send, Sync);

impl Display for CreateSurfaceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Creating a surface failed")
}
}

impl error::Error for CreateSurfaceError {}

/// Error occurred when trying to async map a buffer.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct BufferAsyncError;
Expand Down

0 comments on commit 952035b

Please sign in to comment.