use euclid::Size2D; use femtovg::{renderer::OpenGl, Canvas}; use std::num::NonZeroU32; use std::sync::{Mutex, RwLock}; use std::{cell::RefCell, sync::Arc}; use surfman::{device, Adapter, Connection, Context, Device, Error}; pub struct OffscreenRenderer { context: Arc>, device: Device, // renderer: Arc>, canvas: Arc>>, } impl OffscreenRenderer { pub fn new() -> Result { let connection = Connection::new()?; let adapter = connection.create_adapter()?; let mut device = connection.create_device(&adapter)?; let api = device.gl_api(); let descriptor = device.create_context_descriptor(&surfman::ContextAttributes { version: surfman::GLVersion::new(3, 3), flags: surfman::ContextAttributeFlags::empty(), })?; let mut context = device.create_context(&descriptor, None)?; let mut surface = device.create_surface( &context, surfman::SurfaceAccess::GPUOnly, surfman::SurfaceType::Generic { size: euclid::Size2D::new(500, 500), }, )?; let surface_info = device.surface_info(&surface); device .bind_surface_to_context(&mut context, surface) .expect("Failed to bind surface to context"); device.make_context_current(&context).unwrap(); static LOAD_FN: fn(&str) -> *const std::ffi::c_void = |s| epoxy::get_proc_addr(s) as *const _; let (mut renderer, fbo) = unsafe { let renderer = OpenGl::new_from_function(LOAD_FN).expect("Cannot create renderer"); let fbo = glow::NativeFramebuffer(NonZeroU32::new(surface_info.framebuffer_object).unwrap()); (renderer, fbo) }; renderer.set_screen_target(Some(fbo)); let mut canvas = Canvas::new(renderer).expect("Cannot create canvas"); canvas.set_size(500, 500, 1.0); Ok(Self { context: Arc::new(RwLock::new(context)), device, canvas: Arc::new(RwLock::new(canvas)), }) } pub fn canvas(&self) -> Arc>> { self.canvas.clone() } } impl Drop for OffscreenRenderer { fn drop(&mut self) { let mut context = self.context.write().unwrap(); self.device.destroy_context(&mut context).unwrap(); let _ = self; } } unsafe impl Send for OffscreenRenderer {} unsafe impl Sync for OffscreenRenderer {}