radar-g/src/pipeline/offscreen_renderer.rs
2024-01-18 22:35:43 +08:00

80 lines
2.5 KiB
Rust

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<RwLock<Context>>,
device: Device,
// renderer: Arc<Mutex<femtovg::renderer::OpenGl>>,
canvas: Arc<RwLock<Canvas<OpenGl>>>,
}
impl OffscreenRenderer {
pub fn new() -> Result<Self, surfman::Error> {
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<RwLock<Canvas<OpenGl>>> {
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 {}