WIP: Experimentation with a generating headless frames in a loop. #116

Draft
hydra wants to merge 1 commit from hydra/headless_loop into master
hydra commented 2025-12-13 13:43:46 +00:00 (Migrated from github.com)

Hi, i tried out BlueEngine today and had some success, but was met with quite a few failures too.

This PR shows the changes I made in order to create a headless_loop example.

However, there were issues:

  1. it didn't seem possible to exit the main update_loop, I fixed this by adjusting the return type of the closure that's passed to update_loop so it returns ControlFlow, thus there was no way to exit gracefully from the application.
  2. the colors of the shapes are not as expected, the results don't match the values passed to the set_color according to method signatures.
  3. the rotating triangle disappears from the output on some frames.
image
  1. rotation on the cube doesn't apply till the 4th frame.

log (from raspberry pi 5):

/home/makerpnp/.cargo/bin/cargo run --color=always --example headless_loop --no-default-features --features "static_link headless" --profile release
    Finished `release` profile [optimized] target(s) in 0.35s
     Running `target/release/examples/headless_loop`
rotation: 12.000001deg
frame 1, elapsed: 56ms, frame_duration: 56ms
rotation: 24.000002deg
frame 2, elapsed: 98ms, frame_duration: 41ms
rotation: 36deg
frame 3, elapsed: 137ms, frame_duration: 38ms
rotation: 48.000004deg
frame 4, elapsed: 167ms, frame_duration: 30ms
rotation: 60deg
frame 5, elapsed: 197ms, frame_duration: 30ms
rotation: 72deg
frame 6, elapsed: 230ms, frame_duration: 32ms
rotation: 84deg
frame 7, elapsed: 270ms, frame_duration: 40ms
rotation: 96.00001deg
frame 8, elapsed: 305ms, frame_duration: 34ms
rotation: 108.00001deg
frame 9, elapsed: 351ms, frame_duration: 46ms
rotation: 120deg
frame 10, elapsed: 396ms, frame_duration: 45ms
rotation: 132deg
frame 11, elapsed: 422ms, frame_duration: 25ms
rotation: 144deg
frame 12, elapsed: 446ms, frame_duration: 24ms
rotation: 156deg
frame 13, elapsed: 476ms, frame_duration: 29ms
rotation: 168deg
frame 14, elapsed: 507ms, frame_duration: 31ms
rotation: 180deg
frame 15, elapsed: 534ms, frame_duration: 26ms
rotation: 192.00002deg
frame 16, elapsed: 566ms, frame_duration: 32ms
rotation: 204deg
frame 17, elapsed: 592ms, frame_duration: 26ms
rotation: 216.00002deg
frame 18, elapsed: 617ms, frame_duration: 24ms
rotation: 228deg
frame 19, elapsed: 642ms, frame_duration: 25ms
rotation: 240deg
frame 20, elapsed: 667ms, frame_duration: 24ms
rotation: 252deg
frame 21, elapsed: 695ms, frame_duration: 28ms
rotation: 264deg
frame 22, elapsed: 720ms, frame_duration: 24ms
rotation: 276deg
frame 23, elapsed: 746ms, frame_duration: 26ms
rotation: 288deg
frame 24, elapsed: 775ms, frame_duration: 29ms
rotation: 300deg
frame 25, elapsed: 801ms, frame_duration: 26ms
rotation: 312deg
frame 26, elapsed: 827ms, frame_duration: 25ms
rotation: 324deg
frame 27, elapsed: 853ms, frame_duration: 26ms
rotation: 336deg
frame 28, elapsed: 880ms, frame_duration: 27ms
rotation: 348deg
frame 29, elapsed: 907ms, frame_duration: 26ms
rotation: 360deg
frame 30, elapsed: 933ms, frame_duration: 26ms
Done!, took 934ms

log from Windows 11 (AMD 5950X + NVidia 4090)

