Skip to content

Commit

Permalink
Allow selecting the GL API kind at construction.
Browse files Browse the repository at this point in the history
  • Loading branch information
emilio committed Feb 26, 2017
1 parent db90636 commit 23d0368
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 28 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "offscreen_gl_context"
license = "MIT / Apache-2.0"
version = "0.6.1"
version = "0.7.0"
authors = ["Emilio Cobos Álvarez <emilio@crisal.io>", "The Servo Project Developers"]
description = "Creation and manipulation of HW accelerated offscreen rendering contexts in multiple platforms. Originally intended for the Servo project's WebGL implementation."
repository = "https://github.com/emilio/rust-offscreen-rendering-context"
Expand Down
22 changes: 9 additions & 13 deletions src/draw_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ impl ColorAttachment {
/// a depth or stencil buffer, depending on context
/// requirements.
pub struct DrawBuffer {
// See the comment in GLContext to see why this is safe, we never let a
// buffer outlive the context (we only return it by reference in
// borrow_draw_buffer).
gl_: Rc<gl::Gl>,
size: Size2D<i32>,
framebuffer: GLuint,
Expand Down Expand Up @@ -119,9 +116,10 @@ impl DrawBuffer {

try!(draw_buffer.init(context, color_attachment_type));

debug_assert!(
draw_buffer.gl().check_frame_buffer_status(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE);
debug_assert!(draw_buffer.gl().get_error() == gl::NO_ERROR);
debug_assert_eq!(draw_buffer.gl().check_frame_buffer_status(gl::FRAMEBUFFER),
gl::FRAMEBUFFER_COMPLETE);
debug_assert_eq!(draw_buffer.gl().get_error(),
gl::NO_ERROR);

Ok(draw_buffer)
}
Expand Down Expand Up @@ -158,8 +156,6 @@ impl DrawBuffer {
}

fn gl(&self) -> &gl::Gl {
// See the comment on top the GLContext field to see why our usage of
// this is safe.
&*self.gl_
}

Expand Down Expand Up @@ -201,7 +197,7 @@ impl DrawBuffer {

self.gl().bind_texture(gl::TEXTURE_2D, 0);

debug_assert!(self.gl().get_error() == gl::NO_ERROR);
debug_assert_eq!(self.gl().get_error(), gl::NO_ERROR);

Some(ColorAttachment::Texture(texture))
},
Expand All @@ -228,15 +224,15 @@ impl DrawBuffer {
fn attach_to_framebuffer(&mut self) -> Result<(), &'static str> {
self.gl().bind_framebuffer(gl::FRAMEBUFFER, self.framebuffer);
// NOTE: The assertion fails if the framebuffer is not bound
debug_assert!(self.gl().is_framebuffer(self.framebuffer) == gl::TRUE);
debug_assert_eq!(self.gl().is_framebuffer(self.framebuffer), gl::TRUE);

match *self.color_attachment.as_ref().unwrap() {
ColorAttachment::Renderbuffer(color_renderbuffer) => {
self.gl().framebuffer_renderbuffer(gl::FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::RENDERBUFFER,
color_renderbuffer);
debug_assert!(self.gl().is_renderbuffer(color_renderbuffer) == gl::TRUE);
debug_assert_eq!(self.gl().is_renderbuffer(color_renderbuffer), gl::TRUE);
},
ColorAttachment::Texture(texture_id) => {
self.gl().framebuffer_texture_2d(gl::FRAMEBUFFER,
Expand All @@ -251,15 +247,15 @@ impl DrawBuffer {
gl::DEPTH_ATTACHMENT,
gl::RENDERBUFFER,
self.depth_renderbuffer);
debug_assert!(self.gl().is_renderbuffer(self.depth_renderbuffer) == gl::TRUE);
debug_assert_eq!(self.gl().is_renderbuffer(self.depth_renderbuffer), gl::TRUE);
}

if self.stencil_renderbuffer != 0 {
self.gl().framebuffer_renderbuffer(gl::FRAMEBUFFER,
gl::STENCIL_ATTACHMENT,
gl::RENDERBUFFER,
self.stencil_renderbuffer);
debug_assert!(self.gl().is_renderbuffer(self.stencil_renderbuffer) == gl::TRUE);
debug_assert_eq!(self.gl().is_renderbuffer(self.stencil_renderbuffer), gl::TRUE);
}

Ok(())
Expand Down
31 changes: 20 additions & 11 deletions src/gl_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ use ColorAttachmentType;

/// This is a wrapper over a native headless GL context
pub struct GLContext<Native> {
/// Immutable, always non-null, and owned by the context.
///
/// Done this way so the buffer and attachments can have references to it,
/// which is safe because it's completely immutable.
gl_: Rc<gl::Gl>,
native_context: Native,
/// This an abstraction over a custom framebuffer
Expand All @@ -34,16 +30,22 @@ pub struct GLContext<Native> {
impl<Native> GLContext<Native>
where Native: NativeGLContextMethods,
{
pub fn create(shared_with: Option<&Native::Handle>) -> Result<Self, &'static str> {
Self::create_shared_with_dispatcher(shared_with, None)
pub fn create(api_type: gl::GlType,
shared_with: Option<&Native::Handle>)
-> Result<Self, &'static str> {
Self::create_shared_with_dispatcher(api_type, shared_with, None)
}

pub fn create_shared_with_dispatcher(shared_with: Option<&Native::Handle>,
pub fn create_shared_with_dispatcher(api_type: gl::GlType,
shared_with: Option<&Native::Handle>,
dispatcher: Option<Box<GLContextDispatcher>>)
-> Result<Self, &'static str> {
let native_context = try!(Native::create_shared_with_dispatcher(shared_with, dispatcher));
// XXX how to handle GLES instantiation?
let gl_ = gl::GlFns::load_with(|s| GLContext::<Native>::get_proc_address(s) as *const _);
let gl_ = match api_type {
gl::GlType::Gl => gl::GlFns::load_with(|s| Self::get_proc_address(s) as *const _),
gl::GlType::Gles => gl::GlesFns::load_with(|s| Self::get_proc_address(s) as *const _),
};

try!(native_context.make_current());
let attributes = GLContextAttributes::any();
let formats = GLFormats::detect(&attributes);
Expand Down Expand Up @@ -73,24 +75,30 @@ impl<Native> GLContext<Native>
pub fn new(size: Size2D<i32>,
attributes: GLContextAttributes,
color_attachment_type: ColorAttachmentType,
api_type: gl::GlType,
shared_with: Option<&Native::Handle>)
-> Result<Self, &'static str> {
Self::new_shared_with_dispatcher(size,
attributes,
color_attachment_type,
api_type,
shared_with,
None)
}

pub fn new_shared_with_dispatcher(size: Size2D<i32>,
attributes: GLContextAttributes,
color_attachment_type: ColorAttachmentType,
api_type: gl::GlType,
shared_with: Option<&Native::Handle>,
dispatcher: Option<Box<GLContextDispatcher>>)
-> Result<Self, &'static str> {
// We create a headless context with a dummy size, we're painting to the
// draw_buffer's framebuffer anyways.
let mut context = try!(Self::create_shared_with_dispatcher(shared_with, dispatcher));
let mut context =
try!(Self::create_shared_with_dispatcher(api_type,
shared_with,
dispatcher));

context.formats = GLFormats::detect(&attributes);
context.attributes = attributes;
Expand All @@ -103,9 +111,10 @@ impl<Native> GLContext<Native>
#[inline(always)]
pub fn with_default_color_attachment(size: Size2D<i32>,
attributes: GLContextAttributes,
api_type: gl::GlType,
shared_with: Option<&Native::Handle>)
-> Result<Self, &'static str> {
GLContext::new(size, attributes, ColorAttachmentType::default(), shared_with)
Self::new(size, attributes, ColorAttachmentType::default(), api_type, shared_with)
}

#[inline(always)]
Expand Down
24 changes: 21 additions & 3 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ fn test_unbinding() {
let ctx = GLContext::<NativeGLContext>::new(Size2D::new(256, 256),
GLContextAttributes::default(),
ColorAttachmentType::Renderbuffer,
gl::GlType::default(),
None).unwrap();

assert!(NativeGLContext::current_handle().is_some());
Expand All @@ -67,6 +68,7 @@ fn test_renderbuffer_color_attachment() {
test_gl_context(&GLContext::<NativeGLContext>::new(Size2D::new(256, 256),
GLContextAttributes::default(),
ColorAttachmentType::Renderbuffer,
gl::GlType::default(),
None).unwrap());
}

Expand All @@ -76,6 +78,7 @@ fn test_texture_color_attachment() {
let context = GLContext::<NativeGLContext>::new(size,
GLContextAttributes::default(),
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
test_gl_context(&context);

Expand All @@ -101,6 +104,7 @@ fn test_sharing() {
let primary = GLContext::<NativeGLContext>::new(size,
GLContextAttributes::default(),
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();

let primary_texture_id = primary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap();
Expand All @@ -109,6 +113,7 @@ fn test_sharing() {
let secondary = GLContext::<NativeGLContext>::new(size,
GLContextAttributes::default(),
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(&primary.handle())).unwrap();

// Paint the second context red
Expand Down Expand Up @@ -149,16 +154,18 @@ fn test_multithread_render() {
let primary = GLContext::<NativeGLContext>::new(size,
GLContextAttributes::default(),
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
test_gl_context(&primary);
let (tx, rx) = mpsc::channel();
let (end_tx, end_rx) = mpsc::channel();
thread::spawn(move ||{
//create the context in a different thread
let secondary = GLContext::<NativeGLContext>::new(size,
GLContextAttributes::default(),
ColorAttachmentType::Texture,
None).unwrap();
GLContextAttributes::default(),
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
secondary.make_current().unwrap();
assert!(secondary.is_current());
//render green adn test pixels
Expand Down Expand Up @@ -195,6 +202,7 @@ fn test_multithread_sharing() {
let primary = GLContext::<NativeGLContext>::new(size,
GLContextAttributes::default(),
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
primary.make_current().unwrap();

Expand All @@ -213,6 +221,7 @@ fn test_multithread_sharing() {
let secondary = GLContext::<NativeGLContext>::new(size,
GLContextAttributes::default(),
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(&primary_handle)).unwrap();
// Make the context current on this thread only
secondary.make_current().unwrap();
Expand Down Expand Up @@ -258,6 +267,7 @@ fn test_limits() {
let context = GLContext::<NativeGLContext>::new(size,
GLContextAttributes::default(),
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
assert!(context.borrow_limits().max_vertex_attribs != 0);
}
Expand All @@ -271,6 +281,7 @@ fn test_no_alpha() {
let context = GLContext::<NativeGLContext>::new(size,
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
assert!(context.borrow_limits().max_vertex_attribs != 0);
}
Expand All @@ -284,6 +295,7 @@ fn test_no_depth() {
let context = GLContext::<NativeGLContext>::new(size,
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
assert!(context.borrow_limits().max_vertex_attribs != 0);
}
Expand All @@ -298,6 +310,7 @@ fn test_no_depth_no_alpha() {
let context = GLContext::<NativeGLContext>::new(size,
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
assert!(context.borrow_limits().max_vertex_attribs != 0);
}
Expand All @@ -313,6 +326,7 @@ fn test_no_premul_alpha() {
let context = GLContext::<NativeGLContext>::new(size,
attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
assert!(context.borrow_limits().max_vertex_attribs != 0);
}
Expand All @@ -328,18 +342,21 @@ fn test_in_a_row() {
let context = GLContext::<NativeGLContext>::new(size,
attributes.clone(),
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();

let handle = context.handle();

GLContext::<NativeGLContext>::new(size,
attributes.clone(),
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(&handle)).unwrap();

GLContext::<NativeGLContext>::new(size,
attributes.clone(),
ColorAttachmentType::Texture,
gl::GlType::default(),
Some(&handle)).unwrap();
}

Expand All @@ -348,5 +365,6 @@ fn test_zero_size() {
GLContext::<NativeGLContext>::new(Size2D::new(0, 320),
GLContextAttributes::default(),
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
}

0 comments on commit 23d0368

Please sign in to comment.