Bug 1346856 - Revendor rust dependencies. r?jrmuizel draft
authorKartikaya Gupta <kgupta@mozilla.com>
Mon, 20 Mar 2017 12:10:57 -0400
changeset 501603 a16ab47a7aa800d5668aedaaff03480ef1101b3e
parent 501602 b5171ae3693caa61d8cb941b5b1edeb78d4b6c0b
child 549933 b3ad1921bf8bd4f158707af4a5d319fb6baccea7
push id50041
push userkgupta@mozilla.com
push dateMon, 20 Mar 2017 16:11:50 +0000
reviewersjrmuizel
bugs1346856
milestone55.0a1
Bug 1346856 - Revendor rust dependencies. r?jrmuizel MozReview-Commit-ID: 4EMBJOtIE6g
third_party/rust/cgl/.cargo-checksum.json
third_party/rust/cgl/Cargo.toml
third_party/rust/gleam/.cargo-checksum.json
third_party/rust/gleam/.travis.yml
third_party/rust/gleam/Cargo.toml
third_party/rust/gleam/build.rs
third_party/rust/gleam/src/gl.rs
third_party/rust/gleam/src/gl_fns.rs
third_party/rust/gleam/src/gles_fns.rs
third_party/rust/gleam/src/lib.rs
third_party/rust/offscreen_gl_context/.cargo-checksum.json
third_party/rust/offscreen_gl_context/Cargo.toml
third_party/rust/offscreen_gl_context/build.rs
third_party/rust/offscreen_gl_context/src/draw_buffer.rs
third_party/rust/offscreen_gl_context/src/gl_context.rs
third_party/rust/offscreen_gl_context/src/gl_limits.rs
third_party/rust/offscreen_gl_context/src/lib.rs
third_party/rust/offscreen_gl_context/src/platform/mod.rs
third_party/rust/offscreen_gl_context/src/platform/with_osmesa/mod.rs
third_party/rust/offscreen_gl_context/src/tests.rs
--- a/third_party/rust/cgl/.cargo-checksum.json
+++ b/third_party/rust/cgl/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"944bf600c6230664922a011cbca026699969f2f89f6c7ff689835836ccd7b1de",".travis.yml":"ea512c9287deceaab4ee436a1246874c84e7a422a90cd3aa3e8f9d3121824674","COPYING":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"e651a297d1d1445870a6380de53f1fd33f4ac9c349ff4197d740e24c9a16ca47","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"5b2cad1e1bd53b9f986974a23dbcbd951270a567d6c661f3584707d7ad198e82","src/cgl.rs":"d41fea7f18c07912f485d041baeb99010023084b449af69c6c92dfdcaf1c96e8","src/lib.rs":"8a86ac23aaea868d951a1c51300670d1eda525681d0b144964a6c81737f485e6"},"package":"8bdd78cca65a739cb5475dbf6b6bbb49373e327f4a6f2b499c0f98632df38c10"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"944bf600c6230664922a011cbca026699969f2f89f6c7ff689835836ccd7b1de",".travis.yml":"ea512c9287deceaab4ee436a1246874c84e7a422a90cd3aa3e8f9d3121824674","COPYING":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"95753be1a55ae87129e69f594f2dc3f14a4f6df4401296aad9fde35b40177814","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"5b2cad1e1bd53b9f986974a23dbcbd951270a567d6c661f3584707d7ad198e82","src/cgl.rs":"d41fea7f18c07912f485d041baeb99010023084b449af69c6c92dfdcaf1c96e8","src/lib.rs":"8a86ac23aaea868d951a1c51300670d1eda525681d0b144964a6c81737f485e6"},"package":"86765cb42c2a2c497e142af72517c1b4d7ae5bb2f25dfa77a5c69642f2342d89"}
\ No newline at end of file
--- a/third_party/rust/cgl/Cargo.toml
+++ b/third_party/rust/cgl/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "cgl"
 license = "MIT / Apache-2.0"
-version = "0.1.5"
+version = "0.2.1"
 authors = ["The Servo Project Developers"]
 description = "Rust bindings for CGL on Mac"
 repository = "https://github.com/servo/cgl-rs"
 
 [dependencies]
 libc = "0.2"
-gleam = "0.2"
+gleam = "0.4"
--- a/third_party/rust/gleam/.cargo-checksum.json
+++ b/third_party/rust/gleam/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"c1e953ee360e77de57f7b02f1b7880bd6a3dc22d1a69e953c2ac2c52cc52d247",".travis.yml":"46f5e5da873985b56fc97643a27f610feec18724aad8e899379f3b8c84c329ae","COPYING":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"a1d227749271af1ad64516277ee655b66bfcd53a13006bf94d41380c5dd345db","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"2de24b7458d6b88f20324303a48acf64a4f2bbfb83d2ec4d6ff2b4f4a1fd2275","build.rs":"5b2abf3e2b85f4d0bdbbaa5778c8fd7480eb151db3bd699ec63b77fa3afdfd7b","src/gl.rs":"f9acc199591d06018b75924fc1ad881e9deb67f4ad8f0213f028b4aacdffb5ca","src/lib.rs":"ad33ebcb3f4a0edc36e95c837cda6f01a0be8a6ab1bcf485565fb03f70831324"},"package":"9590e0e578d528a080c5abac678e7efbe349a73c7316faafd4073edf5f462d01"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"c1e953ee360e77de57f7b02f1b7880bd6a3dc22d1a69e953c2ac2c52cc52d247",".travis.yml":"29b74b95210896ce634c11a9037638668473b5a1b3b1716c505cb04dbb6341fa","COPYING":"ec82b96487e9e778ee610c7ab245162464782cfa1f555c2299333f8dbe5c036a","Cargo.toml":"5fd8124cb3073a87b04271d343b8bb73c749f97bfef800d5ccb2b461a1a84354","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"62065228e42caebca7e7d7db1204cbb867033de5982ca4009928915e4095f3a3","README.md":"2de24b7458d6b88f20324303a48acf64a4f2bbfb83d2ec4d6ff2b4f4a1fd2275","build.rs":"16a89f28717ffeae75219889d6560aa8b089adff46f821a724e28e20fddafb81","src/gl.rs":"ed01b1c8e5cb31de68dde54a857722f3d5b2bdeb8e30bfb2a95b500e3bf5f98a","src/gl_fns.rs":"d6eb7dd171030fe1b350f1616cd2c2e33d9051f70f5edcdd85f146b2745418a0","src/gles_fns.rs":"91c15619b8fbabe2324358d3c6ada27559acc42b0a21c64cc37ccd3729a9582a","src/lib.rs":"16610c19b45a3f26d56b379a3591aa2e4fc9477e7bd88f86b31c6ea32e834861"},"package":"2958396a0a358d2de747b31329f5ae2229070602b0f51edd5d682f92c307c332"}
\ No newline at end of file
--- a/third_party/rust/gleam/.travis.yml
+++ b/third_party/rust/gleam/.travis.yml
@@ -1,3 +1,8 @@
 language: rust
+rust:
+  - nightly
+  - beta
+  - stable
+
 notifications:
   webhooks: http://build.servo.org:54856/travis
--- a/third_party/rust/gleam/Cargo.toml
+++ b/third_party/rust/gleam/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "gleam"
-version = "0.2.32"
+version = "0.4.1"
 license = "Apache-2.0/MIT"
 authors = ["The Servo Project Developers"]
 build = "build.rs"
 documentation = "http://doc.servo.org/gleam/"
 repository = "https://github.com/servo/gleam"
 description = "Generated OpenGL bindings and wrapper for Servo."
 
 [build-dependencies]
--- a/third_party/rust/gleam/build.rs
+++ b/third_party/rust/gleam/build.rs
@@ -3,38 +3,29 @@ extern crate pkg_config;
 
 use std::env;
 use std::fs::File;
 use std::path::Path;
 use gl_generator::{Registry, Api, Profile, Fallbacks};
 
 fn main() {
     let dest = env::var("OUT_DIR").unwrap();
-    let mut file = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap();
-
-    let target = env::var("TARGET").unwrap();
+    let mut file_gl_and_gles = File::create(&Path::new(&dest).join("gl_and_gles_bindings.rs")).unwrap();
+    let mut file_gl = File::create(&Path::new(&dest).join("gl_bindings.rs")).unwrap();
+    let mut file_gles = File::create(&Path::new(&dest).join("gles_bindings.rs")).unwrap();
 
-    if target.contains("android") {
-        let extensions = ["GL_EXT_texture_format_BGRA8888"];
-        // GLES 2.0 bindings for Android
-        Registry::new(Api::Gles2, (3, 0), Profile::Core, Fallbacks::All, extensions)
-            .write_bindings(gl_generator::StaticGenerator, &mut file)
+    // OpenGL 3.3 bindings
+    let gl_extensions = ["GL_ARB_texture_rectangle", "GL_EXT_debug_marker"];
+    let gl_reg = Registry::new(Api::Gl, (3, 3), Profile::Core, Fallbacks::All, gl_extensions);
+    gl_reg.write_bindings(gl_generator::StructGenerator, &mut file_gl)
+          .unwrap();
+
+    // GLES 2.0 bindings
+    let gles_extensions = ["GL_EXT_texture_format_BGRA8888"];
+    let gles_reg = Registry::new(Api::Gles2, (3, 0), Profile::Core, Fallbacks::All, gles_extensions);
+    gles_reg.write_bindings(gl_generator::StructGenerator, &mut file_gles)
             .unwrap();
 
-        println!("cargo:rustc-link-lib=GLESv3");
-    } else {
-        let extensions = ["GL_ARB_texture_rectangle", "GL_EXT_debug_marker"];
-        // OpenGL 3.3 bindings for Linux/Mac/Windows
-        Registry::new(Api::Gl, (3, 3), Profile::Core, Fallbacks::All, extensions)
-            .write_bindings(gl_generator::GlobalGenerator, &mut file)
-            .unwrap();
-
-        if target.contains("darwin") {
-            println!("cargo:rustc-link-lib=framework=OpenGL");
-        } else if target.contains("windows") {
-            println!("cargo:rustc-link-lib=opengl32");
-        } else {
-            if let Err(_) = pkg_config::probe_library("gl") {
-                println!("cargo:rustc-link-lib=GL");
-            }
-        }
-    }
+    // OpenGL 3.3 + GLES 2.0 bindings. Used to get all enums
+    let gl_reg = gl_reg + gles_reg;
+    gl_reg.write_bindings(gl_generator::StructGenerator, &mut file_gl_and_gles)
+          .unwrap();
 }
--- a/third_party/rust/gleam/src/gl.rs
+++ b/third_party/rust/gleam/src/gl.rs
@@ -6,1533 +6,407 @@
 // <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.
 
 use std::mem;
 use std::mem::size_of;
 use std::os::raw::{c_char, c_int, c_void};
 use std::ptr;
-use std::str::{self};
+use std::rc::Rc;
+use std::str;
 use std::iter::repeat;
 use std::ffi::{CString, CStr};
 use ffi;
 
 pub use ffi::types::*;
 pub use ffi::*;
 
+pub use ffi_gl::Gl as GlFfi;
+pub use ffi_gles::Gles2 as GlesFfi;
+
 #[derive(Debug, Eq, PartialEq)]
 pub enum GlType {
     Gl,
     Gles,
 }
 
 impl Default for GlType {
-  #[cfg(target_os="android")]
-  fn default() -> GlType {
-    GlType::Gles
-  }
-  #[cfg(not(target_os="android"))]
-  fn default() -> GlType {
-    GlType::Gl
-  }
-}
-
-#[inline]
-pub fn buffer_data<T>(target: GLenum, data: &[T], usage: GLenum) {
-    unsafe {
-        ffi::BufferData(target,
-                       (data.len() * size_of::<T>()) as GLsizeiptr,
-                       data.as_ptr() as *const GLvoid,
-                       usage);
-    }
-}
-
-#[inline]
-pub fn buffer_data_raw<T>(target: GLenum, data: &T, usage: GLenum) {
-    unsafe {
-        ffi::BufferData(target,
-                        size_of::<T>() as GLsizeiptr,
-                        data as *const T as *const GLvoid,
-                        usage);
+    #[cfg(target_os="android")]
+    fn default() -> GlType {
+        GlType::Gles
     }
-}
-
-#[inline]
-pub fn buffer_sub_data<T>(target: GLenum, offset: isize, data: &[T]) {
-    unsafe {
-        ffi::BufferSubData(target,
-                           offset,
-                           (data.len() * size_of::<T>()) as GLsizeiptr,
-                           data.as_ptr() as *const GLvoid);
-    }
-}
-
-pub fn shader_source(shader: GLuint, strings: &[&[u8]]) {
-    let pointers: Vec<*const u8> = strings.iter().map(|string| (*string).as_ptr()).collect();
-    let lengths: Vec<GLint> = strings.iter().map(|string| string.len() as GLint).collect();
-    unsafe {
-        ffi::ShaderSource(shader, pointers.len() as GLsizei,
-                         pointers.as_ptr() as *const *const GLchar, lengths.as_ptr());
-    }
-    drop(lengths);
-    drop(pointers);
-}
-
-#[cfg(not(target_os="android"))]
-pub fn read_buffer(mode: GLenum) {
-    unsafe {
-        ffi::ReadBuffer(mode);
+    #[cfg(not(target_os="android"))]
+    fn default() -> GlType {
+        GlType::Gl
     }
 }
 
 fn calculate_length(width: GLsizei, height: GLsizei, format: GLenum, pixel_type: GLenum) -> usize {
     let colors = match format {
         ffi::RGB => 3,
-#[cfg(not(target_os="android"))]
         ffi::BGR => 3,
 
         ffi::RGBA => 4,
-#[cfg(not(target_os="android"))]
         ffi::BGRA => 4,
 
         ffi::ALPHA => 1,
-#[cfg(target_os="android")]
         ffi::LUMINANCE => 1,
         _ => panic!("unsupported format for read_pixels"),
     };
     let depth = match pixel_type {
         ffi::UNSIGNED_BYTE => 1,
         _ => panic!("unsupported pixel_type for read_pixels"),
     };
 
     return (width * height * colors * depth) as usize;
 }
 
-pub fn read_pixels_into_buffer(x: GLint, y: GLint, width: GLsizei, height: GLsizei,
-                               format: GLenum, pixel_type: GLenum, dst_buffer: &mut [u8]) {
-    // Assumes that the user properly allocated the size for dst_buffer.
-    assert!(calculate_length(width, height, format, pixel_type) == dst_buffer.len());
-
-    unsafe {
-        // We don't want any alignment padding on pixel rows.
-        ffi::PixelStorei(ffi::PACK_ALIGNMENT, 1);
-        ffi::ReadPixels(x, y, width, height, format, pixel_type, dst_buffer.as_mut_ptr() as *mut c_void);
-    }
-}
-
-pub fn read_pixels(x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, pixel_type: GLenum) -> Vec<u8> {
-    let len = calculate_length(width, height, format, pixel_type);
-    let mut pixels: Vec<u8> = Vec::new();
-    pixels.reserve(len);
-    unsafe { pixels.set_len(len); }
-
-    read_pixels_into_buffer(x, y, width, height, format, pixel_type, pixels.as_mut_slice());
-
-    pixels
-}
-
-#[inline]
-pub fn sample_coverage(value: GLclampf, invert: bool) {
-    unsafe {
-        ffi::SampleCoverage(value, invert as GLboolean);
-    }
-}
-
-#[inline]
-pub fn polygon_offset(factor: GLfloat, units: GLfloat) {
-    unsafe {
-        ffi::PolygonOffset(factor, units);
-    }
-}
-
-#[inline]
-pub fn pixel_store_i(name: GLenum, param: GLint) {
-    unsafe {
-        ffi::PixelStorei(name, param);
-    }
-}
-
-#[inline]
-pub fn gen_buffers(n: GLsizei) -> Vec<GLuint> {
-    unsafe {
-        let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
-        ffi::GenBuffers(n, result.as_mut_ptr());
-        return result;
-    }
-}
-
-#[inline]
-pub fn gen_renderbuffers(n: GLsizei) -> Vec<GLuint> {
-    unsafe {
-        let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
-        ffi::GenRenderbuffers(n, result.as_mut_ptr());
-        return result;
-    }
-}
-
-#[inline]
-pub fn gen_framebuffers(n: GLsizei) -> Vec<GLuint> {
-    unsafe {
-        let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
-        ffi::GenFramebuffers(n, result.as_mut_ptr());
-        return result;
-    }
-}
-
-#[inline]
-pub fn gen_textures(n: GLsizei) -> Vec<GLuint> {
-    unsafe {
-        let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
-        ffi::GenTextures(n, result.as_mut_ptr());
-        return result;
-    }
-}
-
-#[inline]
-pub fn gen_vertex_arrays(n: GLsizei) -> Vec<GLuint> {
-    unsafe {
-        let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
-        ffi::GenVertexArrays(n, result.as_mut_ptr());
-        return result;
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn gen_queries(n: GLsizei) -> Vec<GLuint> {
-    unsafe {
-        let mut result = vec![0; n as usize];
-        ffi::GenQueries(n, result.as_mut_ptr());
-        return result;
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn begin_query(target: GLenum, id: GLuint) {
-    unsafe {
-        ffi::BeginQuery(target, id);
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn end_query(target: GLenum) {
-    unsafe {
-        ffi::EndQuery(target);
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn query_counter(id: GLuint, target: GLenum) {
-    unsafe {
-        ffi::QueryCounter(id, target);
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn get_query_object_iv(id: GLuint, pname: GLenum) -> i32 {
-    unsafe {
-        let mut result = 0;
-        ffi::GetQueryObjectiv(id, pname, &mut result);
-        result
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn get_query_object_uiv(id: GLuint, pname: GLenum) -> u32 {
-    unsafe {
-        let mut result = 0;
-        ffi::GetQueryObjectuiv(id, pname, &mut result);
-        result
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn get_query_object_i64v(id: GLuint, pname: GLenum) -> i64 {
-    unsafe {
-        let mut result = 0;
-        ffi::GetQueryObjecti64v(id, pname, &mut result);
-        result
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn get_query_object_ui64v(id: GLuint, pname: GLenum) -> u64 {
-    unsafe {
-        let mut result = 0;
-        ffi::GetQueryObjectui64v(id, pname, &mut result);
-        result
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn delete_queries(queries: &[GLuint]) {
-    unsafe {
-        ffi::DeleteQueries(queries.len() as GLsizei, queries.as_ptr());
-    }
-}
-
-#[inline]
-pub fn delete_vertex_arrays(vertex_arrays: &[GLuint]) {
-    unsafe {
-        ffi::DeleteVertexArrays(vertex_arrays.len() as GLsizei, vertex_arrays.as_ptr());
-    }
-}
-
-#[inline]
-pub fn delete_buffers(buffers: &[GLuint]) {
-    unsafe {
-        ffi::DeleteBuffers(buffers.len() as GLsizei, buffers.as_ptr());
-    }
-}
-
-#[inline]
-pub fn delete_renderbuffers(renderbuffers: &[GLuint]) {
-    unsafe {
-        ffi::DeleteRenderbuffers(renderbuffers.len() as GLsizei, renderbuffers.as_ptr());
-    }
-}
-
-#[inline]
-pub fn delete_framebuffers(framebuffers: &[GLuint]) {
-    unsafe {
-        ffi::DeleteFramebuffers(framebuffers.len() as GLsizei, framebuffers.as_ptr());
-    }
-}
-
-// NB: The name of this function is wrong, it's here for compatibility reasons,
-// but should be removed.
-#[inline]
-pub fn delete_frame_buffers(framebuffers: &[GLuint]) {
-    delete_framebuffers(framebuffers);
-}
-
-#[inline]
-pub fn delete_textures(textures: &[GLuint]) {
-    unsafe {
-        ffi::DeleteTextures(textures.len() as GLsizei, textures.as_ptr());
-    }
-}
-
-#[inline]
-pub fn framebuffer_renderbuffer(target: GLenum,
+pub trait Gl {
+    fn get_type(&self) -> GlType;
+    fn buffer_data_untyped(&self,
+                           target: GLenum,
+                           size: GLsizeiptr,
+                           data: *const GLvoid,
+                           usage: GLenum);
+    fn buffer_sub_data_untyped(&self,
+                               target: GLenum,
+                               offset: isize,
+                               size: GLsizeiptr,
+                               data: *const GLvoid);
+    fn shader_source(&self, shader: GLuint, strings: &[&[u8]]);
+    fn read_buffer(&self, mode: GLenum);
+    fn read_pixels_into_buffer(&self,
+                               x: GLint,
+                               y: GLint,
+                               width: GLsizei,
+                               height: GLsizei,
+                               format: GLenum,
+                               pixel_type: GLenum,
+                               dst_buffer: &mut [u8]);
+    fn read_pixels(&self,
+                   x: GLint,
+                   y: GLint,
+                   width: GLsizei,
+                   height: GLsizei,
+                   format: GLenum,
+                   pixel_type: GLenum)
+                   -> Vec<u8>;
+    fn sample_coverage(&self, value: GLclampf, invert: bool);
+    fn polygon_offset(&self, factor: GLfloat, units: GLfloat);
+    fn pixel_store_i(&self, name: GLenum, param: GLint);
+    fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint>;
+    fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint>;
+    fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint>;
+    fn gen_textures(&self, n: GLsizei) -> Vec<GLuint>;
+    fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint>;
+    fn gen_queries(&self, n: GLsizei) -> Vec<GLuint>;
+    fn begin_query(&self, target: GLenum, id: GLuint);
+    fn end_query(&self, target: GLenum);
+    fn query_counter(&self, id: GLuint, target: GLenum);
+    fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32;
+    fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32;
+    fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64;
+    fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64;
+    fn delete_queries(&self, queries: &[GLuint]);
+    fn delete_vertex_arrays(&self, vertex_arrays: &[GLuint]);
+    fn delete_buffers(&self, buffers: &[GLuint]);
+    fn delete_renderbuffers(&self, renderbuffers: &[GLuint]);
+    fn delete_framebuffers(&self, framebuffers: &[GLuint]);
+    fn delete_textures(&self, textures: &[GLuint]);
+    fn framebuffer_renderbuffer(&self,
+                                target: GLenum,
                                 attachment: GLenum,
                                 renderbuffertarget: GLenum,
-                                renderbuffer: GLuint) {
-    unsafe {
-        ffi::FramebufferRenderbuffer(target,
-                                     attachment,
-                                     renderbuffertarget,
-                                     renderbuffer);
-    }
-}
-
-#[inline]
-pub fn renderbuffer_storage(target: GLenum,
+                                renderbuffer: GLuint);
+    fn renderbuffer_storage(&self,
+                            target: GLenum,
                             internalformat: GLenum,
                             width: GLsizei,
-                            height: GLsizei) {
-    unsafe {
-        ffi::RenderbufferStorage(target,
-                                 internalformat,
-                                 width,
-                                 height);
-    }
-}
-
-#[inline]
-pub fn depth_func(func: GLenum) {
-    unsafe {
-        ffi::DepthFunc(func);
-    }
-}
-
-#[inline]
-pub fn active_texture(texture: GLenum) {
-    unsafe {
-        ffi::ActiveTexture(texture);
-    }
-}
-
-#[inline]
-pub fn attach_shader(program: GLuint, shader: GLuint) {
-    unsafe {
-        ffi::AttachShader(program, shader);
-    }
-}
-
-#[inline]
-pub fn bind_attrib_location(program: GLuint, index: GLuint, name: &str) {
-    let c_string = CString::new(name).unwrap();
-    unsafe {
-        ffi::BindAttribLocation(program, index, c_string.as_ptr())
-    }
-}
-
-#[inline]
-pub fn get_uniform_block_index(program: GLuint, name: &str) -> GLuint {
-    let c_string = CString::new(name).unwrap();
-    unsafe {
-        ffi::GetUniformBlockIndex(program, c_string.as_ptr())
-    }
-}
-
-#[inline]
-pub fn bind_buffer_base(target: GLenum, index: GLuint, buffer: GLuint) {
-    unsafe {
-        ffi::BindBufferBase(target, index, buffer);
-    }
-}
-
-#[inline]
-pub fn uniform_block_binding(program: GLuint, uniform_block_index: GLuint, uniform_block_binding: GLuint) {
-    unsafe {
-        ffi::UniformBlockBinding(program, uniform_block_index, uniform_block_binding);
-    }
-}
-
-#[inline]
-pub fn bind_buffer(target: GLenum, buffer: GLuint) {
-    unsafe {
-        ffi::BindBuffer(target, buffer);
-    }
-}
-
-#[inline]
-pub fn bind_vertex_array(vao: GLuint) {
-    unsafe {
-        ffi::BindVertexArray(vao);
-    }
-}
-
-#[inline]
-pub fn bind_renderbuffer(target: GLenum, renderbuffer: GLuint) {
-    unsafe {
-        ffi::BindRenderbuffer(target, renderbuffer);
-    }
-}
-
-#[inline]
-pub fn bind_framebuffer(target: GLenum, framebuffer: GLuint) {
-    unsafe {
-        ffi::BindFramebuffer(target, framebuffer);
-    }
-}
-
-#[inline]
-pub fn bind_texture(target: GLenum, texture: GLuint) {
-    unsafe {
-        ffi::BindTexture(target, texture);
-    }
-}
-
-// FIXME: Does not verify buffer size -- unsafe!
-pub fn tex_image_2d(target: GLenum,
+                            height: GLsizei);
+    fn depth_func(&self, func: GLenum);
+    fn active_texture(&self, texture: GLenum);
+    fn attach_shader(&self, program: GLuint, shader: GLuint);
+    fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str);
+    fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint;
+    fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint);
+    fn uniform_block_binding(&self,
+                             program: GLuint,
+                             uniform_block_index: GLuint,
+                             uniform_block_binding: GLuint);
+    fn bind_buffer(&self, target: GLenum, buffer: GLuint);
+    fn bind_vertex_array(&self, vao: GLuint);
+    fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint);
+    fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint);
+    fn bind_texture(&self, target: GLenum, texture: GLuint);
+    fn tex_image_2d(&self,
+                    target: GLenum,
                     level: GLint,
                     internal_format: GLint,
                     width: GLsizei,
                     height: GLsizei,
                     border: GLint,
                     format: GLenum,
                     ty: GLenum,
-                    opt_data: Option<&[u8]>) {
-    match opt_data {
-        Some(data) => {
-            unsafe {
-                ffi::TexImage2D(target, level, internal_format, width, height, border, format, ty,
-                                data.as_ptr() as *const GLvoid);
-            }
-        }
-        None => {
-            unsafe {
-                ffi::TexImage2D(target, level, internal_format, width, height, border, format, ty,
-                               ptr::null());
-            }
-        }
-    }
-}
-
-pub fn compressed_tex_image_2d(target: GLenum,
+                    opt_data: Option<&[u8]>);
+    fn compressed_tex_image_2d(&self,
+                               target: GLenum,
                                level: GLint,
                                internal_format: GLenum,
                                width: GLsizei,
                                height: GLsizei,
                                border: GLint,
-                               data: &[u8]) {
-    unsafe {
-        ffi::CompressedTexImage2D(target, level, internal_format, width, height, border,
-                                  data.len() as GLsizei, data.as_ptr() as *const GLvoid);
-    }
-}
-
-pub fn compressed_tex_sub_image_2d(target: GLenum,
+                               data: &[u8]);
+    fn compressed_tex_sub_image_2d(&self,
+                                   target: GLenum,
                                    level: GLint,
                                    xoffset: GLint,
                                    yoffset: GLint,
                                    width: GLsizei,
                                    height: GLsizei,
                                    format: GLenum,
-                                   data: &[u8]) {
-    unsafe {
-        ffi::CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format,
-                                     data.len() as GLsizei, data.as_ptr() as *const GLvoid);
-    }
-}
-
-// FIXME: Does not verify buffer size -- unsafe!
-pub fn tex_image_3d(target: GLenum,
+                                   data: &[u8]);
+    fn tex_image_3d(&self,
+                    target: GLenum,
                     level: GLint,
                     internal_format: GLint,
                     width: GLsizei,
                     height: GLsizei,
                     depth: GLsizei,
                     border: GLint,
                     format: GLenum,
                     ty: GLenum,
-                    opt_data: Option<&[u8]>) {
-    unsafe {
-        let pdata = match opt_data {
-            Some(data) => mem::transmute(data.as_ptr()),
-            None => ptr::null(),
-        };
-        ffi::TexImage3D(target,
-                        level,
-                        internal_format,
-                        width,
-                        height,
-                        depth,
-                        border,
-                        format,
-                        ty,
-                        pdata);
-    }
-}
-
-pub fn copy_tex_image_2d(target: GLenum,
+                    opt_data: Option<&[u8]>);
+    fn copy_tex_image_2d(&self,
+                         target: GLenum,
                          level: GLint,
                          internal_format: GLenum,
                          x: GLint,
                          y: GLint,
                          width: GLsizei,
                          height: GLsizei,
-                         border: GLint) {
-    unsafe {
-        ffi::CopyTexImage2D(target,
-                            level,
-                            internal_format,
-                            x,
-                            y,
-                            width,
-                            height,
-                            border);
-    }
-}
-
-pub fn copy_tex_sub_image_2d(target: GLenum,
+                         border: GLint);
+    fn copy_tex_sub_image_2d(&self,
+                             target: GLenum,
                              level: GLint,
                              xoffset: GLint,
                              yoffset: GLint,
                              x: GLint,
                              y: GLint,
                              width: GLsizei,
-                             height: GLsizei) {
-    unsafe {
-        ffi::CopyTexSubImage2D(target,
-                               level,
-                               xoffset,
-                               yoffset,
-                               x,
-                               y,
-                               width,
-                               height);
-    }
-}
-
-#[inline]
-pub fn copy_tex_sub_image_3d(target: GLenum,
+                             height: GLsizei);
+    fn copy_tex_sub_image_3d(&self,
+                             target: GLenum,
                              level: GLint,
                              xoffset: GLint,
                              yoffset: GLint,
                              zoffset: GLint,
                              x: GLint,
                              y: GLint,
                              width: GLsizei,
-                             height: GLsizei) {
-    unsafe {
-        ffi::CopyTexSubImage3D(target,
-                               level,
-                               xoffset,
-                               yoffset,
-                               zoffset,
-                               x,
-                               y,
-                               width,
-                               height);
-    }
-}
-
-pub fn tex_sub_image_2d(target: GLenum,
+                             height: GLsizei);
+    fn tex_sub_image_2d(&self,
+                        target: GLenum,
                         level: GLint,
                         xoffset: GLint,
                         yoffset: GLint,
                         width: GLsizei,
                         height: GLsizei,
                         format: GLenum,
                         ty: GLenum,
-                        data: &[u8]) {
-    unsafe {
-        ffi::TexSubImage2D(target, level, xoffset, yoffset, width, height, format, ty, data.as_ptr() as *const c_void);
-    }
-}
-
-pub fn tex_sub_image_3d(target: GLenum,
+                        data: &[u8]);
+    fn tex_sub_image_3d(&self,
+                        target: GLenum,
                         level: GLint,
                         xoffset: GLint,
                         yoffset: GLint,
                         zoffset: GLint,
                         width: GLsizei,
                         height: GLsizei,
                         depth: GLsizei,
                         format: GLenum,
                         ty: GLenum,
-                        data: &[u8]) {
-    unsafe {
-        ffi::TexSubImage3D(target,
-                           level,
-                           xoffset,
-                           yoffset,
-                           zoffset,
-                           width,
-                           height,
-                           depth,
-                           format,
-                           ty,
-                           data.as_ptr() as *const c_void);
-    }
-}
-
-#[inline]
-pub fn get_integer_v(name: GLenum) -> GLint {
-    let mut result: GLint = 0 as GLint;
-    unsafe {
-        ffi::GetIntegerv(name, &mut result);
-    }
-    result
-}
-
-#[inline]
-pub fn get_boolean_v(name: GLenum) -> GLboolean {
-    let mut result: GLboolean = 0 as GLboolean;
-    unsafe {
-        ffi::GetBooleanv(name, &mut result);
-    }
-    result
-}
-
-
-#[inline]
-pub fn get_float_v(name: GLenum) -> GLfloat {
-    let mut result: GLfloat = 0 as GLfloat;
-    unsafe {
-        ffi::GetFloatv(name, &mut result);
-    }
-    result
-}
-
-#[inline]
-pub fn tex_parameter_i(target: GLenum, pname: GLenum, param: GLint) {
-    unsafe {
-        ffi::TexParameteri(target, pname, param);
-    }
-}
-
-#[inline]
-pub fn tex_parameter_f(target: GLenum, pname: GLenum, param: GLfloat) {
-    unsafe {
-        ffi::TexParameterf(target, pname, param);
-    }
-}
-
-#[inline]
-pub fn framebuffer_texture_2d(target: GLenum,
+                        data: &[u8]);
+    fn get_integer_v(&self, name: GLenum) -> GLint;
+    fn get_boolean_v(&self, name: GLenum) -> GLboolean;
+    fn get_float_v(&self, name: GLenum) -> GLfloat;
+    fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint);
+    fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat);
+    fn framebuffer_texture_2d(&self,
+                              target: GLenum,
                               attachment: GLenum,
                               textarget: GLenum,
                               texture: GLuint,
-                              level: GLint) {
-    unsafe {
-        ffi::FramebufferTexture2D(target, attachment, textarget, texture, level);
-    }
-}
-
-#[inline]
-pub fn framebuffer_texture_layer(target: GLenum,
+                              level: GLint);
+    fn framebuffer_texture_layer(&self,
+                                 target: GLenum,
                                  attachment: GLenum,
                                  texture: GLuint,
                                  level: GLint,
-                                 layer: GLint) {
-    unsafe {
-        ffi::FramebufferTextureLayer(target, attachment, texture, level, layer);
-    }
-}
-
-#[inline]
-pub fn blit_framebuffer(srcX0: GLint,
-                        srcY0: GLint,
-                        srcX1: GLint,
-                        srcY1: GLint,
-                        dstX0: GLint,
-                        dstY0: GLint,
-                        dstX1: GLint,
-                        dstY1: GLint,
+                                 layer: GLint);
+    fn blit_framebuffer(&self,
+                        src_x0: GLint,
+                        src_y0: GLint,
+                        src_x1: GLint,
+                        src_y1: GLint,
+                        dst_x0: GLint,
+                        dst_y0: GLint,
+                        dst_x1: GLint,
+                        dst_y1: GLint,
                         mask: GLbitfield,
-                        filter: GLenum) {
-    unsafe {
-        ffi::BlitFramebuffer(srcX0,
-                             srcY0,
-                             srcX1,
-                             srcY1,
-                             dstX0,
-                             dstY0,
-                             dstX1,
-                             dstY1,
-                             mask,
-                             filter);
-    }
-}
-
-#[inline]
-pub fn vertex_attrib_4f(index: GLuint,
-                        x: GLfloat,
-                        y: GLfloat,
-                        z: GLfloat,
-                        w: GLfloat) {
-    unsafe {
-        ffi::VertexAttrib4f(index, x, y, z, w)
-    }
-}
-
-#[inline]
-pub fn vertex_attrib_pointer_f32(index: GLuint,
+                        filter: GLenum);
+    fn vertex_attrib_4f(&self, index: GLuint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat);
+    fn vertex_attrib_pointer_f32(&self,
+                                 index: GLuint,
                                  size: GLint,
                                  normalized: bool,
                                  stride: GLsizei,
-                                 offset: GLuint) {
-    unsafe {
-        ffi::VertexAttribPointer(index,
-                                size,
-                                ffi::FLOAT,
-                                normalized as GLboolean,
-                                stride,
-                                offset as *const GLvoid)
-    }
-}
-
-#[inline]
-pub fn vertex_attrib_pointer(index: GLuint,
+                                 offset: GLuint);
+    fn vertex_attrib_pointer(&self,
+                             index: GLuint,
                              size: GLint,
                              type_: GLenum,
                              normalized: bool,
                              stride: GLsizei,
-                             offset: GLuint) {
-    unsafe {
-        ffi::VertexAttribPointer(index,
-                                 size,
-                                 type_,
-                                 normalized as GLboolean,
-                                 stride,
-                                 offset as *const GLvoid)
-    }
-}
-
-#[inline]
-pub fn vertex_attrib_i_pointer(index: GLuint,
+                             offset: GLuint);
+    fn vertex_attrib_i_pointer(&self,
+                               index: GLuint,
                                size: GLint,
                                type_: GLenum,
                                stride: GLsizei,
-                               offset: GLuint) {
-    unsafe {
-        ffi::VertexAttribIPointer(index,
-                                  size,
-                                  type_,
-                                  stride,
-                                  offset as *const GLvoid)
-    }
-}
-
-#[inline]
-pub fn vertex_attrib_divisor(index: GLuint, divisor: GLuint) {
-    unsafe {
-        ffi::VertexAttribDivisor(index, divisor)
-    }
-}
-
-#[inline]
-pub fn viewport(x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
-    unsafe {
-        ffi::Viewport(x, y, width, height);
-    }
-}
-
-#[inline]
-pub fn scissor(x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
-    unsafe {
-        ffi::Scissor(x, y, width, height);
-    }
-}
-
-#[inline]
-pub fn line_width(width: GLfloat) {
-    unsafe {
-        ffi::LineWidth(width);
-    }
-}
-
-#[inline]
-pub fn use_program(program: GLuint) {
-    unsafe {
-        ffi::UseProgram(program);
-    }
-}
-
-#[inline]
-pub fn validate_program(program: GLuint) {
-    unsafe {
-        ffi::ValidateProgram(program);
-    }
-}
-
-#[inline]
-pub fn draw_arrays(mode: GLenum, first: GLint, count: GLsizei) {
-    unsafe {
-        return ffi::DrawArrays(mode, first, count);
-    }
-}
-
-#[inline]
-pub fn draw_arrays_instanced(mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei) {
-    unsafe {
-        return ffi::DrawArraysInstanced(mode, first, count, primcount);
-    }
-}
-
-#[inline]
-pub fn draw_elements(mode: GLenum, count: GLsizei, element_type: GLenum, indices_offset: GLuint) {
-    unsafe {
-        return ffi::DrawElements(mode, count, element_type, indices_offset as *const c_void)
-    }
-}
-
-#[inline]
-pub fn draw_elements_instanced(mode: GLenum,
+                               offset: GLuint);
+    fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint);
+    fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei);
+    fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei);
+    fn line_width(&self, width: GLfloat);
+    fn use_program(&self, program: GLuint);
+    fn validate_program(&self, program: GLuint);
+    fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei);
+    fn draw_arrays_instanced(&self,
+                             mode: GLenum,
+                             first: GLint,
+                             count: GLsizei,
+                             primcount: GLsizei);
+    fn draw_elements(&self,
+                     mode: GLenum,
+                     count: GLsizei,
+                     element_type: GLenum,
+                     indices_offset: GLuint);
+    fn draw_elements_instanced(&self,
+                               mode: GLenum,
                                count: GLsizei,
                                element_type: GLenum,
                                indices_offset: GLuint,
-                               primcount: GLsizei) {
-    unsafe {
-        return ffi::DrawElementsInstanced(mode,
-                                          count,
-                                          element_type,
-                                          indices_offset as *const c_void,
-                                          primcount)
-    }
-}
-
-#[inline]
-pub fn blend_color(r: f32, g: f32, b: f32, a: f32) {
-    unsafe {
-        ffi::BlendColor(r, g, b, a);
-    }
-}
-
-#[inline]
-pub fn blend_func(sfactor: GLenum, dfactor: GLenum) {
-    unsafe {
-        ffi::BlendFunc(sfactor, dfactor);
-    }
-}
-
-#[inline]
-pub fn blend_func_separate(src_rgb: GLenum, dest_rgb: GLenum, src_alpha: GLenum, dest_alpha: GLenum) {
-    unsafe {
-        ffi::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha);
-    }
-}
-
-#[inline]
-pub fn blend_equation(mode: GLenum) {
-    unsafe {
-        ffi::BlendEquation(mode);
-    }
-}
-
-#[inline]
-pub fn blend_equation_separate(mode_rgb: GLenum, mode_alpha: GLenum) {
-    unsafe {
-        ffi::BlendEquationSeparate(mode_rgb, mode_alpha);
-    }
-}
-
-#[inline]
-pub fn color_mask(r: bool, g: bool, b: bool, a: bool) {
-    unsafe {
-        ffi::ColorMask(r as GLboolean, g as GLboolean, b as GLboolean, a as GLboolean);
-    }
-}
-
-#[inline]
-pub fn cull_face(mode: GLenum) {
-    unsafe {
-        ffi::CullFace(mode);
-    }
-}
-
-#[inline]
-pub fn front_face(mode: GLenum) {
-    unsafe {
-        ffi::FrontFace(mode);
-    }
-}
-
-#[inline]
-pub fn enable(cap: GLenum) {
-    unsafe {
-        ffi::Enable(cap);
-    }
-}
-
-#[inline]
-pub fn disable(cap: GLenum) {
-    unsafe {
-        ffi::Disable(cap);
-    }
-}
-
-#[inline]
-pub fn hint(param_name: GLenum, param_val: GLenum) {
-    unsafe {
-        ffi::Hint(param_name, param_val);
-    }
-}
-
-#[inline]
-pub fn is_enabled(cap: GLenum) -> GLboolean {
-    unsafe {
-        ffi::IsEnabled(cap)
-    }
-}
-
-#[inline]
-pub fn is_shader(shader: GLuint) -> GLboolean {
-    unsafe {
-        ffi::IsShader(shader)
-    }
-}
-
-#[inline]
-pub fn is_texture(texture: GLenum) -> GLboolean {
-    unsafe {
-        ffi::IsTexture(texture)
-    }
-}
-
-#[inline]
-pub fn is_framebuffer(framebuffer: GLenum) -> GLboolean {
-    unsafe {
-        ffi::IsFramebuffer(framebuffer)
-    }
-}
-
-#[inline]
-pub fn is_renderbuffer(renderbuffer: GLenum) -> GLboolean {
-    unsafe {
-        ffi::IsRenderbuffer(renderbuffer)
-    }
-}
-
-#[inline]
-pub fn check_frame_buffer_status(target: GLenum) -> GLenum {
-    unsafe {
-        ffi::CheckFramebufferStatus(target)
-    }
-}
-
-#[inline]
-pub fn enable_vertex_attrib_array(index: GLuint) {
-    unsafe {
-        ffi::EnableVertexAttribArray(index);
-    }
-}
-
-#[inline]
-pub fn disable_vertex_attrib_array(index: GLuint) {
-    unsafe {
-        ffi::DisableVertexAttribArray(index);
-    }
-}
-
-#[inline]
-pub fn uniform_1f(location: GLint, v0: GLfloat) {
-    unsafe {
-        ffi::Uniform1f(location, v0);
-    }
-}
-
-#[inline]
-pub fn uniform_1fv(location: GLint, values: &[f32]) {
-    unsafe {
-        ffi::Uniform1fv(location,
-                        values.len() as GLsizei,
-                        values.as_ptr());
-    }
-}
-
-#[inline]
-pub fn uniform_1i(location: GLint, v0: GLint) {
-    unsafe {
-        ffi::Uniform1i(location, v0);
-    }
-}
-
-#[inline]
-pub fn uniform_1iv(location: GLint, values: &[i32]) {
-    unsafe {
-        ffi::Uniform1iv(location,
-                        values.len() as GLsizei,
-                        values.as_ptr());
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn uniform_1ui(location: GLint, v0: GLuint) {
-    unsafe {
-        ffi::Uniform1ui(location, v0);
-    }
-}
-
-#[inline]
-pub fn uniform_2f(location: GLint, v0: GLfloat, v1: GLfloat) {
-    unsafe {
-        ffi::Uniform2f(location, v0, v1);
-    }
-}
-
-#[inline]
-pub fn uniform_2fv(location: GLint, values: &[f32]) {
-    unsafe {
-        ffi::Uniform2fv(location,
-                        (values.len() / 2) as GLsizei,
-                        values.as_ptr());
-    }
-}
-
-#[inline]
-pub fn uniform_2i(location: GLint, v0: GLint, v1: GLint) {
-    unsafe {
-        ffi::Uniform2i(location, v0, v1);
-    }
-}
-
-#[inline]
-pub fn uniform_2iv(location: GLint, values: &[i32]) {
-    unsafe {
-        ffi::Uniform2iv(location,
-                        (values.len() / 2) as GLsizei,
-                        values.as_ptr());
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn uniform_2ui(location: GLint, v0: GLuint, v1: GLuint) {
-    unsafe {
-        ffi::Uniform2ui(location, v0, v1);
-    }
-}
-
-#[inline]
-pub fn uniform_3f(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {
-    unsafe {
-        ffi::Uniform3f(location, v0, v1, v2);
-    }
-}
-
-#[inline]
-pub fn uniform_3fv(location: GLint, values: &[f32]) {
-    unsafe {
-        ffi::Uniform3fv(location,
-                        (values.len() / 3) as GLsizei,
-                        values.as_ptr());
-    }
-}
-
-#[inline]
-pub fn uniform_3i(location: GLint, v0: GLint, v1: GLint, v2: GLint) {
-    unsafe {
-        ffi::Uniform3i(location, v0, v1, v2);
-    }
-}
-
-#[inline]
-pub fn uniform_3iv(location: GLint, values: &[i32]) {
-    unsafe {
-        ffi::Uniform3iv(location,
-                        (values.len() / 3) as GLsizei,
-                        values.as_ptr());
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn uniform_3ui(location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {
-    unsafe {
-        ffi::Uniform3ui(location, v0, v1, v2);
-    }
-}
-
-#[inline]
-pub fn uniform_4f(location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
-    unsafe {
-        ffi::Uniform4f(location, x, y, z, w);
-    }
-}
-
-#[inline]
-pub fn uniform_4i(location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) {
-    unsafe {
-        ffi::Uniform4i(location, x, y, z, w);
-    }
-}
-
-#[inline]
-pub fn uniform_4iv(location: GLint, values: &[i32]) {
-    unsafe {
-        ffi::Uniform4iv(location,
-                        (values.len() / 4) as GLsizei,
-                        values.as_ptr());
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn uniform_4ui(location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {
-    unsafe {
-        ffi::Uniform4ui(location, x, y, z, w);
-    }
-}
-
-#[inline]
-pub fn uniform_4fv(location: GLint, values: &[f32]) {
-    unsafe {
-        ffi::Uniform4fv(location,
-                        (values.len() / 4) as GLsizei,
-                        values.as_ptr());
-    }
+                               primcount: GLsizei);
+    fn blend_color(&self, r: f32, g: f32, b: f32, a: f32);
+    fn blend_func(&self, sfactor: GLenum, dfactor: GLenum);
+    fn blend_func_separate(&self,
+                           src_rgb: GLenum,
+                           dest_rgb: GLenum,
+                           src_alpha: GLenum,
+                           dest_alpha: GLenum);
+    fn blend_equation(&self, mode: GLenum);
+    fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum);
+    fn color_mask(&self, r: bool, g: bool, b: bool, a: bool);
+    fn cull_face(&self, mode: GLenum);
+    fn front_face(&self, mode: GLenum);
+    fn enable(&self, cap: GLenum);
+    fn disable(&self, cap: GLenum);
+    fn hint(&self, param_name: GLenum, param_val: GLenum);
+    fn is_enabled(&self, cap: GLenum) -> GLboolean;
+    fn is_shader(&self, shader: GLuint) -> GLboolean;
+    fn is_texture(&self, texture: GLenum) -> GLboolean;
+    fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean;
+    fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean;
+    fn check_frame_buffer_status(&self, target: GLenum) -> GLenum;
+    fn enable_vertex_attrib_array(&self, index: GLuint);
+    fn disable_vertex_attrib_array(&self, index: GLuint);
+    fn uniform_1f(&self, location: GLint, v0: GLfloat);
+    fn uniform_1fv(&self, location: GLint, values: &[f32]);
+    fn uniform_1i(&self, location: GLint, v0: GLint);
+    fn uniform_1iv(&self, location: GLint, values: &[i32]);
+    fn uniform_1ui(&self, location: GLint, v0: GLuint);
+    fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat);
+    fn uniform_2fv(&self, location: GLint, values: &[f32]);
+    fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint);
+    fn uniform_2iv(&self, location: GLint, values: &[i32]);
+    fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint);
+    fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat);
+    fn uniform_3fv(&self, location: GLint, values: &[f32]);
+    fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint);
+    fn uniform_3iv(&self, location: GLint, values: &[i32]);
+    fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint);
+    fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat);
+    fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint);
+    fn uniform_4iv(&self, location: GLint, values: &[i32]);
+    fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint);
+    fn uniform_4fv(&self, location: GLint, values: &[f32]);
+    fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: &[f32]);
+    fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: &[f32]);
+    fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: &[f32]);
+    fn depth_mask(&self, flag: bool);
+    fn depth_range(&self, near: f64, far: f64);
+    fn get_active_attrib(&self, program: GLuint, index: GLuint) -> (i32, u32, String);
+    fn get_active_uniform(&self, program: GLuint, index: GLuint) -> (i32, u32, String);
+    fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int;
+    fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int;
+    fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int;
+    fn get_program_info_log(&self, program: GLuint) -> String;
+    fn get_program_iv(&self, program: GLuint, pname: GLenum) -> GLint;
+    fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum) -> GLint;
+    fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum) -> Vec<GLfloat>;
+    fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint;
+    fn get_shader_info_log(&self, shader: GLuint) -> String;
+    fn get_string(&self, which: GLenum) -> String;
+    fn get_shader_iv(&self, shader: GLuint, pname: GLenum) -> GLint;
+    fn compile_shader(&self, shader: GLuint);
+    fn create_program(&self) -> GLuint;
+    fn delete_program(&self, program: GLuint);
+    fn create_shader(&self, shader_type: GLenum) -> GLuint;
+    fn delete_shader(&self, shader: GLuint);
+    fn detach_shader(&self, program: GLuint, shader: GLuint);
+    fn link_program(&self, program: GLuint);
+    fn clear_color(&self, r: f32, g: f32, b: f32, a: f32);
+    fn clear(&self, buffer_mask: GLbitfield);
+    fn clear_depth(&self, depth: f64);
+    fn clear_stencil(&self, s: GLint);
+    fn flush(&self);
+    fn finish(&self);
+    fn get_error(&self) -> GLenum;
+    fn stencil_mask(&self, mask: GLuint);
+    fn stencil_mask_separate(&self, face: GLenum, mask: GLuint);
+    fn stencil_func(&self, func: GLenum, ref_: GLint, mask: GLuint);
+    fn stencil_func_separate(&self, face: GLenum, func: GLenum, ref_: GLint, mask: GLuint);
+    fn stencil_op(&self, sfail: GLenum, dpfail: GLenum, dppass: GLenum);
+    fn stencil_op_separate(&self, face: GLenum, sfail: GLenum, dpfail: GLenum, dppass: GLenum);
+    fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GLeglImageOES);
+    fn generate_mipmap(&self, target: GLenum);
+    fn insert_event_marker_ext(&self, message: &str);
+    fn push_group_marker_ext(&self, message: &str);
+    fn pop_group_marker_ext(&self);
 }
 
 #[inline]
-pub fn uniform_matrix_2fv(location: GLint, transpose: bool, value: &[f32]) {
-    unsafe {
-        ffi::UniformMatrix2fv(location,
-                              (value.len() / 4) as GLsizei,
-                              transpose as GLboolean,
-                              value.as_ptr());
-    }
-}
-
-#[inline]
-pub fn uniform_matrix_3fv(location: GLint, transpose: bool, value: &[f32]) {
-    unsafe {
-        ffi::UniformMatrix3fv(location,
-                              (value.len() / 9) as GLsizei,
-                              transpose as GLboolean,
-                              value.as_ptr());
-    }
-}
-
-#[inline]
-pub fn uniform_matrix_4fv(location: GLint, transpose: bool, value: &[f32]) {
-    unsafe {
-        ffi::UniformMatrix4fv(location,
-                              (value.len() / 16) as GLsizei,
-                              transpose as GLboolean,
-                              value.as_ptr());
-    }
-}
-
-#[inline]
-pub fn depth_mask(flag: bool) {
-    unsafe {
-        ffi::DepthMask(flag as GLboolean);
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn depth_range(near: f64, far: f64) {
-    unsafe {
-        ffi::DepthRange(near as GLclampd, far as GLclampd);
-    }
-}
-
-#[cfg(target_os="android")]
-#[inline]
-pub fn depth_range(near: f64, far: f64) {
-    unsafe {
-        ffi::DepthRangef(near as GLclampf, far as GLclampf);
-    }
-}
-
-#[inline]
-pub fn get_active_attrib(program: GLuint, index: GLuint) -> (i32, u32, String) {
-    let buf_size = get_program_iv(program, ffi::ACTIVE_ATTRIBUTE_MAX_LENGTH);
-    let mut name = vec![0u8; buf_size as usize];
-    let mut length = 0 as GLsizei;
-    let mut size = 0 as i32;
-    let mut type_ = 0 as u32;
-    unsafe {
-        ffi::GetActiveAttrib(program, index, buf_size, &mut length, &mut size, &mut type_, name.as_mut_ptr() as *mut GLchar);
-    }
-    name.truncate(if length > 0 {length as usize} else {0});
-    (size, type_, String::from_utf8(name).unwrap())
-}
-
-#[inline]
-pub fn get_active_uniform(program: GLuint, index: GLuint) -> (i32, u32, String) {
-    let buf_size = get_program_iv(program, ffi::ACTIVE_UNIFORM_MAX_LENGTH);
-    let mut name = vec![0 as u8; buf_size as usize];
-    let mut length: GLsizei = 0;
-    let mut size: i32 = 0;
-    let mut type_: u32 = 0;
-
-    unsafe {
-        ffi::GetActiveUniform(program, index, buf_size, &mut length, &mut size,
-                              &mut type_, name.as_mut_ptr() as *mut GLchar);
-    }
-
-    name.truncate(if length > 0 { length as usize } else { 0 });
-
-    (size, type_, String::from_utf8(name).unwrap())
-}
-
-#[inline]
-pub fn get_attrib_location(program: GLuint, name: &str) -> c_int {
-    let name = CString::new(name).unwrap();
-    unsafe {
-        ffi::GetAttribLocation(program, name.as_ptr())
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn get_frag_data_location(program: GLuint, name: &str) -> c_int {
-    let name = CString::new(name).unwrap();
-    unsafe {
-        ffi::GetFragDataLocation(program, name.as_ptr())
-    }
-}
-
-#[inline]
-pub fn get_uniform_location(program: GLuint, name: &str) -> c_int {
-    let name = CString::new(name).unwrap();
-    unsafe {
-        ffi::GetUniformLocation(program, name.as_ptr())
-    }
-}
-
-pub fn get_program_info_log(program: GLuint) -> String {
-    unsafe {
-        let mut result = vec![0u8; 1024];
-        let mut result_len: GLsizei = 0 as GLsizei;
-        ffi::GetProgramInfoLog(program,
-                            1024 as GLsizei,
-                            &mut result_len,
-                            result.as_mut_ptr() as *mut GLchar);
-        result.truncate(if result_len > 0 {result_len as usize} else {0});
-        String::from_utf8(result).unwrap()
-    }
-}
-
-#[inline]
-pub fn get_program_iv(program: GLuint, pname: GLenum) -> GLint {
-    unsafe {
-        let mut result: GLint = 0 as GLint;
-        ffi::GetProgramiv(program, pname, &mut result);
-        return result;
-    }
-}
-
-#[inline]
-pub fn get_vertex_attrib_iv(index: GLuint, pname: GLenum) -> GLint {
-    unsafe {
-        let mut result: GLint = 0 as GLint;
-        ffi::GetVertexAttribiv(index, pname, &mut result);
-        return result;
-    }
-}
-
-#[inline]
-pub fn get_vertex_attrib_fv(index: GLuint, pname: GLenum) -> Vec<GLfloat> {
-    unsafe {
-        let mut result = vec![0 as GLfloat; 4];
-        ffi::GetVertexAttribfv(index, pname, result.as_mut_ptr());
-        return result;
-    }
-}
-
-#[inline]
-pub fn get_buffer_parameter_iv(target: GLuint, pname: GLenum) -> GLint {
-    unsafe {
-        let mut result: GLint = 0 as GLint;
-        ffi::GetBufferParameteriv(target, pname, &mut result);
-        return result;
-    }
-}
-
-pub fn get_shader_info_log(shader: GLuint) -> String {
-    unsafe {
-        let mut result = vec![0u8; 1024];
-        let mut result_len: GLsizei = 0 as GLsizei;
-        ffi::GetShaderInfoLog(shader,
-                           1024 as GLsizei,
-                           &mut result_len,
-                           result.as_mut_ptr() as *mut GLchar);
-        result.truncate(if result_len > 0 {result_len as usize} else {0});
-        String::from_utf8(result).unwrap()
-    }
-}
-
-#[inline]
-pub fn get_string(which: GLenum) -> String {
-    unsafe {
-        let llstr = ffi::GetString(which);
-        if !llstr.is_null() {
-            return str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()).to_string();
-        } else {
-            return "".to_string();
-        }
-    }
-}
-
-#[inline]
-pub fn get_shader_iv(shader: GLuint, pname: GLenum) -> GLint {
-    unsafe {
-        let mut result: GLint = 0 as GLint;
-        ffi::GetShaderiv(shader, pname, &mut result);
-        return result;
-    }
-}
-
-#[inline]
-pub fn compile_shader(shader: GLuint) {
-    unsafe {
-        ffi::CompileShader(shader);
-    }
+pub fn buffer_data<T>(gl_: &Gl, target: GLenum, data: &[T], usage: GLenum) {
+    gl_.buffer_data_untyped(target,
+                            (data.len() * size_of::<T>()) as GLsizeiptr,
+                            data.as_ptr() as *const GLvoid,
+                            usage)
 }
 
 #[inline]
-pub fn create_program() -> GLuint {
-    unsafe {
-        return ffi::CreateProgram();
-    }
-}
-
-#[inline]
-pub fn delete_program(program: GLuint) {
-    unsafe {
-        ffi::DeleteProgram(program);
-    }
-}
-
-#[inline]
-pub fn create_shader(shader_type: GLenum) -> GLuint {
-    unsafe {
-        return ffi::CreateShader(shader_type);
-    }
-}
-
-#[inline]
-pub fn delete_shader(shader: GLuint) {
-    unsafe {
-        ffi::DeleteShader(shader);
-    }
-}
-
-#[inline]
-pub fn detach_shader(program: GLuint, shader: GLuint) {
-    unsafe {
-        ffi::DetachShader(program, shader);
-    }
-}
-
-#[inline]
-pub fn link_program(program: GLuint) {
-    unsafe {
-        return ffi::LinkProgram(program);
-    }
-}
-
-#[inline]
-pub fn clear_color(r: f32, g: f32, b: f32, a: f32) {
-    unsafe {
-        ffi::ClearColor(r, g, b, a);
-    }
-}
-
-#[inline]
-pub fn clear(buffer_mask: GLbitfield) {
-    unsafe {
-        ffi::Clear(buffer_mask);
-    }
-}
-
-#[cfg(not(target_os="android"))]
-#[inline]
-pub fn clear_depth(depth: f64) {
-    unsafe {
-        ffi::ClearDepth(depth as GLclampd);
-    }
-}
-
-#[cfg(target_os="android")]
-#[inline]
-pub fn clear_depth(depth: f64) {
-    unsafe {
-        ffi::ClearDepthf(depth as GLclampf);
-    }
-}
-
-#[inline]
-pub fn clear_stencil(s: GLint) {
-    unsafe {
-        ffi::ClearStencil(s);
-    }
-}
-
-#[inline]
-pub fn flush() {
-    unsafe {
-        ffi::Flush();
-    }
-}
-
-#[inline]
-pub fn finish() {
-    unsafe {
-        ffi::Finish();
-    }
-}
-
-#[inline]
-pub fn get_error() -> GLenum {
-    unsafe {
-        ffi::GetError()
-    }
+pub fn buffer_data_raw<T>(gl_: &Gl, target: GLenum, data: &T, usage: GLenum) {
+    gl_.buffer_data_untyped(target,
+                            size_of::<T>() as GLsizeiptr,
+                            data as *const T as *const GLvoid,
+                            usage)
 }
 
 #[inline]
-pub fn stencil_mask(mask: GLuint) {
-    unsafe {
-        ffi::StencilMask(mask)
-    }
-}
-
-#[inline]
-pub fn stencil_mask_separate(face: GLenum, mask: GLuint) {
-    unsafe {
-        ffi::StencilMaskSeparate(face, mask)
-    }
-}
-
-#[inline]
-pub fn stencil_func(func: GLenum,
-                    ref_: GLint,
-                    mask: GLuint) {
-    unsafe {
-        ffi::StencilFunc(func, ref_, mask)
-    }
-}
-
-#[inline]
-pub fn stencil_func_separate(face: GLenum,
-                             func: GLenum,
-                             ref_: GLint,
-                             mask: GLuint) {
-    unsafe {
-        ffi::StencilFuncSeparate(face, func, ref_, mask)
-    }
-}
-
-#[inline]
-pub fn stencil_op(sfail: GLenum,
-                  dpfail: GLenum,
-                  dppass: GLenum) {
-    unsafe {
-        ffi::StencilOp(sfail, dpfail, dppass)
-    }
+pub fn buffer_sub_data<T>(gl_: &Gl, target: GLenum, offset: isize, data: &[T]) {
+    gl_.buffer_sub_data_untyped(target,
+                                offset,
+                                (data.len() * size_of::<T>()) as GLsizeiptr,
+                                data.as_ptr() as *const GLvoid);
 }
 
-#[inline]
-pub fn stencil_op_separate(face: GLenum,
-                           sfail: GLenum,
-                           dpfail: GLenum,
-                           dppass: GLenum) {
-    unsafe {
-        ffi::StencilOpSeparate(face, sfail, dpfail, dppass)
-    }
-}
-
-#[cfg(target_os="android")]
-extern {
-    pub fn glEGLImageTargetTexture2DOES(target: GLenum, image: GLeglImageOES);
-}
-
-#[cfg(target_os="android")]
-pub fn egl_image_target_texture2d_oes(target: GLenum, image: GLeglImageOES) {
-    unsafe {
-        glEGLImageTargetTexture2DOES(target, image);
-    }
-}
-
-#[inline]
-pub fn generate_mipmap(target: GLenum) {
-    unsafe {
-        ffi::GenerateMipmap(target)
-    }
-}
-
-#[inline]
-#[cfg(not(target_os="android"))]
-pub fn insert_event_marker_ext(message: &str) {
-    if ffi::InsertEventMarkerEXT::is_loaded() {
-        unsafe {
-            ffi::InsertEventMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _);
-        }
-    }
-}
-
-#[inline]
-#[cfg(not(target_os="android"))]
-pub fn push_group_marker_ext(message: &str) {
-    if ffi::PushGroupMarkerEXT::is_loaded() {
-        unsafe {
-            ffi::PushGroupMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _);
-        }
-    }
-}
-
-#[inline]
-#[cfg(not(target_os="android"))]
-pub fn pop_group_marker_ext() {
-    if ffi::PopGroupMarkerEXT::is_loaded() {
-        unsafe {
-            ffi::PopGroupMarkerEXT();
-        }
-    }
-}
+include!("gl_fns.rs");
+include!("gles_fns.rs");
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gleam/src/gl_fns.rs
@@ -0,0 +1,1329 @@
+// Copyright 2014 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.
+
+pub struct GlFns {
+    ffi_gl_: GlFfi,
+}
+
+impl GlFns
+{
+    pub unsafe fn load_with<'a, F>(loadfn: F) -> Rc<Gl> where F: FnMut(&str) -> *const c_void {
+        let ffi_gl_ = GlFfi::load_with(loadfn);
+        Rc::new(GlFns {
+            ffi_gl_: ffi_gl_,
+        }) as Rc<Gl>
+    }
+}
+
+impl Gl for GlFns {
+    fn get_type(&self) -> GlType {
+        GlType::Gl
+    }
+
+    fn buffer_data_untyped(&self, target: GLenum, size: GLsizeiptr, data: *const GLvoid, usage: GLenum) {
+        unsafe {
+            self.ffi_gl_.BufferData(target,
+                                    size,
+                                    data,
+                                    usage);
+        }
+    }
+
+    fn buffer_sub_data_untyped(&self, target: GLenum, offset: isize, size: GLsizeiptr, data: *const GLvoid) {
+        unsafe {
+            self.ffi_gl_.BufferSubData(target,
+                                       offset,
+                                       size,
+                                       data);
+        }
+    }
+
+    fn shader_source(&self, shader: GLuint, strings: &[&[u8]]) {
+        let pointers: Vec<*const u8> = strings.iter().map(|string| (*string).as_ptr()).collect();
+        let lengths: Vec<GLint> = strings.iter().map(|string| string.len() as GLint).collect();
+        unsafe {
+            self.ffi_gl_.ShaderSource(shader, pointers.len() as GLsizei,
+                                      pointers.as_ptr() as *const *const GLchar, lengths.as_ptr());
+        }
+        drop(lengths);
+        drop(pointers);
+    }
+
+    fn read_buffer(&self, mode: GLenum) {
+        unsafe {
+            self.ffi_gl_.ReadBuffer(mode);
+        }
+    }
+
+    fn read_pixels_into_buffer(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei,
+                               format: GLenum, pixel_type: GLenum, dst_buffer: &mut [u8]) {
+        // Assumes that the user properly allocated the size for dst_buffer.
+        assert!(calculate_length(width, height, format, pixel_type) == dst_buffer.len());
+
+        unsafe {
+            // We don't want any alignment padding on pixel rows.
+            self.ffi_gl_.PixelStorei(ffi::PACK_ALIGNMENT, 1);
+            self.ffi_gl_.ReadPixels(x, y, width, height, format, pixel_type, dst_buffer.as_mut_ptr() as *mut c_void);
+        }
+    }
+
+    fn read_pixels(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, pixel_type: GLenum) -> Vec<u8> {
+        let len = calculate_length(width, height, format, pixel_type);
+        let mut pixels: Vec<u8> = Vec::new();
+        pixels.reserve(len);
+        unsafe { pixels.set_len(len); }
+
+        self.read_pixels_into_buffer(x, y, width, height, format, pixel_type, pixels.as_mut_slice());
+
+        pixels
+    }
+
+    fn sample_coverage(&self, value: GLclampf, invert: bool) {
+        unsafe {
+            self.ffi_gl_.SampleCoverage(value, invert as GLboolean);
+        }
+    }
+
+    fn polygon_offset(&self, factor: GLfloat, units: GLfloat) {
+        unsafe {
+            self.ffi_gl_.PolygonOffset(factor, units);
+        }
+    }
+
+    fn pixel_store_i(&self, name: GLenum, param: GLint) {
+        unsafe {
+            self.ffi_gl_.PixelStorei(name, param);
+        }
+    }
+
+    fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenBuffers(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenRenderbuffers(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenFramebuffers(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn gen_textures(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenTextures(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenVertexArrays(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn gen_queries(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result = vec![0; n as usize];
+            self.ffi_gl_.GenQueries(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn begin_query(&self, target: GLenum, id: GLuint) {
+        unsafe {
+            self.ffi_gl_.BeginQuery(target, id);
+        }
+    }
+
+    fn end_query(&self, target: GLenum) {
+        unsafe {
+            self.ffi_gl_.EndQuery(target);
+        }
+    }
+
+    fn query_counter(&self, id: GLuint, target: GLenum) {
+        unsafe {
+            self.ffi_gl_.QueryCounter(id, target);
+        }
+    }
+
+    fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32 {
+        unsafe {
+            let mut result = 0;
+            self.ffi_gl_.GetQueryObjectiv(id, pname, &mut result);
+            result
+        }
+    }
+
+    fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32 {
+        unsafe {
+            let mut result = 0;
+            self.ffi_gl_.GetQueryObjectuiv(id, pname, &mut result);
+            result
+        }
+    }
+
+    fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64 {
+        unsafe {
+            let mut result = 0;
+            self.ffi_gl_.GetQueryObjecti64v(id, pname, &mut result);
+            result
+        }
+    }
+
+    fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64 {
+        unsafe {
+            let mut result = 0;
+            self.ffi_gl_.GetQueryObjectui64v(id, pname, &mut result);
+            result
+        }
+    }
+
+    fn delete_queries(&self, queries: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteQueries(queries.len() as GLsizei, queries.as_ptr());
+        }
+    }
+
+    fn delete_vertex_arrays(&self, vertex_arrays: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteVertexArrays(vertex_arrays.len() as GLsizei, vertex_arrays.as_ptr());
+        }
+    }
+
+    fn delete_buffers(&self, buffers: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteBuffers(buffers.len() as GLsizei, buffers.as_ptr());
+        }
+    }
+
+    fn delete_renderbuffers(&self, renderbuffers: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteRenderbuffers(renderbuffers.len() as GLsizei, renderbuffers.as_ptr());
+        }
+    }
+
+    fn delete_framebuffers(&self, framebuffers: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteFramebuffers(framebuffers.len() as GLsizei, framebuffers.as_ptr());
+        }
+    }
+
+    fn delete_textures(&self, textures: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteTextures(textures.len() as GLsizei, textures.as_ptr());
+        }
+    }
+
+    fn framebuffer_renderbuffer(&self,
+                                target: GLenum,
+                                attachment: GLenum,
+                                renderbuffertarget: GLenum,
+                                renderbuffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.FramebufferRenderbuffer(target,
+                                                 attachment,
+                                                 renderbuffertarget,
+                                                 renderbuffer);
+        }
+    }
+
+    fn renderbuffer_storage(&self,
+                                target: GLenum,
+                                internalformat: GLenum,
+                                width: GLsizei,
+                                height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.RenderbufferStorage(target,
+                                             internalformat,
+                                             width,
+                                             height);
+        }
+    }
+
+    fn depth_func(&self, func: GLenum) {
+        unsafe {
+            self.ffi_gl_.DepthFunc(func);
+        }
+    }
+
+    fn active_texture(&self, texture: GLenum) {
+        unsafe {
+            self.ffi_gl_.ActiveTexture(texture);
+        }
+    }
+
+    fn attach_shader(&self, program: GLuint, shader: GLuint) {
+        unsafe {
+            self.ffi_gl_.AttachShader(program, shader);
+        }
+    }
+
+    fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) {
+        let c_string = CString::new(name).unwrap();
+        unsafe {
+            self.ffi_gl_.BindAttribLocation(program, index, c_string.as_ptr())
+        }
+    }
+
+    fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint {
+        let c_string = CString::new(name).unwrap();
+        unsafe {
+            self.ffi_gl_.GetUniformBlockIndex(program, c_string.as_ptr())
+        }
+    }
+
+    fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindBufferBase(target, index, buffer);
+        }
+    }
+
+    fn uniform_block_binding(&self, program: GLuint, uniform_block_index: GLuint, uniform_block_binding: GLuint) {
+        unsafe {
+            self.ffi_gl_.UniformBlockBinding(program, uniform_block_index, uniform_block_binding);
+        }
+    }
+
+    fn bind_buffer(&self, target: GLenum, buffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindBuffer(target, buffer);
+        }
+    }
+
+    fn bind_vertex_array(&self, vao: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindVertexArray(vao);
+        }
+    }
+
+    fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindRenderbuffer(target, renderbuffer);
+        }
+    }
+
+    fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindFramebuffer(target, framebuffer);
+        }
+    }
+
+    fn bind_texture(&self, target: GLenum, texture: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindTexture(target, texture);
+        }
+    }
+
+    // FIXME: Does not verify buffer size -- unsafe!
+    fn tex_image_2d(&self,
+                    target: GLenum,
+                    level: GLint,
+                    internal_format: GLint,
+                    width: GLsizei,
+                    height: GLsizei,
+                    border: GLint,
+                    format: GLenum,
+                    ty: GLenum,
+                    opt_data: Option<&[u8]>) {
+        match opt_data {
+            Some(data) => {
+                unsafe {
+                    self.ffi_gl_.TexImage2D(target, level, internal_format, width, height, border, format, ty,
+                                            data.as_ptr() as *const GLvoid);
+                }
+            }
+            None => {
+                unsafe {
+                    self.ffi_gl_.TexImage2D(target, level, internal_format, width, height, border, format, ty,
+                                            ptr::null());
+                }
+            }
+        }
+    }
+
+    fn compressed_tex_image_2d(&self,
+                               target: GLenum,
+                               level: GLint,
+                               internal_format: GLenum,
+                               width: GLsizei,
+                               height: GLsizei,
+                               border: GLint,
+                               data: &[u8]) {
+        unsafe {
+            self.ffi_gl_.CompressedTexImage2D(target, level, internal_format, width, height, border,
+                                              data.len() as GLsizei, data.as_ptr() as *const GLvoid);
+        }
+    }
+
+    fn compressed_tex_sub_image_2d(&self,
+                                   target: GLenum,
+                                   level: GLint,
+                                   xoffset: GLint,
+                                   yoffset: GLint,
+                                   width: GLsizei,
+                                   height: GLsizei,
+                                   format: GLenum,
+                                   data: &[u8]) {
+        unsafe {
+            self.ffi_gl_.CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format,
+                                                 data.len() as GLsizei, data.as_ptr() as *const GLvoid);
+        }
+    }
+
+    // FIXME: Does not verify buffer size -- unsafe!
+    fn tex_image_3d(&self,
+                    target: GLenum,
+                    level: GLint,
+                    internal_format: GLint,
+                    width: GLsizei,
+                    height: GLsizei,
+                    depth: GLsizei,
+                    border: GLint,
+                    format: GLenum,
+                    ty: GLenum,
+                    opt_data: Option<&[u8]>) {
+        unsafe {
+            let pdata = match opt_data {
+                Some(data) => mem::transmute(data.as_ptr()),
+                None => ptr::null(),
+            };
+            self.ffi_gl_.TexImage3D(target,
+                                    level,
+                                    internal_format,
+                                    width,
+                                    height,
+                                    depth,
+                                    border,
+                                    format,
+                                    ty,
+                                    pdata);
+        }
+    }
+
+    fn copy_tex_image_2d(&self,
+                         target: GLenum,
+                         level: GLint,
+                         internal_format: GLenum,
+                         x: GLint,
+                         y: GLint,
+                         width: GLsizei,
+                         height: GLsizei,
+                         border: GLint) {
+        unsafe {
+            self.ffi_gl_.CopyTexImage2D(target,
+                                        level,
+                                        internal_format,
+                                        x,
+                                        y,
+                                        width,
+                                        height,
+                                        border);
+        }
+    }
+
+    fn copy_tex_sub_image_2d(&self,
+                             target: GLenum,
+                             level: GLint,
+                             xoffset: GLint,
+                             yoffset: GLint,
+                             x: GLint,
+                             y: GLint,
+                             width: GLsizei,
+                             height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.CopyTexSubImage2D(target,
+                                           level,
+                                           xoffset,
+                                           yoffset,
+                                           x,
+                                           y,
+                                           width,
+                                           height);
+        }
+    }
+
+    fn copy_tex_sub_image_3d(&self,
+                             target: GLenum,
+                             level: GLint,
+                             xoffset: GLint,
+                             yoffset: GLint,
+                             zoffset: GLint,
+                             x: GLint,
+                             y: GLint,
+                             width: GLsizei,
+                             height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.CopyTexSubImage3D(target,
+                                           level,
+                                           xoffset,
+                                           yoffset,
+                                           zoffset,
+                                           x,
+                                           y,
+                                           width,
+                                           height);
+        }
+    }
+
+    fn tex_sub_image_2d(&self,
+                        target: GLenum,
+                        level: GLint,
+                        xoffset: GLint,
+                        yoffset: GLint,
+                        width: GLsizei,
+                        height: GLsizei,
+                        format: GLenum,
+                        ty: GLenum,
+                        data: &[u8]) {
+        unsafe {
+            self.ffi_gl_.TexSubImage2D(target, level, xoffset, yoffset, width, height, format, ty, data.as_ptr() as *const c_void);
+        }
+    }
+
+    fn tex_sub_image_3d(&self,
+                        target: GLenum,
+                        level: GLint,
+                        xoffset: GLint,
+                        yoffset: GLint,
+                        zoffset: GLint,
+                        width: GLsizei,
+                        height: GLsizei,
+                        depth: GLsizei,
+                        format: GLenum,
+                        ty: GLenum,
+                        data: &[u8]) {
+        unsafe {
+            self.ffi_gl_.TexSubImage3D(target,
+                                       level,
+                                       xoffset,
+                                       yoffset,
+                                       zoffset,
+                                       width,
+                                       height,
+                                       depth,
+                                       format,
+                                       ty,
+                                       data.as_ptr() as *const c_void);
+        }
+    }
+
+    fn get_integer_v(&self, name: GLenum) -> GLint {
+        let mut result: GLint = 0 as GLint;
+        unsafe {
+            self.ffi_gl_.GetIntegerv(name, &mut result);
+        }
+        result
+    }
+
+    fn get_boolean_v(&self, name: GLenum) -> GLboolean {
+        let mut result: GLboolean = 0 as GLboolean;
+        unsafe {
+            self.ffi_gl_.GetBooleanv(name, &mut result);
+        }
+        result
+    }
+
+    fn get_float_v(&self, name: GLenum) -> GLfloat {
+        let mut result: GLfloat = 0 as GLfloat;
+        unsafe {
+            self.ffi_gl_.GetFloatv(name, &mut result);
+        }
+        result
+    }
+
+    fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) {
+        unsafe {
+            self.ffi_gl_.TexParameteri(target, pname, param);
+        }
+    }
+
+    fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) {
+        unsafe {
+            self.ffi_gl_.TexParameterf(target, pname, param);
+        }
+    }
+
+    fn framebuffer_texture_2d(&self,
+                              target: GLenum,
+                              attachment: GLenum,
+                              textarget: GLenum,
+                              texture: GLuint,
+                              level: GLint) {
+        unsafe {
+            self.ffi_gl_.FramebufferTexture2D(target, attachment, textarget, texture, level);
+        }
+    }
+
+    fn framebuffer_texture_layer(&self,
+                                 target: GLenum,
+                                 attachment: GLenum,
+                                 texture: GLuint,
+                                 level: GLint,
+                                 layer: GLint) {
+        unsafe {
+            self.ffi_gl_.FramebufferTextureLayer(target, attachment, texture, level, layer);
+        }
+    }
+
+    fn blit_framebuffer(&self,
+                        src_x0: GLint,
+                        src_y0: GLint,
+                        src_x1: GLint,
+                        src_y1: GLint,
+                        dst_x0: GLint,
+                        dst_y0: GLint,
+                        dst_x1: GLint,
+                        dst_y1: GLint,
+                        mask: GLbitfield,
+                        filter: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlitFramebuffer(src_x0,
+                                         src_y0,
+                                         src_x1,
+                                         src_y1,
+                                         dst_x0,
+                                         dst_y0,
+                                         dst_x1,
+                                         dst_y1,
+                                         mask,
+                                         filter);
+        }
+    }
+
+    fn vertex_attrib_4f(&self,
+                        index: GLuint,
+                        x: GLfloat,
+                        y: GLfloat,
+                        z: GLfloat,
+                        w: GLfloat) {
+        unsafe {
+            self.ffi_gl_.VertexAttrib4f(index, x, y, z, w)
+        }
+    }
+
+    fn vertex_attrib_pointer_f32(&self,
+                                 index: GLuint,
+                                 size: GLint,
+                                 normalized: bool,
+                                 stride: GLsizei,
+                                 offset: GLuint) {
+        unsafe {
+            self.ffi_gl_.VertexAttribPointer(index,
+                                             size,
+                                             ffi::FLOAT,
+                                             normalized as GLboolean,
+                                             stride,
+                                             offset as *const GLvoid)
+        }
+    }
+
+    fn vertex_attrib_pointer(&self,
+                                 index: GLuint,
+                                 size: GLint,
+                                 type_: GLenum,
+                                 normalized: bool,
+                                 stride: GLsizei,
+                                 offset: GLuint) {
+        unsafe {
+            self.ffi_gl_.VertexAttribPointer(index,
+                                             size,
+                                             type_,
+                                             normalized as GLboolean,
+                                             stride,
+                                             offset as *const GLvoid)
+        }
+    }
+
+    fn vertex_attrib_i_pointer(&self,
+                               index: GLuint,
+                               size: GLint,
+                               type_: GLenum,
+                               stride: GLsizei,
+                               offset: GLuint) {
+        unsafe {
+            self.ffi_gl_.VertexAttribIPointer(index,
+                                              size,
+                                              type_,
+                                              stride,
+                                              offset as *const GLvoid)
+        }
+    }
+
+    fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint) {
+        unsafe {
+            self.ffi_gl_.VertexAttribDivisor(index, divisor)
+        }
+    }
+
+    fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.Viewport(x, y, width, height);
+        }
+    }
+
+    fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.Scissor(x, y, width, height);
+        }
+    }
+
+    fn line_width(&self, width: GLfloat) {
+        unsafe {
+            self.ffi_gl_.LineWidth(width);
+        }
+    }
+
+    fn use_program(&self, program: GLuint) {
+        unsafe {
+            self.ffi_gl_.UseProgram(program);
+        }
+    }
+
+    fn validate_program(&self, program: GLuint) {
+        unsafe {
+            self.ffi_gl_.ValidateProgram(program);
+        }
+    }
+
+    fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) {
+        unsafe {
+            return self.ffi_gl_.DrawArrays(mode, first, count);
+        }
+    }
+
+    fn draw_arrays_instanced(&self, mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei) {
+        unsafe {
+            return self.ffi_gl_.DrawArraysInstanced(mode, first, count, primcount);
+        }
+    }
+
+    fn draw_elements(&self, mode: GLenum, count: GLsizei, element_type: GLenum, indices_offset: GLuint) {
+        unsafe {
+            return self.ffi_gl_.DrawElements(mode, count, element_type, indices_offset as *const c_void)
+        }
+    }
+
+    fn draw_elements_instanced(&self,
+                                   mode: GLenum,
+                                   count: GLsizei,
+                                   element_type: GLenum,
+                                   indices_offset: GLuint,
+                                   primcount: GLsizei) {
+        unsafe {
+            return self.ffi_gl_.DrawElementsInstanced(mode,
+                                                      count,
+                                                      element_type,
+                                                      indices_offset as *const c_void,
+                                                      primcount)
+        }
+    }
+
+    fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) {
+        unsafe {
+            self.ffi_gl_.BlendColor(r, g, b, a);
+        }
+    }
+
+    fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlendFunc(sfactor, dfactor);
+        }
+    }
+
+    fn blend_func_separate(&self, src_rgb: GLenum, dest_rgb: GLenum, src_alpha: GLenum, dest_alpha: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha);
+        }
+    }
+
+    fn blend_equation(&self, mode: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlendEquation(mode);
+        }
+    }
+
+    fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlendEquationSeparate(mode_rgb, mode_alpha);
+        }
+    }
+
+    fn color_mask(&self, r: bool, g: bool, b: bool, a: bool) {
+        unsafe {
+            self.ffi_gl_.ColorMask(r as GLboolean, g as GLboolean, b as GLboolean, a as GLboolean);
+        }
+    }
+
+    fn cull_face(&self, mode: GLenum) {
+        unsafe {
+            self.ffi_gl_.CullFace(mode);
+        }
+    }
+
+    fn front_face(&self, mode: GLenum) {
+        unsafe {
+            self.ffi_gl_.FrontFace(mode);
+        }
+    }
+
+    fn enable(&self, cap: GLenum) {
+        unsafe {
+            self.ffi_gl_.Enable(cap);
+        }
+    }
+
+    fn disable(&self, cap: GLenum) {
+        unsafe {
+            self.ffi_gl_.Disable(cap);
+        }
+    }
+
+    fn hint(&self, param_name: GLenum, param_val: GLenum) {
+        unsafe {
+            self.ffi_gl_.Hint(param_name, param_val);
+        }
+    }
+
+    fn is_enabled(&self, cap: GLenum) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsEnabled(cap)
+        }
+    }
+
+    fn is_shader(&self, shader: GLuint) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsShader(shader)
+        }
+    }
+
+    fn is_texture(&self, texture: GLenum) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsTexture(texture)
+        }
+    }
+
+    fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsFramebuffer(framebuffer)
+        }
+    }
+
+    fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsRenderbuffer(renderbuffer)
+        }
+    }
+
+    fn check_frame_buffer_status(&self, target: GLenum) -> GLenum {
+        unsafe {
+            self.ffi_gl_.CheckFramebufferStatus(target)
+        }
+    }
+
+    fn enable_vertex_attrib_array(&self, index: GLuint) {
+        unsafe {
+            self.ffi_gl_.EnableVertexAttribArray(index);
+        }
+    }
+
+    fn disable_vertex_attrib_array(&self, index: GLuint) {
+        unsafe {
+            self.ffi_gl_.DisableVertexAttribArray(index);
+        }
+    }
+
+    fn uniform_1f(&self, location: GLint, v0: GLfloat) {
+        unsafe {
+            self.ffi_gl_.Uniform1f(location, v0);
+        }
+    }
+
+    fn uniform_1fv(&self, location: GLint, values: &[f32]) {
+        unsafe {
+            self.ffi_gl_.Uniform1fv(location,
+                                    values.len() as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_1i(&self, location: GLint, v0: GLint) {
+        unsafe {
+            self.ffi_gl_.Uniform1i(location, v0);
+        }
+    }
+
+    fn uniform_1iv(&self, location: GLint, values: &[i32]) {
+        unsafe {
+            self.ffi_gl_.Uniform1iv(location,
+                                    values.len() as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_1ui(&self, location: GLint, v0: GLuint) {
+        unsafe {
+            self.ffi_gl_.Uniform1ui(location, v0);
+        }
+    }
+
+    fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat) {
+        unsafe {
+            self.ffi_gl_.Uniform2f(location, v0, v1);
+        }
+    }
+
+    fn uniform_2fv(&self, location: GLint, values: &[f32]) {
+        unsafe {
+            self.ffi_gl_.Uniform2fv(location,
+                                    (values.len() / 2) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint) {
+        unsafe {
+            self.ffi_gl_.Uniform2i(location, v0, v1);
+        }
+    }
+
+    fn uniform_2iv(&self, location: GLint, values: &[i32]) {
+        unsafe {
+            self.ffi_gl_.Uniform2iv(location,
+                                    (values.len() / 2) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint) {
+        unsafe {
+            self.ffi_gl_.Uniform2ui(location, v0, v1);
+        }
+    }
+
+    fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {
+        unsafe {
+            self.ffi_gl_.Uniform3f(location, v0, v1, v2);
+        }
+    }
+
+    fn uniform_3fv(&self, location: GLint, values: &[f32]) {
+        unsafe {
+            self.ffi_gl_.Uniform3fv(location,
+                                    (values.len() / 3) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint) {
+        unsafe {
+            self.ffi_gl_.Uniform3i(location, v0, v1, v2);
+        }
+    }
+
+    fn uniform_3iv(&self, location: GLint, values: &[i32]) {
+        unsafe {
+            self.ffi_gl_.Uniform3iv(location,
+                                    (values.len() / 3) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {
+        unsafe {
+            self.ffi_gl_.Uniform3ui(location, v0, v1, v2);
+        }
+    }
+
+    fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
+        unsafe {
+            self.ffi_gl_.Uniform4f(location, x, y, z, w);
+        }
+    }
+
+    fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) {
+        unsafe {
+            self.ffi_gl_.Uniform4i(location, x, y, z, w);
+        }
+    }
+
+    fn uniform_4iv(&self, location: GLint, values: &[i32]) {
+        unsafe {
+            self.ffi_gl_.Uniform4iv(location,
+                                    (values.len() / 4) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {
+        unsafe {
+            self.ffi_gl_.Uniform4ui(location, x, y, z, w);
+        }
+    }
+
+    fn uniform_4fv(&self, location: GLint, values: &[f32]) {
+        unsafe {
+            self.ffi_gl_.Uniform4fv(location,
+                                    (values.len() / 4) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: &[f32]) {
+        unsafe {
+            self.ffi_gl_.UniformMatrix2fv(location,
+                                          (value.len() / 4) as GLsizei,
+                                          transpose as GLboolean,
+                                          value.as_ptr());
+        }
+    }
+
+    fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: &[f32]) {
+        unsafe {
+            self.ffi_gl_.UniformMatrix3fv(location,
+                                          (value.len() / 9) as GLsizei,
+                                          transpose as GLboolean,
+                                          value.as_ptr());
+        }
+    }
+
+    fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: &[f32]) {
+        unsafe {
+            self.ffi_gl_.UniformMatrix4fv(location,
+                                          (value.len() / 16) as GLsizei,
+                                          transpose as GLboolean,
+                                          value.as_ptr());
+        }
+    }
+
+    fn depth_mask(&self, flag: bool) {
+        unsafe {
+            self.ffi_gl_.DepthMask(flag as GLboolean);
+        }
+    }
+
+    fn depth_range(&self, near: f64, far: f64) {
+        unsafe {
+            self.ffi_gl_.DepthRange(near as GLclampd, far as GLclampd);
+        }
+    }
+
+    fn get_active_attrib(&self, program: GLuint, index: GLuint) -> (i32, u32, String) {
+        let buf_size = self.get_program_iv(program, ffi::ACTIVE_ATTRIBUTE_MAX_LENGTH);
+        let mut name = vec![0u8; buf_size as usize];
+        let mut length = 0 as GLsizei;
+        let mut size = 0 as i32;
+        let mut type_ = 0 as u32;
+        unsafe {
+            self.ffi_gl_.GetActiveAttrib(program, index, buf_size, &mut length, &mut size, &mut type_, name.as_mut_ptr() as *mut GLchar);
+        }
+        name.truncate(if length > 0 {length as usize} else {0});
+        (size, type_, String::from_utf8(name).unwrap())
+    }
+
+    fn get_active_uniform(&self, program: GLuint, index: GLuint) -> (i32, u32, String) {
+        let buf_size = self.get_program_iv(program, ffi::ACTIVE_UNIFORM_MAX_LENGTH);
+        let mut name = vec![0 as u8; buf_size as usize];
+        let mut length: GLsizei = 0;
+        let mut size: i32 = 0;
+        let mut type_: u32 = 0;
+
+        unsafe {
+            self.ffi_gl_.GetActiveUniform(program, index, buf_size, &mut length, &mut size,
+                                  &mut type_, name.as_mut_ptr() as *mut GLchar);
+        }
+
+        name.truncate(if length > 0 { length as usize } else { 0 });
+
+        (size, type_, String::from_utf8(name).unwrap())
+    }
+
+    fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int {
+        let name = CString::new(name).unwrap();
+        unsafe {
+            self.ffi_gl_.GetAttribLocation(program, name.as_ptr())
+        }
+    }
+
+    fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int {
+        let name = CString::new(name).unwrap();
+        unsafe {
+            self.ffi_gl_.GetFragDataLocation(program, name.as_ptr())
+        }
+    }
+
+    fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int {
+        let name = CString::new(name).unwrap();
+        unsafe {
+            self.ffi_gl_.GetUniformLocation(program, name.as_ptr())
+        }
+    }
+
+    fn get_program_info_log(&self, program: GLuint) -> String {
+        unsafe {
+            let mut result = vec![0u8; 1024];
+            let mut result_len: GLsizei = 0 as GLsizei;
+            self.ffi_gl_.GetProgramInfoLog(program,
+                                           1024 as GLsizei,
+                                           &mut result_len,
+                                           result.as_mut_ptr() as *mut GLchar);
+            result.truncate(if result_len > 0 {result_len as usize} else {0});
+            String::from_utf8(result).unwrap()
+        }
+    }
+
+    fn get_program_iv(&self, program: GLuint, pname: GLenum) -> GLint {
+        unsafe {
+            let mut result: GLint = 0 as GLint;
+            self.ffi_gl_.GetProgramiv(program, pname, &mut result);
+            return result;
+        }
+    }
+
+    fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum) -> GLint {
+        unsafe {
+            let mut result: GLint = 0 as GLint;
+            self.ffi_gl_.GetVertexAttribiv(index, pname, &mut result);
+            return result;
+        }
+    }
+
+    fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum) -> Vec<GLfloat> {
+        unsafe {
+            let mut result = vec![0 as GLfloat; 4];
+            self.ffi_gl_.GetVertexAttribfv(index, pname, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint {
+        unsafe {
+            let mut result: GLint = 0 as GLint;
+            self.ffi_gl_.GetBufferParameteriv(target, pname, &mut result);
+            return result;
+        }
+    }
+
+    fn get_shader_info_log(&self, shader: GLuint) -> String {
+        unsafe {
+            let mut result = vec![0u8; 1024];
+            let mut result_len: GLsizei = 0 as GLsizei;
+            self.ffi_gl_.GetShaderInfoLog(shader,
+                                          1024 as GLsizei,
+                                          &mut result_len,
+                                          result.as_mut_ptr() as *mut GLchar);
+            result.truncate(if result_len > 0 {result_len as usize} else {0});
+            String::from_utf8(result).unwrap()
+        }
+    }
+
+    fn get_string(&self, which: GLenum) -> String {
+        unsafe {
+            let llstr = self.ffi_gl_.GetString(which);
+            if !llstr.is_null() {
+                return str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()).to_string();
+            } else {
+                return "".to_string();
+            }
+        }
+    }
+
+    fn get_shader_iv(&self, shader: GLuint, pname: GLenum) -> GLint {
+        unsafe {
+            let mut result: GLint = 0 as GLint;
+            self.ffi_gl_.GetShaderiv(shader, pname, &mut result);
+            return result;
+        }
+    }
+
+    fn compile_shader(&self, shader: GLuint) {
+        unsafe {
+            self.ffi_gl_.CompileShader(shader);
+        }
+    }
+
+    fn create_program(&self) -> GLuint {
+        unsafe {
+            return self.ffi_gl_.CreateProgram();
+        }
+    }
+
+    fn delete_program(&self, program: GLuint) {
+        unsafe {
+            self.ffi_gl_.DeleteProgram(program);
+        }
+    }
+
+    fn create_shader(&self, shader_type: GLenum) -> GLuint {
+        unsafe {
+            return self.ffi_gl_.CreateShader(shader_type);
+        }
+    }
+
+    fn delete_shader(&self, shader: GLuint) {
+        unsafe {
+            self.ffi_gl_.DeleteShader(shader);
+        }
+    }
+
+    fn detach_shader(&self, program: GLuint, shader: GLuint) {
+        unsafe {
+            self.ffi_gl_.DetachShader(program, shader);
+        }
+    }
+
+    fn link_program(&self, program: GLuint) {
+        unsafe {
+            return self.ffi_gl_.LinkProgram(program);
+        }
+    }
+
+    fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
+        unsafe {
+            self.ffi_gl_.ClearColor(r, g, b, a);
+        }
+    }
+
+    fn clear(&self, buffer_mask: GLbitfield) {
+        unsafe {
+            self.ffi_gl_.Clear(buffer_mask);
+        }
+    }
+
+    fn clear_depth(&self, depth: f64) {
+        unsafe {
+            self.ffi_gl_.ClearDepth(depth as GLclampd);
+        }
+    }
+
+    fn clear_stencil(&self, s: GLint) {
+        unsafe {
+            self.ffi_gl_.ClearStencil(s);
+        }
+    }
+
+    fn flush(&self) {
+        unsafe {
+            self.ffi_gl_.Flush();
+        }
+    }
+
+    fn finish(&self) {
+        unsafe {
+            self.ffi_gl_.Finish();
+        }
+    }
+
+    fn get_error(&self) -> GLenum {
+        unsafe {
+            self.ffi_gl_.GetError()
+        }
+    }
+
+    fn stencil_mask(&self, mask: GLuint) {
+        unsafe {
+            self.ffi_gl_.StencilMask(mask)
+        }
+    }
+
+    fn stencil_mask_separate(&self, face: GLenum, mask: GLuint) {
+        unsafe {
+            self.ffi_gl_.StencilMaskSeparate(face, mask)
+        }
+    }
+
+    fn stencil_func(&self,
+                    func: GLenum,
+                    ref_: GLint,
+                    mask: GLuint) {
+        unsafe {
+            self.ffi_gl_.StencilFunc(func, ref_, mask)
+        }
+    }
+
+    fn stencil_func_separate(&self,
+                             face: GLenum,
+                             func: GLenum,
+                             ref_: GLint,
+                             mask: GLuint) {
+        unsafe {
+            self.ffi_gl_.StencilFuncSeparate(face, func, ref_, mask)
+        }
+    }
+
+    fn stencil_op(&self,
+                  sfail: GLenum,
+                  dpfail: GLenum,
+                  dppass: GLenum) {
+        unsafe {
+            self.ffi_gl_.StencilOp(sfail, dpfail, dppass)
+        }
+    }
+
+    fn stencil_op_separate(&self,
+                           face: GLenum,
+                           sfail: GLenum,
+                           dpfail: GLenum,
+                           dppass: GLenum) {
+        unsafe {
+            self.ffi_gl_.StencilOpSeparate(face, sfail, dpfail, dppass)
+        }
+    }
+
+    #[allow(unused_variables)]
+    fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GLeglImageOES) {
+        panic!("not supported")
+    }
+
+    fn generate_mipmap(&self, target: GLenum) {
+        unsafe {
+            self.ffi_gl_.GenerateMipmap(target)
+        }
+    }
+
+    fn insert_event_marker_ext(&self, message: &str) {
+        if self.ffi_gl_.InsertEventMarkerEXT.is_loaded() {
+            unsafe {
+                self.ffi_gl_.InsertEventMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _);
+            }
+        }
+    }
+
+    fn push_group_marker_ext(&self, message: &str) {
+        if self.ffi_gl_.PushGroupMarkerEXT.is_loaded() {
+            unsafe {
+                self.ffi_gl_.PushGroupMarkerEXT(message.len() as GLsizei, message.as_ptr() as *const _);
+            }
+        }
+    }
+
+    fn pop_group_marker_ext(&self) {
+        if self.ffi_gl_.PopGroupMarkerEXT.is_loaded() {
+            unsafe {
+                self.ffi_gl_.PopGroupMarkerEXT();
+            }
+        }
+    }
+}
+
new file mode 100644
--- /dev/null
+++ b/third_party/rust/gleam/src/gles_fns.rs
@@ -0,0 +1,1304 @@
+// Copyright 2014 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.
+
+pub struct GlesFns {
+    ffi_gl_: GlesFfi,
+}
+
+impl GlesFns
+{
+    pub unsafe fn load_with<'a, F>(loadfn: F) -> Rc<Gl> where F: FnMut(&str) -> *const c_void {
+        let ffi_gl_ = GlesFfi::load_with(loadfn);
+        Rc::new(GlesFns {
+            ffi_gl_: ffi_gl_,
+        }) as Rc<Gl>
+    }
+}
+
+#[cfg(target_os="android")]
+extern {
+    fn glEGLImageTargetTexture2DOES(target: GLenum, image: GLeglImageOES);
+}
+
+impl Gl for GlesFns {
+    fn get_type(&self) -> GlType {
+        GlType::Gles
+    }
+
+    fn buffer_data_untyped(&self, target: GLenum, size: GLsizeiptr, data: *const GLvoid, usage: GLenum) {
+        unsafe {
+            self.ffi_gl_.BufferData(target,
+                                    size,
+                                    data,
+                                    usage);
+        }
+    }
+
+    fn buffer_sub_data_untyped(&self, target: GLenum, offset: isize, size: GLsizeiptr, data: *const GLvoid) {
+        unsafe {
+            self.ffi_gl_.BufferSubData(target,
+                                       offset,
+                                       size,
+                                       data);
+        }
+    }
+
+    fn shader_source(&self, shader: GLuint, strings: &[&[u8]]) {
+        let pointers: Vec<*const u8> = strings.iter().map(|string| (*string).as_ptr()).collect();
+        let lengths: Vec<GLint> = strings.iter().map(|string| string.len() as GLint).collect();
+        unsafe {
+            self.ffi_gl_.ShaderSource(shader, pointers.len() as GLsizei,
+                                      pointers.as_ptr() as *const *const GLchar, lengths.as_ptr());
+        }
+        drop(lengths);
+        drop(pointers);
+    }
+
+    #[allow(unused_variables)]
+    fn read_buffer(&self, mode: GLenum) {
+        panic!("not supported")
+    }
+
+    fn read_pixels_into_buffer(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei,
+                               format: GLenum, pixel_type: GLenum, dst_buffer: &mut [u8]) {
+        // Assumes that the user properly allocated the size for dst_buffer.
+        assert!(calculate_length(width, height, format, pixel_type) == dst_buffer.len());
+
+        unsafe {
+            // We don't want any alignment padding on pixel rows.
+            self.ffi_gl_.PixelStorei(ffi::PACK_ALIGNMENT, 1);
+            self.ffi_gl_.ReadPixels(x, y, width, height, format, pixel_type, dst_buffer.as_mut_ptr() as *mut c_void);
+        }
+    }
+
+    fn read_pixels(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei, format: GLenum, pixel_type: GLenum) -> Vec<u8> {
+        let len = calculate_length(width, height, format, pixel_type);
+        let mut pixels: Vec<u8> = Vec::new();
+        pixels.reserve(len);
+        unsafe { pixels.set_len(len); }
+
+        self.read_pixels_into_buffer(x, y, width, height, format, pixel_type, pixels.as_mut_slice());
+
+        pixels
+    }
+
+    fn sample_coverage(&self, value: GLclampf, invert: bool) {
+        unsafe {
+            self.ffi_gl_.SampleCoverage(value, invert as GLboolean);
+        }
+    }
+
+    fn polygon_offset(&self, factor: GLfloat, units: GLfloat) {
+        unsafe {
+            self.ffi_gl_.PolygonOffset(factor, units);
+        }
+    }
+
+    fn pixel_store_i(&self, name: GLenum, param: GLint) {
+        unsafe {
+            self.ffi_gl_.PixelStorei(name, param);
+        }
+    }
+
+    fn gen_buffers(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenBuffers(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn gen_renderbuffers(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenRenderbuffers(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn gen_framebuffers(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenFramebuffers(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn gen_textures(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenTextures(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn gen_vertex_arrays(&self, n: GLsizei) -> Vec<GLuint> {
+        unsafe {
+            let mut result: Vec<_> = repeat(0 as GLuint).take(n as usize).collect();
+            self.ffi_gl_.GenVertexArrays(n, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    #[allow(unused_variables)]
+    fn gen_queries(&self, n: GLsizei) -> Vec<GLuint> {
+        panic!("not supported")
+    }
+
+    #[allow(unused_variables)]
+    fn begin_query(&self, target: GLenum, id: GLuint) {
+        panic!("not supported")
+    }
+
+    #[allow(unused_variables)]
+    fn end_query(&self, target: GLenum) {
+        panic!("not supported")
+    }
+
+    #[allow(unused_variables)]
+    fn query_counter(&self, id: GLuint, target: GLenum) {
+        panic!("not supported")
+    }
+
+    #[allow(unused_variables)]
+    fn get_query_object_iv(&self, id: GLuint, pname: GLenum) -> i32 {
+        panic!("not supported")
+    }
+
+    #[allow(unused_variables)]
+    fn get_query_object_uiv(&self, id: GLuint, pname: GLenum) -> u32 {
+        panic!("not supported")
+    }
+
+    #[allow(unused_variables)]
+    fn get_query_object_i64v(&self, id: GLuint, pname: GLenum) -> i64 {
+        panic!("not supported")
+    }
+
+    #[allow(unused_variables)]
+    fn get_query_object_ui64v(&self, id: GLuint, pname: GLenum) -> u64 {
+        panic!("not supported")
+    }
+
+    #[allow(unused_variables)]
+    fn delete_queries(&self, queries: &[GLuint]) {
+        panic!("not supported")
+    }
+
+    fn delete_vertex_arrays(&self, vertex_arrays: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteVertexArrays(vertex_arrays.len() as GLsizei, vertex_arrays.as_ptr());
+        }
+    }
+
+    fn delete_buffers(&self, buffers: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteBuffers(buffers.len() as GLsizei, buffers.as_ptr());
+        }
+    }
+
+    fn delete_renderbuffers(&self, renderbuffers: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteRenderbuffers(renderbuffers.len() as GLsizei, renderbuffers.as_ptr());
+        }
+    }
+
+    fn delete_framebuffers(&self, framebuffers: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteFramebuffers(framebuffers.len() as GLsizei, framebuffers.as_ptr());
+        }
+    }
+
+    fn delete_textures(&self, textures: &[GLuint]) {
+        unsafe {
+            self.ffi_gl_.DeleteTextures(textures.len() as GLsizei, textures.as_ptr());
+        }
+    }
+
+    fn framebuffer_renderbuffer(&self,
+                                target: GLenum,
+                                attachment: GLenum,
+                                renderbuffertarget: GLenum,
+                                renderbuffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.FramebufferRenderbuffer(target,
+                                                 attachment,
+                                                 renderbuffertarget,
+                                                 renderbuffer);
+        }
+    }
+
+    fn renderbuffer_storage(&self,
+                                target: GLenum,
+                                internalformat: GLenum,
+                                width: GLsizei,
+                                height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.RenderbufferStorage(target,
+                                             internalformat,
+                                             width,
+                                             height);
+        }
+    }
+
+    fn depth_func(&self, func: GLenum) {
+        unsafe {
+            self.ffi_gl_.DepthFunc(func);
+        }
+    }
+
+    fn active_texture(&self, texture: GLenum) {
+        unsafe {
+            self.ffi_gl_.ActiveTexture(texture);
+        }
+    }
+
+    fn attach_shader(&self, program: GLuint, shader: GLuint) {
+        unsafe {
+            self.ffi_gl_.AttachShader(program, shader);
+        }
+    }
+
+    fn bind_attrib_location(&self, program: GLuint, index: GLuint, name: &str) {
+        let c_string = CString::new(name).unwrap();
+        unsafe {
+            self.ffi_gl_.BindAttribLocation(program, index, c_string.as_ptr())
+        }
+    }
+
+    fn get_uniform_block_index(&self, program: GLuint, name: &str) -> GLuint {
+        let c_string = CString::new(name).unwrap();
+        unsafe {
+            self.ffi_gl_.GetUniformBlockIndex(program, c_string.as_ptr())
+        }
+    }
+
+    fn bind_buffer_base(&self, target: GLenum, index: GLuint, buffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindBufferBase(target, index, buffer);
+        }
+    }
+
+    fn uniform_block_binding(&self, program: GLuint, uniform_block_index: GLuint, uniform_block_binding: GLuint) {
+        unsafe {
+            self.ffi_gl_.UniformBlockBinding(program, uniform_block_index, uniform_block_binding);
+        }
+    }
+
+    fn bind_buffer(&self, target: GLenum, buffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindBuffer(target, buffer);
+        }
+    }
+
+    fn bind_vertex_array(&self, vao: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindVertexArray(vao);
+        }
+    }
+
+    fn bind_renderbuffer(&self, target: GLenum, renderbuffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindRenderbuffer(target, renderbuffer);
+        }
+    }
+
+    fn bind_framebuffer(&self, target: GLenum, framebuffer: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindFramebuffer(target, framebuffer);
+        }
+    }
+
+    fn bind_texture(&self, target: GLenum, texture: GLuint) {
+        unsafe {
+            self.ffi_gl_.BindTexture(target, texture);
+        }
+    }
+
+    // FIXME: Does not verify buffer size -- unsafe!
+    fn tex_image_2d(&self,
+                    target: GLenum,
+                    level: GLint,
+                    internal_format: GLint,
+                    width: GLsizei,
+                    height: GLsizei,
+                    border: GLint,
+                    format: GLenum,
+                    ty: GLenum,
+                    opt_data: Option<&[u8]>) {
+        match opt_data {
+            Some(data) => {
+                unsafe {
+                    self.ffi_gl_.TexImage2D(target, level, internal_format, width, height, border, format, ty,
+                                            data.as_ptr() as *const GLvoid);
+                }
+            }
+            None => {
+                unsafe {
+                    self.ffi_gl_.TexImage2D(target, level, internal_format, width, height, border, format, ty,
+                                            ptr::null());
+                }
+            }
+        }
+    }
+
+    fn compressed_tex_image_2d(&self,
+                               target: GLenum,
+                               level: GLint,
+                               internal_format: GLenum,
+                               width: GLsizei,
+                               height: GLsizei,
+                               border: GLint,
+                               data: &[u8]) {
+        unsafe {
+            self.ffi_gl_.CompressedTexImage2D(target, level, internal_format, width, height, border,
+                                              data.len() as GLsizei, data.as_ptr() as *const GLvoid);
+        }
+    }
+
+    fn compressed_tex_sub_image_2d(&self,
+                                   target: GLenum,
+                                   level: GLint,
+                                   xoffset: GLint,
+                                   yoffset: GLint,
+                                   width: GLsizei,
+                                   height: GLsizei,
+                                   format: GLenum,
+                                   data: &[u8]) {
+        unsafe {
+            self.ffi_gl_.CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format,
+                                                 data.len() as GLsizei, data.as_ptr() as *const GLvoid);
+        }
+    }
+
+    // FIXME: Does not verify buffer size -- unsafe!
+    fn tex_image_3d(&self,
+                    target: GLenum,
+                    level: GLint,
+                    internal_format: GLint,
+                    width: GLsizei,
+                    height: GLsizei,
+                    depth: GLsizei,
+                    border: GLint,
+                    format: GLenum,
+                    ty: GLenum,
+                    opt_data: Option<&[u8]>) {
+        unsafe {
+            let pdata = match opt_data {
+                Some(data) => mem::transmute(data.as_ptr()),
+                None => ptr::null(),
+            };
+            self.ffi_gl_.TexImage3D(target,
+                                    level,
+                                    internal_format,
+                                    width,
+                                    height,
+                                    depth,
+                                    border,
+                                    format,
+                                    ty,
+                                    pdata);
+        }
+    }
+
+    fn copy_tex_image_2d(&self,
+                         target: GLenum,
+                         level: GLint,
+                         internal_format: GLenum,
+                         x: GLint,
+                         y: GLint,
+                         width: GLsizei,
+                         height: GLsizei,
+                         border: GLint) {
+        unsafe {
+            self.ffi_gl_.CopyTexImage2D(target,
+                                        level,
+                                        internal_format,
+                                        x,
+                                        y,
+                                        width,
+                                        height,
+                                        border);
+        }
+    }
+
+    fn copy_tex_sub_image_2d(&self,
+                             target: GLenum,
+                             level: GLint,
+                             xoffset: GLint,
+                             yoffset: GLint,
+                             x: GLint,
+                             y: GLint,
+                             width: GLsizei,
+                             height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.CopyTexSubImage2D(target,
+                                           level,
+                                           xoffset,
+                                           yoffset,
+                                           x,
+                                           y,
+                                           width,
+                                           height);
+        }
+    }
+
+    fn copy_tex_sub_image_3d(&self,
+                             target: GLenum,
+                             level: GLint,
+                             xoffset: GLint,
+                             yoffset: GLint,
+                             zoffset: GLint,
+                             x: GLint,
+                             y: GLint,
+                             width: GLsizei,
+                             height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.CopyTexSubImage3D(target,
+                                           level,
+                                           xoffset,
+                                           yoffset,
+                                           zoffset,
+                                           x,
+                                           y,
+                                           width,
+                                           height);
+        }
+    }
+
+    fn tex_sub_image_2d(&self,
+                        target: GLenum,
+                        level: GLint,
+                        xoffset: GLint,
+                        yoffset: GLint,
+                        width: GLsizei,
+                        height: GLsizei,
+                        format: GLenum,
+                        ty: GLenum,
+                        data: &[u8]) {
+        unsafe {
+            self.ffi_gl_.TexSubImage2D(target, level, xoffset, yoffset, width, height, format, ty, data.as_ptr() as *const c_void);
+        }
+    }
+
+    fn tex_sub_image_3d(&self,
+                        target: GLenum,
+                        level: GLint,
+                        xoffset: GLint,
+                        yoffset: GLint,
+                        zoffset: GLint,
+                        width: GLsizei,
+                        height: GLsizei,
+                        depth: GLsizei,
+                        format: GLenum,
+                        ty: GLenum,
+                        data: &[u8]) {
+        unsafe {
+            self.ffi_gl_.TexSubImage3D(target,
+                                       level,
+                                       xoffset,
+                                       yoffset,
+                                       zoffset,
+                                       width,
+                                       height,
+                                       depth,
+                                       format,
+                                       ty,
+                                       data.as_ptr() as *const c_void);
+        }
+    }
+
+    fn get_integer_v(&self, name: GLenum) -> GLint {
+        let mut result: GLint = 0 as GLint;
+        unsafe {
+            self.ffi_gl_.GetIntegerv(name, &mut result);
+        }
+        result
+    }
+
+    fn get_boolean_v(&self, name: GLenum) -> GLboolean {
+        let mut result: GLboolean = 0 as GLboolean;
+        unsafe {
+            self.ffi_gl_.GetBooleanv(name, &mut result);
+        }
+        result
+    }
+
+    fn get_float_v(&self, name: GLenum) -> GLfloat {
+        let mut result: GLfloat = 0 as GLfloat;
+        unsafe {
+            self.ffi_gl_.GetFloatv(name, &mut result);
+        }
+        result
+    }
+
+    fn tex_parameter_i(&self, target: GLenum, pname: GLenum, param: GLint) {
+        unsafe {
+            self.ffi_gl_.TexParameteri(target, pname, param);
+        }
+    }
+
+    fn tex_parameter_f(&self, target: GLenum, pname: GLenum, param: GLfloat) {
+        unsafe {
+            self.ffi_gl_.TexParameterf(target, pname, param);
+        }
+    }
+
+    fn framebuffer_texture_2d(&self,
+                              target: GLenum,
+                              attachment: GLenum,
+                              textarget: GLenum,
+                              texture: GLuint,
+                              level: GLint) {
+        unsafe {
+            self.ffi_gl_.FramebufferTexture2D(target, attachment, textarget, texture, level);
+        }
+    }
+
+    fn framebuffer_texture_layer(&self,
+                                 target: GLenum,
+                                 attachment: GLenum,
+                                 texture: GLuint,
+                                 level: GLint,
+                                 layer: GLint) {
+        unsafe {
+            self.ffi_gl_.FramebufferTextureLayer(target, attachment, texture, level, layer);
+        }
+    }
+
+    fn blit_framebuffer(&self,
+                        src_x0: GLint,
+                        src_y0: GLint,
+                        src_x1: GLint,
+                        src_y1: GLint,
+                        dst_x0: GLint,
+                        dst_y0: GLint,
+                        dst_x1: GLint,
+                        dst_y1: GLint,
+                        mask: GLbitfield,
+                        filter: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlitFramebuffer(src_x0,
+                                         src_y0,
+                                         src_x1,
+                                         src_y1,
+                                         dst_x0,
+                                         dst_y0,
+                                         dst_x1,
+                                         dst_y1,
+                                         mask,
+                                         filter);
+        }
+    }
+
+    fn vertex_attrib_4f(&self,
+                        index: GLuint,
+                        x: GLfloat,
+                        y: GLfloat,
+                        z: GLfloat,
+                        w: GLfloat) {
+        unsafe {
+            self.ffi_gl_.VertexAttrib4f(index, x, y, z, w)
+        }
+    }
+
+    fn vertex_attrib_pointer_f32(&self,
+                                 index: GLuint,
+                                 size: GLint,
+                                 normalized: bool,
+                                 stride: GLsizei,
+                                 offset: GLuint) {
+        unsafe {
+            self.ffi_gl_.VertexAttribPointer(index,
+                                             size,
+                                             ffi::FLOAT,
+                                             normalized as GLboolean,
+                                             stride,
+                                             offset as *const GLvoid)
+        }
+    }
+
+    fn vertex_attrib_pointer(&self,
+                                 index: GLuint,
+                                 size: GLint,
+                                 type_: GLenum,
+                                 normalized: bool,
+                                 stride: GLsizei,
+                                 offset: GLuint) {
+        unsafe {
+            self.ffi_gl_.VertexAttribPointer(index,
+                                             size,
+                                             type_,
+                                             normalized as GLboolean,
+                                             stride,
+                                             offset as *const GLvoid)
+        }
+    }
+
+    fn vertex_attrib_i_pointer(&self,
+                               index: GLuint,
+                               size: GLint,
+                               type_: GLenum,
+                               stride: GLsizei,
+                               offset: GLuint) {
+        unsafe {
+            self.ffi_gl_.VertexAttribIPointer(index,
+                                              size,
+                                              type_,
+                                              stride,
+                                              offset as *const GLvoid)
+        }
+    }
+
+    fn vertex_attrib_divisor(&self, index: GLuint, divisor: GLuint) {
+        unsafe {
+            self.ffi_gl_.VertexAttribDivisor(index, divisor)
+        }
+    }
+
+    fn viewport(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.Viewport(x, y, width, height);
+        }
+    }
+
+    fn scissor(&self, x: GLint, y: GLint, width: GLsizei, height: GLsizei) {
+        unsafe {
+            self.ffi_gl_.Scissor(x, y, width, height);
+        }
+    }
+
+    fn line_width(&self, width: GLfloat) {
+        unsafe {
+            self.ffi_gl_.LineWidth(width);
+        }
+    }
+
+    fn use_program(&self, program: GLuint) {
+        unsafe {
+            self.ffi_gl_.UseProgram(program);
+        }
+    }
+
+    fn validate_program(&self, program: GLuint) {
+        unsafe {
+            self.ffi_gl_.ValidateProgram(program);
+        }
+    }
+
+    fn draw_arrays(&self, mode: GLenum, first: GLint, count: GLsizei) {
+        unsafe {
+            return self.ffi_gl_.DrawArrays(mode, first, count);
+        }
+    }
+
+    fn draw_arrays_instanced(&self, mode: GLenum, first: GLint, count: GLsizei, primcount: GLsizei) {
+        unsafe {
+            return self.ffi_gl_.DrawArraysInstanced(mode, first, count, primcount);
+        }
+    }
+
+    fn draw_elements(&self, mode: GLenum, count: GLsizei, element_type: GLenum, indices_offset: GLuint) {
+        unsafe {
+            return self.ffi_gl_.DrawElements(mode, count, element_type, indices_offset as *const c_void)
+        }
+    }
+
+    fn draw_elements_instanced(&self,
+                                   mode: GLenum,
+                                   count: GLsizei,
+                                   element_type: GLenum,
+                                   indices_offset: GLuint,
+                                   primcount: GLsizei) {
+        unsafe {
+            return self.ffi_gl_.DrawElementsInstanced(mode,
+                                                      count,
+                                                      element_type,
+                                                      indices_offset as *const c_void,
+                                                      primcount)
+        }
+    }
+
+    fn blend_color(&self, r: f32, g: f32, b: f32, a: f32) {
+        unsafe {
+            self.ffi_gl_.BlendColor(r, g, b, a);
+        }
+    }
+
+    fn blend_func(&self, sfactor: GLenum, dfactor: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlendFunc(sfactor, dfactor);
+        }
+    }
+
+    fn blend_func_separate(&self, src_rgb: GLenum, dest_rgb: GLenum, src_alpha: GLenum, dest_alpha: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha);
+        }
+    }
+
+    fn blend_equation(&self, mode: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlendEquation(mode);
+        }
+    }
+
+    fn blend_equation_separate(&self, mode_rgb: GLenum, mode_alpha: GLenum) {
+        unsafe {
+            self.ffi_gl_.BlendEquationSeparate(mode_rgb, mode_alpha);
+        }
+    }
+
+    fn color_mask(&self, r: bool, g: bool, b: bool, a: bool) {
+        unsafe {
+            self.ffi_gl_.ColorMask(r as GLboolean, g as GLboolean, b as GLboolean, a as GLboolean);
+        }
+    }
+
+    fn cull_face(&self, mode: GLenum) {
+        unsafe {
+            self.ffi_gl_.CullFace(mode);
+        }
+    }
+
+    fn front_face(&self, mode: GLenum) {
+        unsafe {
+            self.ffi_gl_.FrontFace(mode);
+        }
+    }
+
+    fn enable(&self, cap: GLenum) {
+        unsafe {
+            self.ffi_gl_.Enable(cap);
+        }
+    }
+
+    fn disable(&self, cap: GLenum) {
+        unsafe {
+            self.ffi_gl_.Disable(cap);
+        }
+    }
+
+    fn hint(&self, param_name: GLenum, param_val: GLenum) {
+        unsafe {
+            self.ffi_gl_.Hint(param_name, param_val);
+        }
+    }
+
+    fn is_enabled(&self, cap: GLenum) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsEnabled(cap)
+        }
+    }
+
+    fn is_shader(&self, shader: GLuint) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsShader(shader)
+        }
+    }
+
+    fn is_texture(&self, texture: GLenum) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsTexture(texture)
+        }
+    }
+
+    fn is_framebuffer(&self, framebuffer: GLenum) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsFramebuffer(framebuffer)
+        }
+    }
+
+    fn is_renderbuffer(&self, renderbuffer: GLenum) -> GLboolean {
+        unsafe {
+            self.ffi_gl_.IsRenderbuffer(renderbuffer)
+        }
+    }
+
+    fn check_frame_buffer_status(&self, target: GLenum) -> GLenum {
+        unsafe {
+            self.ffi_gl_.CheckFramebufferStatus(target)
+        }
+    }
+
+    fn enable_vertex_attrib_array(&self, index: GLuint) {
+        unsafe {
+            self.ffi_gl_.EnableVertexAttribArray(index);
+        }
+    }
+
+    fn disable_vertex_attrib_array(&self, index: GLuint) {
+        unsafe {
+            self.ffi_gl_.DisableVertexAttribArray(index);
+        }
+    }
+
+    fn uniform_1f(&self, location: GLint, v0: GLfloat) {
+        unsafe {
+            self.ffi_gl_.Uniform1f(location, v0);
+        }
+    }
+
+    fn uniform_1fv(&self, location: GLint, values: &[f32]) {
+        unsafe {
+            self.ffi_gl_.Uniform1fv(location,
+                                    values.len() as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_1i(&self, location: GLint, v0: GLint) {
+        unsafe {
+            self.ffi_gl_.Uniform1i(location, v0);
+        }
+    }
+
+    fn uniform_1iv(&self, location: GLint, values: &[i32]) {
+        unsafe {
+            self.ffi_gl_.Uniform1iv(location,
+                                    values.len() as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    #[allow(unused_variables)]
+    fn uniform_1ui(&self, location: GLint, v0: GLuint) {
+        panic!("not supported")
+    }
+
+    fn uniform_2f(&self, location: GLint, v0: GLfloat, v1: GLfloat) {
+        unsafe {
+            self.ffi_gl_.Uniform2f(location, v0, v1);
+        }
+    }
+
+    fn uniform_2fv(&self, location: GLint, values: &[f32]) {
+        unsafe {
+            self.ffi_gl_.Uniform2fv(location,
+                                    (values.len() / 2) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_2i(&self, location: GLint, v0: GLint, v1: GLint) {
+        unsafe {
+            self.ffi_gl_.Uniform2i(location, v0, v1);
+        }
+    }
+
+    fn uniform_2iv(&self, location: GLint, values: &[i32]) {
+        unsafe {
+            self.ffi_gl_.Uniform2iv(location,
+                                    (values.len() / 2) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    #[allow(unused_variables)]
+    fn uniform_2ui(&self, location: GLint, v0: GLuint, v1: GLuint) {
+        panic!("not supported")
+    }
+
+    fn uniform_3f(&self, location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat) {
+        unsafe {
+            self.ffi_gl_.Uniform3f(location, v0, v1, v2);
+        }
+    }
+
+    fn uniform_3fv(&self, location: GLint, values: &[f32]) {
+        unsafe {
+            self.ffi_gl_.Uniform3fv(location,
+                                    (values.len() / 3) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_3i(&self, location: GLint, v0: GLint, v1: GLint, v2: GLint) {
+        unsafe {
+            self.ffi_gl_.Uniform3i(location, v0, v1, v2);
+        }
+    }
+
+    fn uniform_3iv(&self, location: GLint, values: &[i32]) {
+        unsafe {
+            self.ffi_gl_.Uniform3iv(location,
+                                    (values.len() / 3) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    #[allow(unused_variables)]
+    fn uniform_3ui(&self, location: GLint, v0: GLuint, v1: GLuint, v2: GLuint) {
+        panic!("not supported")
+    }
+
+    fn uniform_4f(&self, location: GLint, x: GLfloat, y: GLfloat, z: GLfloat, w: GLfloat) {
+        unsafe {
+            self.ffi_gl_.Uniform4f(location, x, y, z, w);
+        }
+    }
+
+    fn uniform_4i(&self, location: GLint, x: GLint, y: GLint, z: GLint, w: GLint) {
+        unsafe {
+            self.ffi_gl_.Uniform4i(location, x, y, z, w);
+        }
+    }
+
+    fn uniform_4iv(&self, location: GLint, values: &[i32]) {
+        unsafe {
+            self.ffi_gl_.Uniform4iv(location,
+                                    (values.len() / 4) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    #[allow(unused_variables)]
+    fn uniform_4ui(&self, location: GLint, x: GLuint, y: GLuint, z: GLuint, w: GLuint) {
+        panic!("not supported")
+    }
+
+    fn uniform_4fv(&self, location: GLint, values: &[f32]) {
+        unsafe {
+            self.ffi_gl_.Uniform4fv(location,
+                                    (values.len() / 4) as GLsizei,
+                                    values.as_ptr());
+        }
+    }
+
+    fn uniform_matrix_2fv(&self, location: GLint, transpose: bool, value: &[f32]) {
+        unsafe {
+            self.ffi_gl_.UniformMatrix2fv(location,
+                                          (value.len() / 4) as GLsizei,
+                                          transpose as GLboolean,
+                                          value.as_ptr());
+        }
+    }
+
+    fn uniform_matrix_3fv(&self, location: GLint, transpose: bool, value: &[f32]) {
+        unsafe {
+            self.ffi_gl_.UniformMatrix3fv(location,
+                                          (value.len() / 9) as GLsizei,
+                                          transpose as GLboolean,
+                                          value.as_ptr());
+        }
+    }
+
+    fn uniform_matrix_4fv(&self, location: GLint, transpose: bool, value: &[f32]) {
+        unsafe {
+            self.ffi_gl_.UniformMatrix4fv(location,
+                                          (value.len() / 16) as GLsizei,
+                                          transpose as GLboolean,
+                                          value.as_ptr());
+        }
+    }
+
+    fn depth_mask(&self, flag: bool) {
+        unsafe {
+            self.ffi_gl_.DepthMask(flag as GLboolean);
+        }
+    }
+
+    fn depth_range(&self, near: f64, far: f64) {
+        unsafe {
+            self.ffi_gl_.DepthRangef(near as GLclampf, far as GLclampf);
+        }
+    }
+
+    fn get_active_attrib(&self, program: GLuint, index: GLuint) -> (i32, u32, String) {
+        let buf_size = self.get_program_iv(program, ffi::ACTIVE_ATTRIBUTE_MAX_LENGTH);
+        let mut name = vec![0u8; buf_size as usize];
+        let mut length = 0 as GLsizei;
+        let mut size = 0 as i32;
+        let mut type_ = 0 as u32;
+        unsafe {
+            self.ffi_gl_.GetActiveAttrib(program, index, buf_size, &mut length, &mut size, &mut type_, name.as_mut_ptr() as *mut GLchar);
+        }
+        name.truncate(if length > 0 {length as usize} else {0});
+        (size, type_, String::from_utf8(name).unwrap())
+    }
+
+    fn get_active_uniform(&self, program: GLuint, index: GLuint) -> (i32, u32, String) {
+        let buf_size = self.get_program_iv(program, ffi::ACTIVE_UNIFORM_MAX_LENGTH);
+        let mut name = vec![0 as u8; buf_size as usize];
+        let mut length: GLsizei = 0;
+        let mut size: i32 = 0;
+        let mut type_: u32 = 0;
+
+        unsafe {
+            self.ffi_gl_.GetActiveUniform(program, index, buf_size, &mut length, &mut size,
+                                  &mut type_, name.as_mut_ptr() as *mut GLchar);
+        }
+
+        name.truncate(if length > 0 { length as usize } else { 0 });
+
+        (size, type_, String::from_utf8(name).unwrap())
+    }
+
+    fn get_attrib_location(&self, program: GLuint, name: &str) -> c_int {
+        let name = CString::new(name).unwrap();
+        unsafe {
+            self.ffi_gl_.GetAttribLocation(program, name.as_ptr())
+        }
+    }
+
+    #[allow(unused_variables)]
+    fn get_frag_data_location(&self, program: GLuint, name: &str) -> c_int {
+        panic!("not supported")
+    }
+
+    fn get_uniform_location(&self, program: GLuint, name: &str) -> c_int {
+        let name = CString::new(name).unwrap();
+        unsafe {
+            self.ffi_gl_.GetUniformLocation(program, name.as_ptr())
+        }
+    }
+
+    fn get_program_info_log(&self, program: GLuint) -> String {
+        unsafe {
+            let mut result = vec![0u8; 1024];
+            let mut result_len: GLsizei = 0 as GLsizei;
+            self.ffi_gl_.GetProgramInfoLog(program,
+                                           1024 as GLsizei,
+                                           &mut result_len,
+                                           result.as_mut_ptr() as *mut GLchar);
+            result.truncate(if result_len > 0 {result_len as usize} else {0});
+            String::from_utf8(result).unwrap()
+        }
+    }
+
+    fn get_program_iv(&self, program: GLuint, pname: GLenum) -> GLint {
+        unsafe {
+            let mut result: GLint = 0 as GLint;
+            self.ffi_gl_.GetProgramiv(program, pname, &mut result);
+            return result;
+        }
+    }
+
+    fn get_vertex_attrib_iv(&self, index: GLuint, pname: GLenum) -> GLint {
+        unsafe {
+            let mut result: GLint = 0 as GLint;
+            self.ffi_gl_.GetVertexAttribiv(index, pname, &mut result);
+            return result;
+        }
+    }
+
+    fn get_vertex_attrib_fv(&self, index: GLuint, pname: GLenum) -> Vec<GLfloat> {
+        unsafe {
+            let mut result = vec![0 as GLfloat; 4];
+            self.ffi_gl_.GetVertexAttribfv(index, pname, result.as_mut_ptr());
+            return result;
+        }
+    }
+
+    fn get_buffer_parameter_iv(&self, target: GLuint, pname: GLenum) -> GLint {
+        unsafe {
+            let mut result: GLint = 0 as GLint;
+            self.ffi_gl_.GetBufferParameteriv(target, pname, &mut result);
+            return result;
+        }
+    }
+
+    fn get_shader_info_log(&self, shader: GLuint) -> String {
+        unsafe {
+            let mut result = vec![0u8; 1024];
+            let mut result_len: GLsizei = 0 as GLsizei;
+            self.ffi_gl_.GetShaderInfoLog(shader,
+                                          1024 as GLsizei,
+                                          &mut result_len,
+                                          result.as_mut_ptr() as *mut GLchar);
+            result.truncate(if result_len > 0 {result_len as usize} else {0});
+            String::from_utf8(result).unwrap()
+        }
+    }
+
+    fn get_string(&self, which: GLenum) -> String {
+        unsafe {
+            let llstr = self.ffi_gl_.GetString(which);
+            if !llstr.is_null() {
+                return str::from_utf8_unchecked(CStr::from_ptr(llstr as *const c_char).to_bytes()).to_string();
+            } else {
+                return "".to_string();
+            }
+        }
+    }
+
+    fn get_shader_iv(&self, shader: GLuint, pname: GLenum) -> GLint {
+        unsafe {
+            let mut result: GLint = 0 as GLint;
+            self.ffi_gl_.GetShaderiv(shader, pname, &mut result);
+            return result;
+        }
+    }
+
+    fn compile_shader(&self, shader: GLuint) {
+        unsafe {
+            self.ffi_gl_.CompileShader(shader);
+        }
+    }
+
+    fn create_program(&self) -> GLuint {
+        unsafe {
+            return self.ffi_gl_.CreateProgram();
+        }
+    }
+
+    fn delete_program(&self, program: GLuint) {
+        unsafe {
+            self.ffi_gl_.DeleteProgram(program);
+        }
+    }
+
+    fn create_shader(&self, shader_type: GLenum) -> GLuint {
+        unsafe {
+            return self.ffi_gl_.CreateShader(shader_type);
+        }
+    }
+
+    fn delete_shader(&self, shader: GLuint) {
+        unsafe {
+            self.ffi_gl_.DeleteShader(shader);
+        }
+    }
+
+    fn detach_shader(&self, program: GLuint, shader: GLuint) {
+        unsafe {
+            self.ffi_gl_.DetachShader(program, shader);
+        }
+    }
+
+    fn link_program(&self, program: GLuint) {
+        unsafe {
+            return self.ffi_gl_.LinkProgram(program);
+        }
+    }
+
+    fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) {
+        unsafe {
+            self.ffi_gl_.ClearColor(r, g, b, a);
+        }
+    }
+
+    fn clear(&self, buffer_mask: GLbitfield) {
+        unsafe {
+            self.ffi_gl_.Clear(buffer_mask);
+        }
+    }
+
+    fn clear_depth(&self, depth: f64) {
+        unsafe {
+            self.ffi_gl_.ClearDepthf(depth as GLclampf);
+        }
+    }
+
+    fn clear_stencil(&self, s: GLint) {
+        unsafe {
+            self.ffi_gl_.ClearStencil(s);
+        }
+    }
+
+    fn flush(&self) {
+        unsafe {
+            self.ffi_gl_.Flush();
+        }
+    }
+
+    fn finish(&self) {
+        unsafe {
+            self.ffi_gl_.Finish();
+        }
+    }
+
+    fn get_error(&self) -> GLenum {
+        unsafe {
+            self.ffi_gl_.GetError()
+        }
+    }
+
+    fn stencil_mask(&self, mask: GLuint) {
+        unsafe {
+            self.ffi_gl_.StencilMask(mask)
+        }
+    }
+
+    fn stencil_mask_separate(&self, face: GLenum, mask: GLuint) {
+        unsafe {
+            self.ffi_gl_.StencilMaskSeparate(face, mask)
+        }
+    }
+
+    fn stencil_func(&self,
+                    func: GLenum,
+                    ref_: GLint,
+                    mask: GLuint) {
+        unsafe {
+            self.ffi_gl_.StencilFunc(func, ref_, mask)
+        }
+    }
+
+    fn stencil_func_separate(&self,
+                             face: GLenum,
+                             func: GLenum,
+                             ref_: GLint,
+                             mask: GLuint) {
+        unsafe {
+            self.ffi_gl_.StencilFuncSeparate(face, func, ref_, mask)
+        }
+    }
+
+    fn stencil_op(&self,
+                  sfail: GLenum,
+                  dpfail: GLenum,
+                  dppass: GLenum) {
+        unsafe {
+            self.ffi_gl_.StencilOp(sfail, dpfail, dppass)
+        }
+    }
+
+    fn stencil_op_separate(&self,
+                           face: GLenum,
+                           sfail: GLenum,
+                           dpfail: GLenum,
+                           dppass: GLenum) {
+        unsafe {
+            self.ffi_gl_.StencilOpSeparate(face, sfail, dpfail, dppass)
+        }
+    }
+
+    #[allow(unused_variables)]
+    #[cfg(not(target_os="android"))]
+    fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GLeglImageOES) {
+        panic!("not supported")
+    }
+
+    #[cfg(target_os="android")]
+    fn egl_image_target_texture2d_oes(&self, target: GLenum, image: GLeglImageOES) {
+        unsafe {
+            glEGLImageTargetTexture2DOES(target, image);
+        }
+    }
+
+    fn generate_mipmap(&self, target: GLenum) {
+        unsafe {
+            self.ffi_gl_.GenerateMipmap(target)
+        }
+    }
+
+    #[allow(unused_variables)]
+    fn insert_event_marker_ext(&self, message: &str) {
+    }
+
+    #[allow(unused_variables)]
+    fn push_group_marker_ext(&self, message: &str) {
+    }
+
+    #[allow(unused_variables)]
+    fn pop_group_marker_ext(&self) {
+    }
+}
+
--- a/third_party/rust/gleam/src/lib.rs
+++ b/third_party/rust/gleam/src/lib.rs
@@ -8,10 +8,18 @@
 // except according to those terms.
 
 #![crate_name = "gleam"]
 #![crate_type = "lib"]
 
 pub mod gl;
 
 mod ffi {
+    include!(concat!(env!("OUT_DIR"), "/gl_and_gles_bindings.rs"));
+}
+
+mod ffi_gl {
     include!(concat!(env!("OUT_DIR"), "/gl_bindings.rs"));
 }
+
+mod ffi_gles {
+    include!(concat!(env!("OUT_DIR"), "/gles_bindings.rs"));
+}
--- a/third_party/rust/offscreen_gl_context/.cargo-checksum.json
+++ b/third_party/rust/offscreen_gl_context/.cargo-checksum.json
@@ -1,1 +1,1 @@
-{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"7150ee9391a955b2ef7e0762fc61c0c1aab167620ca36d88d78062d93b8334ba",".travis.yml":"9b8376fc479996f32f8a690e6009fc2f7e9f6dc1b1224e0180a92ad65b0b2183","Cargo.toml":"2377d25abb4a8cd857355e101af61480e9e5718e1d5fcfb12e41993b8ec211c9","Makefile":"85b6d903eecac170ac97f10d9d89b8366cd91f5ea2f7c6212704bc590b64cf50","README.md":"614cf0c6242be3e62e45a3d60ce9a2a1581bdc46b28b25d5f40caba558e4d615","build.rs":"86776b47fac1d9368e3c3c5d57c62731729ed859bb1c4e4db0fe219251812cab","src/draw_buffer.rs":"52bef86972f40e0dd13a6e81f3aa76d4d0c28ea0b63f5f9da9650a34d75488c0","src/gl_context.rs":"28953e3752ea7fd2b19327f98c06fe53f7618efc4d3f0cb2262eba403756df2a","src/gl_context_attributes.rs":"8ddf99864f838ba847783d824e85eb71c8eea7d5dfb9950737dfb1472a33a4f6","src/gl_context_capabilities.rs":"9f665ad04d42d47d15ecbd430639d95da526ec5951f0b7abe2434adc1415c85d","src/gl_feature.rs":"b826884900c0e8d6317a41ebb6c30bdb468601bf1c030c376749bdb2ecd2f15a","src/gl_formats.rs":"d15a8e102ebac82c166be4ba2a6e6702a82d509ac61102157c26a0ae25f54ac7","src/gl_limits.rs":"ccecc941207f1f27d9eaf96f0ffadb03d991ab5e6ad2ef73a5af1b9dbbbd7cad","src/lib.rs":"daaf4e26504dbb97f3803de4337f601d616adf0633e5c4415c2c172fb257ebd6","src/platform/mod.rs":"f6ec310e5b8fb519607b8e4d5ca71a0c07c83737a83c3785b5b44e7902498c8a","src/platform/not_implemented/mod.rs":"d576e9fc3164f9e2a8ff9460a60eaa8ecada44c600de1a4d1bb5513ab93569af","src/platform/not_implemented/native_gl_context.rs":"fe018722b8bebbd59b6fae759dd78b0175d10bf110205b113ff155fd06d0f75d","src/platform/with_cgl/mod.rs":"b05dc146c9ba82d62410d9b0566a8aa70c77e7ec583ad4881c531d7118454543","src/platform/with_cgl/native_gl_context.rs":"c6271cfa96836d8f833f5efbc90352852557d582db41d2c513cc36c3f966ae88","src/platform/with_egl/mod.rs":"c52ac147eb051733070c36b2c62be8c57427f80999507f62a9ce801f4aac284c","src/platform/with_egl/native_gl_context.rs":"3a8342d53de9525a5478cc96b323dbad2b3628aa6655fe5f092834cc72256116","src/platform/with_egl/utils.rs":"508521e2bf3809ffe0dfea4fa4a358903f49c77a33aa42cc6c0e7458d992a2a7","src/platform/with_glx/mod.rs":"0e497f38b2071ed189995c91b27b0b199d31bfcc10836e2d26b55023d7aff503","src/platform/with_glx/native_gl_context.rs":"2c648ae18baac14290b2eca3581d474adfea00a29a7ad47a1100e564e74b9152","src/platform/with_glx/utils.rs":"eb81e0a4c62947fa5099c241cfe2e4dd075376d30b22864e042c0f536ac6be58","src/platform/with_osmesa/mod.rs":"9f6d69878125185f16740f52ba5cdd8a45e8812af1a3561482c9b43edaf4514a","src/platform/with_wgl/mod.rs":"38f9b44b54c8a1bd4d25ae77a4ea6a2e5454a00b816764d7d74152c1f3c1b126","src/platform/with_wgl/native_gl_context.rs":"4aecd40a811cf38607b17db9724f79bb934e056f85c90c987b2aa82d637b7bb4","src/platform/with_wgl/utils.rs":"d9640c000dcb513cf0a13c4a0d35c423366b7d0894deff299affe0202bdeb770","src/platform/with_wgl/wgl_attributes.rs":"73b75da18519e048011e9c303e402cf7961e3652aa8f4d4ebf507b4ab83d06a3","src/tests.rs":"a2e5ceecd6b12def2f66a5c576b4ad8ca0dce1834aebe69ebc8474a5c06ec798"},"package":"4ac875ea951d7d695a1cc8c370777d6a0e2b7355ca49506034683df09b24b1bc"}
\ No newline at end of file
+{"files":{".cargo-ok":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",".gitignore":"7150ee9391a955b2ef7e0762fc61c0c1aab167620ca36d88d78062d93b8334ba",".travis.yml":"9b8376fc479996f32f8a690e6009fc2f7e9f6dc1b1224e0180a92ad65b0b2183","Cargo.toml":"c9adde499850222639dec26ff52a2f7c2285a970095a437231856bf3182eb3c6","Makefile":"85b6d903eecac170ac97f10d9d89b8366cd91f5ea2f7c6212704bc590b64cf50","README.md":"614cf0c6242be3e62e45a3d60ce9a2a1581bdc46b28b25d5f40caba558e4d615","build.rs":"95e0820ac2e24e0a4951b92454bbf4eb0967d389a4bc358a844156e5f425bd56","src/draw_buffer.rs":"4b3c61b230e4b4f025ec60b594489570b0ea159e1dada5910d3c0edadbaf6542","src/gl_context.rs":"633392d4b558d89877f70125f799a9c6f1788505d6837456e359198f028884d0","src/gl_context_attributes.rs":"8ddf99864f838ba847783d824e85eb71c8eea7d5dfb9950737dfb1472a33a4f6","src/gl_context_capabilities.rs":"9f665ad04d42d47d15ecbd430639d95da526ec5951f0b7abe2434adc1415c85d","src/gl_feature.rs":"b826884900c0e8d6317a41ebb6c30bdb468601bf1c030c376749bdb2ecd2f15a","src/gl_formats.rs":"d15a8e102ebac82c166be4ba2a6e6702a82d509ac61102157c26a0ae25f54ac7","src/gl_limits.rs":"a7837b11ded456ce454d9beb642359ac1ca755262654ac53bca371dd55b2d172","src/lib.rs":"9d66fc08d6fe533644e2f7dec11e3cdc6f2f237b2fb0bb1fc5996a933c87ab8e","src/platform/mod.rs":"29887128ed1e0c77b5b5dcd1bfc39ef0a53598db5325d76b71f5a772b480789b","src/platform/not_implemented/mod.rs":"d576e9fc3164f9e2a8ff9460a60eaa8ecada44c600de1a4d1bb5513ab93569af","src/platform/not_implemented/native_gl_context.rs":"fe018722b8bebbd59b6fae759dd78b0175d10bf110205b113ff155fd06d0f75d","src/platform/with_cgl/mod.rs":"b05dc146c9ba82d62410d9b0566a8aa70c77e7ec583ad4881c531d7118454543","src/platform/with_cgl/native_gl_context.rs":"c6271cfa96836d8f833f5efbc90352852557d582db41d2c513cc36c3f966ae88","src/platform/with_egl/mod.rs":"c52ac147eb051733070c36b2c62be8c57427f80999507f62a9ce801f4aac284c","src/platform/with_egl/native_gl_context.rs":"3a8342d53de9525a5478cc96b323dbad2b3628aa6655fe5f092834cc72256116","src/platform/with_egl/utils.rs":"508521e2bf3809ffe0dfea4fa4a358903f49c77a33aa42cc6c0e7458d992a2a7","src/platform/with_glx/mod.rs":"0e497f38b2071ed189995c91b27b0b199d31bfcc10836e2d26b55023d7aff503","src/platform/with_glx/native_gl_context.rs":"2c648ae18baac14290b2eca3581d474adfea00a29a7ad47a1100e564e74b9152","src/platform/with_glx/utils.rs":"eb81e0a4c62947fa5099c241cfe2e4dd075376d30b22864e042c0f536ac6be58","src/platform/with_osmesa/mod.rs":"995c1f1af7cb113e51f154796f65e95e145f4b25ea32354756f3380e9a7764b5","src/platform/with_wgl/mod.rs":"38f9b44b54c8a1bd4d25ae77a4ea6a2e5454a00b816764d7d74152c1f3c1b126","src/platform/with_wgl/native_gl_context.rs":"4aecd40a811cf38607b17db9724f79bb934e056f85c90c987b2aa82d637b7bb4","src/platform/with_wgl/utils.rs":"d9640c000dcb513cf0a13c4a0d35c423366b7d0894deff299affe0202bdeb770","src/platform/with_wgl/wgl_attributes.rs":"73b75da18519e048011e9c303e402cf7961e3652aa8f4d4ebf507b4ab83d06a3","src/tests.rs":"c0f7ab2584ee97691a9ab8cc00ebd725a040ef54ef56c285ed0cfbf84a7b0263"},"package":"cebfb377484b8fe608acabed968bc4108d44dcfa22318c2e8614eaffd8c5c5f8"}
\ No newline at end of file
--- a/third_party/rust/offscreen_gl_context/Cargo.toml
+++ b/third_party/rust/offscreen_gl_context/Cargo.toml
@@ -1,39 +1,39 @@
 [package]
 name = "offscreen_gl_context"
 license = "MIT / Apache-2.0"
-version = "0.6.1"
+version = "0.8.2"
 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"
 build = "build.rs"
 
 [build-dependencies]
 gl_generator = "0.5"
 
 [features]
-default = []
+default = ["x11"]
 osmesa = ["osmesa-sys"]
 # NOTE: Just for testing use, there are no other changes
 test_egl_in_linux = []
-test_osmesa = []
 
 [dependencies]
 log  = "0.3"
-gleam = "0.2.31"
+gleam = "0.4"
 euclid = "0.11"
 serde = { version = "0.9", optional = true }
 osmesa-sys = { version = "0.1", optional = true }
 
 [target.x86_64-apple-darwin.dependencies]
 core-foundation = "0.3.0"
-cgl = "0.1"
+cgl = "0.2"
 
 [target.'cfg(target_os = "linux")'.dependencies.x11]
+optional = true
 version = "2.3.0"
 features = ["xlib"]
 
 [target.'cfg(target_os = "windows")'.dependencies]
 winapi = "0.2"
 gdi32-sys = "0.2"
 user32-sys = "0.2"
 kernel32-sys = "0.2"
--- a/third_party/rust/offscreen_gl_context/build.rs
+++ b/third_party/rust/offscreen_gl_context/build.rs
@@ -4,20 +4,21 @@ use std::env;
 use std::fs::File;
 use std::path::PathBuf;
 use gl_generator::{Registry, Api, Profile, Fallbacks};
 
 fn main() {
     let target = env::var("TARGET").unwrap();
     let dest = PathBuf::from(&env::var("OUT_DIR").unwrap());
 
-    if target.contains("linux") {
+    if target.contains("linux") && cfg!(feature = "x11") {
         let mut file = File::create(&dest.join("glx_bindings.rs")).unwrap();
         Registry::new(Api::Glx, (1, 4), Profile::Core, Fallbacks::All, [])
             .write_bindings(gl_generator::StaticGenerator, &mut file).unwrap();
+        println!("cargo:rustc-link-lib=GL");
     }
 
     if target.contains("android") || (target.contains("linux") && cfg!(feature = "test_egl_in_linux")) {
         let mut file = File::create(&dest.join("egl_bindings.rs")).unwrap();
         Registry::new(Api::Egl, (1, 4), Profile::Core, Fallbacks::All, [])
             .write_bindings(gl_generator::StaticGenerator, &mut file).unwrap();
         println!("cargo:rustc-link-lib=EGL");
     }
@@ -41,11 +42,15 @@ fn main() {
                           "WGL_ARB_pixel_format_float",
                           "WGL_EXT_create_context_es2_profile",
                           "WGL_EXT_extensions_string",
                           "WGL_EXT_framebuffer_sRGB",
                           "WGL_EXT_swap_control",
                       ])
             .write_bindings(gl_generator::StructGenerator, &mut file).unwrap();
 
+        println!("cargo:rustc-link-lib=opengl32");
+    }
 
+    if target.contains("darwin") {
+        println!("cargo:rustc-link-lib=framework=OpenGL");
     }
 }
--- a/third_party/rust/offscreen_gl_context/src/draw_buffer.rs
+++ b/third_party/rust/offscreen_gl_context/src/draw_buffer.rs
@@ -1,11 +1,12 @@
 use euclid::Size2D;
 use gleam::gl;
 use gleam::gl::types::{GLuint, GLenum, GLint};
+use std::rc::Rc;
 
 use GLContext;
 use NativeGLContextMethods;
 
 #[derive(Debug)]
 pub enum ColorAttachmentType {
     Texture,
     Renderbuffer,
@@ -13,76 +14,77 @@ pub enum ColorAttachmentType {
 
 impl Default for ColorAttachmentType {
     fn default() -> ColorAttachmentType {
         ColorAttachmentType::Renderbuffer
     }
 }
 
 
-/// We either have a color renderbuffer
-/// Or a surface bound to a texture
-/// bound to a framebuffer as a color
-/// attachment
+/// We either have a color renderbuffer, or a surface bound to a texture bound
+/// to a framebuffer as a color attachment.
+///
+/// NB: The draw buffer manages it, and calls its destroy method on drop, this
+/// is just to avoid propagating the GL functions pointer further down.
 #[derive(Debug)]
 pub enum ColorAttachment {
     Renderbuffer(GLuint),
     Texture(GLuint),
 }
 
 impl ColorAttachment {
     pub fn color_attachment_type(&self) -> ColorAttachmentType {
         match *self {
             ColorAttachment::Renderbuffer(_) => ColorAttachmentType::Renderbuffer,
             ColorAttachment::Texture(_) => ColorAttachmentType::Texture,
         }
     }
-}
 
-impl Drop for ColorAttachment {
-    fn drop(&mut self) {
-        match *self {
-            ColorAttachment::Renderbuffer(id) => gl::delete_renderbuffers(&[id]),
-            ColorAttachment::Texture(tex_id) => gl::delete_textures(&[tex_id]),
+    fn destroy(self, gl: &gl::Gl) {
+        match self {
+            ColorAttachment::Renderbuffer(id) => gl.delete_renderbuffers(&[id]),
+            ColorAttachment::Texture(tex_id) => gl.delete_textures(&[tex_id]),
         }
     }
 }
 
 /// This structure represents an offscreen context
 /// draw buffer. It has a framebuffer, with at least
 /// color renderbuffer (alpha or not). It may also have
 /// a depth or stencil buffer, depending on context
 /// requirements.
 pub struct DrawBuffer {
+    gl_: Rc<gl::Gl>,
     size: Size2D<i32>,
     framebuffer: GLuint,
     stencil_renderbuffer: GLuint,
     depth_renderbuffer: GLuint,
     color_attachment: Option<ColorAttachment>
     // samples: GLsizei,
 }
 
 /// Helper function to create a render buffer
-/// TODO(ecoal95): We'll need to switch between `glRenderbufferStorage` and
-///   `glRenderbufferStorageMultisample` when we support antialising
-fn create_renderbuffer(format: GLenum,
+/// TODO(emilio): We'll need to switch between `glRenderbufferStorage` and
+/// `glRenderbufferStorageMultisample` when we support antialising
+fn create_renderbuffer(gl_: &gl::Gl,
+                       format: GLenum,
                        size: &Size2D<i32>) -> GLuint {
-    let ret = gl::gen_renderbuffers(1)[0];
-    gl::bind_renderbuffer(gl::RENDERBUFFER, ret);
-    gl::renderbuffer_storage(gl::RENDERBUFFER, format, size.width, size.height);
-    gl::bind_renderbuffer(gl::RENDERBUFFER, 0);
+    let ret = gl_.gen_renderbuffers(1)[0];
+    gl_.bind_renderbuffer(gl::RENDERBUFFER, ret);
+    gl_.renderbuffer_storage(gl::RENDERBUFFER, format, size.width, size.height);
+    gl_.bind_renderbuffer(gl::RENDERBUFFER, 0);
 
     ret
 }
 
 impl DrawBuffer {
     pub fn new<T: NativeGLContextMethods>(context: &GLContext<T>,
                                           mut size: Size2D<i32>,
                                           color_attachment_type: ColorAttachmentType)
-                                          -> Result<DrawBuffer, &'static str>
+                                          -> Result<Self, &'static str>
     {
         const MIN_DRAWING_BUFFER_SIZE: i32 = 16;
         use std::cmp;
 
         let attrs = context.borrow_attributes();
         let capabilities = context.borrow_capabilities();
 
         debug!("Creating draw buffer {:?}, {:?}, attrs: {:?}, caps: {:?}",
@@ -96,30 +98,33 @@ impl DrawBuffer {
             return Err("preserveDrawingBuffer is not supported yet");
         }
 
         // See https://github.com/servo/servo/issues/12320
         size.width = cmp::max(MIN_DRAWING_BUFFER_SIZE, size.width);
         size.height = cmp::max(MIN_DRAWING_BUFFER_SIZE, size.height);
 
         let mut draw_buffer = DrawBuffer {
+            gl_: context.clone_gl(),
             size: size,
             framebuffer: 0,
             color_attachment: None,
             stencil_renderbuffer: 0,
             depth_renderbuffer: 0,
             // samples: 0,
         };
 
         try!(context.make_current());
 
         try!(draw_buffer.init(context, color_attachment_type));
 
-        debug_assert!(gl::check_frame_buffer_status(gl::FRAMEBUFFER) == gl::FRAMEBUFFER_COMPLETE);
-        debug_assert!(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)
     }
 
     #[inline(always)]
     pub fn get_framebuffer(&self) -> GLuint {
         self.framebuffer
     }
@@ -144,132 +149,133 @@ impl DrawBuffer {
     }
 
     pub fn get_bound_texture_id(&self) -> Option<GLuint> {
         match self.color_attachment.as_ref().unwrap() {
             &ColorAttachment::Renderbuffer(_) => None,
             &ColorAttachment::Texture(id) => Some(id),
         }
     }
+
+    fn gl(&self) -> &gl::Gl {
+        &*self.gl_
+    }
+
+
+    fn init<T: NativeGLContextMethods>(&mut self,
+                                       context: &GLContext<T>,
+                                       color_attachment_type: ColorAttachmentType)
+        -> Result<(), &'static str> {
+        let attrs = context.borrow_attributes();
+        let formats = context.borrow_formats();
+
+        assert!(self.color_attachment.is_none(),
+                "Would leak color attachment!");
+        self.color_attachment = match color_attachment_type {
+            ColorAttachmentType::Renderbuffer => {
+                let color_renderbuffer =
+                    create_renderbuffer(self.gl(), formats.color_renderbuffer, &self.size);
+                debug_assert!(color_renderbuffer != 0);
+
+                Some(ColorAttachment::Renderbuffer(color_renderbuffer))
+            },
+
+            // TODO(ecoal95): Allow more customization of textures
+            ColorAttachmentType::Texture => {
+                let texture = self.gl().gen_textures(1)[0];
+                debug_assert!(texture != 0);
+
+                self.gl().bind_texture(gl::TEXTURE_2D, texture);
+                self.gl().tex_image_2d(gl::TEXTURE_2D, 0,
+                                 formats.texture_internal as GLint, self.size.width, self.size.height, 0, formats.texture, formats.texture_type, None);
+
+                // Low filtering to allow rendering
+                self.gl().tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
+                self.gl().tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint);
+
+                // TODO(emilio): Check if these two are neccessary, probably not
+                self.gl().tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
+                self.gl().tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
+
+                self.gl().bind_texture(gl::TEXTURE_2D, 0);
+
+                debug_assert_eq!(self.gl().get_error(), gl::NO_ERROR);
+
+                Some(ColorAttachment::Texture(texture))
+            },
+        };
+
+        // After this we check if we need stencil and depth buffers
+        if attrs.depth {
+            self.depth_renderbuffer = create_renderbuffer(self.gl(), formats.depth, &self.size);
+            debug_assert!(self.depth_renderbuffer != 0);
+        }
+
+        if attrs.stencil {
+            self.stencil_renderbuffer = create_renderbuffer(self.gl(), formats.stencil, &self.size);
+            debug_assert!(self.stencil_renderbuffer != 0);
+        }
+
+        self.framebuffer = self.gl().gen_framebuffers(1)[0];
+        debug_assert!(self.framebuffer != 0);
+
+        // Finally we attach them to the framebuffer
+        self.attach_to_framebuffer()
+    }
+
+    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_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_eq!(self.gl().is_renderbuffer(color_renderbuffer), gl::TRUE);
+            },
+            ColorAttachment::Texture(texture_id) => {
+                self.gl().framebuffer_texture_2d(gl::FRAMEBUFFER,
+                                                gl::COLOR_ATTACHMENT0,
+                                                gl::TEXTURE_2D,
+                                                texture_id, 0);
+            },
+        }
+
+        if self.depth_renderbuffer != 0 {
+            self.gl().framebuffer_renderbuffer(gl::FRAMEBUFFER,
+                                              gl::DEPTH_ATTACHMENT,
+                                              gl::RENDERBUFFER,
+                                              self.depth_renderbuffer);
+            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_eq!(self.gl().is_renderbuffer(self.stencil_renderbuffer), gl::TRUE);
+        }
+
+        Ok(())
+    }
 }
 
 // NOTE: The initially associated GLContext MUST be the current gl context
 // when drop is called. I know this is an important constraint.
 // Right now there are no problems, if not, consider using a pointer to a
 // parent with Rc<GLContext> and call make_current()
 impl Drop for DrawBuffer {
     fn drop(&mut self) {
-        gl::delete_framebuffers(&[self.framebuffer]);
+        if let Some(att) = self.color_attachment.take() {
+            att.destroy(self.gl());
+        }
+
+        self.gl().delete_framebuffers(&[self.framebuffer]);
 
         // NOTE: Color renderbuffer is destroyed on drop of
         //   ColorAttachment
-        gl::delete_renderbuffers(&[self.stencil_renderbuffer, self.depth_renderbuffer]);
+        self.gl().delete_renderbuffers(&[self.stencil_renderbuffer, self.depth_renderbuffer]);
     }
 }
-
-trait DrawBufferHelpers {
-    fn init<T: NativeGLContextMethods>(&mut self,
-                                       &GLContext<T>,
-                                       color_attachment_type: ColorAttachmentType)
-        -> Result<(), &'static str>;
-    fn attach_to_framebuffer(&mut self)
-        -> Result<(), &'static str>;
-}
-
-impl DrawBufferHelpers for DrawBuffer {
-    fn init<T: NativeGLContextMethods>(&mut self,
-                                       context: &GLContext<T>,
-                                       color_attachment_type: ColorAttachmentType)
-        -> Result<(), &'static str> {
-        let attrs = context.borrow_attributes();
-        let formats = context.borrow_formats();
-
-        self.color_attachment = match color_attachment_type {
-            ColorAttachmentType::Renderbuffer => {
-                let color_renderbuffer = create_renderbuffer(formats.color_renderbuffer, &self.size);
-                debug_assert!(color_renderbuffer != 0);
-
-                Some(ColorAttachment::Renderbuffer(color_renderbuffer))
-            },
-
-            // TODO(ecoal95): Allow more customization of textures
-            ColorAttachmentType::Texture => {
-                let texture = gl::gen_textures(1)[0];
-                debug_assert!(texture != 0);
-
-                gl::bind_texture(gl::TEXTURE_2D, texture);
-                gl::tex_image_2d(gl::TEXTURE_2D, 0,
-                                 formats.texture_internal as GLint, self.size.width, self.size.height, 0, formats.texture, formats.texture_type, None);
-
-                // Low filtering to allow rendering
-                gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
-                gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint);
-
-                // TODO(ecoal95): Check if these two are neccessary, probably not
-                gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
-                gl::tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
-
-                gl::bind_texture(gl::TEXTURE_2D, 0);
-
-                debug_assert!(gl::get_error() == gl::NO_ERROR);
-
-                Some(ColorAttachment::Texture(texture))
-            },
-        };
-
-        // After this we check if we need stencil and depth buffers
-        if attrs.depth {
-            self.depth_renderbuffer = create_renderbuffer(formats.depth, &self.size);
-            debug_assert!(self.depth_renderbuffer != 0);
-        }
-
-        if attrs.stencil {
-            self.stencil_renderbuffer = create_renderbuffer(formats.stencil, &self.size);
-            debug_assert!(self.stencil_renderbuffer != 0);
-        }
-
-        self.framebuffer = gl::gen_framebuffers(1)[0];
-        debug_assert!(self.framebuffer != 0);
-
-        // Finally we attach them to the framebuffer
-        self.attach_to_framebuffer()
-    }
-
-    fn attach_to_framebuffer(&mut self) -> Result<(), &'static str> {
-        gl::bind_framebuffer(gl::FRAMEBUFFER, self.framebuffer);
-        // NOTE: The assertion fails if the framebuffer is not bound
-        debug_assert!(gl::is_framebuffer(self.framebuffer) == gl::TRUE);
-
-        match *self.color_attachment.as_ref().unwrap() {
-            ColorAttachment::Renderbuffer(color_renderbuffer) => {
-                gl::framebuffer_renderbuffer(gl::FRAMEBUFFER,
-                                             gl::COLOR_ATTACHMENT0,
-                                             gl::RENDERBUFFER,
-                                             color_renderbuffer);
-                debug_assert!(gl::is_renderbuffer(color_renderbuffer) == gl::TRUE);
-            },
-            ColorAttachment::Texture(texture_id) => {
-                gl::framebuffer_texture_2d(gl::FRAMEBUFFER,
-                                           gl::COLOR_ATTACHMENT0,
-                                           gl::TEXTURE_2D,
-                                           texture_id, 0);
-            },
-        }
-
-        if self.depth_renderbuffer != 0 {
-            gl::framebuffer_renderbuffer(gl::FRAMEBUFFER,
-                                         gl::DEPTH_ATTACHMENT,
-                                         gl::RENDERBUFFER,
-                                         self.depth_renderbuffer);
-            debug_assert!(gl::is_renderbuffer(self.depth_renderbuffer) == gl::TRUE);
-        }
-
-        if self.stencil_renderbuffer != 0 {
-            gl::framebuffer_renderbuffer(gl::FRAMEBUFFER,
-                                         gl::STENCIL_ATTACHMENT,
-                                         gl::RENDERBUFFER,
-                                         self.stencil_renderbuffer);
-            debug_assert!(gl::is_renderbuffer(self.stencil_renderbuffer) == gl::TRUE);
-        }
-
-        Ok(())
-    }
-}
--- a/third_party/rust/offscreen_gl_context/src/gl_context.rs
+++ b/third_party/rust/offscreen_gl_context/src/gl_context.rs
@@ -1,52 +1,63 @@
 use euclid::Size2D;
 use gleam::gl;
 use gleam::gl::types::{GLuint};
+use std::rc::Rc;
 
 use NativeGLContextMethods;
 use GLContextAttributes;
 use GLContextCapabilities;
 use GLFormats;
 use GLLimits;
 use DrawBuffer;
 use ColorAttachmentType;
 
 /// This is a wrapper over a native headless GL context
 pub struct GLContext<Native> {
+    gl_: Rc<gl::Gl>,
     native_context: Native,
     /// This an abstraction over a custom framebuffer
     /// with attachments according to WebGLContextAttributes
     // TODO(ecoal95): Ideally we may want a read and a draw
     // framebuffer, but this is not supported in GLES2, review
     // when we have better support
     draw_buffer: Option<DrawBuffer>,
     attributes: GLContextAttributes,
     capabilities: GLContextCapabilities,
     formats: GLFormats,
     limits: GLLimits,
 }
 
 impl<Native> GLContext<Native>
-    where Native: NativeGLContextMethods
+    where Native: NativeGLContextMethods,
 {
-    pub fn create(shared_with: Option<&Native::Handle>) -> Result<GLContext<Native>, &'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<GLContext<Native>, &'static str> {
+        -> Result<Self, &'static str> {
         let native_context = try!(Native::create_shared_with_dispatcher(shared_with, dispatcher));
+        let gl_ = match api_type {
+            gl::GlType::Gl => unsafe { gl::GlFns::load_with(|s| Self::get_proc_address(s) as *const _) },
+            gl::GlType::Gles => unsafe { 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);
-        let limits = GLLimits::detect();
+        let limits = GLLimits::detect(&*gl_);
 
         Ok(GLContext {
+            gl_: gl_,
             native_context: native_context,
             draw_buffer: None,
             attributes: attributes,
             capabilities: GLContextCapabilities::detect(),
             formats: formats,
             limits: limits,
         })
     }
@@ -59,67 +70,99 @@ impl<Native> GLContext<Native>
     #[inline(always)]
     pub fn current_handle() -> Option<Native::Handle> {
         Native::current_handle()
     }
 
     pub fn new(size: Size2D<i32>,
                attributes: GLContextAttributes,
                color_attachment_type: ColorAttachmentType,
+               api_type: gl::GlType,
                shared_with: Option<&Native::Handle>)
-        -> Result<GLContext<Native>, &'static str> {
-        Self::new_shared_with_dispatcher(size, attributes, color_attachment_type, shared_with, None)
+        -> 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<GLContext<Native>, &'static str> {
+        -> 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;
 
         try!(context.init_offscreen(size, color_attachment_type));
 
         Ok(context)
     }
 
     #[inline(always)]
     pub fn with_default_color_attachment(size: Size2D<i32>,
                                          attributes: GLContextAttributes,
+                                         api_type: gl::GlType,
                                          shared_with: Option<&Native::Handle>)
-        -> Result<GLContext<Native>, &'static str> {
-        GLContext::new(size, attributes, ColorAttachmentType::default(), shared_with)
+        -> Result<Self, &'static str> {
+        Self::new(size, attributes, ColorAttachmentType::default(), api_type, shared_with)
     }
 
     #[inline(always)]
     pub fn make_current(&self) -> Result<(), &'static str> {
         self.native_context.make_current()
     }
 
     #[inline(always)]
     pub fn unbind(&self) -> Result<(), &'static str> {
-        self.native_context.unbind()
+        let ret = self.native_context.unbind();
+
+        // OSMesa doesn't allow any API to unbind a context before [1], and just
+        // bails out on null context, buffer, or whatever, so not much we can do
+        // here. Thus, ignore the failure and just flush the context if we're
+        // using an old OSMesa version.
+        //
+        // [1]: https://www.mail-archive.com/mesa-dev@lists.freedesktop.org/msg128408.html
+        if self.native_context.is_osmesa() && ret.is_err() {
+            self.gl().flush();
+            return Ok(())
+        }
+
+        ret
     }
 
     #[inline(always)]
     pub fn is_current(&self) -> bool {
         self.native_context.is_current()
     }
 
     #[inline(always)]
     pub fn handle(&self) -> Native::Handle {
         self.native_context.handle()
     }
 
+    pub fn gl(&self) -> &gl::Gl {
+        &*self.gl_
+    }
+
+    pub fn clone_gl(&self) -> Rc<gl::Gl> {
+        self.gl_.clone()
+    }
+
     // Allow borrowing these unmutably
     pub fn borrow_attributes(&self) -> &GLContextAttributes {
         &self.attributes
     }
 
     pub fn borrow_capabilities(&self) -> &GLContextCapabilities {
         &self.capabilities
     }
@@ -136,60 +179,53 @@ impl<Native> GLContext<Native>
         self.draw_buffer.as_ref()
     }
 
     pub fn get_framebuffer(&self) -> GLuint {
         if let Some(ref db) = self.draw_buffer {
             return db.get_framebuffer();
         }
 
-        let ret = gl::get_integer_v(gl::FRAMEBUFFER_BINDING);
+        let ret = self.gl().get_integer_v(gl::FRAMEBUFFER_BINDING);
         ret as GLuint
     }
 
     pub fn draw_buffer_size(&self) -> Option<Size2D<i32>> {
-        self.draw_buffer.as_ref().map( |db| db.size() )
+        self.draw_buffer.as_ref().map(|db| db.size())
     }
 
     // We resize just replacing the draw buffer, we don't perform size optimizations
     // in order to keep this generic
     pub fn resize(&mut self, size: Size2D<i32>) -> Result<(), &'static str> {
         if self.draw_buffer.is_some() {
             let color_attachment_type =
                 self.borrow_draw_buffer().unwrap().color_attachment_type();
             self.init_offscreen(size, color_attachment_type)
         } else {
             Err("No DrawBuffer found")
         }
     }
+
+    fn init_offscreen(&mut self, size: Size2D<i32>, color_attachment_type: ColorAttachmentType) -> Result<(), &'static str> {
+        try!(self.create_draw_buffer(size, color_attachment_type));
+
+        debug_assert!(self.is_current());
+
+        self.gl().clear_color(0.0, 0.0, 0.0, 0.0);
+        self.gl().clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
+        self.gl().scissor(0, 0, size.width, size.height);
+        self.gl().viewport(0, 0, size.width, size.height);
+
+        Ok(())
+    }
+
+    fn create_draw_buffer(&mut self, size: Size2D<i32>, color_attachment_type: ColorAttachmentType) -> Result<(), &'static str> {
+        self.draw_buffer = Some(try!(DrawBuffer::new(self, size, color_attachment_type)));
+        Ok(())
+    }
 }
 
 // Dispatches functions to the thread where a NativeGLContext is bound.
 // Right now it's used in the WGL implementation to dispatch functions to the thread
 // where the context we share from is bound. See the WGL implementation for more details.
 pub trait GLContextDispatcher {
     fn dispatch(&self, Box<Fn() + Send>);
 }
-
-trait GLContextPrivateMethods {
-    fn init_offscreen(&mut self, Size2D<i32>, ColorAttachmentType) -> Result<(), &'static str>;
-    fn create_draw_buffer(&mut self, Size2D<i32>, ColorAttachmentType) -> Result<(), &'static str>;
-}
-
-impl<T: NativeGLContextMethods> GLContextPrivateMethods for GLContext<T> {
-    fn init_offscreen(&mut self, size: Size2D<i32>, color_attachment_type: ColorAttachmentType) -> Result<(), &'static str> {
-        try!(self.create_draw_buffer(size, color_attachment_type));
-
-        debug_assert!(self.is_current());
-
-        gl::clear_color(0.0, 0.0, 0.0, 0.0);
-        gl::clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
-        gl::scissor(0, 0, size.width, size.height);
-        gl::viewport(0, 0, size.width, size.height);
-
-        Ok(())
-    }
-
-    fn create_draw_buffer(&mut self, size: Size2D<i32>, color_attachment_type: ColorAttachmentType) -> Result<(), &'static str> {
-        self.draw_buffer = Some(try!(DrawBuffer::new(&self, size, color_attachment_type)));
-        Ok(())
-    }
-}
--- a/third_party/rust/offscreen_gl_context/src/gl_limits.rs
+++ b/third_party/rust/offscreen_gl_context/src/gl_limits.rs
@@ -1,9 +1,10 @@
 use gleam::gl;
+
 #[cfg(feature = "serde")]
 use serde::{Deserialize, Deserializer, Serialize, Serializer};
 
 #[derive(Debug, Clone)]
 pub struct GLLimits {
     pub max_vertex_attribs: u32,
     pub max_tex_size: u32,
     pub max_cube_map_tex_size: u32
@@ -29,16 +30,16 @@ impl Serialize for GLLimits {
         where S: Serializer
     {
         [self.max_vertex_attribs, self.max_tex_size, self.max_cube_map_tex_size]
             .serialize(serializer)
     }
 }
 
 impl GLLimits {
-    pub fn detect() -> GLLimits {
+    pub fn detect(gl_: &gl::Gl) -> GLLimits {
         GLLimits {
-            max_vertex_attribs: gl::get_integer_v(gl::MAX_VERTEX_ATTRIBS) as u32,
-            max_tex_size: gl::get_integer_v(gl::MAX_TEXTURE_SIZE) as u32,
-            max_cube_map_tex_size: gl::get_integer_v(gl::MAX_CUBE_MAP_TEXTURE_SIZE) as u32
+            max_vertex_attribs: gl_.get_integer_v(gl::MAX_VERTEX_ATTRIBS) as u32,
+            max_tex_size: gl_.get_integer_v(gl::MAX_TEXTURE_SIZE) as u32,
+            max_cube_map_tex_size: gl_.get_integer_v(gl::MAX_CUBE_MAP_TEXTURE_SIZE) as u32
         }
     }
 }
--- a/third_party/rust/offscreen_gl_context/src/lib.rs
+++ b/third_party/rust/offscreen_gl_context/src/lib.rs
@@ -2,17 +2,17 @@ extern crate gleam;
 extern crate euclid;
 
 #[macro_use]
 extern crate log;
 
 #[cfg(feature="serde")]
 extern crate serde;
 
-#[cfg(target_os="linux")]
+#[cfg(all(target_os="linux", feature="x11"))]
 extern crate x11;
 #[cfg(target_os="macos")]
 extern crate cgl;
 #[cfg(target_os="macos")]
 extern crate core_foundation;
 #[cfg(feature="osmesa")]
 extern crate osmesa_sys;
 #[cfg(target_os = "windows")]
@@ -24,16 +24,17 @@ extern crate gdi32;
 #[cfg(target_os = "windows")]
 extern crate user32;
 #[cfg(any(target_os="macos", target_os="windows"))]
 #[macro_use]
 extern crate lazy_static;
 
 mod platform;
 pub use platform::{NativeGLContext, NativeGLContextMethods, NativeGLContextHandle};
+
 #[cfg(feature="osmesa")]
 pub use platform::{OSMesaContext, OSMesaContextHandle};
 
 mod gl_context;
 pub use gl_context::{GLContext, GLContextDispatcher};
 
 mod draw_buffer;
 pub use draw_buffer::{DrawBuffer, ColorAttachmentType};
@@ -48,17 +49,17 @@ mod gl_feature;
 pub use gl_feature::GLFeature;
 
 mod gl_formats;
 pub use gl_formats::GLFormats;
 
 mod gl_limits;
 pub use gl_limits::GLLimits;
 
-#[cfg(target_os="linux")]
+#[cfg(all(target_os="linux", feature="x11"))]
 #[allow(improper_ctypes)]
 mod glx {
     include!(concat!(env!("OUT_DIR"), "/glx_bindings.rs"));
 }
 
 #[cfg(any(target_os="android", all(target_os="linux", feature = "test_egl_in_linux")))]
 #[allow(non_camel_case_types)]
 mod egl {
--- a/third_party/rust/offscreen_gl_context/src/platform/mod.rs
+++ b/third_party/rust/offscreen_gl_context/src/platform/mod.rs
@@ -19,27 +19,34 @@ pub trait NativeGLContextMethods: Sized 
     fn create_headless() -> Result<Self, &'static str> {
         Self::create_shared(None)
     }
 
     fn handle(&self) -> Self::Handle;
     fn is_current(&self) -> bool;
     fn make_current(&self) -> Result<(), &'static str>;
     fn unbind(&self) -> Result<(), &'static str>;
+
+    /// Just a somewhat dirty hack to special-case the handling of context
+    /// unbinding on old OSMesa versions.
+    fn is_osmesa(&self) -> bool { false }
 }
 
-#[cfg(target_os="linux")]
+#[cfg(all(target_os="linux", feature="x11"))]
 pub mod with_glx;
-#[cfg(target_os="linux")]
+#[cfg(all(target_os="linux", feature="x11"))]
 pub use self::with_glx::{NativeGLContext, NativeGLContextHandle};
 
 #[cfg(feature="osmesa")]
 pub mod with_osmesa;
 #[cfg(feature="osmesa")]
 pub use self::with_osmesa::{OSMesaContext, OSMesaContextHandle};
+#[cfg(all(target_os="linux", not(feature="x11")))]
+pub use self::with_osmesa::{OSMesaContext as NativeGLContext, OSMesaContextHandle as NativeGLContextHandle};
+
 
 #[cfg(any(target_os="android", all(target_os="linux", feature = "test_egl_in_linux")))]
 pub mod with_egl;
 #[cfg(target_os="android")]
 pub use self::with_egl::{NativeGLContext, NativeGLContextHandle};
 
 #[cfg(target_os="macos")]
 pub mod with_cgl;
--- a/third_party/rust/offscreen_gl_context/src/platform/with_osmesa/mod.rs
+++ b/third_party/rust/offscreen_gl_context/src/platform/with_osmesa/mod.rs
@@ -93,33 +93,29 @@ impl NativeGLContextMethods for OSMesaCo
                Err("OSMesaMakeCurrent")
            } else {
                Ok(())
            }
         }
     }
 
     fn unbind(&self) -> Result<(), &'static str> {
-        // OSMesa doesn't allow any API to unbind a context before [1], and just
-        // bails out on null context, buffer, or whatever, so not much we can do
-        // here. Thus, ignore the failure and just flush the context if we're
-        // using an old OSMesa version.
-        //
-        // [1]: https://www.mail-archive.com/mesa-dev@lists.freedesktop.org/msg128408.html
         if self.is_current() {
             let ret = unsafe {
                 osmesa_sys::OSMesaMakeCurrent(ptr::null_mut(),
                                               ptr::null_mut(), 0, 0, 0)
             };
             if ret == gl::FALSE {
-                gl::flush();
+                return Err("OSMesaMakeCurrent");
             }
         }
 
         Ok(())
     }
+
+    fn is_osmesa(&self) -> bool { true }
 }
 
 impl Drop for OSMesaContext {
     fn drop(&mut self) {
         unsafe { osmesa_sys::OSMesaDestroyContext(self.context) }
     }
 }
--- a/third_party/rust/offscreen_gl_context/src/tests.rs
+++ b/third_party/rust/offscreen_gl_context/src/tests.rs
@@ -1,11 +1,10 @@
 use gleam::gl;
 use euclid::Size2D;
-use std::sync::{Once, ONCE_INIT};
 
 use GLContext;
 #[cfg(all(target_os = "linux", feature = "test_egl_in_linux"))]
 use platform::with_egl::NativeGLContext;
 #[cfg(feature="test_osmesa")]
 use platform::OSMesaContext as NativeGLContext;
 #[cfg(not(any(feature = "test_egl_in_linux", feature = "test_osmesa")))]
 use NativeGLContext;
@@ -14,42 +13,29 @@ use GLContextAttributes;
 use ColorAttachmentType;
 use std::thread;
 use std::sync::mpsc;
 
 #[cfg(target_os="macos")]
 #[link(name="OpenGL", kind="framework")]
 extern {}
 
-#[cfg(target_os="linux")]
+#[cfg(all(target_os="linux", feature="x11"))]
 #[link(name="GL")]
 extern {}
 
-#[cfg(not(target_os="android"))]
-static LOAD_GL: Once = ONCE_INIT;
-
-#[cfg(not(target_os="android"))]
-fn load_gl() {
-    LOAD_GL.call_once(|| {
-        gl::load_with(|s| GLContext::<NativeGLContext>::get_proc_address(s) as *const _);
-    });
-}
-#[cfg(target_os="android")]
-fn load_gl() {
-}
-
 fn test_gl_context<T: NativeGLContextMethods>(context: &GLContext<T>) {
     context.make_current().unwrap();
 
-    gl::clear_color(1.0, 0.0, 0.0, 1.0);
-    gl::clear(gl::COLOR_BUFFER_BIT);
+    context.gl().clear_color(1.0, 0.0, 0.0, 1.0);
+    context.gl().clear(gl::COLOR_BUFFER_BIT);
 
     let size = context.draw_buffer_size().unwrap();
 
-    let pixels = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
+    let pixels = context.gl().read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
 
     assert!(pixels.len() == (size.width * size.height * 4) as usize);
     test_pixels(&pixels);
 }
 
 fn test_pixels_eq(pixels: &[u8], to: &[u8]) {
     assert!(to.len() == 4);
     for pixel in pixels.chunks(4) {
@@ -60,171 +46,168 @@ fn test_pixels_eq(pixels: &[u8], to: &[u
 
 fn test_pixels(pixels: &[u8]) {
     test_pixels_eq(pixels, &[255, 0, 0, 255]);
 }
 
 #[test]
 #[cfg(not(feature = "test_osmesa"))]
 fn test_unbinding() {
-    load_gl();
     let ctx = GLContext::<NativeGLContext>::new(Size2D::new(256, 256),
                                                 GLContextAttributes::default(),
                                                 ColorAttachmentType::Renderbuffer,
+                                                gl::GlType::default(),
                                                 None).unwrap();
 
     assert!(NativeGLContext::current_handle().is_some());
 
     ctx.unbind().unwrap();
     assert!(NativeGLContext::current_handle().is_none());
 }
 
 #[test]
 fn test_renderbuffer_color_attachment() {
-    load_gl();
     test_gl_context(&GLContext::<NativeGLContext>::new(Size2D::new(256, 256),
                                                        GLContextAttributes::default(),
                                                        ColorAttachmentType::Renderbuffer,
+                                                       gl::GlType::default(),
                                                        None).unwrap());
 }
 
 #[test]
 fn test_texture_color_attachment() {
-    load_gl();
     let size = Size2D::new(256, 256);
     let context = GLContext::<NativeGLContext>::new(size,
                                                     GLContextAttributes::default(),
                                                     ColorAttachmentType::Texture,
+                                                    gl::GlType::default(),
                                                     None).unwrap();
     test_gl_context(&context);
 
     // Get the bound texture and check we're painting on it
     let texture_id = context.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap();
     assert!(texture_id != 0);
 
-    assert!(gl::get_error() == gl::NO_ERROR);
+    assert!(context.gl().get_error() == gl::NO_ERROR);
 
     // Actually we just check that writing to the framebuffer works, and that there's a texture
     // attached to it. Doing a getTexImage should be a good idea, but it's not available on gles,
     // so what we should do is rebinding to another FBO.
     //
     // This is done in the `test_sharing` test though, so if that passes we know everything
     // works and we're just happy.
-    let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
+    let vec = context.gl().read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
     test_pixels(&vec);
 }
 
 #[test]
 fn test_sharing() {
-    load_gl();
-
     let size = Size2D::new(256, 256);
     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();
     assert!(primary_texture_id != 0);
 
     let secondary = GLContext::<NativeGLContext>::new(size,
                                                       GLContextAttributes::default(),
                                                       ColorAttachmentType::Texture,
+                                                      gl::GlType::default(),
                                                       Some(&primary.handle())).unwrap();
 
     // Paint the second context red
     test_gl_context(&secondary);
 
     // Now the secondary context is bound, get the texture id, switch contexts, and check the
     // texture is there.
     let secondary_texture_id = secondary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap();
     assert!(secondary_texture_id != 0);
 
     primary.make_current().unwrap();
-    assert!(unsafe { gl::IsTexture(secondary_texture_id) != 0 });
+    assert!(primary.gl().is_texture(secondary_texture_id) != 0);
 
-    // Clearing and re-binding to a framebuffer instead of using getTexImage since it's not
-    // available in GLES2
-    gl::clear_color(0.0, 0.0, 0.0, 1.0);
-    gl::clear(gl::COLOR_BUFFER_BIT);
+    // Clearing and re-binding to a framebuffer instead of using getTexImage
+    // since it's not available in GLES2
+    primary.gl().clear_color(0.0, 0.0, 0.0, 1.0);
+    primary.gl().clear(gl::COLOR_BUFFER_BIT);
 
-    let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
+    let vec = primary.gl().read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
     test_pixels_eq(&vec, &[0, 0, 0, 255]);
 
-    gl::bind_texture(gl::TEXTURE_2D, secondary_texture_id);
+    primary.gl().bind_texture(gl::TEXTURE_2D, secondary_texture_id);
 
-    unsafe {
-        gl::FramebufferTexture2D(gl::FRAMEBUFFER,
-                                 gl::COLOR_ATTACHMENT0,
-                                 gl::TEXTURE_2D,
-                                 secondary_texture_id, 0);
-    }
+    primary.gl().framebuffer_texture_2d(gl::FRAMEBUFFER,
+                                        gl::COLOR_ATTACHMENT0,
+                                        gl::TEXTURE_2D,
+                                        secondary_texture_id, 0);
 
-    let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
-    assert!(gl::get_error() == gl::NO_ERROR);
+    let vec = primary.gl().read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
+    assert!(primary.gl().get_error() == gl::NO_ERROR);
 
     test_pixels(&vec);
 }
 
 #[test]
 fn test_multithread_render() {
-    load_gl();
-
     let size = Size2D::new(256, 256);
     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
-        gl::clear_color(0.0, 1.0, 0.0, 1.0);
-        gl::clear(gl::COLOR_BUFFER_BIT);
+        secondary.gl().clear_color(0.0, 1.0, 0.0, 1.0);
+        secondary.gl().clear(gl::COLOR_BUFFER_BIT);
 
-        let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
+        let vec = secondary.gl().read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
         test_pixels_eq(&vec, &[0, 255, 0, 255]);
 
         tx.send(()).unwrap();
 
         // Avoid drop until test ends
         end_rx.recv().unwrap();
     });
     // Wait until thread has drawn the texture
     rx.recv().unwrap();
     // This context must remain to be current in this thread
     assert!(primary.is_current());
 
     // The colors must remain unchanged
-    let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
+    let vec = primary.gl().read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
     test_pixels_eq(&vec, &[255, 0, 0, 255]);
 
     end_tx.send(()).unwrap();
 }
 
 struct SGLUint(gl::GLuint);
 unsafe impl Sync for SGLUint {}
 unsafe impl Send for SGLUint {}
 
 #[test]
 fn test_multithread_sharing() {
-    load_gl();
-
     let size = Size2D::new(256, 256);
     let primary = GLContext::<NativeGLContext>::new(size,
                                                     GLContextAttributes::default(),
                                                     ColorAttachmentType::Texture,
+                                                    gl::GlType::default(),
                                                     None).unwrap();
     primary.make_current().unwrap();
 
     let primary_texture_id = primary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap();
     assert!(primary_texture_id != 0);
 
     let (tx, rx) = mpsc::channel();
     let (end_tx, end_rx) = mpsc::channel();
@@ -233,16 +216,17 @@ fn test_multithread_sharing() {
     // Unbind required by some APIs as WGL
     primary.unbind().unwrap();
 
     thread::spawn(move || {
         // Create the context in a different thread
         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();
         // Paint the second context red
         test_gl_context(&secondary);
         // Send texture_id to main thread
         let texture_id = secondary.borrow_draw_buffer().unwrap().get_bound_texture_id().unwrap();
         assert!(texture_id != 0);
@@ -250,138 +234,137 @@ fn test_multithread_sharing() {
         // Avoid drop until test ends
         end_rx.recv().unwrap();
     });
     // Wait until thread has drawn the texture
     let secondary_texture_id = rx.recv().unwrap().0;
 
     primary.make_current().unwrap();
 
-    // Clearing and re-binding to a framebuffer instead of using getTexImage since it's not
-    // available in GLES2
-    gl::clear_color(0.0, 0.0, 0.0, 1.0);
-    gl::clear(gl::COLOR_BUFFER_BIT);
+    // Clearing and re-binding to a framebuffer instead of using getTexImage
+    // since it's not available in GLES2
+    primary.gl().clear_color(0.0, 0.0, 0.0, 1.0);
+    primary.gl().clear(gl::COLOR_BUFFER_BIT);
 
-    let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
+    let vec = primary.gl().read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
     test_pixels_eq(&vec, &[0, 0, 0, 255]);
 
 
-    unsafe {
-        gl::FramebufferTexture2D(gl::FRAMEBUFFER,
-                                 gl::COLOR_ATTACHMENT0,
-                                 gl::TEXTURE_2D,
-                                 secondary_texture_id, 0);
-    }
+    primary.gl().framebuffer_texture_2d(gl::FRAMEBUFFER,
+                                        gl::COLOR_ATTACHMENT0,
+                                        gl::TEXTURE_2D,
+                                        secondary_texture_id,
+                                        0);
 
-    let vec = gl::read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
-    assert!(gl::get_error() == gl::NO_ERROR);
+    let vec = primary.gl().read_pixels(0, 0, size.width, size.height, gl::RGBA, gl::UNSIGNED_BYTE);
+    assert!(primary.gl().get_error() == gl::NO_ERROR);
 
     test_pixels(&vec);
     end_tx.send(()).unwrap();
 }
 
 #[test]
 fn test_limits() {
-    load_gl();
-
     let size = Size2D::new(256, 256);
     let context = GLContext::<NativeGLContext>::new(size,
                                                     GLContextAttributes::default(),
                                                     ColorAttachmentType::Texture,
+                                                    gl::GlType::default(),
                                                     None).unwrap();
     assert!(context.borrow_limits().max_vertex_attribs != 0);
 }
 
 #[test]
 fn test_no_alpha() {
-    load_gl();
     let mut attributes = GLContextAttributes::default();
     attributes.alpha = false;
 
     let size = Size2D::new(256, 256);
     let context = GLContext::<NativeGLContext>::new(size,
                                                     attributes,
                                                     ColorAttachmentType::Texture,
+                                                    gl::GlType::default(),
                                                     None).unwrap();
     assert!(context.borrow_limits().max_vertex_attribs != 0);
 }
 
 #[test]
 fn test_no_depth() {
-    load_gl();
     let mut attributes = GLContextAttributes::default();
     attributes.depth = false;
 
     let size = Size2D::new(256, 256);
     let context = GLContext::<NativeGLContext>::new(size,
                                                     attributes,
                                                     ColorAttachmentType::Texture,
+                                                    gl::GlType::default(),
                                                     None).unwrap();
     assert!(context.borrow_limits().max_vertex_attribs != 0);
 }
 
 #[test]
 fn test_no_depth_no_alpha() {
-    load_gl();
     let mut attributes = GLContextAttributes::default();
     attributes.depth = false;
     attributes.alpha = false;
 
     let size = Size2D::new(256, 256);
     let context = GLContext::<NativeGLContext>::new(size,
                                                     attributes,
                                                     ColorAttachmentType::Texture,
+                                                    gl::GlType::default(),
                                                     None).unwrap();
     assert!(context.borrow_limits().max_vertex_attribs != 0);
 }
 
 #[test]
 fn test_no_premul_alpha() {
-    load_gl();
     let mut attributes = GLContextAttributes::default();
     attributes.depth = false;
     attributes.alpha = false;
     attributes.premultiplied_alpha = false;
 
     let size = Size2D::new(256, 256);
     let context = GLContext::<NativeGLContext>::new(size,
                                                     attributes,
                                                     ColorAttachmentType::Texture,
+                                                    gl::GlType::default(),
                                                     None).unwrap();
     assert!(context.borrow_limits().max_vertex_attribs != 0);
 }
 
 #[test]
 fn test_in_a_row() {
-    load_gl();
     let mut attributes = GLContextAttributes::default();
     attributes.depth = false;
     attributes.alpha = false;
     attributes.premultiplied_alpha = false;
 
     let size = Size2D::new(256, 256);
     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();
 }
 
 #[test]
 fn test_zero_size() {
-    load_gl();
-
     GLContext::<NativeGLContext>::new(Size2D::new(0, 320),
                                       GLContextAttributes::default(),
                                       ColorAttachmentType::Texture,
+                                      gl::GlType::default(),
                                       None).unwrap();
 }