rotation: 12.000001deg
frame 1, elapsed: 7ms, frame_duration: 7ms
rotation: 24.000002deg
frame 2, elapsed: 14ms, frame_duration: 6ms
rotation: 36deg
frame 3, elapsed: 20ms, frame_duration: 6ms
rotation: 48.000004deg
frame 4, elapsed: 26ms, frame_duration: 6ms
rotation: 60deg
frame 5, elapsed: 32ms, frame_duration: 6ms
rotation: 72deg
frame 6, elapsed: 39ms, frame_duration: 6ms
rotation: 84deg
frame 7, elapsed: 47ms, frame_duration: 7ms
rotation: 96.00001deg
frame 8, elapsed: 53ms, frame_duration: 6ms
rotation: 108.00001deg
frame 9, elapsed: 59ms, frame_duration: 5ms
rotation: 120deg
frame 10, elapsed: 66ms, frame_duration: 7ms
rotation: 132deg
frame 11, elapsed: 73ms, frame_duration: 6ms
rotation: 144deg
frame 12, elapsed: 80ms, frame_duration: 6ms
rotation: 156deg
frame 13, elapsed: 86ms, frame_duration: 6ms
rotation: 168deg
frame 14, elapsed: 93ms, frame_duration: 6ms
rotation: 180deg
frame 15, elapsed: 99ms, frame_duration: 6ms
rotation: 192.00002deg
frame 16, elapsed: 105ms, frame_duration: 6ms
rotation: 204deg
frame 17, elapsed: 112ms, frame_duration: 6ms
rotation: 216.00002deg
frame 18, elapsed: 119ms, frame_duration: 6ms
rotation: 228deg
frame 19, elapsed: 125ms, frame_duration: 5ms
rotation: 240deg
frame 20, elapsed: 131ms, frame_duration: 6ms
rotation: 252deg
frame 21, elapsed: 137ms, frame_duration: 6ms
rotation: 264deg
frame 22, elapsed: 144ms, frame_duration: 6ms
rotation: 276deg
frame 23, elapsed: 150ms, frame_duration: 6ms
rotation: 288deg
frame 24, elapsed: 157ms, frame_duration: 6ms
rotation: 300deg
frame 25, elapsed: 163ms, frame_duration: 6ms
rotation: 312deg
frame 26, elapsed: 170ms, frame_duration: 6ms
rotation: 324deg
frame 27, elapsed: 177ms, frame_duration: 6ms
rotation: 336deg
frame 28, elapsed: 183ms, frame_duration: 6ms
rotation: 348deg
frame 29, elapsed: 189ms, frame_duration: 6ms
rotation: 360deg
frame 30, elapsed: 196ms, frame_duration: 6ms
Done!, took 196ms

I'm providing this feedback in the form of a draft PR, I don't expect you to merge this directly, since addtional changes are required - feel free to fix this up or make other changes.

