Skip to content
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

Help with rendering empty scenes. #356

Closed
Sol-Ell opened this issue Aug 20, 2023 · 1 comment
Closed

Help with rendering empty scenes. #356

Sol-Ell opened this issue Aug 20, 2023 · 1 comment

Comments

@Sol-Ell
Copy link

Sol-Ell commented Aug 20, 2023

Intro

Recently I have been experimenting with Vello. As an initial project I decided to make an app with one circle at top.
Getting started, I realized that the Renderer can not render empty scenes or scenes with empty fragments added on the surface. However, if add fragment filled with circle into scene, scene would be rendered. This error also occurs when scene fragment added when creating window(fn new() called).

Where am I wrong, is it bug?

Error

Empty scene error

Everything works fine if you uncomment these lines:

            // let mut builder = SceneBuilder::for_scene(&mut self.scene);
            // builder.append(&self.fragment, None);

Code

#![allow(warnings, unused)]

use glazier::{Application, WinHandler, WindowBuilder, WindowHandle, Scalable};
use glazier::kurbo::{self, Affine, Circle, Point};
use tokio::runtime::Runtime;
use vello::peniko::{Color, BrushRef};
use vello::{Renderer, RendererOptions, Scene, SceneBuilder, SceneFragment, RenderParams};
use vello::util::{RenderContext, RenderSurface, DeviceHandle};

struct MainWin {
    handle: WindowHandle,
    rt: Runtime,
    renderer: Option<Renderer>,
    render_ctx: RenderContext,
    surface: Option<RenderSurface>,
    scene: Scene,
    fragment: SceneFragment,
}

impl MainWin {
    fn new() -> Self {
        let mut fragment = SceneFragment::default();

        // Fill scene fragment with circle
        SceneBuilder::for_fragment(&mut fragment)
            .fill(
                vello::peniko::Fill::EvenOdd, 
                Affine::IDENTITY, 
                BrushRef::Solid(Color::AQUA), 
                None, 
                &Circle::new(Point::new(50.0, 50.0), 20.0)
            );
        
        let scene = Scene::default();

        // Error remains even after adding scene fragment.
        // SceneBuilder::for_scene(&mut self.scene)
        //     .append(&self.fragment, None);
        Self {
            handle: WindowHandle::default(),
            rt: Runtime::new().unwrap(),
            renderer: None,
            render_ctx: RenderContext::new().unwrap(),
            surface: None,
            scene,
            fragment
        }
    }
} 

impl WinHandler for MainWin {
    fn connect(&mut self, handle: &glazier::WindowHandle) {
        self.handle = handle.clone();
        
        SceneBuilder::for_scene(&mut self.scene);
    }

    fn prepare_paint(&mut self) {
        
    }

    fn paint(&mut self, _invalid: &glazier::Region) {
        // Create surface 
        if self.surface.is_none() {
            let kurbo::Size { width, height } = self.handle.get_size();

            let surface = self.rt.block_on(
                    self.render_ctx.create_surface(&self.handle, width as u32, height as u32)
                )
                .unwrap();
            let dev_id = surface.dev_id;
            let DeviceHandle { device, queue, .. } = &self.render_ctx.devices[dev_id];
            self.renderer = Some(Renderer::new(
                &device, 
                &RendererOptions {
                    surface_format: Some(surface.format),
                    timestamp_period: queue.get_timestamp_period(),
                }
            ).unwrap());

            self.surface = Some(surface);
        }

        // get window dimensions
        let (width, height) = {
            let handle = &self.handle;
            let scale = handle.get_scale().unwrap_or_default();
            let insets = handle.content_insets().to_px(scale);
            let size = handle.get_size().to_px(scale);
            (   
                (size.width - insets.x_value()) as u32,
                (size.height - insets.y_value()) as u32
            )
        };

        if let Some(surface) = &mut self.surface {
            // Resize surface if needed
            if surface.config.width != width || surface.config.height != height {
                self.render_ctx.resize_surface(surface, width, height);
            }

            // Append fragment with circle
            // Everything is file until scene has some fragment added
            // let mut builder = SceneBuilder::for_scene(&mut self.scene);
            // builder.append(&self.fragment, None);

            let surface_texture = surface
                .surface
                .get_current_texture()
                .expect("failed to acquire next swapchain texture");

            let DeviceHandle { device, queue, .. } = 
                &self.render_ctx.devices[surface.dev_id];
            
            let renderer_options = RendererOptions {
                surface_format: Some(surface.format),
                timestamp_period: queue.get_timestamp_period(),
            };

            let render_params = RenderParams {
                base_color: Color::BLACK,
                width,
                height,
            };

            // Render empty scene to surface
            self.renderer
                .get_or_insert_with(|| Renderer::new(device, &renderer_options).unwrap())
                .render_to_surface(device, queue, &self.scene, &surface_texture, &render_params)
                .expect("failed to render to surface");
            
            surface_texture.present();
            device.poll(wgpu::Maintain::Wait);
        }
    }

    fn as_any(&mut self) -> &mut dyn std::any::Any {
        self
    }

    fn request_close(&mut self) {
        self.handle.close();
        Application::global().quit();
    }
}

fn main() {
    let app = Application::new()
        .unwrap();

    let win = WindowBuilder::new(app.clone())
        .handler(Box::new(MainWin::new()))
        .resizable(false)
        .build()
        .unwrap();

    win.show();
    
    app.run(None);
}
@DJMcNab
Copy link
Member

DJMcNab commented Aug 20, 2023

Seems like a duplicate of #291. For now, basically we say to not render empty scenes

@Sol-Ell Sol-Ell closed this as completed Aug 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants