Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the interface for safe GL context wrapping and implement on Mac. #6

Merged
merged 1 commit into from Jun 25, 2013
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -0,0 +1,29 @@
// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A platform-independent interface to 3D graphics contexts.

/// Platform-independent interface to 3D graphics contexts.
pub trait GraphicsContextMethods<NativeContextType> {
/// Returns the current 3D graphics context, incrementing its reference count.
pub fn current() -> Self;

/// Wraps the given instance of the native 3D context, incrementing its reference count.
pub fn wrap(instance: NativeContextType) -> Self;

/// Returns the underlying native 3D context without modifying its reference count.
pub fn native(&self) -> NativeContextType;

/// Creates a new offscreen 3D graphics context.
pub fn new() -> Self;

/// Makes this context the current context, so that all graphics operations will go here.
pub fn make_current(&self);
}

File renamed without changes.
@@ -7,78 +7,122 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub extern mod core_foundation;
pub extern mod io_surface;
pub extern mod opengles;

use platform::opengles::gl2;
use base::ShareContext;
use context::GraphicsContextMethods;

use core::cast::transmute;
use core::ptr::{null, to_unsafe_ptr};
use geom::size::Size2D;
use platform::io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow};
use platform::io_surface::{kIOSurfaceHeight, kIOSurfaceIsGlobal, kIOSurfaceWidth};
use platform::io_surface::IOSurfaceMethods;
use platform::opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext};
use platform::opengles::cgl::{CGLLockContext, CGLSetCurrentContext, CGLTexImageIOSurface2D};
use platform::opengles::cgl::{kCGLNoError, kCGLPFACompliant, kCGLPFADoubleBuffer};
use platform::opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER};
use platform::opengles::gl2::{FRAMEBUFFER_COMPLETE, GLenum, GLint, GLsizei, GLuint, LINEAR};
use platform::opengles::gl2::{NEAREST, RGBA, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use platform::opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use platform::opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};

use base::ShareContext;
use io_surface::{IOSurface, kIOSurfaceBytesPerElement, kIOSurfaceBytesPerRow};
use io_surface::{kIOSurfaceHeight, kIOSurfaceIsGlobal, kIOSurfaceWidth};
use io_surface::IOSurfaceMethods;
use opengles::cgl::{CGLChoosePixelFormat, CGLContextObj, CGLCreateContext, CGLGetCurrentContext};
use opengles::cgl::{CGLReleaseContext, CGLRetainContext, CGLSetCurrentContext};
use opengles::cgl::{CGLTexImageIOSurface2D, kCGLNoError, kCGLPFACompliant, kCGLPFADoubleBuffer};
use opengles::gl2::{BGRA, CLAMP_TO_EDGE, COLOR_ATTACHMENT0, FRAMEBUFFER};
use opengles::gl2::{FRAMEBUFFER_COMPLETE, GLenum, GLint, GLsizei, GLuint, LINEAR};
use opengles::gl2::{NEAREST, RGBA, TEXTURE_MAG_FILTER, TEXTURE_MIN_FILTER};
use opengles::gl2::{TEXTURE_RECTANGLE_ARB, TEXTURE_WRAP_S, TEXTURE_WRAP_T};
use opengles::gl2::{UNSIGNED_INT_8_8_8_8_REV};
use opengles::gl2;

// FIXME: This is not good.
#[link_args="-framework IOSurface -framework CoreFoundation"]
#[nolink]
extern {}

pub type Context = MacContext;
/// Mac-specific interface to 3D graphics contexts.
pub struct GraphicsContext {
contents: CGLContextObj
}

impl GraphicsContextMethods<CGLContextObj> for GraphicsContext {
/// Returns the current graphics context.
fn current() -> GraphicsContext {
unsafe {
GraphicsContextMethods::wrap(CGLGetCurrentContext())
}
}

pub struct MacContext {
/// Wraps the given instance of the native Core OpenGL graphics context.
fn wrap(instance: CGLContextObj) -> GraphicsContext {
unsafe {
GraphicsContext {
contents: CGLRetainContext(instance)
}
}
}

/// Returns the underlying native 3D context without modifying its reference count.
fn native(&self) -> CGLContextObj {
self.contents
}

/// Creates a new offscreen 3D graphics context.
fn new() -> GraphicsContext {
unsafe {
// Choose a pixel format.
let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
let pixel_format = null();
let pixel_format_count = 1;
let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
to_unsafe_ptr(&pixel_format),
to_unsafe_ptr(&pixel_format_count));
assert!(gl_error == kCGLNoError);

// Create the context.
let cgl_context = null();
let gl_error = CGLCreateContext(pixel_format, null(), to_unsafe_ptr(&cgl_context));
assert!(gl_error == kCGLNoError);

GraphicsContextMethods::wrap(cgl_context)
}
}

/// Makes this context the current context.
fn make_current(&self) {
unsafe {
let gl_error = CGLSetCurrentContext(self.contents);
assert!(gl_error == kCGLNoError)
}
}
}