Hi, i tried out BlueEngine today and had some success, but was met with quite a few failures too. This PR shows the changes I made in order to create a `headless_loop` example. However, there were issues: 1) it didn't seem possible to exit the main `update_loop`, I fixed this by adjusting the return type of the closure that's passed to `update_loop` so it returns `ControlFlow`, thus there was no way to exit gracefully from the application. 2) the colors of the shapes are not as expected, the results don't match the values passed to the set_color according to method signatures. 3) the rotating triangle disappears from the output on some frames. <img width="771" height="591" alt="image" src="https://github.com/user-attachments/assets/4c94f69c-ebcd-49c9-a62d-c565b1a4fd43" /> 4) rotation on the cube doesn't apply till the 4th frame. log (from raspberry pi 5): ``` /home/makerpnp/.cargo/bin/cargo run --color=always --example headless_loop --no-default-features --features "static_link headless" --profile release Finished `release` profile [optimized] target(s) in 0.35s Running `target/release/examples/headless_loop` rotation: 12.000001deg frame 1, elapsed: 56ms, frame_duration: 56ms rotation: 24.000002deg frame 2, elapsed: 98ms, frame_duration: 41ms rotation: 36deg frame 3, elapsed: 137ms, frame_duration: 38ms rotation: 48.000004deg frame 4, elapsed: 167ms, frame_duration: 30ms rotation: 60deg frame 5, elapsed: 197ms, frame_duration: 30ms rotation: 72deg frame 6, elapsed: 230ms, frame_duration: 32ms rotation: 84deg frame 7, elapsed: 270ms, frame_duration: 40ms rotation: 96.00001deg frame 8, elapsed: 305ms, frame_duration: 34ms rotation: 108.00001deg frame 9, elapsed: 351ms, frame_duration: 46ms rotation: 120deg frame 10, elapsed: 396ms, frame_duration: 45ms rotation: 132deg frame 11, elapsed: 422ms, frame_duration: 25ms rotation: 144deg frame 12, elapsed: 446ms, frame_duration: 24ms rotation: 156deg frame 13, elapsed: 476ms, frame_duration: 29ms rotation: 168deg frame 14, elapsed: 507ms, frame_duration: 31ms rotation: 180deg frame 15, elapsed: 534ms, frame_duration: 26ms rotation: 192.00002deg frame 16, elapsed: 566ms, frame_duration: 32ms rotation: 204deg frame 17, elapsed: 592ms, frame_duration: 26ms rotation: 216.00002deg frame 18, elapsed: 617ms, frame_duration: 24ms rotation: 228deg frame 19, elapsed: 642ms, frame_duration: 25ms rotation: 240deg frame 20, elapsed: 667ms, frame_duration: 24ms rotation: 252deg frame 21, elapsed: 695ms, frame_duration: 28ms rotation: 264deg frame 22, elapsed: 720ms, frame_duration: 24ms rotation: 276deg frame 23, elapsed: 746ms, frame_duration: 26ms rotation: 288deg frame 24, elapsed: 775ms, frame_duration: 29ms rotation: 300deg frame 25, elapsed: 801ms, frame_duration: 26ms rotation: 312deg frame 26, elapsed: 827ms, frame_duration: 25ms rotation: 324deg frame 27, elapsed: 853ms, frame_duration: 26ms rotation: 336deg frame 28, elapsed: 880ms, frame_duration: 27ms rotation: 348deg frame 29, elapsed: 907ms, frame_duration: 26ms rotation: 360deg frame 30, elapsed: 933ms, frame_duration: 26ms Done!, took 934ms ``` log from Windows 11 (AMD 5950X + NVidia 4090) ``` rotation: 12.000001deg frame 1, elapsed: 7ms, frame_duration: 7ms rotation: 24.000002deg frame 2, elapsed: 14ms, frame_duration: 6ms rotation: 36deg frame 3, elapsed: 20ms, frame_duration: 6ms rotation: 48.000004deg frame 4, elapsed: 26ms, frame_duration: 6ms rotation: 60deg frame 5, elapsed: 32ms, frame_duration: 6ms rotation: 72deg frame 6, elapsed: 39ms, frame_duration: 6ms rotation: 84deg frame 7, elapsed: 47ms, frame_duration: 7ms rotation: 96.00001deg frame 8, elapsed: 53ms, frame_duration: 6ms rotation: 108.00001deg frame 9, elapsed: 59ms, frame_duration: 5ms rotation: 120deg frame 10, elapsed: 66ms, frame_duration: 7ms rotation: 132deg frame 11, elapsed: 73ms, frame_duration: 6ms rotation: 144deg frame 12, elapsed: 80ms, frame_duration: 6ms rotation: 156deg frame 13, elapsed: 86ms, frame_duration: 6ms rotation: 168deg frame 14, elapsed: 93ms, frame_duration: 6ms rotation: 180deg frame 15, elapsed: 99ms, frame_duration: 6ms rotation: 192.00002deg frame 16, elapsed: 105ms, frame_duration: 6ms rotation: 204deg frame 17, elapsed: 112ms, frame_duration: 6ms rotation: 216.00002deg frame 18, elapsed: 119ms, frame_duration: 6ms rotation: 228deg frame 19, elapsed: 125ms, frame_duration: 5ms rotation: 240deg frame 20, elapsed: 131ms, frame_duration: 6ms rotation: 252deg frame 21, elapsed: 137ms, frame_duration: 6ms rotation: 264deg frame 22, elapsed: 144ms, frame_duration: 6ms rotation: 276deg frame 23, elapsed: 150ms, frame_duration: 6ms rotation: 288deg frame 24, elapsed: 157ms, frame_duration: 6ms rotation: 300deg frame 25, elapsed: 163ms, frame_duration: 6ms rotation: 312deg frame 26, elapsed: 170ms, frame_duration: 6ms rotation: 324deg frame 27, elapsed: 177ms, frame_duration: 6ms rotation: 336deg frame 28, elapsed: 183ms, frame_duration: 6ms rotation: 348deg frame 29, elapsed: 189ms, frame_duration: 6ms rotation: 360deg frame 30, elapsed: 196ms, frame_duration: 6ms Done!, took 196ms ``` I'm providing this feedback in the form of a draft PR, I don't expect you to merge this directly, since addtional changes are required - feel free to fix this up or make other changes.
Gipson62 commented 2025-12-13 13:59:23 +00:00 (Migrated from github.com)

Damn, crazy PR, very good work. And I would say the issue of object disappearing is partially happening in this loop. Potentially related to the bind group logic. The other potential issue would be the culling used by wgpu hiding the triangle, but I doubt that.

