summaryrefslogblamecommitdiffstats
path: root/glow/src/window/compositor.rs
blob: 8f770065bb5432c4b657bfe8d842f8b24fe10118 (plain) (tree)
1
2
3
4
5
6
7
8
9







                                                         
                       





                                    
                                                     




                              
                                               



















                                                                                
              











                                                                   
                                                                               
































































































                                                                                  






                                                




















                                                                       
                          





                                                  
use crate::{Renderer, Settings, Viewport};

use glow::HasContext;
use iced_native::mouse;
use raw_window_handle::HasRawWindowHandle;

/// A window graphics backend for iced powered by `glow`.
#[allow(missing_debug_implementations)]
pub struct Compositor {
    connection: surfman::Connection,
    device: surfman::Device,
    gl_context: surfman::Context,
    gl: Option<glow::Context>,
}

impl iced_native::window::Compositor for Compositor {
    type Settings = Settings;
    type Renderer = Renderer;
    type Surface = ();
    type SwapChain = Viewport;

    fn new(_settings: Self::Settings) -> Self {
        let connection = surfman::Connection::new().expect("Create connection");

        let adapter = connection
            .create_hardware_adapter()
            .expect("Create adapter");

        let mut device =
            connection.create_device(&adapter).expect("Create device");

        let context_descriptor = device
            .create_context_descriptor(&surfman::ContextAttributes {
                version: surfman::GLVersion::new(3, 0),
                flags: surfman::ContextAttributeFlags::empty(),
            })
            .expect("Create context descriptor");

        let gl_context = device
            .create_context(&context_descriptor)
            .expect("Create context");

        Self {
            connection,
            device,
            gl_context,
            gl: None,
        }
    }

    fn create_renderer(&mut self, settings: Settings) -> Renderer {
        self.device
            .make_context_current(&self.gl_context)
            .expect("Make context current");

        Renderer::new(crate::Backend::new(self.gl.as_ref().unwrap(), settings))
    }

    fn create_surface<W: HasRawWindowHandle>(
        &mut self,
        window: &W,
    ) -> Self::Surface {
        let native_widget = self
            .connection
            .create_native_widget_from_rwh(window.raw_window_handle())
            .expect("Create widget");

        let surface = self
            .device
            .create_surface(
                &self.gl_context,
                surfman::SurfaceAccess::GPUOnly,
                surfman::SurfaceType::Widget { native_widget },
            )
            .expect("Create surface");

        let surfman::SurfaceInfo { .. } = self.device.surface_info(&surface);

        self.device
            .bind_surface_to_context(&mut self.gl_context, surface)
            .expect("Bind surface to context");

        self.device
            .make_context_current(&self.gl_context)
            .expect("Make context current");

        self.gl = Some(glow::Context::from_loader_function(|s| {
            self.device.get_proc_address(&self.gl_context, s)
        }));

        //let mut framebuffer =
        //    skia_safe::gpu::gl::FramebufferInfo::from_fboid(framebuffer_object);

        //framebuffer.format = gl::RGBA8;

        //framebuffer
    }

    fn create_swap_chain(
        &mut self,
        _surface: &Self::Surface,
        width: u32,
        height: u32,
    ) -> Self::SwapChain {
        let mut surface = self
            .device
            .unbind_surface_from_context(&mut self.gl_context)
            .expect("Unbind surface")
            .expect("Active surface");

        self.device
            .resize_surface(
                &self.gl_context,
                &mut surface,
                euclid::Size2D::new(width as i32, height as i32),
            )
            .expect("Resize surface");

        self.device
            .bind_surface_to_context(&mut self.gl_context, surface)
            .expect("Bind surface to context");

        let gl = self.gl.as_ref().unwrap();

        unsafe {
            gl.viewport(0, 0, width as i32, height as i32);
            gl.clear_color(1.0, 1.0, 1.0, 1.0);

            // Enable auto-conversion from/to sRGB
            gl.enable(glow::FRAMEBUFFER_SRGB);

            // Enable alpha blending
            gl.enable(glow::BLEND);
            gl.blend_func(glow::SRC_ALPHA, glow::ONE_MINUS_SRC_ALPHA);
        }

        Viewport::new(width, height)
    }

    fn draw<T: AsRef<str>>(
        &mut self,
        renderer: &mut Self::Renderer,
        swap_chain: &mut Self::SwapChain,
        output: &<Self::Renderer as iced_native::Renderer>::Output,
        scale_factor: f64,
        overlay: &[T],
    ) -> mouse::Interaction {
        let gl = self.gl.as_ref().unwrap();

        unsafe {
            gl.clear(glow::COLOR_BUFFER_BIT);
        }

        let mouse = renderer.backend_mut().draw(
            gl,
            swap_chain,
            output,
            scale_factor,
            overlay,
        );

        {
            let mut surface = self
                .device
                .unbind_surface_from_context(&mut self.gl_context)
                .expect("Unbind surface")
                .expect("Active surface");

            self.device
                .present_surface(&self.gl_context, &mut surface)
                .expect("Present surface");

            self.device
                .bind_surface_to_context(&mut self.gl_context, surface)
                .expect("Bind surface to context");
        }

        mouse
    }
}

impl Drop for Compositor {
    fn drop(&mut self) {
        self.device
            .destroy_context(&mut self.gl_context)
            .expect("Destroy context");
    }
}