impl Drop for GraphicsContext {
fn finalize(&self) {
unsafe {
CGLReleaseContext(self.native())
}
}
}

impl Clone for GraphicsContext {
fn clone(&self) -> GraphicsContext {
GraphicsContextMethods::wrap(self.native())
}
}

pub struct Context {
surface: IOSurface,
framebuffer: GLuint,
texture: GLuint

// FIXME: Needs drop.
}

pub fn init_cgl() -> CGLContextObj {
// FIXME: We should expose some higher-level, safe abstractions inside the CGL module.
unsafe {
// Choose a pixel format.
let attributes = [ kCGLPFADoubleBuffer, kCGLPFACompliant, 0 ];
let pixel_format = null();
let pixel_format_count = 1;
let gl_error = CGLChoosePixelFormat(transmute(&attributes[0]),
to_unsafe_ptr(&pixel_format),
to_unsafe_ptr(&pixel_format_count));
assert!(gl_error == kCGLNoError);

// Create the context.
let cgl_context = null();
let gl_error = CGLCreateContext(pixel_format, null(), to_unsafe_ptr(&cgl_context));
assert!(gl_error == kCGLNoError);

// Set the context.
let gl_error = CGLSetCurrentContext(cgl_context);
assert!(gl_error == kCGLNoError);

// Lock the context.
let gl_error = CGLLockContext(cgl_context);
assert!(gl_error == kCGLNoError);

return cgl_context;
}
pub fn init_cgl() -> GraphicsContext {
let context: GraphicsContext = GraphicsContextMethods::new();
context.make_current();
context
}


pub fn init_surface(size: Size2D<int>) -> IOSurface {
use platform::core_foundation::boolean::CFBoolean;
use number = platform::core_foundation::number::CFNumber::new;
use string = platform::core_foundation::string::CFString::wrap_shared;
use core_foundation::boolean::CFBoolean;
use core_foundation;
use io_surface;
use number = core_foundation::number::CFNumber::new;
use string = core_foundation::string::CFString::wrap_shared;

// TODO: dictionary constructor should be less ridiculous.
// Or, we could add bindings for mutable dictionaries.
@@ -119,10 +163,10 @@ pub fn init_texture() -> GLuint {
}

// Assumes the texture is already bound via gl2::bind_texture().
pub fn bind_surface_to_texture(context: &CGLContextObj, surface: &IOSurface, size: Size2D<int>) {
pub fn bind_surface_to_texture(context: &GraphicsContext, surface: &IOSurface, size: Size2D<int>) {
// FIXME: There should be safe wrappers for this.
unsafe {
let gl_error = CGLTexImageIOSurface2D(*context,
let gl_error = CGLTexImageIOSurface2D(context.native(),
TEXTURE_RECTANGLE_ARB,
RGBA as GLenum,
size.width as GLsizei,
@@ -141,8 +185,8 @@ pub fn bind_texture_to_framebuffer(texture: GLuint) {
assert!(gl2::check_framebuffer_status(FRAMEBUFFER) == FRAMEBUFFER_COMPLETE);
}

impl ShareContext for MacContext {
fn new(size: Size2D<int>) -> MacContext {
impl ShareContext for Context {
fn new(size: Size2D<int>) -> Context {
// Initialize CGL.
let context = init_cgl();

@@ -160,7 +204,7 @@ impl ShareContext for MacContext {
// Bind the texture to the framebuffer.
bind_texture_to_framebuffer(texture);

MacContext {
Context {
surface: surface,
framebuffer: framebuffer,
texture: texture
@@ -14,16 +14,24 @@
extern mod std;
extern mod geom;

#[cfg(target_os="macos")]
extern mod core_foundation;
#[cfg(target_os="macos")]
extern mod io_surface;
#[cfg(target_os="macos")]
extern mod opengles;

pub mod base;
pub mod context;

#[cfg(target_os="macos")]
#[path="macos.rs"]
#[path="platform/macos.rs"]
pub mod platform;

#[cfg(target_os="linux")]
#[path="dummy.rs"]
#[path="platform/dummy.rs"]
pub mod platform;

#[cfg(target_os="windows")]
#[path="dummy.rs"]
#[path="platform/dummy.rs"]
pub mod platform;
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.