-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: headless rendering #1176
feat: headless rendering #1176
Conversation
with to run, this test, you can clone this branch, cd into If we do not limit test threads to 1, then we crash trying to create a |
Hey! Thanks for giving this a shot! There were already some existing efforts in the same direction in #957 by @derezzedex with some discussion. It'd be great to compare both approaches and finally settle on the best way to expose the offscreen functionality. When it comes to testing, I believe there is a lot of room to build the functionality on top of the |
I agree, we should have consensus on which direction we'd like to go with offscreen rendering. To give my perspective comparing #957 and this PR: features in #957 :
features in this PR:
This is a good point, I agree that it would be best to have all testing live as a layer "above" iced and an the big question that I'd like to answer with this PR is: what API should we expose in iced to run a headless application the two ways I think we could address this question:
There are a lot of ways to approach this though. what does everyone think? FWIW, the pub fn main() -> iced::Result {
let msg_trace = vec![
(Message::IncrementPressed, Duration::new(1, 0)),
(Message::IncrementPressed, Duration::new(2, 0)),
(Message::IncrementPressed, Duration::new(2, 0)),
(Message::TakeScreenshot, Duration::new(3, 0)),
];
Counter::run_with_message_trace(
Settings {
headless: true,
window: iced::window::Settings {
size: (600, 600),
..iced::window::Settings::default()
},
..Settings::default()
},
msg_trace,
)
} I think a |
e6ab610
to
8b0f2e6
Compare
I've peeled back a lot of changes originally in this commit; an updated list: Changes visible to end users
Internal changes:
I'm open to removing the On a related note; I've created a small iced-test crate here. This crate uses the screenshot APIs brought up by this PR, and provides an interface to run applications headlessly via |
* headless propegation from Application settings-> Compositor settings * Removed the InitHeadlessBuffer; initializing a headless buffer is done now in Compositor instation (if the setting is set) * refactored code for less copy and pasting (still some to clean up in the read read impl current strategy is to create a buffer anytime we want a screenshot (and we are in non-headless mode. we dont map this buffer when we instatiate it, but it might be faster to do that
…nheadless mode as a render to a buffer
To be fair, if we would want to have Screenshot support in Iced, it's much better to split them in another PR. 😇 |
As a side note, it's maybe a good solution to have them behind a |
I think this PR was trying to do a little too much :) I spun these changes out into a third party lib earlier this year: https://github.com/1024bees/iced_test. It almost certainly out of date as I've not been focusing on iced, but it should be a starting point if anyone wants to add in testing utils (if they havent been added in). Closing this now. Cheers! |
Hey folks, this is a first best effort to add headless rendering into Iced. Alot of these changes are built up from #957
Changes visible to end users
Screenshot
type and screenshotCommand
s. Screenshots can be serialized to/from pngs. the interface provided isfn take_screenshot(message_generator : Box<dyn Fn(Option<Screenshot>) -> Message>) -> Command<Message>
headless
flag inSettings
run_with_message_trace
interface to run an application without user interaction. This interface allows end users to provide "Message Traces" that a vectors of items (Application::Message, std::time::Duration). Each Message is sent to the Application after Duration passes. After the last message is dispatched.Internal changes:
RunetimeArgs
type to encapsulate extra args passed tocrate::runtime::application::run
VirtualCompositor
trait and aVirtualCompositor
trait bound to eachCompositor
backend (wgpu, opengl). This trait object is passed as an argument torun_command
, and allowsrun_command
to be shared across glutin and winit still.Comments
I like the idea of "Message Traces" and think they're a good first effort to provide a "test-like way" to run applications. Not sure if Message Trace is the best name to describe the concept though.
The
VirtualCompositor
trait is a leaky abstraction; it broadly encapsulates behaviors from bothwgpu
andopengl
. To be concrete, therequires_rerender
,queue_screenshot
,is_screenshot_queued
anddequeue_screenshot
are all methods that are only implemented for thewgpu
compositor. These methods are required to support screenshotiting wgpu applications that are presenting windows to the user. They are required because currently, textures that are presented to the screen can NOT be directly copied from into a buffer.This is a limitation of WGPU's (to be explicit, the issue is that Textures attached to Surfaces cannot configured to be the sources of copies) current implementation, and the folks over there said that in theory, this limitation could be addressed. As a work around, the current implimentation of screenshots on WGPU requires us to re-render the screen to a framebuffer, that is then copied into a screenshot object. If/when the limitation on textures attached to surfaces is addressed in WGPU, the screenshotting strategy (and VirtualCompositor trait) should be streamlined across wgpu and opengl compositors.
not sure if the location of
Screenshot
andRuntimeArgs
data structures is correct. I put them both iniced_native
, worth reviewing.I would like to add a mechanism to inspect Application state once a "Message Trace" has been exhausted. One idea is that we could have
run_with_message_trace
return the Application, and state could be inspected from that point onwards.Blockers
cargo test
is called to run an application, check the differences between a "golden" png and a png created by runtime