rust-windowing / softbuffer

Easily write an image to a window
Apache License 2.0
312 stars 45 forks source link

hardware scaling #177

Open jkarneges opened 10 months ago

jkarneges commented 10 months ago

The readme says:

Softbuffer should be used over pixels when its GPU-accelerated post-processing effects are not needed.

When I first read this, it didn't occur to me that "post-processing effects" included scaling. I was thinking it was more about things like CRT simulation. Unfortunately, scaling is often a requirement due to high resolution displays. Anyone doing full frame redraws and desiring good performance (60fps+) will almost certainly need to operate on a smaller buffer that can be scaled up, which pixels can do. I couldn't get acceptable performance with softbuffer and software scaling, although admittedly I didn't try very hard on the scaling algorithm.

I wonder if softbuffer could make an exception and support hardware scaling, if it wouldn't go against the spirit of the project. It feels like an almost table-stakes feature for most real world use.

kpreid commented 10 months ago

Even without explicitly using GPU APIs, platforms likely have a built-in scaling operation available in their 2D graphics APIs, which could be faster due to knowing platform details, being fused with other necessary copies along the buffer-to-screen path, or actually being GPU-based.

ids1024 commented 10 months ago

On Wayland, https://wayland.app/protocols/viewporter can be used to crop and scale a buffer. It doesn't provide a way to control the scaling algorithm, but probably would provide good results if you're careful to use an integer scale factor? If so it could be useful for software-rendered pixel art games.

It's not necessarily supported on all compositors. Though it probably should be. Mir doesn't seem to support it yet, anyway (https://github.com/MirServer/mir/issues/2599).

I'm not sure about other platforms.

On most platforms, you shouldn't need this just for handling hiDPI displays, since applications that don't advertise HiDPI support will be scaled automatically. Though the results are ugly with fractional scales. X11 doesn't really seem to have that though, and HiDPI can be a mess there.

notgull commented 10 months ago

X11 and Windows do not support intrinsic scaling

ids1024 commented 10 months ago

On Windows we're currently using BitBlt (comments in SDL said this was the fastest solution when they tried it; but that was a while ago). Looks like https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchblt may work here?

On macOS, would https://developer.apple.com/documentation/quartzcore/calayer/1410746-contentsscale be applicable? I'm not sure.

Anyway, if it works on some platforms, but isn't supported on others, or only sometimes is available, either:

For HiDPI uses, some platforms have a specific way to communicate what DPI scale an application should use, and for the application to indicate if it handles the scale itself or needs upscaling (for legacy software, mainly). That doesn't necessarily require handling from Softbuffer, but probably should be discussed in any documentation for this feature.

Fuseteam commented 1 month ago

It's not necessarily supported on all compositors. Though it probably should be. Mir doesn't seem to support it yet, anyway (canonical/mir#2599).

It does now :D

MarijnS95 commented 1 week ago

On Android scaling is implicitly supported (and should be executed by the presentation hardware or software GPU compositing depending on the vendor/SoC). The default ANativeWindow_setBuffersGeometry() that we call to set up a format and size on the backing buffers describes explicitly what happens when the "window" surrounding it (really just a Surface in the compositor tree where the buffers is drawn) has different dimensions from the values passed in this call (i.e. scaling occurs).

The lower-level SurfaceControl.Transaction.setGeometry() / ASurfaceTransaction_setGeometry() variants of this method more explicitly show how to select and scale a region of the source-buffer to put in a rectangle on the screen. With these methods now deprecated, setScale()/setPosition()/`setCrop()/setBufferTransform() make this even more clear.