use euclid::Size2D; use femtovg::{renderer::OpenGl, Canvas}; use gl; use gl::types::{GLchar, GLenum, GLint, GLuint, GLvoid}; use glow::HasContext; use std::borrow::{Borrow, BorrowMut}; use std::fmt::{Debug, Formatter}; use std::num::NonZeroU32; use std::ops::{Deref, DerefMut}; use std::sync::{Mutex, RwLock}; use std::{cell::RefCell, sync::Arc}; use surfman::{ device, Adapter, Connection, Context, ContextAttributeFlags, Device, Error, GLApi, NativeConnection, NativeDevice, }; use super::Target; pub struct OffscreenRenderer { context: Arc>, device: Device, fbo: NonZeroU32, glow_ctx: Option, size: (i32, i32), // canvas: Arc>, } impl Debug for OffscreenRenderer { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("OffscreenRenderer").finish() } } impl OffscreenRenderer { pub fn new(width: i32, height: i32) -> Result { let connection = Connection::new()?; let adapter = connection.create_adapter()?; let mut device = connection.create_device(&adapter)?; let descriptor = device.create_context_descriptor(&surfman::ContextAttributes { version: surfman::GLVersion::new(4, 1), flags: ContextAttributeFlags::ALPHA .union(ContextAttributeFlags::DEPTH) .union(ContextAttributeFlags::STENCIL), })?; let mut context = device.create_context(&descriptor, None)?; let surface = device.create_surface( &context, surfman::SurfaceAccess::GPUOnly, surfman::SurfaceType::Generic { size: euclid::Size2D::new(width, height), }, )?; device .bind_surface_to_context(&mut context, surface) .expect("Failed to bind surface to context"); device.make_context_current(&context).unwrap(); let surface_info = device.context_surface_info(&context).unwrap().unwrap(); gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name)); unsafe { gl::BindFramebuffer(gl::FRAMEBUFFER, surface_info.framebuffer_object); gl::Viewport(0, 0, width, height); debug_assert_eq!(gl::GetError(), gl::NO_ERROR); } Ok(Self { context: Arc::new(RwLock::new(context)), device, fbo: NonZeroU32::new(surface_info.framebuffer_object).unwrap(), glow_ctx: None, size: (width, height), }) } pub fn create_canvas(&mut self) -> CanvasWrapper { let (w, h) = self.size; let (mut renderer, fbo) = unsafe { let renderer = OpenGl::new_from_function(|s| { self.device .get_proc_address(&self.context.read().unwrap(), s) as *const _ }) .expect("Cannot create renderer"); let ctx = glow::Context::from_loader_function(|s| { self.device .get_proc_address(&self.context.read().unwrap(), s) as *const _ }); let surface_info = self .device .context_surface_info(&self.context.read().unwrap()) .unwrap() .unwrap(); let fbo = glow::NativeFramebuffer(NonZeroU32::new(surface_info.framebuffer_object).unwrap()); ctx.bind_framebuffer(glow::FRAMEBUFFER, None); (renderer, fbo) }; renderer.set_screen_target(Some(fbo)); let mut canvas = Canvas::new(renderer).expect("Cannot create canvas"); canvas.set_size(w as u32, h as u32, 1.0); CanvasWrapper::new(canvas) } pub fn get_img(&self, target: Target) {} pub fn get_mem_img(&self) -> Vec { let (w, h) = self.size; let mut pixels: Vec = vec![0; w as usize * h as usize * 4]; unsafe { gl::ReadPixels( 0, 0, w, h, gl::RGBA, gl::UNSIGNED_BYTE, pixels.as_mut_ptr() as *mut GLvoid, ); debug_assert_eq!(gl::GetError(), gl::NO_ERROR); } pixels } } 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 {} pub struct CanvasWrapper(femtovg::Canvas); impl Debug for CanvasWrapper { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("CanvasWrapper").finish() } } impl CanvasWrapper { fn new(canvas: femtovg::Canvas) -> Self { Self(canvas) } } impl Deref for CanvasWrapper { type Target = femtovg::Canvas; fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for CanvasWrapper { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } unsafe impl Send for CanvasWrapper {} unsafe impl Sync for CanvasWrapper {} impl Drop for CanvasWrapper { fn drop(&mut self) { let _ = self; } } impl From> for CanvasWrapper { fn from(canvas: Canvas) -> Self { Self(canvas) } } impl Borrow> for CanvasWrapper { fn borrow(&self) -> &Canvas { &self } } impl BorrowMut> for CanvasWrapper { fn borrow_mut(&mut self) -> &mut Canvas { self } } impl AsRef> for CanvasWrapper { fn as_ref(&self) -> &Canvas { &self } } impl AsMut> for CanvasWrapper { fn as_mut(&mut self) -> &mut Canvas { self } }