Damn, crazy PR, very good work. And I would say the issue of object disappearing is partially happening in [this loop](https://github.com/AryanpurTech/BlueEngine/blob/master/crates/blue_engine_core/src/render.rs#L341). Potentially related to the bind group logic. The other potential issue would be the culling used by `wgpu` hiding the triangle, but I doubt that.
ElhamAryanpur commented 2025-12-14 06:51:12 +00:00 (Migrated from github.com)

Amazing work! Thank you so much, I really appreciate this!

Gipson is right, the wgpu usualy culls backface by default hence why when triangle is rotated backwards, it disappears. This can be set in ObjectSettings, I'll look into it myself too since I was planning for an overhaul to them.

About the cube not moving, that is a good point, I should look into that. Thank you!

Amazing work! Thank you so much, I really appreciate this! Gipson is right, the wgpu usualy culls backface by default hence why when triangle is rotated backwards, it disappears. This can be set in ObjectSettings, I'll look into it myself too since I was planning for an overhaul to them. About the cube not moving, that is a good point, I should look into that. Thank you!
ElhamAryanpur commented 2025-12-14 06:53:05 +00:00 (Migrated from github.com)

I should look into colors as well. The colors are passed directly, but it could also have been texture color formats as well causing it 👀

I should look into colors as well. The colors are passed directly, but it could also have been texture color formats as well causing it 👀
ElhamAryanpur commented 2025-12-14 07:41:30 +00:00 (Migrated from github.com)

I see that this is a breaking change by default since it requires a ControlFlow return. It may do good to have it optional instead. Let me investigate

I see that this is a breaking change by default since it requires a ControlFlow return. It may do good to have it optional instead. Let me investigate
ElhamAryanpur commented 2025-12-14 10:18:56 +00:00 (Migrated from github.com)

After a lot of investigating, the best way in my opinion would be to remove it from the return type and rather set it in the engine as a field instead. This helps both not break backwards compatibility, but also allows users to not require to set it on every loop as well.

Closest thing that would've worked as return would've been a struct with From<()> implemented, but even then it'd require ().into() to be called every time.

After a lot of investigating, the best way in my opinion would be to remove it from the return type and rather set it in the engine as a field instead. This helps both not break backwards compatibility, but also allows users to not require to set it on every loop as well. Closest thing that would've worked as return would've been a struct with From<()> implemented, but even then it'd require ().into() to be called every time.
ElhamAryanpur commented 2025-12-14 10:52:18 +00:00 (Migrated from github.com)

github.com/AryanpurTech/BlueEngine@679410d15d

Also fixed the triangle not displaying issue

https://github.com/AryanpurTech/BlueEngine/commit/679410d15d4b93a717c617f47c4c5748fa1546e4 Also fixed the triangle not displaying issue
Gipson62 commented 2025-12-14 12:30:18 +00:00 (Migrated from github.com)

Maybe it's kind of stupid, but why not making it possible for everyone, be it headless or not, to break from the update loop? Why should it be restricted only to headless mode? What if I wanted to do it on a game? It wouldn't be that much of an issue to allow it globally

Maybe it's kind of stupid, but why not making it possible for everyone, be it headless or not, to break from the update loop? Why should it be restricted only to headless mode? What if I wanted to do it on a game? It wouldn't be that much of an issue to allow it globally
ElhamAryanpur commented 2025-12-14 13:30:35 +00:00 (Migrated from github.com)

non headless mode already has it, with engine.window.should_close I believe.

There are many reasons as to why theres a difference, but simplest reason is that the windowed version's loop is controlled by winit, hence why it is based on window to close itself

non headless mode already has it, with engine.window.should_close I believe. There are many reasons as to why theres a difference, but simplest reason is that the windowed version's loop is controlled by winit, hence why it is based on window to close itself
This pull request is marked as a work in progress.
This branch is out-of-date with the base branch
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin hydra/headless_loop:hydra/headless_loop
git switch hydra/headless_loop

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch master
git merge --no-ff hydra/headless_loop
git switch hydra/headless_loop
git rebase master
git switch master
git merge --ff-only hydra/headless_loop
git switch hydra/headless_loop
git rebase master
git switch master
git merge --no-ff hydra/headless_loop
git switch master
git merge --squash hydra/headless_loop
git switch master
git merge --ff-only hydra/headless_loop
git switch master
git merge hydra/headless_loop
git push origin master
Sign in to join this conversation.
No description provided.