Skip to content

Conversation

@nicoburns
Copy link
Contributor

@nicoburns nicoburns commented Jul 4, 2025

Created in answer to #4362

Some notes:

  • Uses dioxus-native-dom crate which contains the Dioxus <-> Blitz integration without the event loop / winit bits.
  • I am assuming that you would let Bevy setup WGPU and then use the Device and Queue from Bevy in this scenario (so you wouldn't need the WGPUContext). I am also assuming that you would do texture management.
  • You would probably store the DioxusDocument and VelloRenderer in the ECS somewhere.
  • You would need to integrate with Bevy's event loop and input
  • I think Blitz defaults to a white background, so we may need to make some changes to allow for transparent.
    Dioxus Native isn't really set up for this yet (just hasn't been something we've really worked on). So there's definitely room for improvement.

@nicoburns nicoburns added example Update examples native Related to dioxus-native labels Jul 5, 2025
@nicoburns nicoburns changed the title Create example of rendering a dioxus-native app to a texture Example of rendering a dioxus-native app to a texture Jul 7, 2025
@nicoburns nicoburns force-pushed the render-dioxus-native-to-texture branch from a72f160 to 303816d Compare July 7, 2025 18:29
@nicoburns nicoburns marked this pull request as ready for review July 7, 2025 18:29
@nicoburns nicoburns requested a review from a team as a code owner July 7, 2025 18:29
@nicoburns nicoburns force-pushed the render-dioxus-native-to-texture branch from 303816d to 17c4e29 Compare July 7, 2025 18:37
@nicoburns nicoburns force-pushed the render-dioxus-native-to-texture branch from 17c4e29 to ea8eac7 Compare July 7, 2025 22:26
@nicoburns
Copy link
Contributor Author

@jerome-caucat I've updated this to use the new dioxus-native-dom crate. This crate is split out of dioxus-native and only includes the bits you need for "headless" / "embedded" setup like this (doesn't pull in things like winit and tokio).

@jerome-caucat
Copy link
Contributor

jerome-caucat commented Jul 8, 2025

@nicoburns Thank you for this example.

I've started implementing an example rendering dioxus-native to a texture in bevy: native-headless-in-bevy

However, I'm running into an issue: the content of the Dioxus app (rsx!) doesn't appear in the texture (see the FIXME).

The VelloRenderer is rendering to the texture — I can confirm this because:

Would you happen to have an idea of what is going on, or how I could debug this?

EDIT: More info:

  • The waker callback is never called.
  • dioxus_doc.poll retruns false

@nicoburns
Copy link
Contributor Author

On vacation this week. But I think you need to call .resolve() on the inner BaseDocument before rendering (this was missing from my example). This should be called every frame.

@jerome-caucat
Copy link
Contributor

On vacation this week. But I think you need to call .resolve() on the inner BaseDocument before rendering (this was missing from my example). This should be called every frame.

@nicoburns Thanks, this helped, but I also had to add a call to initial_build:

        let mut dioxus_doc = DioxusDocument::new(vdom, None);
        dioxus_doc.initial_build();
        dioxus_doc.set_viewport(Viewport::new(WIDTH, HEIGHT, SCALE_FACTOR, COLOR_SCHEME));

BTW the call to initial_build is commented in DioxusDocument::new.

I'll handle some event and submit a PR once I have a working example.

@nicoburns
Copy link
Contributor Author

Glad you've got it working!

@jkelleyrtp Can you remember why you removed the call to "initial_build" from "new", and made it a separate method? Perhaps there is something that needs to be done in between in some use cases?

@jkelleyrtp
Copy link
Member

initial_build

Glad you've got it working!

@jkelleyrtp Can you remember why you removed the call to "initial_build" from "new", and made it a separate method? Perhaps there is something that needs to be done in between in some use cases?

This is because we need to set up the virtualdom and inject the window context into it before the first render.

See this code:

        if let Some(config) = self.pending_window.take() {
            let mut window = View::init(config, event_loop, &self.proxy);
            let renderer = window.renderer.clone();
            let window_id = window.window_id();
            let doc = window.downcast_doc_mut::<DioxusDocument>();

            doc.vdom.in_runtime(|| {
                let shared: Rc<dyn dioxus_document::Document> =
                    Rc::new(DioxusNativeDocument::new(self.proxy.clone(), window_id));
                ScopeId::ROOT.provide_context(shared);
            });

            // Add history
            let history_provider: Rc<dyn History> = Rc::new(MemoryHistory::default());
            doc.vdom
                .in_runtime(move || ScopeId::ROOT.provide_context(history_provider));

            // Add renderer
            doc.vdom
                .in_runtime(move || ScopeId::ROOT.provide_context(renderer));

            // Queue rebuild
            doc.initial_build();

            // And then request redraw
            window.request_redraw();

            // todo(jon): we should actually mess with the pending windows instead of passing along the contexts
            self.inner.windows.insert(window_id, window);
        }

@jkelleyrtp jkelleyrtp merged commit 9db593e into main Jul 15, 2025
20 checks passed
@jkelleyrtp jkelleyrtp deleted the render-dioxus-native-to-texture branch July 15, 2025 00:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

example Update examples native Related to dioxus-native

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants