The subscription feature doesn't work when integrating iced with existing application

Recently I am developing PDF Viewer on top of iced GUI and try to render PDF with vello. So I need to get following from wgpu and winit.

    window,
    device,
    queue,
    surface

I tried the integration example which shows how to do this job, but the subscription feature doesn’t work.

The example does something like this

use iced_winit::runtime::program;

  let state = program::State::new(
          program,
          viewport.logical_size(),
          &mut renderer,
          &mut debug,
      );

the iced_winit::runtime::program doesn’t have the subscription method, not the one from iced_winit crate, so no executor exists, that is why the subscription feature not work.

Any other way to do the integration without compromise please?

@hecrj Can I get a hand on this topic please?

The wgpu renderer has a draw_primitive method, it seems we can use it to render anything inside a customized widget, nice !

The primitive can’t be used this way, failed with following code.


impl PdfPrimitive
{
    pub fn new() -> Self
    {
        let render_params = vello::RenderParams {
            base_color: vello::peniko::Color::BLACK,
            width,
            height,
            antialiasing_method: vello::AaConfig::Area,
        };

        Self {
            render_params
        }
    }
}

impl iced_wgpu::Primitive for PdfPrimitive
{
    fn prepare(
        &self,
        device: &wgpu::Device,
        queue: &wgpu::Queue,
        format: wgpu::TextureFormat,
        storage: &mut iced_wgpu::primitive::Storage,
        bounds: &Rectangle,
        viewport: &iced::graphics::Viewport,
    )
    {
        // 1. Unable to save renderer variable  to self for it is not mutable
        // 2. also  the vello Renderer doesn't fulfill the  
        // this constraint:    pub trait Primitive: Debug + Send + Sync + 'static,
       let renderer = vello::Renderer::new(
            device,
            RendererOptions {
                surface_format: None,
                use_cpu: false,
                num_init_threads: NonZeroUsize::new(1),
                antialiasing_support: vello::AaSupport::area_only(),
            },
        ).ok();
    }

    fn render(
        &self,
        encoder: &mut wgpu::CommandEncoder,
        storage: &Storage,
        target: &wgpu::TextureView,
        clip_bounds: &Rectangle<u32>,
    ) {
        // the VelloBackend needs to mutate its argument, but  self is not mutable
        // maybe I can use Refcell
        let mut backend: VelloBackend<'_> = VelloBackend::new(&mut self.cache);

        let resolver = self.file.resolver();

        render_page(&mut backend, &resolver, &page, Transform2F::default()).ok()?;

        let scene = backend.finish();

        let mut render_pass = encoder.begin_render_pass(
            &wgpu::RenderPassDescriptor {
                label: Some("iced_wgpu render pass"),
                color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                    view: frame,
                    resolve_target: None,
                    ops: wgpu::Operations {
                        load: match clear_color {
                            Some(background_color) => wgpu::LoadOp::Clear({
                                let [r, g, b, a] =
                                    graphics::color::pack(background_color)
                                        .components();

                                wgpu::Color {
                                    r: f64::from(r),
                                    g: f64::from(g),
                                    b: f64::from(b),
                                    a: f64::from(a),
                                }
                            }),
                            None => wgpu::LoadOp::Load,
                        },
                        store: wgpu::StoreOp::Store,
                    },
                })],
                depth_stencil_attachment: None,
                timestamp_writes: None,
                occlusion_query_set: None,
            },
        );
        render_pass.set_scissor_rect(clip_bounds.x, clip_bounds.y, clip_bounds.width, clip_bounds.height);

        // Unable to get queue and device, because the prepare method is not mutable

        if let Some(renderer) = self.renderer.as_mut() {
            renderer
                .render_to_texture(device, queue, &scene, &target, &self.render_params)
                .or_else(|_| bail!("Got non-Send/Sync error from rendering"))?;
        }
    }
}

Hi, @videni! Could you get your PDF Viewer running? I’m interested in this functionality and it will be nice to know if it worked for you.

Thanks!

Yes, but there’s still a lot of work to do. My original intention was to make it a free, cross-platform, high-performance PDF Reader, but I don’t have enough resources to invest further. Once my current project is completed and stabilized, I should continue to invest in it. My previous implementation, with the help of Sebatisian, the author of pdf.rs, has been able to render via Vello. You can go there for help, and Sebastisian will be very enthusiastic to assist you.