radar-g/src/pipeline/offscreen_renderer.rs
2024-04-30 14:34:06 +08:00

212 lines
5.8 KiB
Rust

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<RwLock<Context>>,
device: Device,
fbo: NonZeroU32,
glow_ctx: Option<glow::Context>,
size: (i32, i32), // canvas: Arc<Mutex<CanvasWrapper>>,
}
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<Self, surfman::Error> {
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<u8> {
let (w, h) = self.size;
let mut pixels: Vec<u8> = 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<OpenGl>);
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<OpenGl>) -> Self {
Self(canvas)
}
}
impl Deref for CanvasWrapper {
type Target = femtovg::Canvas<OpenGl>;
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<Canvas<OpenGl>> for CanvasWrapper {
fn from(canvas: Canvas<OpenGl>) -> Self {
Self(canvas)
}
}
impl Borrow<Canvas<OpenGl>> for CanvasWrapper {
fn borrow(&self) -> &Canvas<OpenGl> {
&self
}
}
impl BorrowMut<Canvas<OpenGl>> for CanvasWrapper {
fn borrow_mut(&mut self) -> &mut Canvas<OpenGl> {
self
}
}
impl AsRef<Canvas<OpenGl>> for CanvasWrapper {
fn as_ref(&self) -> &Canvas<OpenGl> {
&self
}
}
impl AsMut<Canvas<OpenGl>> for CanvasWrapper {
fn as_mut(&mut self) -> &mut Canvas<OpenGl> {
self
}
}