Skip to content

Expose window 'surface' size, distinct from the 'inner' size #2308

@rib

Description

@rib

Edited: to use "surface size" instead of "physical size" as discussed. The edit also tries to clarify the table information.

Currently the general, go-to API for querying the size of a winit window is .inner_size() which has conflicting requirements due to some downstream consumers wanting to know the size to create render surfaces and other downstream consumers wanting to know the safe, inner bounds of content (which could exist within a potentially larger surface).

For lower-level rendering needs, such as for supporting integration with wgpu and or directly with opengl / vulkan etc then what downstream wants to know is the size of the surface they should create, which effectively determines how much memory to allocate for a render target and the width and height of that render target.

Incidentally, 'physical size' is how the Bevy engine refers to the size it tracks, based on reading the winit .inner_size() which is a good example where it's quite clear what semantics they are primarily looking for (since they will pass the size to wgpu to configure render surfaces). In this case Bevy is not conceptually interested in knowing about insets for things like frame decorations or mobile OS safe areas.

Conceptually the inner_size() is 'inner' with respect to the 'outer' size, and the outer_size() is primarily applicable to desktop window systems which may have window frames that extend outside the content area of the applications window, and may also be larger than the surface size that's used by the application for rendering. For example on X11 the inner size will technically relate to a separate smaller child window that's parented by the window manager onto a larger frame window.

Incidentally on Wayland which was designed to try and encourage client-side window decorations and also sandbox clients the core protocol doesn't let you introspect frame details or an outer screen position.

Here's a matrix to try and summarize the varying semantics for the inner/outer and surface sizes across window systems to help show why I think it would be useful to expose the physical size explicitly, to decouple it from the inner_size:

Window System Outer Size Inner Size Surface Size
X11 Size of parent frame window owned by the window manager (e.g. with title bar and border around content) Size of nested content window (which is usually a child of the frame window)

This may vary but I want to highlight that on X11 due to it's async nature there are times where it makes sense to optimistically refer to a pending/requested size (so e.g. .set_inner_size() followed by .inner_size() can return a pending size) but the 'surface' size would be the remote, server-side size
Size of nested content window (which is usually a child of the frame window)

In some situations the driver may need to reconcile mismatched surface/window sizes due to async resizing of window, e.g. using a top-left gravity and no scaling.
Wayland wl_surface size.

Protocol has no notion of frames but clients may draw their own window decorations and impose their own inner inset.
Based on wl_surface size but application defined. Wayland clients may have client-side decorations whereby an 'inner size' could be smaller than the surface (Would be a bit like a self-imposed safe area as seen on mobile) Size of client-side allocated wl_buffer.

Notably there may be a scale and rotation between the wl_buffer and the wl_surface to account for the physical display (e.g. client may render rotated 90 degrees for a display that's connected with an internal rotation that doesn't match the product from the user's pov)
Windows Size of full frame (e.g. with title bar and border around content) Content Size Same as content size I think?

Tbh this is the window system I'm least familiar with so I'm not clear on how the compositor maps rendered buffers to windows, and what kind of transforms it allows, if any)
macOS NSWindow size NSView size CAMetalLayer drawableSize
iOS UIView size UIView safeAreaInsets CAMetalLayer drawableSize.

Note that in wgpu it looks like they ignore sizes given by the application for configuring surfaces which is lucky considering winit reports an inset safe area which also gets treated as a physical size for configuring render surfaces
Android Screen size.

Possibly transposed according to how a display is physically mounted
Inset (safe) content area SurfaceView size

Note: similar to Wayland it's possible to have a render-surface transform to account for how a display is physically mounted to take full advantage of hardware compositing

An example where the conflation of inner and surface size is problematic is on Android where we want to let downstream APIs like Bevy know what size they should allocate render surfaces but we also want to let downstream users (e.g. also Bevy, or any UI toolkit such as egui) know what the safe inner bounds are for rendering content that won't be obscured by things like camera notches or system
toolbars. (ref: #2235)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions