Skip to content

Commit

Permalink
Adjust internal canvas size on Surface::configure() (#3690)
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda authored Apr 19, 2023
1 parent 62ea781 commit 85fc427
Show file tree
Hide file tree
Showing 8 changed files with 71 additions and 28 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@ By @cwfitzgerald in [#3671](https://github.com/gfx-rs/wgpu/pull/3671).
- Change type of `mip_level_count` and `array_layer_count` (members of `TextureViewDescriptor` and `ImageSubresourceRange`) from `Option<NonZeroU32>` to `Option<u32>`. By @teoxoy in [#3445](https://github.com/gfx-rs/wgpu/pull/3445)
- All `fxhash` dependencies have been replaced with `rustc-hash`. By @james7132 in [#3502](https://github.com/gfx-rs/wgpu/pull/3502)
- Change type of `bytes_per_row` and `rows_per_image` (members of `ImageDataLayout`) from `Option<NonZeroU32>` to `Option<u32>`. By @teoxoy in [#3529](https://github.com/gfx-rs/wgpu/pull/3529)
- On Web, `Instance::create_surface_from_canvas()` and `create_surface_from_offscreen_canvas()` now take the canvas by value. By @daxpedda in [#3690](https://github.com/gfx-rs/wgpu/pull/3690)

### Changes

Expand All @@ -144,6 +145,7 @@ By @cwfitzgerald in [#3671](https://github.com/gfx-rs/wgpu/pull/3671).
- Don't include ANSI terminal color escape sequences in shader module validation error messages. By @jimblandy in [#3591](https://github.com/gfx-rs/wgpu/pull/3591)
- Report error messages from DXC compile. By @Davidster in [#3632](https://github.com/gfx-rs/wgpu/pull/3632)
- Error in native when using a filterable `TextureSampleType::Float` on a multisample `BindingType::Texture`. By @mockersf in [#3686](https://github.com/gfx-rs/wgpu/pull/3686)
- On Web, the size of the canvas is adjusted when using `Surface::configure()`. If the canvas was given an explicit size (via CSS), this will not affect the visual size of the canvas. By @daxpedda in [#3690](https://github.com/gfx-rs/wgpu/pull/3690)

#### WebGPU

Expand Down
4 changes: 2 additions & 2 deletions wgpu-core/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn create_surface_webgl_canvas(
&self,
canvas: &web_sys::HtmlCanvasElement,
canvas: web_sys::HtmlCanvasElement,
id_in: Input<G, SurfaceId>,
) -> Result<SurfaceId, hal::InstanceError> {
profiling::scope!("Instance::create_surface_webgl_canvas");
Expand All @@ -547,7 +547,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn create_surface_webgl_offscreen_canvas(
&self,
canvas: &web_sys::OffscreenCanvas,
canvas: web_sys::OffscreenCanvas,
id_in: Input<G, SurfaceId>,
) -> Result<SurfaceId, hal::InstanceError> {
profiling::scope!("Instance::create_surface_webgl_offscreen_canvas");
Expand Down
38 changes: 29 additions & 9 deletions wgpu-hal/src/gles/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@ pub struct Instance {
impl Instance {
pub fn create_surface_from_canvas(
&self,
canvas: &web_sys::HtmlCanvasElement,
canvas: web_sys::HtmlCanvasElement,
) -> Result<Surface, crate::InstanceError> {
self.create_surface_from_context(
canvas.get_context_with_context_options("webgl2", &Self::create_context_options()),
)
let result =
canvas.get_context_with_context_options("webgl2", &Self::create_context_options());
self.create_surface_from_context(Canvas::Canvas(canvas), result)
}

pub fn create_surface_from_offscreen_canvas(
&self,
canvas: &web_sys::OffscreenCanvas,
canvas: web_sys::OffscreenCanvas,
) -> Result<Surface, crate::InstanceError> {
self.create_surface_from_context(
canvas.get_context_with_context_options("webgl2", &Self::create_context_options()),
)
let result =
canvas.get_context_with_context_options("webgl2", &Self::create_context_options());
self.create_surface_from_context(Canvas::Offscreen(canvas), result)
}

/// Common portion of public `create_surface_from_*` functions.
Expand All @@ -53,6 +53,7 @@ impl Instance {
/// `wgpu::backend::web::Context`.
fn create_surface_from_context(
&self,
canvas: Canvas,
context_result: Result<Option<js_sys::Object>, wasm_bindgen::JsValue>,
) -> Result<Surface, crate::InstanceError> {
let context_object: js_sys::Object = match context_result {
Expand Down Expand Up @@ -84,6 +85,7 @@ impl Instance {
*self.webgl2_context.lock() = Some(webgl2_context.clone());

Ok(Surface {
canvas,
webgl2_context,
srgb_present_program: None,
swapchain: None,
Expand Down Expand Up @@ -142,7 +144,7 @@ impl crate::Instance<super::Api> for Instance {
.dyn_into()
.expect("Failed to downcast to canvas type");

self.create_surface_from_canvas(&canvas)
self.create_surface_from_canvas(canvas)
} else {
Err(crate::InstanceError)
}
Expand All @@ -161,13 +163,20 @@ impl crate::Instance<super::Api> for Instance {

#[derive(Clone, Debug)]
pub struct Surface {
canvas: Canvas,
webgl2_context: web_sys::WebGl2RenderingContext,
pub(super) swapchain: Option<Swapchain>,
texture: Option<glow::Texture>,
pub(super) presentable: bool,
srgb_present_program: Option<glow::Program>,
}

#[derive(Clone, Debug)]
enum Canvas {
Canvas(web_sys::HtmlCanvasElement),
Offscreen(web_sys::OffscreenCanvas),
}

// SAFE: Because web doesn't have threads ( yet )
unsafe impl Sync for Surface {}
unsafe impl Send for Surface {}
Expand Down Expand Up @@ -270,6 +279,17 @@ impl crate::Surface<super::Api> for Surface {
device: &super::Device,
config: &crate::SurfaceConfiguration,
) -> Result<(), crate::SurfaceError> {
match self.canvas {
Canvas::Canvas(ref canvas) => {
canvas.set_width(config.extent.width);
canvas.set_height(config.extent.height);
}
Canvas::Offscreen(ref canvas) => {
canvas.set_width(config.extent.width);
canvas.set_height(config.extent.height);
}
}

let gl = &device.shared.context.lock();

if let Some(swapchain) = self.swapchain.take() {
Expand Down
5 changes: 3 additions & 2 deletions wgpu/examples/framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,9 @@ async fn setup<E: Example>(title: &str) -> Setup {
let surface = {
if let Some(offscreen_canvas_setup) = &offscreen_canvas_setup {
log::info!("Creating surface from OffscreenCanvas");
instance
.create_surface_from_offscreen_canvas(&offscreen_canvas_setup.offscreen_canvas)
instance.create_surface_from_offscreen_canvas(
offscreen_canvas_setup.offscreen_canvas.clone(),
)
} else {
instance.create_surface(&window)
}
Expand Down
4 changes: 2 additions & 2 deletions wgpu/src/backend/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ impl Context {
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn instance_create_surface_from_canvas(
&self,
canvas: &web_sys::HtmlCanvasElement,
canvas: web_sys::HtmlCanvasElement,
) -> Result<Surface, crate::CreateSurfaceError> {
let id = self
.0
Expand All @@ -220,7 +220,7 @@ impl Context {
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn instance_create_surface_from_offscreen_canvas(
&self,
canvas: &web_sys::OffscreenCanvas,
canvas: web_sys::OffscreenCanvas,
) -> Result<Surface, crate::CreateSurfaceError> {
let id = self
.0
Expand Down
40 changes: 30 additions & 10 deletions wgpu/src/backend/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -762,28 +762,30 @@ where
impl Context {
pub fn instance_create_surface_from_canvas(
&self,
canvas: &web_sys::HtmlCanvasElement,
canvas: web_sys::HtmlCanvasElement,
) -> Result<
(
<Self as crate::Context>::SurfaceId,
<Self as crate::Context>::SurfaceData,
),
crate::CreateSurfaceError,
> {
self.create_surface_from_context(canvas.get_context("webgpu"))
let result = canvas.get_context("webgpu");
self.create_surface_from_context(Canvas::Canvas(canvas), result)
}

pub fn instance_create_surface_from_offscreen_canvas(
&self,
canvas: &web_sys::OffscreenCanvas,
canvas: web_sys::OffscreenCanvas,
) -> Result<
(
<Self as crate::Context>::SurfaceId,
<Self as crate::Context>::SurfaceData,
),
crate::CreateSurfaceError,
> {
self.create_surface_from_context(canvas.get_context("webgpu"))
let result = canvas.get_context("webgpu");
self.create_surface_from_context(Canvas::Offscreen(canvas), result)
}

/// Common portion of public `instance_create_surface_from_*` functions.
Expand All @@ -792,6 +794,7 @@ impl Context {
/// `wgpu_hal::gles::web::Instance`.
fn create_surface_from_context(
&self,
canvas: Canvas,
context_result: Result<Option<js_sys::Object>, wasm_bindgen::JsValue>,
) -> Result<
(
Expand Down Expand Up @@ -825,7 +828,7 @@ impl Context {
.dyn_into()
.expect("canvas context is not a GPUCanvasContext");

Ok(create_identified(context))
Ok(create_identified((canvas, context)))
}
}

Expand All @@ -844,6 +847,12 @@ extern "C" {
fn worker(this: &Global) -> JsValue;
}

#[derive(Debug)]
pub enum Canvas {
Canvas(web_sys::HtmlCanvasElement),
Offscreen(web_sys::OffscreenCanvas),
}

impl crate::context::Context for Context {
type AdapterId = Identified<web_sys::GpuAdapter>;
type AdapterData = Sendable<web_sys::GpuAdapter>;
Expand Down Expand Up @@ -885,8 +894,8 @@ impl crate::context::Context for Context {
type RenderBundleEncoderData = Sendable<web_sys::GpuRenderBundleEncoder>;
type RenderBundleId = Identified<web_sys::GpuRenderBundle>;
type RenderBundleData = Sendable<web_sys::GpuRenderBundle>;
type SurfaceId = Identified<web_sys::GpuCanvasContext>;
type SurfaceData = Sendable<web_sys::GpuCanvasContext>;
type SurfaceId = Identified<(Canvas, web_sys::GpuCanvasContext)>;
type SurfaceData = Sendable<(Canvas, web_sys::GpuCanvasContext)>;

type SurfaceOutputDetail = SurfaceOutputDetail;
type SubmissionIndex = Unused;
Expand Down Expand Up @@ -949,7 +958,7 @@ impl crate::context::Context for Context {
.expect("expected to find single canvas")
.into();
let canvas_element: web_sys::HtmlCanvasElement = canvas_node.into();
self.instance_create_surface_from_canvas(&canvas_element)
self.instance_create_surface_from_canvas(canvas_element)
}

fn instance_request_adapter(
Expand Down Expand Up @@ -1138,6 +1147,17 @@ impl crate::context::Context for Context {
device_data: &Self::DeviceData,
config: &crate::SurfaceConfiguration,
) {
match surface_data.0 .0 {
Canvas::Canvas(ref canvas) => {
canvas.set_width(config.width);
canvas.set_height(config.height);
}
Canvas::Offscreen(ref canvas) => {
canvas.set_width(config.width);
canvas.set_height(config.height);
}
}

if let wgt::PresentMode::Mailbox | wgt::PresentMode::Immediate = config.present_mode {
panic!("Only FIFO/Auto* is supported on web");
}
Expand All @@ -1160,7 +1180,7 @@ impl crate::context::Context for Context {
.map(|format| JsValue::from(map_texture_format(*format)))
.collect::<js_sys::Array>();
mapped.view_formats(&mapped_view_formats);
surface_data.0.configure(&mapped);
surface_data.0 .1.configure(&mapped);
}

fn surface_get_current_texture(
Expand All @@ -1173,7 +1193,7 @@ impl crate::context::Context for Context {
wgt::SurfaceStatus,
Self::SurfaceOutputDetail,
) {
let (surface_id, surface_data) = create_identified(surface_data.0.get_current_texture());
let (surface_id, surface_data) = create_identified(surface_data.0 .1.get_current_texture());
(
Some(surface_id),
Some(surface_data),
Expand Down
4 changes: 2 additions & 2 deletions wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1599,7 +1599,7 @@ impl Instance {
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn create_surface_from_canvas(
&self,
canvas: &web_sys::HtmlCanvasElement,
canvas: web_sys::HtmlCanvasElement,
) -> Result<Surface, CreateSurfaceError> {
let surface = self
.context
Expand Down Expand Up @@ -1635,7 +1635,7 @@ impl Instance {
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
pub fn create_surface_from_offscreen_canvas(
&self,
canvas: &web_sys::OffscreenCanvas,
canvas: web_sys::OffscreenCanvas,
) -> Result<Surface, CreateSurfaceError> {
let surface = self
.context
Expand Down
2 changes: 1 addition & 1 deletion wgpu/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ fn initialize_adapter() -> (Adapter, SurfaceGuard) {
let canvas = create_html_canvas();

let surface = instance
.create_surface_from_canvas(&canvas)
.create_surface_from_canvas(canvas.clone())
.expect("could not create surface from canvas");

surface_guard = SurfaceGuard { canvas };
Expand Down

0 comments on commit 85fc427

Please sign in to comment.