use super::error::*;
use super::opengl::*;
use super::offscreen_trait::*;
use gl;
use flo_render_gl_offscreen::egl;
use flo_render_gl_offscreen::egl::ffi;
use flo_render_gl_offscreen::gbm;
use libc::{open, close, O_RDWR};
use std::ptr;
use std::ffi::{CString, c_void};
struct EglOffscreenRenderContext {
card_fd: i32,
display: egl::EGLDisplay,
context: egl::EGLContext,
}
pub fn initialize_offscreen_rendering() -> Result<impl OffscreenRenderContext, RenderInitError> {
unsafe {
let card0_file = CString::new("/dev/dri/card0").unwrap();
let card0 = open(card0_file.as_ptr(), O_RDWR);
if card0 == 0 { Err(RenderInitError::CannotOpenGraphicsDevice)? }
let gbm = gbm::gbm_create_device(card0);
if gbm.is_null() { Err(RenderInitError::CannotCreateGraphicsDevice)? }
if !egl::bind_api(egl::EGL_OPENGL_API) { Err(RenderInitError::ApiNotAvailable)? }
let egl_display = ffi::eglGetPlatformDisplay(egl::EGL_PLATFORM_GBM_MESA, gbm as *mut c_void, ptr::null());
let egl_display = if egl_display.is_null() { None } else { Some(egl_display) };
let egl_display = if let Some(egl_display) = egl_display { egl_display } else { println!("eglGetPlatformDisplay {:x}", egl::get_error()); Err(RenderInitError::DisplayNotAvailable)? };
let mut major = 0;
let mut minor = 0;
let init_result = egl::initialize(egl_display as *mut c_void, &mut major, &mut minor);
if !init_result { println!("egl::initialize {:x}", egl::get_error()); Err(RenderInitError::CannotStartGraphicsDriver)? }
let extensions = egl::query_string(egl_display, egl::EGL_EXTENSIONS);
let extensions = if let Some(extensions) = extensions { extensions } else { Err(RenderInitError::MissingRequiredExtension)? };
let extensions = extensions.to_string_lossy();
if !extensions.contains("EGL_KHR_create_context ") { Err(RenderInitError::MissingRequiredExtension)? }
if !extensions.contains("EGL_KHR_surfaceless_context ") { Err(RenderInitError::MissingRequiredExtension)? }
let config = egl::choose_config(egl_display, &[
egl::EGL_RED_SIZE, 8,
egl::EGL_GREEN_SIZE, 8,
egl::EGL_BLUE_SIZE, 8,
egl::EGL_DEPTH_SIZE, 24,
egl::EGL_CONFORMANT, egl::EGL_OPENGL_BIT,
egl::EGL_RENDERABLE_TYPE, egl::EGL_OPENGL_BIT,
egl::EGL_NONE
], 1);
let config = if let Some(config) = config { config } else { println!("egl::choose_config {:x}", egl::get_error()); Err(RenderInitError::CouldNotConfigureDisplay)? };
let context = egl::create_context(egl_display, config, egl::EGL_NO_CONTEXT, &[
egl::EGL_CONTEXT_MAJOR_VERSION, 3,
egl::EGL_CONTEXT_MINOR_VERSION, 3,
egl::EGL_NONE
]);
let context = if let Some(context) = context { context } else { println!("egl::create_context {:x}", egl::get_error()); Err(RenderInitError::CouldNotCreateContext)? };
let activated_context = egl::make_current(egl_display, egl::EGL_NO_SURFACE, egl::EGL_NO_SURFACE, context);
if !activated_context { println!("egl::make_current {:x}", egl::get_error()); Err(RenderInitError::ContextDidNotStart)? }
gl::load_with(|s| egl::get_proc_address(s) as *const c_void);
let error = gl::GetError();
if error != gl::NO_ERROR { println!("gl::GetError {:x}", error); Err(RenderInitError::ContextDidNotStart)? }
assert!(error == gl::NO_ERROR);
Ok(EglOffscreenRenderContext {
card_fd: card0,
display: egl_display,
context: context
})
}
}
impl OffscreenRenderContext for EglOffscreenRenderContext {
type RenderTarget = OpenGlOffscreenRenderer;
fn create_render_target(&mut self, width: usize, height: usize) -> Self::RenderTarget {
let activated_context = egl::make_current(self.display, egl::EGL_NO_SURFACE, egl::EGL_NO_SURFACE, self.context);
if !activated_context { panic!("egl::make_current {:x}", egl::get_error()); }
OpenGlOffscreenRenderer::new(width, height)
}
}
impl Drop for EglOffscreenRenderContext {
fn drop(&mut self) {
unsafe {
egl::destroy_context(self.display, self.context);
close(self.card_fd);
}
}
}