Skip to content

Commit

Permalink
Merge context creation code.
Browse files Browse the repository at this point in the history
Signed-off-by: Hal Gentz <[email protected]>
  • Loading branch information
goddessfreya committed Jul 10, 2018
1 parent 3a0854c commit 68a0c71
Show file tree
Hide file tree
Showing 20 changed files with 510 additions and 826 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Unreleased

- ***Breaking*** The entire api for Headless contexts have been removed. Please instead use `Context::new()` when trying to make a context without a visible window. Also removed `headless` feature.
- ***Breaking*** Structs implementing the `GlContext` trait must now be sized.
- ***Breaking*** Added new `CreationErrorPair` enum variant to enum `CreationError`.
- **Breaking:** Added `OsError` variant to `ContextError`.
- Improved glX error reporting.

Expand Down
111 changes: 39 additions & 72 deletions src/api/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ mod ffi;

struct AndroidContext {
egl_context: EglContext,
stopped: Cell<bool>,
stopped: Option<Cell<bool>>,
}

pub struct Context(Arc<AndroidContext>);
Expand All @@ -39,7 +39,7 @@ impl android_glue::SyncEventHandler for AndroidSyncEventHandler {
// native window surface already destroyed. EGL generates a BAD_SURFACE error in this situation.
// Set stop to true to prevent swap_buffer call race conditions.
android_glue::Event::TermWindow => {
self.0.stopped.set(true);
self.0.stopped.as_ref().unwrap().set(true);
},
_ => { return; }
};
Expand All @@ -66,15 +66,15 @@ impl Context {
.and_then(|p| p.finish(native_window as *const _)));
let ctx = Arc::new(AndroidContext {
egl_context: context,
stopped: Cell::new(false),
stopped: Some(Cell::new(false)),
});

let handler = Box::new(AndroidSyncEventHandler(ctx.clone()));
android_glue::add_sync_event_handler(handler);
let context = Context(ctx.clone());

