Feat: Offscreen Rendering & Screenshots#1783
Feat: Offscreen Rendering & Screenshots#1783bungoboingo wants to merge 4 commits intoiced-rs:advanced-textfrom
Conversation
72af4e8 to
418b3b1
Compare
|
Lint wants me to change |
How about |
Quite subjective, in my opinion. I think it's fairly standard to group evenly. Does |
Lint is happy with 0xFF_00_00_00; I adjusted it to that format, I'm fine with that 👍 |
7c31055 to
4d30cae
Compare
…he window::screenshot command.
Adjusted documentation to be more clear; Fixed some formatting
4d30cae to
72c21ce
Compare
This PR adds support for offscreen rendering in Iced! 🎉
screenshot_demo.mov
📸 Users can now capture screenshots 🖼️ using the
window::screenshot()command.The
window::screenshotcommand requires aMessagewhich takes aScreenshot. This is a new struct exposed in theiced_runtimecrate which contains the RGBA bytes of the screenshot, in addition to its size.For now this command is limited to the entire viewport, with an optional
crop()method available which will crop the bytes to the specifiedRectangle.cropping.mov
This method returns a
Result<Screenshot, CropError>for situations where the cropped region is out of bounds, or is not visible.🎉 Offscreen rendering capabilities are now added to both
wgpuandtiny_skia!Rendering offscreen is now exposed in the
Compositorinterface with arender_offscreenfunction. The outputted texture data is always guaranteed to be in RGBA format in the SRGB color space for compatibility with image libraries & iced images, and to simplify theScreenshotstruct with a predetermined byte order & pixel size.🔢 Implementation details
For
wgpu, performing offscreen rendering was fairly straightforward. I create a texture based on the viewport size & the chosen texture format, and then pass that into the backend with a newbackend.offscreenmethod. This method performs a normal render pass on the new texture, and optionally runs a tiny compute shader after drawing all primitives that converts it towgpu::TextureFormat::Rgba8Unormwith a manual srgb conversion due towgpu::TextureFormat::Rgba8UnormSrgbnot being a supported format for a storage texture. The whole process on my (admittedly very powerful!) test suite of GPUs (AMD, NVIDIA, M1) took about ~2µs in the test example. The only added overhead over a normal render pass is the compute shader to convert to rgba.For
tiny-skiathis was very straightforward, the same as a normalpresentcall but rendering to a new buffer vs the surface buffer. Our backend returnsARGBformat, so just had to do some bit shiftin' and we're all good.🤔 Outstanding API questions
It was discussed whether it's a cleaner API to do a
window::screenshotcommand which optionally can be cropped, or awindow::screenshot(area)command which can either beFullscreenorRegion, which would be a rectangle. Obviously there is a performance hit when rendering the whole window to an offscreen buffer vs a potentially very small region if only a small portion is desired, but the execution is so fast it's almost negligible. I'm curious as to people's thoughts on this!The offscreen render capabilities are only exposed at the moment through this
window::screenshotcommand. The intent was to implement the capabilities for offscreen rendering in this PR and expand upon it further in later iterations if new applications of offscreen rendering are needed. Curious to see if anyone has any thoughts on how else this might be exposed!🧪 Testing
Tested wgpu & tiny-skia implementations on MacOS + M1, Linux + PopOS + AMD, Windows 10 + Nvidia combos. Further testing would be greatly appreciated!
Feedback very much welcome! This was my first time working this deeply with textures on the GPU so might have made some rookie mistakes 😉 I also know that there is an open draft PR for offscreen rendering but it hasn't been updated in a few years so thought I'd take a crack at it.