servo / pathfinder

A fast, practical GPU rasterizer for fonts and vector graphics
Apache License 2.0
3.6k stars 201 forks source link

Example of resizing the window and surface? #403

Closed nathansobo closed 4 years ago

nathansobo commented 4 years ago

I'm hitting some challenges resizing the surface to which a Renderer is drawing. I can resize the window vertically without a problem, but when I resize horizontally, every other draw puts the window in a state where I am rendering garbage. If I get into a state where the draws cleanly, then every subsequent frame at the same size renders fine, as do vertical resizes. If I get into a bad state, subsequent frames render as garbage, as do vertical resizes.

resize-artifacts

Here's my render_scene function which handles resizing if necessary, then renders the scene.

    fn render_scene(
        &mut self,
        window_size: Vector2F,
        scale_factor: f32,
        scene: Scene,
        frame_start: std::time::Instant,
    ) {
        let device_size = window_size * scale_factor;
        if self.device_size != device_size {
            self.scene_proxy
                .set_view_box(RectF::new(Vector2F::zero(), device_size));
            self.device_size = device_size;

            log::info!(
                "resize surface {} {}",
                device_size.x() as i32,
                device_size.y() as i32
            );

            let mut surface = self
                .device
                .unbind_surface_from_context(&mut self.context)
                .unwrap()
                .unwrap();
            self.device
                .resize_surface(
                    &mut self.context,
                    &mut surface,
                    euclid::Size2D::new(device_size.x() as i32, device_size.y() as i32),
                )
                .expect("Failed to resize surface!");
            self.device
                .bind_surface_to_context(&mut self.context, surface)
                .unwrap();

            self.renderer.options_mut().dest = DestFramebuffer::full_window(device_size.to_i32());

            let default_framebuffer = self
                .device
                .context_surface_info(&self.context)
                .unwrap()
                .unwrap()
                .framebuffer_object;
            self.renderer
                .device_mut()
                .set_default_framebuffer(default_framebuffer);
        }

        self.scene_proxy.replace_scene(scene);
        self.scene_proxy
            .build_and_render(&mut self.renderer, BuildOptions::default());

        let mut surface = self
            .device
            .unbind_surface_from_context(&mut self.context)
            .unwrap()
            .unwrap();
        self.device
            .present_surface(&mut self.context, &mut surface)
            .expect("Failed to present surface!");
        self.device
            .bind_surface_to_context(&mut self.context, surface)
            .unwrap();
    }

From my description or this code, is there something obvious I'm doing wrong here? It looks like all your examples don't handle surface resizes. If you had time to demo it I'd be very appreciative.

Apologies if this is the wrong forum for asking about this. No offense taken if you decide to close it.

nathansobo commented 4 years ago

I think I've figured it out. Pretty sure this is a bug in surfman. I'll submit a PR.

nathansobo commented 4 years ago

Here's the PR: https://github.com/servo/surfman/pull/197