events_loop.set_suspend_callback(Some(Box::new(move |suspended| {
ctx.stopped.set(suspended);
ctx.stopped.as_ref().unwrap().set(suspended);
if suspended {
// Android has stopped the activity or sent it to background.
// Release the EGL surface and stop the animation loop.
Expand All @@ -94,12 +94,39 @@ impl Context {
Ok((window, context))
}

#[inline]
pub fn new_context(
_el: &winit::EventsLoop,
pf_reqs: &PixelFormatRequirements,
gl_attr: &GlAttributes<&Context>,
shareable_with_windowed_contexts: bool,
) -> Result<Self, CreationError> {
assert!(shareable_with_windowed_contexts); // TODO: Implement if possible

let gl_attr = gl_attr.clone().map_sharing(|c| &c.0.egl_context);
let context = EglContext::new(
egl::ffi::egl::Egl,
pf_reqs,
&gl_attr,
egl::NativeDisplay::Android
)?;
let context = context.finish_pbuffer((1, 1))?;// TODO:
let ctx = Arc::new(AndroidContext {
egl_context: context,
stopped: None,
});
Ok(Context(ctx))
}

#[inline]
pub unsafe fn make_current(&self) -> Result<(), ContextError> {
if !self.0.stopped.get() {
return self.0.egl_context.make_current();
if let Some(ref stopped) = self.0.stopped {
if stopped.get() {
return Err(ContextError::ContextLost);
}
}
Err(ContextError::ContextLost)

self.0.egl_context.make_current()
}

#[inline]
Expand All @@ -118,10 +145,12 @@ impl Context {

#[inline]
pub fn swap_buffers(&self) -> Result<(), ContextError> {
if !self.0.stopped.get() {
return self.0.egl_context.swap_buffers();
if let Some(ref stopped) = self.0.stopped {
if stopped.get() {
return Err(ContextError::ContextLost);
}
}
Err(ContextError::ContextLost)
self.0.egl_context.swap_buffers()
}

#[inline]
Expand All @@ -139,65 +168,3 @@ impl Context {
self.0.egl_context.raw_handle()
}
}

#[derive(Clone, Default)]
pub struct PlatformSpecificHeadlessBuilderAttributes;

pub struct HeadlessContext(EglContext);

unsafe impl Send for HeadlessContext {}
unsafe impl Sync for HeadlessContext {}

impl HeadlessContext {
/// See the docs in the crate root file.
pub fn new(
dimensions: (u32, u32),
pf_reqs: &PixelFormatRequirements,
gl_attr: &GlAttributes<&HeadlessContext>,
_: &PlatformSpecificHeadlessBuilderAttributes,
) -> Result<Self, CreationError>
{
let gl_attr = gl_attr.clone().map_sharing(|c| &c.0);
let context = EglContext::new(egl::ffi::egl::Egl,
pf_reqs,
&gl_attr,
egl::NativeDisplay::Android)?;
let context = context.finish_pbuffer(dimensions)?; // TODO:
Ok(HeadlessContext(context))
}

#[inline]
pub unsafe fn make_current(&self) -> Result<(), ContextError> {
self.0.make_current()
}

#[inline]
pub fn is_current(&self) -> bool {
self.0.is_current()
}

#[inline]
pub fn get_proc_address(&self, addr: &str) -> *const () {
self.0.get_proc_address(addr)
}

#[inline]
pub fn swap_buffers(&self) -> Result<(), ContextError> {
self.0.swap_buffers()
}

#[inline]
pub fn get_api(&self) -> Api {
self.0.get_api()
}

#[inline]
pub fn get_pixel_format(&self) -> PixelFormat {
self.0.get_pixel_format()
}

#[inline]
pub unsafe fn raw_handle(&self) -> egl::ffi::EGLContext {
self.0.raw_handle()
}
}
4 changes: 2 additions & 2 deletions src/api/egl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ impl Context {
// Restore the EGLContext.
#[cfg(target_os = "android")]
pub unsafe fn on_surface_created(&self, native_window: ffi::EGLNativeWindowType) {
if (self.surface.get() != ffi::egl::NO_SURFACE) {
if self.surface.get() != ffi::egl::NO_SURFACE {
return;
}
self.surface.set(self.egl.CreateWindowSurface(self.display, self.config_id, native_window, ptr::null()));
Expand All @@ -357,7 +357,7 @@ impl Context {
// The EGLContext is not destroyed so it can be restored later.
#[cfg(target_os = "android")]
pub unsafe fn on_surface_destroyed(&self) {
if (self.surface.get() == ffi::egl::NO_SURFACE) {
if self.surface.get() == ffi::egl::NO_SURFACE {
return;
}
let ret = self.egl.MakeCurrent(self.display, ffi::egl::NO_SURFACE, ffi::egl::NO_SURFACE, ffi::egl::NO_CONTEXT);
Expand Down
81 changes: 46 additions & 35 deletions src/api/ios/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,17 @@ impl Context {
Ok((window, context))
}

pub fn new_context(
el: &EventsLoop,
pf_reqs: &PixelFormatRequirements,
gl_attr: &GlAttributes<&Context>,
_shareable_with_windowed_contexts: bool,
) -> Result<Self, CreationError> {
let wb = WindowBuilder::new().with_visibility(false);
Self::new(wb, el, pf_reqs, gl_attr)
.map(|(_window, context)| context)
}

unsafe fn create_context(mut version: NSUInteger) -> Result<id, CreationError> {
let context_class = Class::get("EAGLContext").expect("Failed to get class `EAGLContext`");
let eagl_context: id = msg_send![context_class, alloc];
Expand Down Expand Up @@ -267,6 +278,41 @@ impl Context {
panic!("framebuffer status: {:?}", status);
}
}

#[inline]
pub fn swap_buffers(&self) -> Result<(), ContextError> {
unsafe {
let res: BOOL = msg_send![self.eagl_context, presentRenderbuffer:gles::RENDERBUFFER];
if res == YES {
Ok(())
} else {
Err(ContextError::IoError(
io::Error::new(io::ErrorKind::Other, "`EAGLContext presentRenderbuffer` failed")
))
}
}
}

#[inline]
pub fn get_pixel_format(&self) -> PixelFormat {
let color_format = ColorFormat::for_view(self.view);
PixelFormat {
hardware_accelerated: true,
color_bits: color_format.color_bits(),
alpha_bits: color_format.alpha_bits(),
depth_bits: depth_for_view(self.view),
stencil_bits: stencil_for_view(self.view),
stereoscopy: false,
double_buffer: true,
multisampling: multisampling_for_view(self.view),
srgb: color_format.srgb(),
}
}

#[inline]
pub fn resize(&self, _width: u32, _height: u32) {
// N/A
}
}

impl Drop for Context {
Expand Down Expand Up @@ -306,45 +352,10 @@ impl GlContext for Context {
addr
}

#[inline]
fn swap_buffers(&self) -> Result<(), ContextError> {
unsafe {
let res: BOOL = msg_send![self.eagl_context, presentRenderbuffer:gles::RENDERBUFFER];
if res == YES {
Ok(())
} else {
Err(ContextError::IoError(
io::Error::new(io::ErrorKind::Other, "`EAGLContext presentRenderbuffer` failed")
))
}
}
}

#[inline]
fn get_api(&self) -> Api {
Api::OpenGlEs
}

#[inline]
fn get_pixel_format(&self) -> PixelFormat {
let color_format = ColorFormat::for_view(self.view);
PixelFormat {
hardware_accelerated: true,
color_bits: color_format.color_bits(),
alpha_bits: color_format.alpha_bits(),
depth_bits: depth_for_view(self.view),
stencil_bits: stencil_for_view(self.view),
stereoscopy: false,
double_buffer: true,
multisampling: multisampling_for_view(self.view),
srgb: color_format.srgb(),
}
}

#[inline]
fn resize(&self, _width: u32, _height: u32) {
// N/A
}
}

impl GlContextExt for Context {
Expand Down
6 changes: 1 addition & 5 deletions src/api/osmesa/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,14 @@ impl OsMesaContext {
unsafe { osmesa_sys::OSMesaGetCurrentContext() == self.context }
}

#[inline]
pub fn get_proc_address(&self, addr: &str) -> *const () {
unsafe {
let c_str = CString::new(addr.as_bytes().to_vec()).unwrap();
mem::transmute(osmesa_sys::OSMesaGetProcAddress(mem::transmute(c_str.as_ptr())))
}
}

#[inline]
pub fn swap_buffers(&self) -> Result<(), ContextError> {
Ok(())
}

#[inline]
pub fn get_api(&self) -> Api {
Api::OpenGl
Expand Down
Loading

0 comments on commit 68a0c71

Please sign in to comment.