Merge graphics to m-c a=kats
authorWes Kocher <wkocher@mozilla.com>
Thu, 23 Mar 2017 10:36:55 -0700
changeset 399664 200182ef115692c4ed2909f1a8beae8a6f19d127
parent 399630 439ee2e4fc4ed4a82102608639d9751e376d5536 (current diff)
parent 399663 283ca0666c06b05616e23af2f873652c30d54988 (diff)
child 399744 76dc62ba34d8c473d03daae8315d6e3ab10c8d6e
push id1490
push usermtabara@mozilla.com
push dateMon, 31 Jul 2017 14:08:16 +0000
treeherdermozilla-release@70e32e6bf15e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge graphics to m-c a=kats MozReview-Commit-ID: 9kKfHoyG8kj
gfx/layers/wr/WebRenderBorderLayer.cpp
gfx/layers/wr/WebRenderBorderLayer.h
--- a/dom/canvas/crashtests/crashtests.list
+++ b/dom/canvas/crashtests/crashtests.list
@@ -6,18 +6,18 @@ load 553938-1.html
 load 647480.html
 load 727547.html
 load 729116.html
 asserts-if(stylo,1) load 745699-1.html # bug 1324700
 load 746813-1.html
 load 743499-negative-size.html
 skip-if(Android) load 745818-large-source.html # Bug XXX - Crashes Android mid-run w/o a stack
 load 767337-1.html
-asserts-if(stylo,1) skip-if(Android) skip-if(webrender) load 780392-1.html # bug 1324700. bug 1322816 for webrender
-skip-if(Android) skip-if(gtkWidget&&isDebugBuild) skip-if(webrender) load 789933-1.html # bug 1155252 for linux, bug 1322816 for webrender
+asserts-if(stylo,1) skip-if(Android) load 780392-1.html # bug 1324700
+skip-if(Android) skip-if(gtkWidget&&isDebugBuild) load 789933-1.html # bug 1155252 for linux
 load 794463-1.html
 load 802926-1.html
 load 896047-1.html
 load 916128-1.html
 load 934939-1.html
 asserts-if(stylo,1) load 1099143-1.html # bug 1324700
 load 1161277-1.html
 load 1183363.html
--- a/dom/media/test/crashtests/crashtests.list
+++ b/dom/media/test/crashtests/crashtests.list
@@ -5,17 +5,17 @@ load 466945-1.html
 load 468763-1.html
 load 474744-1.html
 HTTP load 481136-1.html # needs to be HTTP to recognize the ogg as an audio file?
 load 492286-1.xhtml
 load 493915-1.html
 load 495794-1.html
 load 576612-1.html
 load 752784-1.html
-skip-if(webrender) load 789075-1.html # bug 1322816 for webrender
+load 789075-1.html
 HTTP load 795892-1.html
 load 844563.html
 load 846612.html
 load 852838.html
 load 865537-1.html
 load 868504.html
 load 874869.html
 load 874915.html
--- a/gfx/doc/README.webrender
+++ b/gfx/doc/README.webrender
@@ -74,9 +74,9 @@ there is another crate in m-c called moz
 the same folder to store its rust dependencies. If one of the libraries that is
 required by both mozjs_sys and webrender is updated without updating the other
 project's Cargo.lock file, that results in build bustage.
 This means that any time you do this sort of manual update of packages, you need
 to make sure that mozjs_sys also has its Cargo.lock file updated if needed, hence
 the need to run the cargo update command in js/src as well. Hopefully this will
 be resolved soon.
 
-Latest Commit: e30fb2914928c0e596d8632ed234647c0fd1492e
+Latest Commit: 0794911f97cae92496fca992d7430da696fa24eb
--- a/gfx/gl/GLLibraryEGL.cpp
+++ b/gfx/gl/GLLibraryEGL.cpp
@@ -3,23 +3,23 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GLLibraryEGL.h"
 
 #include "angle/Platform.h"
 #include "gfxConfig.h"
 #include "gfxCrashReporterUtils.h"
 #include "gfxUtils.h"
-#include "mozilla/layers/CompositorThread.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/Tokenizer.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Unused.h"
+#include "mozilla/webrender/RenderThread.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsIGfxInfo.h"
 #include "nsPrintfCString.h"
 #ifdef XP_WIN
 #include "nsWindowsHelpers.h"
 #endif
 #include "OGLShaderProgram.h"
@@ -146,17 +146,17 @@ GetAndInitWARPDisplay(GLLibraryEGL& egl,
 
     return display;
 }
 
 static bool
 IsAccelAngleSupported(const nsCOMPtr<nsIGfxInfo>& gfxInfo,
                       nsACString* const out_failureId)
 {
-    if (CompositorThreadHolder::IsInCompositorThread()) {
+    if (wr::RenderThread::IsInRenderThread()) {
         // We can only enter here with WebRender, so assert that this is a
         // WebRender-enabled build.
 #ifndef MOZ_BUILD_WEBRENDER
         MOZ_ASSERT(false);
 #endif
         return true;
     }
     int32_t angleSupport;
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1834,16 +1834,18 @@ CompositorBridgeParent::DidComposite(Tim
 void
 CompositorBridgeParent::NotifyDidCompositeToPipeline(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd)
 {
   if (mPaused) {
     return;
   }
   MOZ_ASSERT(mWrBridge);
 
+  mWrBridge->CompositableHolder()->Update(aPipelineId, aEpoch);
+
   if (mWrBridge->PipelineId() == aPipelineId) {
     uint64_t transactionId = mWrBridge->FlushTransactionIdsForEpoch(aEpoch);
     Unused << SendDidComposite(0, transactionId, aCompositeStart, aCompositeEnd);
 
     nsTArray<ImageCompositeNotificationInfo> notifications;
     mWrBridge->ExtractImageCompositeNotifications(&notifications);
     if (!notifications.IsEmpty()) {
       Unused << ImageBridgeParent::NotifyImageComposites(notifications);
--- a/gfx/layers/ipc/CompositorVsyncScheduler.cpp
+++ b/gfx/layers/ipc/CompositorVsyncScheduler.cpp
@@ -129,16 +129,21 @@ CompositorVsyncScheduler::PostCompositeT
     ScheduleTask(task.forget(), 0);
   }
 }
 
 void
 CompositorVsyncScheduler::ScheduleComposition()
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  if (!mVsyncObserver) {
+    // Destroy was already called on this object.
+    return;
+  }
+
   if (mAsapScheduling) {
     // Used only for performance testing purposes
     PostCompositeTask(TimeStamp::Now());
 #ifdef MOZ_WIDGET_ANDROID
   } else if (mNeedsComposite >= 2 && mIsObservingVsync) {
     // uh-oh, we already requested a composite at least twice so far, and a
     // composite hasn't happened yet. It is possible that the vsync observation
     // is blocked on the main thread, so let's just composite ASAP and not
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -218,17 +218,17 @@ CrossProcessCompositorBridgeParent::Allo
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   MOZ_ASSERT(sIndirectLayerTrees.find(pipelineHandle) != sIndirectLayerTrees.end());
   MOZ_ASSERT(sIndirectLayerTrees[pipelineHandle].mWrBridge == nullptr);
   CompositorBridgeParent* cbp = sIndirectLayerTrees[pipelineHandle].mParent;
   WebRenderBridgeParent* root = sIndirectLayerTrees[cbp->RootLayerTreeId()].mWrBridge.get();
 
   WebRenderBridgeParent* parent = nullptr;
   RefPtr<wr::WebRenderAPI> api = root->GetWebRenderAPI();
-  RefPtr<WebRenderCompositableHolder> holder = new WebRenderCompositableHolder();
+  RefPtr<WebRenderCompositableHolder> holder = root->CompositableHolder();
   parent = new WebRenderBridgeParent(this, aPipelineId, nullptr, root->CompositorScheduler(), Move(api), Move(holder));
 
   parent->AddRef(); // IPDL reference
   sIndirectLayerTrees[pipelineHandle].mCrossProcessParent = this;
   sIndirectLayerTrees[pipelineHandle].mWrBridge = parent;
   *aTextureFactoryIdentifier = parent->GetTextureFactoryIdentifier();
   *aIdNamespace = parent->GetIdNameSpace();
 
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -187,17 +187,16 @@ EXPORTS.mozilla.layers += [
     'opengl/TextureHostOGL.h',
     'PersistentBufferProvider.h',
     'RenderTrace.h',
     'SourceSurfaceSharedData.h',
     'SourceSurfaceVolatileData.h',
     'TextureSourceProvider.h',
     'TextureWrapperImage.h',
     'TransactionIdAllocator.h',
-    'wr/WebRenderBorderLayer.h',
     'wr/WebRenderBridgeChild.h',
     'wr/WebRenderBridgeParent.h',
     'wr/WebRenderCompositableHolder.h',
     'wr/WebRenderDisplayItemLayer.h',
     'wr/WebRenderImageHost.h',
     'wr/WebRenderLayerManager.h',
     'wr/WebRenderLayersLogging.h',
     'wr/WebRenderMessageUtils.h',
@@ -374,17 +373,16 @@ UNIFIED_SOURCES += [
     'ReadbackProcessor.cpp',
     'RenderTrace.cpp',
     'RotatedBuffer.cpp',
     'ShareableCanvasLayer.cpp',
     'SourceSurfaceSharedData.cpp',
     'SourceSurfaceVolatileData.cpp',
     'TextureSourceProvider.cpp',
     'TextureWrapperImage.cpp',
-    'wr/WebRenderBorderLayer.cpp',
     'wr/WebRenderBridgeChild.cpp',
     'wr/WebRenderBridgeParent.cpp',
     'wr/WebRenderCanvasLayer.cpp',
     'wr/WebRenderColorLayer.cpp',
     'wr/WebRenderCompositableHolder.cpp',
     'wr/WebRenderContainerLayer.cpp',
     'wr/WebRenderDisplayItemLayer.cpp',
     'wr/WebRenderImageHost.cpp',
deleted file mode 100644
--- a/gfx/layers/wr/WebRenderBorderLayer.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "WebRenderBorderLayer.h"
-
-#include "gfxPrefs.h"
-#include "LayersLogging.h"
-#include "mozilla/gfx/Rect.h"
-#include "mozilla/webrender/webrender_ffi.h"
-#include "mozilla/layers/WebRenderBridgeChild.h"
-#include "mozilla/webrender/WebRenderTypes.h"
-
-namespace mozilla {
-namespace layers {
-
-using namespace mozilla::gfx;
-
-/* static */void
-WebRenderBorderLayer::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
-                                              WebRenderLayer* aLayer,
-                                              BorderColors& aColors,
-                                              BorderCorners& aCorners,
-                                              BorderWidths& aWidths,
-                                              BorderStyles& aBorderStyles,
-                                              Rect aRect,
-                                              Rect aClipRect,
-                                              Rect aRelBounds,
-                                              Rect aOverflow)
-{
-  aBuilder.PushStackingContext(wr::ToWrRect(aRelBounds),
-                               wr::ToWrRect(aOverflow),
-                               nullptr,
-                               1.0f,
-                               aLayer->GetLayer()->GetTransform(),
-                               wr::MixBlendMode::Normal);
-  aBuilder.PushBorder(wr::ToWrRect(aRect), aBuilder.BuildClipRegion(wr::ToWrRect(aClipRect)),
-                      wr::ToWrBorderWidths(aWidths[0], aWidths[1], aWidths[2], aWidths[3]),
-                      wr::ToWrBorderSide(aColors[0], aBorderStyles[0]),
-                      wr::ToWrBorderSide(aColors[1], aBorderStyles[1]),
-                      wr::ToWrBorderSide(aColors[2], aBorderStyles[2]),
-                      wr::ToWrBorderSide(aColors[3], aBorderStyles[3]),
-                      wr::ToWrBorderRadius(aCorners[eCornerTopLeft], aCorners[eCornerTopRight],
-                                           aCorners[eCornerBottomLeft], aCorners[eCornerBottomRight]));
-  aBuilder.PopStackingContext();
-}
-
-void
-WebRenderBorderLayer::RenderLayer(wr::DisplayListBuilder& aBuilder)
-{
-  gfx::Rect relBounds = GetWrRelBounds();
-  gfx::Rect overflow(0, 0, relBounds.width, relBounds.height);
-
-  gfx::Rect rect = GetWrBoundsRect();
-  gfx::Rect clipRect = GetWrClipRect(rect);
-
-  DumpLayerInfo("BorderLayer", rect);
-
-  aBuilder.PushStackingContext(wr::ToWrRect(relBounds),
-                               wr::ToWrRect(overflow),
-                               nullptr,
-                               1.0f,
-                               //GetAnimations(),
-                               GetTransform(),
-                               wr::MixBlendMode::Normal);
-  aBuilder.PushBorder(wr::ToWrRect(rect), aBuilder.BuildClipRegion(wr::ToWrRect(clipRect)),
-                      wr::ToWrBorderWidths(mWidths[0], mWidths[1], mWidths[2], mWidths[3]),
-                      wr::ToWrBorderSide(mColors[0], mBorderStyles[0]),
-                      wr::ToWrBorderSide(mColors[1], mBorderStyles[1]),
-                      wr::ToWrBorderSide(mColors[2], mBorderStyles[2]),
-                      wr::ToWrBorderSide(mColors[3], mBorderStyles[3]),
-                      wr::ToWrBorderRadius(mCorners[eCornerTopLeft], mCorners[eCornerTopRight],
-                                           mCorners[eCornerBottomLeft], mCorners[eCornerBottomRight]));
-  aBuilder.PopStackingContext();
-}
-
-} // namespace layers
-} // namespace mozilla
deleted file mode 100644
--- a/gfx/layers/wr/WebRenderBorderLayer.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef GFX_WEBRENDERBORDERLAYER_H
-#define GFX_WEBRENDERBORDERLAYER_H
-
-#include "Layers.h"
-#include "WebRenderLayerManager.h"
-
-namespace mozilla {
-namespace layers {
-
-class WebRenderBorderLayer : public WebRenderLayer,
-                             public BorderLayer {
-public:
-  explicit WebRenderBorderLayer(WebRenderLayerManager* aLayerManager)
-    : BorderLayer(aLayerManager, static_cast<WebRenderLayer*>(this))
-  {
-    MOZ_COUNT_CTOR(WebRenderBorderLayer);
-  }
-
-  static void
-  CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
-                          WebRenderLayer* aLayer,
-                          BorderColors& aColors,
-                          BorderCorners& aCorners,
-                          BorderWidths& aWidths,
-                          BorderStyles& aBorderStyles,
-                          gfx::Rect aRect,
-                          gfx::Rect aClipRect,
-                          gfx::Rect aRelBounds,
-                          gfx::Rect aOverflow);
-
-protected:
-  virtual ~WebRenderBorderLayer()
-  {
-    MOZ_COUNT_DTOR(WebRenderBorderLayer);
-  }
-
-public:
-  Layer* GetLayer() override { return this; }
-  void RenderLayer(wr::DisplayListBuilder& aBuilder) override;
-};
-
-} // namespace layers
-} // namespace mozilla
-
-#endif // GFX_WEBRENDERBORDERLAYER_H
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -32,16 +32,27 @@ bool is_in_compositor_thread()
   return mozilla::layers::CompositorThreadHolder::IsInCompositorThread();
 }
 
 bool is_in_render_thread()
 {
   return mozilla::wr::RenderThread::IsInRenderThread();
 }
 
+bool is_glcontext_egl(void* glcontext_ptr)
+{
+  MOZ_ASSERT(glcontext_ptr);
+
+  mozilla::gl::GLContext* glcontext = reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
+  if (!glcontext) {
+    return false;
+  }
+  return glcontext->GetContextType() == mozilla::gl::GLContextType::EGL;
+}
+
 void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname)
 {
   MOZ_ASSERT(glcontext_ptr);
 
   mozilla::gl::GLContext* glcontext = reinterpret_cast<mozilla::gl::GLContext*>(glcontext_ptr);
   if (!glcontext) {
     return nullptr;
   }
@@ -97,16 +108,17 @@ WebRenderBridgeParent::WebRenderBridgePa
   , mCompositorScheduler(aScheduler)
   , mChildLayerObserverEpoch(0)
   , mParentLayerObserverEpoch(0)
   , mWrEpoch(0)
   , mIdNameSpace(++sIdNameSpace)
   , mDestroyed(false)
 {
   MOZ_ASSERT(mCompositableHolder);
+  mCompositableHolder->AddPipeline(mPipelineId);
   if (mWidget) {
     MOZ_ASSERT(!mCompositorScheduler);
     mCompositorScheduler = new CompositorVsyncScheduler(this, mWidget);
   }
 }
 
 
 mozilla::ipc::IPCResult
@@ -311,17 +323,17 @@ WebRenderBridgeParent::ProcessWebRenderC
         if (wrTexture) {
           // XXX handling YUV
           gfx::SurfaceFormat format =
             wrTexture->GetFormat() == SurfaceFormat::YUV ? SurfaceFormat::B8G8R8A8 : wrTexture->GetFormat();
           wr::ImageDescriptor descriptor(wrTexture->GetSize(), wrTexture->GetRGBStride(), format);
           mApi->AddExternalImageBuffer(key,
                                        descriptor,
                                        wrTexture->GetExternalImageKey());
-          mCompositableHolder->HoldExternalImage(aEpoch, texture->AsWebRenderTextureHost());
+          mCompositableHolder->HoldExternalImage(mPipelineId, aEpoch, texture->AsWebRenderTextureHost());
           keysToDelete.push_back(key);
           break;
         }
         RefPtr<DataSourceSurface> dSurf = host->GetAsSurface();
         if (!dSurf) {
           break;
         }
 
@@ -332,20 +344,16 @@ WebRenderBridgeParent::ProcessWebRenderC
 
         IntSize size = dSurf->GetSize();
         wr::ImageDescriptor descriptor(size, map.mStride, dSurf->GetFormat());
         auto slice = Range<uint8_t>(map.mData, size.height * map.mStride);
         mApi->AddImage(key, descriptor, slice);
 
         keysToDelete.push_back(key);
         dSurf->Unmap();
-        // XXX workaround for releasing Readlock. See Bug 1339625
-        if(host->GetType() == CompositableType::CONTENT_SINGLE) {
-          host->CleanupResources();
-        }
         break;
       }
       case WebRenderParentCommand::TCompositableOperation: {
         if (!ReceiveCompositableUpdate(cmd.get_CompositableOperation())) {
           NS_ERROR("ReceiveCompositableUpdate failed");
         }
         break;
       }
@@ -558,19 +566,16 @@ WebRenderBridgeParent::FlushTransactionI
   while (!mPendingTransactionIds.empty()) {
     id = mPendingTransactionIds.front().mId;
     if (mPendingTransactionIds.front().mEpoch == aEpoch) {
       mPendingTransactionIds.pop();
       break;
     }
     mPendingTransactionIds.pop();
   }
-
-  mCompositableHolder->Update(aEpoch);
-
   return id;
 }
 
 WebRenderBridgeParent::~WebRenderBridgeParent()
 {
 }
 
 void
@@ -597,19 +602,17 @@ WebRenderBridgeParent::ClearResources()
     ++mWrEpoch; // Update webrender epoch
     mApi->ClearRootDisplayList(wr::NewEpoch(mWrEpoch), mPipelineId);
     if (!mKeysToDelete.empty()) {
       // XXX Sync wait.
       mApi->WaitFlushed();
       DeleteOldImages();
     }
   }
-  if (mCompositableHolder) {
-    mCompositableHolder->Destroy();
-  }
+  mCompositableHolder->RemovePipeline(mPipelineId);
   mExternalImageIds.Clear();
 
   if (mWidget && mCompositorScheduler) {
     mCompositorScheduler->Destroy();
   }
   mCompositorScheduler = nullptr;
   mApi = nullptr;
   mCompositorBridge = nullptr;
--- a/gfx/layers/wr/WebRenderCompositableHolder.cpp
+++ b/gfx/layers/wr/WebRenderCompositableHolder.cpp
@@ -18,43 +18,61 @@ namespace layers {
 WebRenderCompositableHolder::WebRenderCompositableHolder()
 {
   MOZ_COUNT_CTOR(WebRenderCompositableHolder);
 }
 
 WebRenderCompositableHolder::~WebRenderCompositableHolder()
 {
   MOZ_COUNT_DTOR(WebRenderCompositableHolder);
-  MOZ_ASSERT(mWebRenderTextureHosts.empty());
+  MOZ_ASSERT(mPipelineTexturesHolders.IsEmpty());
 }
 
 void
-WebRenderCompositableHolder::Destroy()
+WebRenderCompositableHolder::AddPipeline(const wr::PipelineId& aPipelineId)
 {
-  while (!mWebRenderTextureHosts.empty()) {
-    mWebRenderTextureHosts.pop();
+  uint64_t id = wr::AsUint64(aPipelineId);
+
+  MOZ_ASSERT(!mPipelineTexturesHolders.Get(id));
+  PipelineTexturesHolder* holder = new PipelineTexturesHolder();
+  mPipelineTexturesHolders.Put(id, holder);
+}
+
+void
+WebRenderCompositableHolder::RemovePipeline(const wr::PipelineId& aPipelineId)
+{
+  uint64_t id = wr::AsUint64(aPipelineId);
+  if (mPipelineTexturesHolders.Get(id)) {
+    mPipelineTexturesHolders.Remove(id);
   }
 }
 
 void
-WebRenderCompositableHolder::HoldExternalImage(const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture)
+WebRenderCompositableHolder::HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture)
 {
   MOZ_ASSERT(aTexture);
+  PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
+  MOZ_ASSERT(holder);
+  if (!holder) {
+    return;
+  }
   // Hold WebRenderTextureHost until end of its usage on RenderThread
-  mWebRenderTextureHosts.push(ForwardingTextureHosts(aEpoch, aTexture));
+  holder->mTextureHosts.push(ForwardingTextureHost(aEpoch, aTexture));
 }
 
 void
-WebRenderCompositableHolder::Update(const wr::Epoch& aEpoch)
+WebRenderCompositableHolder::Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch)
 {
-  if (mWebRenderTextureHosts.empty()) {
+  PipelineTexturesHolder* holder = mPipelineTexturesHolders.Get(wr::AsUint64(aPipelineId));
+  if (!holder || holder->mTextureHosts.empty()) {
     return;
   }
-  while (!mWebRenderTextureHosts.empty()) {
-    if (aEpoch <= mWebRenderTextureHosts.front().mEpoch) {
+
+  while (!holder->mTextureHosts.empty()) {
+    if (aEpoch <= holder->mTextureHosts.front().mEpoch) {
       break;
     }
-    mWebRenderTextureHosts.pop();
+    holder->mTextureHosts.pop();
   }
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/wr/WebRenderCompositableHolder.h
+++ b/gfx/layers/wr/WebRenderCompositableHolder.h
@@ -5,16 +5,17 @@
 
 #ifndef MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H
 #define MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H
 
 #include <queue>
 
 #include "mozilla/layers/TextureHost.h"
 #include "mozilla/webrender/WebRenderTypes.h"
+#include "nsClassHashtable.h"
 
 namespace mozilla {
 
 namespace wr {
 class WebRenderAPI;
 }
 
 namespace layers {
@@ -28,31 +29,36 @@ public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WebRenderCompositableHolder)
 
   explicit WebRenderCompositableHolder();
 
 protected:
   ~WebRenderCompositableHolder();
 
 public:
-  void Destroy();
-  void HoldExternalImage(const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture);
-  void Update(const wr::Epoch& aEpoch);
+  void AddPipeline(const wr::PipelineId& aPipelineId);
+  void RemovePipeline(const wr::PipelineId& aPipelineId);
+  void HoldExternalImage(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch, WebRenderTextureHost* aTexture);
+  void Update(const wr::PipelineId& aPipelineId, const wr::Epoch& aEpoch);
 
 private:
 
-  struct ForwardingTextureHosts {
-    ForwardingTextureHosts(const wr::Epoch& aEpoch, TextureHost* aTexture)
+  struct ForwardingTextureHost {
+    ForwardingTextureHost(const wr::Epoch& aEpoch, TextureHost* aTexture)
       : mEpoch(aEpoch)
       , mTexture(aTexture)
     {}
     wr::Epoch mEpoch;
     CompositableTextureHostRef mTexture;
   };
 
-  // Holds forwarding WebRenderTextureHosts.
-  std::queue<ForwardingTextureHosts> mWebRenderTextureHosts;
+  struct PipelineTexturesHolder {
+    // Holds forwarding WebRenderTextureHosts.
+    std::queue<ForwardingTextureHost> mTextureHosts;
+  };
+
+  nsClassHashtable<nsUint64HashKey, PipelineTexturesHolder> mPipelineTexturesHolders;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_WEBRENDERCOMPOSITABLE_HOLDER_H */
--- a/gfx/layers/wr/WebRenderLayerManager.cpp
+++ b/gfx/layers/wr/WebRenderLayerManager.cpp
@@ -12,17 +12,16 @@
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/AsyncCompositionManager.h"
 #include "mozilla/layers/CompositorBridgeChild.h"
 #include "mozilla/layers/TextureClient.h"
 #include "mozilla/layers/WebRenderBridgeChild.h"
 #include "mozilla/widget/PlatformWidgetTypes.h"
 #include "nsThreadUtils.h"
 #include "TreeTraversal.h"
-#include "WebRenderBorderLayer.h"
 #include "WebRenderCanvasLayer.h"
 #include "WebRenderColorLayer.h"
 #include "WebRenderContainerLayer.h"
 #include "WebRenderImageLayer.h"
 #include "WebRenderPaintedLayer.h"
 #include "WebRenderTextLayer.h"
 #include "WebRenderDisplayItemLayer.h"
 
@@ -536,17 +535,17 @@ already_AddRefed<TextLayer>
 WebRenderLayerManager::CreateTextLayer()
 {
   return MakeAndAddRef<WebRenderTextLayer>(this);
 }
 
 already_AddRefed<BorderLayer>
 WebRenderLayerManager::CreateBorderLayer()
 {
-  return MakeAndAddRef<WebRenderBorderLayer>(this);
+  return nullptr;
 }
 
 already_AddRefed<DisplayItemLayer>
 WebRenderLayerManager::CreateDisplayItemLayer()
 {
   return MakeAndAddRef<WebRenderDisplayItemLayer>(this);
 }
 
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -679,16 +679,19 @@ gfxPlatform::Init()
 #elif defined(MOZ_WIDGET_GTK)
     gPlatform = new gfxPlatformGtk;
 #elif defined(ANDROID)
     gPlatform = new gfxAndroidPlatform;
 #else
     #error "No gfxPlatform implementation available"
 #endif
     gPlatform->InitAcceleration();
+    if (XRE_IsParentProcess()) {
+      gPlatform->InitWebRenderConfig();
+    }
 
     if (gfxConfig::IsEnabled(Feature::GPU_PROCESS)) {
       GPUProcessManager* gpu = GPUProcessManager::Get();
       gpu->LaunchGPUProcess();
     }
 
 #ifdef USE_SKIA
     SkGraphics::Init();
@@ -2192,17 +2195,16 @@ gfxPlatform::InitAcceleration()
   }
 
   sLayersAccelerationPrefsInitialized = true;
 
   if (XRE_IsParentProcess()) {
     Preferences::RegisterCallbackAndCall(VideoDecodingFailedChangedCallback,
                                          "media.hardware-video-decoding.failed");
     InitGPUProcessPrefs();
-    InitWebRenderConfig();
   }
 }
 
 void
 gfxPlatform::InitGPUProcessPrefs()
 {
   // We want to hide this from about:support, so only set a default if the
   // pref is known to be true.
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -459,16 +459,17 @@ private:
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.print-histogram",  FPSPrintHistogram, bool, false);
   DECL_GFX_PREF(Live, "layers.acceleration.draw-fps.write-to-file", WriteFPSToFile, bool, false);
   DECL_GFX_PREF(Once, "layers.acceleration.force-enabled",     LayersAccelerationForceEnabledDoNotUseDirectly, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.border-layers",         LayersAllowBorderLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.boxshadow-inset-layers", LayersAllowInsetBoxShadow, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.boxshadow-outer-layers", LayersAllowOuterBoxShadow, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.bullet-layers",         LayersAllowBulletLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.button-foreground-layers", LayersAllowButtonForegroundLayers, bool, false);
+  DECL_GFX_PREF(Live, "layers.advanced.canvas-background-color", LayersAllowCanvasBackgroundColorLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.caret-layers",          LayersAllowCaretLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.displaybuttonborder-layers", LayersAllowDisplayButtonBorder, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.image-layers",          LayersAllowImageLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.outline-layers",        LayersAllowOutlineLayers, bool, false);
   DECL_GFX_PREF(Live, "layers.advanced.text-layers",           LayersAllowTextLayers, bool, false);
   DECL_GFX_PREF(Once, "layers.amd-switchable-gfx.enabled",     LayersAMDSwitchableGfxEnabled, bool, false);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.enabled",         AsyncPanZoomEnabledDoNotUseDirectly, bool, true);
   DECL_GFX_PREF(Once, "layers.async-pan-zoom.separate-event-thread", AsyncPanZoomSeparateEventThread, bool, false);
--- a/gfx/webrender/Cargo.toml
+++ b/gfx/webrender/Cargo.toml
@@ -1,11 +1,11 @@
 [package]
 name = "webrender"
-version = "0.24.0"
+version = "0.25.0"
 authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
 license = "MPL-2.0"
 repository = "https://github.com/servo/webrender"
 build = "build.rs"
 
 [features]
 default = ["freetype-lib"]
 freetype-lib = ["freetype/servo-freetype-sys"]
@@ -13,21 +13,21 @@ profiler = ["thread_profiler/thread_prof
 
 [dependencies]
 app_units = "0.4"
 bincode = "1.0.0-alpha2"
 bit-set = "0.4"
 byteorder = "1.0"
 euclid = "0.11"
 fnv = "1.0"
-gleam = "0.2.30"
+gleam = "0.4.1"
 lazy_static = "0.2"
 log = "0.3"
 num-traits = "0.1.32"
-offscreen_gl_context = {version = "0.6", features = ["serde", "osmesa"]}
+offscreen_gl_context = {version = "0.8.0", features = ["serde", "osmesa"]}
 time = "0.1"
 threadpool = "1.3.2"
 webrender_traits = {path = "../webrender_traits"}
 bitflags = "0.7"
 gamma-lut = "0.1"
 thread_profiler = "0.1.1"
 
 [dev-dependencies]
--- a/gfx/webrender/res/prim_shared.glsl
+++ b/gfx/webrender/res/prim_shared.glsl
@@ -498,62 +498,114 @@ VertexInfo write_vertex(RectWithSize ins
 #ifdef WR_FEATURE_TRANSFORM
 
 struct TransformVertexInfo {
     vec3 local_pos;
     vec2 screen_pos;
     vec4 clipped_local_rect;
 };
 
+float cross2(vec2 v0, vec2 v1) {
+    return v0.x * v1.y - v0.y * v1.x;
+}
+
+// Return intersection of line (p0,p1) and line (p2,p3)
+vec2 intersect_lines(vec2 p0, vec2 p1, vec2 p2, vec2 p3) {
+    vec2 d0 = p0 - p1;
+    vec2 d1 = p2 - p3;
+
+    float s0 = cross2(p0, p1);
+    float s1 = cross2(p2, p3);
+
+    float d = cross2(d0, d1);
+    float nx = s0 * d1.x - d0.x * s1;
+    float ny = s0 * d1.y - d0.y * s1;
+
+    return vec2(nx / d, ny / d);
+}
+
 TransformVertexInfo write_transform_vertex(RectWithSize instance_rect,
                                            RectWithSize local_clip_rect,
                                            float z,
                                            Layer layer,
                                            AlphaBatchTask task) {
-    vec2 lp0_base = instance_rect.p0;
-    vec2 lp1_base = instance_rect.p0 + instance_rect.size;
+    RectWithEndpoint local_rect = to_rect_with_endpoint(instance_rect);
+
+    vec2 current_local_pos, prev_local_pos, next_local_pos;
 
-    vec2 lp0 = clamp_rect(clamp_rect(lp0_base, local_clip_rect),
-                          layer.local_clip_rect);
-    vec2 lp1 = clamp_rect(clamp_rect(lp1_base, local_clip_rect),
-                          layer.local_clip_rect);
+    // Select the current vertex and the previous/next vertices,
+    // based on the vertex ID that is known based on the instance rect.
+    switch (gl_VertexID) {
+        case 0:
+            current_local_pos = vec2(local_rect.p0.x, local_rect.p0.y);
+            next_local_pos = vec2(local_rect.p0.x, local_rect.p1.y);
+            prev_local_pos = vec2(local_rect.p1.x, local_rect.p0.y);
+            break;
+        case 1:
+            current_local_pos = vec2(local_rect.p1.x, local_rect.p0.y);
+            next_local_pos = vec2(local_rect.p0.x, local_rect.p0.y);
+            prev_local_pos = vec2(local_rect.p1.x, local_rect.p1.y);
+            break;
+        case 2:
+            current_local_pos = vec2(local_rect.p0.x, local_rect.p1.y);
+            prev_local_pos = vec2(local_rect.p0.x, local_rect.p0.y);
+            next_local_pos = vec2(local_rect.p1.x, local_rect.p1.y);
+            break;
+        case 3:
+            current_local_pos = vec2(local_rect.p1.x, local_rect.p1.y);
+            prev_local_pos = vec2(local_rect.p0.x, local_rect.p1.y);
+            next_local_pos = vec2(local_rect.p1.x, local_rect.p0.y);
+            break;
+    }
 
-    vec4 clipped_local_rect = vec4(lp0, lp1 - lp0);
-
-    vec2 p0 = lp0;
-    vec2 p1 = vec2(lp1.x, lp0.y);
-    vec2 p2 = vec2(lp0.x, lp1.y);
-    vec2 p3 = lp1;
+    // Transform them to world space
+    vec4 current_world_pos = layer.transform * vec4(current_local_pos, 0.0, 1.0);
+    vec4 prev_world_pos = layer.transform * vec4(prev_local_pos, 0.0, 1.0);
+    vec4 next_world_pos = layer.transform * vec4(next_local_pos, 0.0, 1.0);
 
-    vec4 t0 = layer.transform * vec4(p0, 0, 1);
-    vec4 t1 = layer.transform * vec4(p1, 0, 1);
-    vec4 t2 = layer.transform * vec4(p2, 0, 1);
-    vec4 t3 = layer.transform * vec4(p3, 0, 1);
+    // Convert to device space
+    vec2 current_device_pos = uDevicePixelRatio * current_world_pos.xy / current_world_pos.w;
+    vec2 prev_device_pos = uDevicePixelRatio * prev_world_pos.xy / prev_world_pos.w;
+    vec2 next_device_pos = uDevicePixelRatio * next_world_pos.xy / next_world_pos.w;
 
-    vec2 tp0 = t0.xy / t0.w;
-    vec2 tp1 = t1.xy / t1.w;
-    vec2 tp2 = t2.xy / t2.w;
-    vec2 tp3 = t3.xy / t3.w;
+    // Get the normals of each of the vectors between the current and next/prev vertices.
+    const float amount = 2.0;
+    vec2 dir_prev = normalize(current_device_pos - prev_device_pos);
+    vec2 dir_next = normalize(current_device_pos - next_device_pos);
+    vec2 norm_prev = vec2(-dir_prev.y,  dir_prev.x);
+    vec2 norm_next = vec2( dir_next.y, -dir_next.x);
 
-    // compute a CSS space aligned bounding box
-    vec2 min_pos = uDevicePixelRatio * min(min(tp0.xy, tp1.xy), min(tp2.xy, tp3.xy));
-    vec2 max_pos = uDevicePixelRatio * max(max(tp0.xy, tp1.xy), max(tp2.xy, tp3.xy));
+    // Push those lines out along the normal by a specific amount of device pixels.
+    vec2 adjusted_prev_p0 = current_device_pos + norm_prev * amount;
+    vec2 adjusted_prev_p1 = prev_device_pos + norm_prev * amount;
+    vec2 adjusted_next_p0 = current_device_pos + norm_next * amount;
+    vec2 adjusted_next_p1 = next_device_pos + norm_next * amount;
 
-    // compute the device space position of this vertex
-    vec2 device_pos = mix(min_pos, max_pos, aPosition.xy);
+    // Intersect those adjusted lines to find the actual vertex position.
+    vec2 device_pos = intersect_lines(adjusted_prev_p0,
+                                      adjusted_prev_p1,
+                                      adjusted_next_p0,
+                                      adjusted_next_p1);
 
-    // compute the point position in side the layer, in CSS space
-    vec4 layer_pos = get_layer_pos(device_pos / uDevicePixelRatio, layer);
+    // Calculate the snap amount based on the first vertex as a reference point.
+    vec4 world_p0 = layer.transform * vec4(local_rect.p0, 0.0, 1.0);
+    vec2 device_p0 = uDevicePixelRatio * world_p0.xy / world_p0.w;
+    vec2 snap_delta = device_p0 - floor(device_p0 + 0.5);
 
-    // apply the task offset
-    vec2 final_pos = device_pos - task.screen_space_origin + task.render_target_origin;
+    // Apply offsets for the render task to get correct screen location.
+    vec2 final_pos = device_pos -
+                     snap_delta -
+                     task.screen_space_origin +
+                     task.render_target_origin;
 
     gl_Position = uTransform * vec4(final_pos, z, 1.0);
 
-    return TransformVertexInfo(layer_pos.xyw, device_pos, clipped_local_rect);
+    vec4 layer_pos = get_layer_pos(device_pos / uDevicePixelRatio, layer);
+
+    return TransformVertexInfo(layer_pos.xyw, device_pos, vec4(instance_rect.p0, instance_rect.size));
 }
 
 #endif //WR_FEATURE_TRANSFORM
 
 struct ResourceRect {
     vec4 uv_rect;
 };
 
@@ -658,30 +710,45 @@ void write_clip(vec2 global_pos, ClipAre
     vec2 texture_size = vec2(textureSize(sCache, 0).xy);
     vec2 uv = global_pos + area.task_bounds.xy - area.screen_origin_target_index.xy;
     vClipMaskUvBounds = area.task_bounds / texture_size.xyxy;
     vClipMaskUv = vec3(uv / texture_size, area.screen_origin_target_index.z);
 }
 #endif //WR_VERTEX_SHADER
 
 #ifdef WR_FRAGMENT_SHADER
-float distance_from_rect(vec2 p, vec2 origin, vec2 size) {
-    vec2 clamped = clamp(p, origin, origin + size);
-    return distance(clamped, p);
+float signed_distance_rect(vec2 pos, vec2 p0, vec2 p1) {
+    vec2 d = max(p0 - pos, pos - p1);
+    return length(max(vec2(0.0), d)) + min(0.0, max(d.x, d.y));
 }
 
 vec2 init_transform_fs(vec3 local_pos, vec4 local_rect, out float fragment_alpha) {
     fragment_alpha = 1.0;
     vec2 pos = local_pos.xy / local_pos.z;
 
-    float border_distance = distance_from_rect(pos, local_rect.xy, local_rect.zw);
-    if (border_distance != 0.0) {
-        float delta = length(fwidth(local_pos.xy));
-        fragment_alpha = 1.0 - smoothstep(0.0, 1.0, border_distance / delta * 2.0);
-    }
+    // Because the local rect is placed on whole coordinates, but the interpolation
+    // occurs at pixel centers, we need to offset the signed distance by that amount.
+    // In the simple case of no zoom, and no transform, this is 0.5. However, we
+    // need to scale this by the amount that the local rect is changing by per
+    // fragment, based on the current zoom and transform.
+    vec2 fw = fwidth(pos.xy);
+    vec2 dxdy = 0.5 * fw;
+
+    // Now get the actual signed distance. Inset the local rect by the offset amount
+    // above to get correct distance values. This ensures that we only apply
+    // anti-aliasing when the fragment has partial coverage.
+    float d = signed_distance_rect(pos,
+                                   local_rect.xy + dxdy,
+                                   local_rect.xy + local_rect.zw - dxdy);
+
+    // Find the appropriate distance to apply the AA smoothstep over.
+    float afwidth = 0.5 / length(fw);
+
+    // Only apply AA to fragments outside the signed distance field.
+    fragment_alpha = 1.0 - smoothstep(0.0, afwidth, d);
 
     return pos;
 }
 
 float do_clip() {
     // anything outside of the mask is considered transparent
     bvec4 inside = lessThanEqual(
         vec4(vClipMaskUvBounds.xy, vClipMaskUv.xy),
--- a/gfx/webrender/res/ps_border.fs.glsl
+++ b/gfx/webrender/res/ps_border.fs.glsl
@@ -51,22 +51,67 @@ float alpha_for_solid_border(float dista
   distance_from_border /= pixels_per_fragment;
 
   // Apply a more gradual fade out to transparent.
   // distance_from_border -= 0.5;
 
   return 1.0 - smoothstep(0.0, 1.0, distance_from_border);
 }
 
+float alpha_for_solid_ellipse_border(vec2 local_pos,
+                                     vec2 inner_radius,
+                                     vec2 outer_radius,
+                                     float pixels_per_fragment) {
+  vec2 distance_from_ref = local_pos - vRefPoint;
+
+  float nudge = pixels_per_fragment;
+  inner_radius += nudge;
+  outer_radius -= nudge;
+
+  float inner_ellipse = distance_from_ref.x * distance_from_ref.x / inner_radius.x / inner_radius.x +
+                        distance_from_ref.y * distance_from_ref.y / inner_radius.y / inner_radius.y;
+  float outer_ellipse = distance_from_ref.x * distance_from_ref.x / outer_radius.x / outer_radius.x +
+                        distance_from_ref.y * distance_from_ref.y / outer_radius.y / outer_radius.y;
+  if (inner_ellipse > 1.0 && outer_ellipse < 1.0) {
+      return 1.0;
+  }
+
+  vec2 offset = step(inner_radius.yx, inner_radius.xy) *
+                (sqrt(abs(inner_radius.x * inner_radius.x - inner_radius.y * inner_radius.y)));
+  vec2 focus1 = vRefPoint + offset;
+  vec2 focus2 = vRefPoint - offset;
+
+  float inner_distance_from_border = max(inner_radius.x, inner_radius.y) -
+                                     (distance(focus1, local_pos) + distance(focus2, local_pos)) / 2.0;
+
+  offset = step(outer_radius.yx, outer_radius.xy) *
+           (sqrt(abs(outer_radius.x * outer_radius.x - outer_radius.y * outer_radius.y)));
+  focus1 = vRefPoint + offset;
+  focus2 = vRefPoint - offset;
+  float outer_distance_from_border = (distance(focus1, local_pos) + distance(focus2, local_pos)) / 2.0 -
+                                     max(outer_radius.x, outer_radius.y);
+
+  float distance_from_border = max(inner_distance_from_border, outer_distance_from_border);
+
+  // Move the distance back into pixels.
+  distance_from_border /= pixels_per_fragment;
+
+  return 1.0 - smoothstep(0.0, 1.0, distance_from_border);
+}
+
 float alpha_for_solid_border_corner(vec2 local_pos,
-                                    float inner_radius,
-                                    float outer_radius,
+                                    vec2 inner_radius,
+                                    vec2 outer_radius,
                                     float pixels_per_fragment) {
-  float distance_from_ref = distance(vRefPoint, local_pos);
-  return alpha_for_solid_border(distance_from_ref, inner_radius, outer_radius, pixels_per_fragment);
+  if (inner_radius.x == inner_radius.y && outer_radius.x == outer_radius.y) {
+    float distance_from_ref = distance(vRefPoint, local_pos);
+    return alpha_for_solid_border(distance_from_ref, inner_radius.x, outer_radius.x, pixels_per_fragment);
+  } else {
+    return alpha_for_solid_ellipse_border(local_pos, inner_radius, outer_radius, pixels_per_fragment);
+  }
 }
 
 vec4 draw_dotted_edge(vec2 local_pos, vec4 piece_rect, float pixels_per_fragment) {
   // We don't use pixels_per_fragment here, since it can change along the edge
   // of a transformed border edge. We want this calculation to be consistent
   // across the entire edge so that the positioning of the dots stays the same.
   float two_pixels = 2.0 * length(fwidth(vLocalPos.xy));
 
@@ -139,18 +184,18 @@ void draw_dashed_or_dotted_border(vec2 l
     case PST_TOP_LEFT:
     case PST_TOP_RIGHT:
     case PST_BOTTOM_LEFT:
     case PST_BOTTOM_RIGHT:
     {
       oFragColor = get_fragment_color(distance_from_mix_line, pixels_per_fragment);
       if (vRadii.x > 0.0) {
         oFragColor *= vec4(1.0, 1.0, 1.0, alpha_for_solid_border_corner(local_pos,
-                                                                  vRadii.z,
-                                                                  vRadii.x,
+                                                                  vRadii.zw,
+                                                                  vRadii.xy,
                                                                   pixels_per_fragment));
       }
 
       break;
     }
     case PST_BOTTOM:
     case PST_TOP: {
       if (vBorderStyle == BORDER_STYLE_DASHED) {
@@ -194,44 +239,47 @@ vec4 draw_double_edge(float pos,
   alpha += alpha_for_solid_border(pos, 0.0, one_third_width, pixels_per_fragment);
   return get_fragment_color(distance_from_mix_line, pixels_per_fragment) * vec4(1.0, 1.0, 1.0, alpha);
 }
 
 vec4 draw_double_edge_vertical(vec2 local_pos,
                                float distance_from_mix_line,
                                float pixels_per_fragment) {
   // Get our position within this specific segment
-  float position = local_pos.x - vLocalRect.x;
-  return draw_double_edge(position, vLocalRect.z, distance_from_mix_line, pixels_per_fragment);
+  float position = abs(local_pos.x - vRefPoint.x);
+  return draw_double_edge(position, abs(vPieceRect.z), distance_from_mix_line, pixels_per_fragment);
 }
 
 vec4 draw_double_edge_horizontal(vec2 local_pos,
                                  float distance_from_mix_line,
                                  float pixels_per_fragment) {
   // Get our position within this specific segment
-  float position = local_pos.y - vLocalRect.y;
-  return draw_double_edge(position, vLocalRect.w, distance_from_mix_line, pixels_per_fragment);
+  float position = abs(local_pos.y - vRefPoint.y);
+  return draw_double_edge(position, abs(vPieceRect.w), distance_from_mix_line, pixels_per_fragment);
 }
 
 vec4 draw_double_edge_corner_with_radius(vec2 local_pos,
                                          float distance_from_mix_line,
                                          float pixels_per_fragment) {
   float total_border_width = vRadii.x - vRadii.z;
   float one_third_width = total_border_width / 3.0;
+  float total_border_height = vRadii.y - vRadii.w;
+  float one_third_height = total_border_height / 3.0;
 
   // Contribution of the outer border segment.
   float alpha = alpha_for_solid_border_corner(local_pos,
-                                              vRadii.x - one_third_width,
-                                              vRadii.x,
+                                              vec2(vRadii.x - one_third_width,
+                                                   vRadii.y - one_third_height),
+                                              vec2(vRadii.x, vRadii.y),
                                               pixels_per_fragment);
 
   // Contribution of the inner border segment.
   alpha += alpha_for_solid_border_corner(local_pos,
-                                         vRadii.z,
-                                         vRadii.z + one_third_width,
+                                         vec2(vRadii.z, vRadii.w),
+                                         vec2(vRadii.z + one_third_width, vRadii.w + one_third_height),
                                          pixels_per_fragment);
   return get_fragment_color(distance_from_mix_line, pixels_per_fragment) * vec4(1.0, 1.0, 1.0, alpha);
 }
 
 vec4 draw_double_edge_corner(vec2 local_pos,
                              float distance_from_mix_line,
                              float pixels_per_fragment) {
   if (vRadii.x > 0.0) {
@@ -286,17 +334,17 @@ void draw_solid_border(float distanceFro
     case PST_TOP_RIGHT:
     case PST_BOTTOM_LEFT:
     case PST_BOTTOM_RIGHT: {
       // This is the conversion factor for transformations and device pixel scaling.
       float pixelsPerFragment = length(fwidth(localPos.xy));
       oFragColor = get_fragment_color(distanceFromMixLine, pixelsPerFragment);
 
       if (vRadii.x > 0.0) {
-        float alpha = alpha_for_solid_border_corner(localPos, vRadii.z, vRadii.x, pixelsPerFragment);
+        float alpha = alpha_for_solid_border_corner(localPos, vRadii.zw, vRadii.xy, pixelsPerFragment);
         oFragColor *= vec4(1.0, 1.0, 1.0, alpha);
       }
 
       break;
     }
     default:
       oFragColor = vHorizontalColor;
       discard_pixels_in_rounded_borders(localPos);
--- a/gfx/webrender/res/ps_box_shadow.fs.glsl
+++ b/gfx/webrender/res/ps_box_shadow.fs.glsl
@@ -1,9 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 void main(void) {
-    vec2 uv = min(vec2(1.0), vMirrorPoint - abs(vUv.xy - vMirrorPoint));
+    // Mirror and stretch the box shadow corner over the entire
+    // primitives.
+    vec2 uv = vMirrorPoint - abs(vUv.xy - vMirrorPoint);
+
+    // Ensure that we don't fetch texels outside the box
+    // shadow corner. This can happen, for example, when
+    // drawing the outer parts of an inset box shadow.
+    uv = clamp(uv, vec2(0.0), vec2(1.0));
+
+    // Map the unit UV to the actual UV rect in the cache.
     uv = mix(vCacheUvRectCoords.xy, vCacheUvRectCoords.zw, uv);
+
+    // Modulate the box shadow by the color.
     oFragColor = vColor * texture(sCache, vec3(uv, vUv.z));
 }
--- a/gfx/webrender/src/clip_scroll_node.rs
+++ b/gfx/webrender/src/clip_scroll_node.rs
@@ -8,17 +8,17 @@ use mask_cache::{ClipSource, MaskCacheIn
 use prim_store::GpuBlock32;
 use renderer::VertexDataStore;
 use spring::{DAMPING, STIFFNESS, Spring};
 use tiling::PackedLayerIndex;
 use util::TransformedRect;
 use webrender_traits::{ClipRegion, LayerPixel, LayerPoint, LayerRect, LayerSize};
 use webrender_traits::{LayerToScrollTransform, LayerToWorldTransform, PipelineId};
 use webrender_traits::{ScrollEventPhase, ScrollLayerId, ScrollLayerRect, ScrollLocation};
-use webrender_traits::{ServoScrollRootId, WorldPoint, WorldPoint4D};
+use webrender_traits::{WorldPoint, WorldPoint4D};
 
 #[cfg(target_os = "macos")]
 const CAN_OVERSCROLL: bool = true;
 
 #[cfg(not(target_os = "macos"))]
 const CAN_OVERSCROLL: bool = false;
 
 #[derive(Clone, Debug)]
@@ -33,37 +33,31 @@ pub struct ClipInfo {
     /// The packed layer index for this node, which is used to render a clip mask
     /// for it, if necessary.
     pub packed_layer_index: PackedLayerIndex,
 
     /// The final transformed rectangle of this clipping region for this node,
     /// which depends on the screen rectangle and the transformation of all of
     /// the parents.
     pub xf_rect: Option<TransformedRect>,
-
-    /// An external identifier that is used to scroll this clipping node
-    /// from the API.
-    pub scroll_root_id: Option<ServoScrollRootId>,
 }
 
 impl ClipInfo {
     pub fn new(clip_region: &ClipRegion,
                clip_store: &mut VertexDataStore<GpuBlock32>,
-               packed_layer_index: PackedLayerIndex,
-               scroll_root_id: Option<ServoScrollRootId>)
+               packed_layer_index: PackedLayerIndex,)
                -> ClipInfo {
         // We pass true here for the MaskCacheInfo because this type of
         // mask needs an extra clip for the clip rectangle.
         let clip_source = ClipSource::Region(clip_region.clone());
         ClipInfo {
             mask_cache_info: MaskCacheInfo::new(&clip_source, true, clip_store),
             clip_source: clip_source,
             packed_layer_index: packed_layer_index,
             xf_rect: None,
-            scroll_root_id: scroll_root_id,
         }
     }
 
     pub fn is_masking(&self) -> bool {
         match self.mask_cache_info {
             Some(ref info) => info.is_masking(),
             _ => false,
         }
@@ -190,16 +184,25 @@ impl ClipScrollNode {
         } else {
             0.0
         };
 
         LayerSize::new(overscroll_x, overscroll_y)
     }
 
     pub fn set_scroll_origin(&mut self, origin: &LayerPoint) -> bool {
+        match self.node_type {
+            NodeType::ReferenceFrame(_) => {
+                warn!("Tried to scroll a reference frame.");
+                return false;
+            }
+            NodeType::Clip(_) => {}
+        };
+
+
         let scrollable_height = self.scrollable_height();
         let scrollable_width = self.scrollable_width();
         if scrollable_height <= 0. && scrollable_width <= 0. {
             return false;
         }
 
         let new_offset = LayerPoint::new((-origin.x).max(-scrollable_width).min(0.0).round(),
                                          (-origin.y).max(-scrollable_height).min(0.0).round());
--- a/gfx/webrender/src/clip_scroll_tree.rs
+++ b/gfx/webrender/src/clip_scroll_tree.rs
@@ -2,25 +2,24 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use clip_scroll_node::{ClipScrollNode, NodeType, ScrollingState};
 use fnv::FnvHasher;
 use std::collections::{HashMap, HashSet};
 use std::hash::BuildHasherDefault;
 use webrender_traits::{LayerPoint, LayerRect, LayerToScrollTransform, LayerToWorldTransform};
-use webrender_traits::{PipelineId, ScrollEventPhase, ScrollLayerId, ScrollLayerInfo};
-use webrender_traits::{ScrollLayerRect, ScrollLayerState, ScrollLocation, ServoScrollRootId};
-use webrender_traits::{WorldPoint, as_scroll_parent_rect};
+use webrender_traits::{PipelineId, ScrollEventPhase, ScrollLayerId, ScrollLayerRect};
+use webrender_traits::{ScrollLayerState, ScrollLocation, WorldPoint, as_scroll_parent_rect};
 
 pub type ScrollStates = HashMap<ScrollLayerId, ScrollingState, BuildHasherDefault<FnvHasher>>;
 
 pub struct ClipScrollTree {
     pub nodes: HashMap<ScrollLayerId, ClipScrollNode, BuildHasherDefault<FnvHasher>>,
-    pub pending_scroll_offsets: HashMap<(PipelineId, ServoScrollRootId), LayerPoint>,
+    pub pending_scroll_offsets: HashMap<ScrollLayerId, LayerPoint>,
 
     /// The ScrollLayerId of the currently scrolling node. Used to allow the same
     /// node to scroll even if a touch operation leaves the boundaries of that node.
     pub current_scroll_layer_id: Option<ScrollLayerId>,
 
     /// The current reference frame id, used for giving a unique id to all new
     /// reference frames. The ClipScrollTree increments this by one every time a
     /// reference frame is created.
@@ -85,17 +84,17 @@ impl ClipScrollTree {
         self.nodes.get(&scroll_layer_id).and_then(|node| {
             for child_layer_id in node.children.iter().rev() {
             if let Some(layer_id) =
                 self.find_scrolling_node_at_point_in_node(cursor, *child_layer_id) {
                     return Some(layer_id);
                 }
             }
 
-            if let ScrollLayerInfo::ReferenceFrame(_) = scroll_layer_id.info {
+            if scroll_layer_id.is_reference_frame() {
                 return None;
             }
 
             if node.ray_intersects_node(cursor) {
                 Some(scroll_layer_id)
             } else {
                 None
             }
@@ -104,79 +103,58 @@ impl ClipScrollTree {
 
     pub fn find_scrolling_node_at_point(&self, cursor: &WorldPoint) -> ScrollLayerId {
         self.find_scrolling_node_at_point_in_node(cursor, self.root_reference_frame_id())
             .unwrap_or(self.topmost_scroll_layer_id())
     }
 
     pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
         let mut result = vec![];
-        for (_, node) in self.nodes.iter() {
+        for (id, node) in self.nodes.iter() {
             match node.node_type {
-                NodeType::Clip(ref info) if info.scroll_root_id.is_some() => {
-                    result.push(ScrollLayerState {
-                        pipeline_id: node.pipeline_id,
-                        scroll_root_id: info.scroll_root_id.unwrap(),
-                        scroll_offset: node.scrolling.offset,
-                    })
-                }
+                NodeType::Clip(_) => result.push(
+                    ScrollLayerState { id: *id, scroll_offset: node.scrolling.offset }),
                 _ => {},
             }
         }
         result
     }
 
     pub fn drain(&mut self) -> ScrollStates {
         self.current_reference_frame_id = 1;
 
         let mut scroll_states = HashMap::with_hasher(Default::default());
         for (layer_id, old_node) in &mut self.nodes.drain() {
-            if !self.pipelines_to_discard.contains(&layer_id.pipeline_id) {
+            if !self.pipelines_to_discard.contains(&layer_id.pipeline_id()) {
                 scroll_states.insert(layer_id, old_node.scrolling);
             }
         }
 
         self.pipelines_to_discard.clear();
         scroll_states
     }
 
-    pub fn scroll_nodes(&mut self,
-                        origin: LayerPoint,
-                        pipeline_id: PipelineId,
-                        scroll_root_id: ServoScrollRootId)
-                        -> bool {
+    pub fn scroll_nodes(&mut self, origin: LayerPoint, id: ScrollLayerId) -> bool {
+        if id.is_reference_frame() {
+            warn!("Tried to scroll a reference frame.");
+            return false;
+        }
+
         if self.nodes.is_empty() {
-            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
+            self.pending_scroll_offsets.insert(id, origin);
             return false;
         }
 
         let origin = LayerPoint::new(origin.x.max(0.0), origin.y.max(0.0));
-
-        let mut scrolled_a_node = false;
-        let mut found_node = false;
-        for (layer_id, node) in self.nodes.iter_mut() {
-            if layer_id.pipeline_id != pipeline_id {
-                continue;
-            }
-
-            match node.node_type {
-                NodeType::Clip(ref info) if info.scroll_root_id != Some(scroll_root_id) => continue,
-                NodeType::ReferenceFrame(..) => continue,
-                NodeType::Clip(_) => {},
-            }
-
-            found_node = true;
-            scrolled_a_node |= node.set_scroll_origin(&origin);
+        if let Some(node) = self.nodes.get_mut(&id) {
+            return node.set_scroll_origin(&origin);
         }
 
-        if !found_node {
-            self.pending_scroll_offsets.insert((pipeline_id, scroll_root_id), origin);
-        }
-
-        scrolled_a_node
+        self.pending_scroll_offsets.insert(id, origin);
+        false
     }
 
     pub fn scroll(&mut self,
                   scroll_location: ScrollLocation,
                   cursor: WorldPoint,
                   phase: ScrollEventPhase)
                   -> bool {
         if self.nodes.is_empty() {
@@ -239,47 +217,17 @@ impl ClipScrollTree {
         };
 
         let scroll_layer_id = if switch_node {
             topmost_scroll_layer_id
         } else {
             scroll_layer_id
         };
 
-        // TODO(mrobinson): Once we remove the concept of shared scroll root ids we can remove
-        // this entirely and just scroll the node based on the ScrollLayerId.
-        let scroll_root_id = {
-            let node = self.nodes.get_mut(&scroll_layer_id).unwrap();
-            let scroll_root_id = match node.node_type {
-                NodeType::Clip(ref info) => info.scroll_root_id,
-                NodeType::ReferenceFrame(..) => unreachable!("Tried to scroll a reference frame."),
-            };
-
-            if scroll_root_id.is_none() {
-                return node.scroll(scroll_location, phase);
-            }
-
-            scroll_root_id
-        };
-
-        let mut scrolled_a_node = false;
-        for (layer_id, node) in self.nodes.iter_mut() {
-            if layer_id.pipeline_id != scroll_layer_id.pipeline_id {
-                continue;
-            }
-
-            match node.node_type {
-                NodeType::Clip(ref info) if info.scroll_root_id == scroll_root_id => { }
-                _ => continue,
-            }
-
-            let scrolled_this_node = node.scroll(scroll_location, phase);
-            scrolled_a_node = scrolled_a_node || scrolled_this_node;
-        }
-        scrolled_a_node
+        self.nodes.get_mut(&scroll_layer_id).unwrap().scroll(scroll_location, phase)
     }
 
     pub fn update_all_node_transforms(&mut self, pan: LayerPoint) {
         if self.nodes.is_empty() {
             return;
         }
 
         let root_reference_frame_id = self.root_reference_frame_id();
@@ -346,42 +294,32 @@ impl ClipScrollTree {
         for (scroll_layer_id, node) in &mut self.nodes {
             let scrolling_state = match old_states.get(&scroll_layer_id) {
                 Some(old_scrolling_state) => *old_scrolling_state,
                 None => ScrollingState::new(),
             };
 
             node.finalize(&scrolling_state);
 
-            let scroll_root_id = match node.node_type {
-                NodeType::Clip(ref info) if info.scroll_root_id.is_some() =>
-                    info.scroll_root_id.unwrap(),
-                _ => continue,
-            };
-
-
-            let pipeline_id = scroll_layer_id.pipeline_id;
-            if let Some(pending_offset) =
-                self.pending_scroll_offsets.remove(&(pipeline_id, scroll_root_id)) {
+            if let Some(pending_offset) = self.pending_scroll_offsets.remove(&scroll_layer_id) {
                 node.set_scroll_origin(&pending_offset);
             }
         }
 
     }
 
     pub fn add_reference_frame(&mut self,
                                rect: &LayerRect,
                                transform: &LayerToScrollTransform,
                                pipeline_id: PipelineId,
                                parent_id: Option<ScrollLayerId>)
                                -> ScrollLayerId {
-        let reference_frame_id = ScrollLayerId {
-            pipeline_id: pipeline_id,
-            info: ScrollLayerInfo::ReferenceFrame(self.current_reference_frame_id),
-        };
+
+        let reference_frame_id =
+            ScrollLayerId::ReferenceFrame(self.current_reference_frame_id, pipeline_id);
         self.current_reference_frame_id += 1;
 
         let node = ClipScrollNode::new_reference_frame(parent_id,
                                                        &rect,
                                                        rect.size,
                                                        &transform,
                                                        pipeline_id);
         self.add_node(node, reference_frame_id);
@@ -398,14 +336,14 @@ impl ClipScrollTree {
         debug_assert!(!self.nodes.contains_key(&id));
         self.nodes.insert(id, node);
     }
 
     pub fn discard_frame_state_for_pipeline(&mut self, pipeline_id: PipelineId) {
         self.pipelines_to_discard.insert(pipeline_id);
 
         match self.current_scroll_layer_id {
-            Some(id) if id.pipeline_id == pipeline_id => self.current_scroll_layer_id = None,
+            Some(id) if id.pipeline_id() == pipeline_id => self.current_scroll_layer_id = None,
             _ => {}
         }
     }
 }
 
--- a/gfx/webrender/src/debug_render.rs
+++ b/gfx/webrender/src/debug_render.rs
@@ -156,17 +156,17 @@ impl DebugRenderer {
         let color1 = PackedColor::from_color(color1);
         self.line_vertices.push(DebugColorVertex::new(x0 as f32, y0 as f32, color0));
         self.line_vertices.push(DebugColorVertex::new(x1 as f32, y1 as f32, color1));
     }
 
     pub fn render(&mut self,
                   device: &mut Device,
                   viewport_size: &DeviceUintSize) {
-        let _gm = GpuMarker::new("debug");
+        let _gm = GpuMarker::new(device.rc_gl(), "debug");
         device.disable_depth();
         device.set_blend(true);
         device.set_blend_mode_alpha();
 
         let projection = Matrix4D::ortho(0.0,
                                          viewport_size.width as f32,
                                          viewport_size.height as f32,
                                          0.0,
--- a/gfx/webrender/src/device.rs
+++ b/gfx/webrender/src/device.rs
@@ -12,41 +12,38 @@ use internal_types::{DebugFontVertex, De
 use super::shader_source;
 use std::collections::HashMap;
 use std::fs::File;
 use std::hash::BuildHasherDefault;
 use std::io::Read;
 use std::iter::repeat;
 use std::mem;
 use std::path::PathBuf;
+use std::rc::Rc;
 //use std::sync::mpsc::{channel, Sender};
 //use std::thread;
 use webrender_traits::{ColorF, ImageFormat};
 use webrender_traits::{DeviceIntPoint, DeviceIntRect, DeviceIntSize, DeviceUintSize};
 
 #[derive(Debug, Copy, Clone)]
 pub struct FrameId(usize);
 
 #[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
 const GL_FORMAT_A: gl::GLuint = gl::RED;
 
 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
 const GL_FORMAT_A: gl::GLuint = gl::ALPHA;
 
-#[cfg(any(target_os = "windows", all(unix, not(target_os = "android"))))]
-const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA;
+const GL_FORMAT_BGRA_GL: gl::GLuint = gl::BGRA;
 
-#[cfg(target_os = "android")]
-const GL_FORMAT_BGRA: gl::GLuint = gl::BGRA_EXT;
+const GL_FORMAT_BGRA_GLES: gl::GLuint = gl::BGRA_EXT;
 
-#[cfg(not(any(target_arch = "arm", target_arch = "aarch64")))]
-const SHADER_VERSION: &'static str = "#version 150\n";
+const SHADER_VERSION_GL: &'static str = "#version 150\n";
 
-#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
-const SHADER_VERSION: &'static str = "#version 300 es\n";
+const SHADER_VERSION_GLES: &'static str = "#version 300 es\n";
 
 static SHADER_PREAMBLE: &'static str = "shared";
 
 #[repr(u32)]
 pub enum DepthFunction {
     Less = gl::LESS,
 }
 
@@ -73,16 +70,38 @@ pub enum VertexFormat {
     Clip,
 }
 
 enum FBOTarget {
     Read,
     Draw,
 }
 
+fn get_gl_format_bgra(gl: &gl::Gl) -> gl::GLuint {
+    match gl.get_type() {
+        gl::GlType::Gl => {
+            GL_FORMAT_BGRA_GL
+        }
+        gl::GlType::Gles => {
+            GL_FORMAT_BGRA_GLES
+        }
+    }
+}
+
+fn get_shader_version(gl: &gl::Gl) -> &'static str {
+    match gl.get_type() {
+        gl::GlType::Gl => {
+            SHADER_VERSION_GL
+        }
+        gl::GlType::Gles => {
+            SHADER_VERSION_GLES
+        }
+    }
+}
+
 fn get_optional_shader_source(shader_name: &str, base_path: &Option<PathBuf>) -> Option<String> {
     if let Some(ref base) = *base_path {
         let shader_path = base.join(&format!("{}.glsl", shader_name));
         if shader_path.exists() {
             let mut source = String::new();
             File::open(&shader_path).unwrap().read_to_string(&mut source).unwrap();
             return Some(source);
         }
@@ -96,198 +115,198 @@ fn get_shader_source(shader_name: &str, 
         .expect(&format!("Couldn't get required shader: {}", shader_name))
 }
 
 pub trait FileWatcherHandler : Send {
     fn file_changed(&self, path: PathBuf);
 }
 
 impl VertexFormat {
-    fn bind(&self, main: VBOId, instance: VBOId, offset: gl::GLuint, instance_stride: gl::GLint) {
-        main.bind();
+    fn bind(&self, gl: &gl::Gl, main: VBOId, instance: VBOId, offset: gl::GLuint, instance_stride: gl::GLint) {
+        main.bind(gl);
 
         match *self {
             VertexFormat::DebugFont => {
-                gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
-                gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint);
-                gl::enable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint);
+                gl.enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
+                gl.enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint);
+                gl.enable_vertex_attrib_array(VertexAttribute::ColorTexCoord as gl::GLuint);
 
-                gl::vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
-                gl::vertex_attrib_divisor(VertexAttribute::Color as gl::GLuint, 0);
-                gl::vertex_attrib_divisor(VertexAttribute::ColorTexCoord as gl::GLuint, 0);
+                gl.vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
+                gl.vertex_attrib_divisor(VertexAttribute::Color as gl::GLuint, 0);
+                gl.vertex_attrib_divisor(VertexAttribute::ColorTexCoord as gl::GLuint, 0);
 
                 let vertex_stride = mem::size_of::<DebugFontVertex>() as gl::GLuint;
 
-                gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
+                gl.vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
                                           2,
                                           gl::FLOAT,
                                           false,
                                           vertex_stride as gl::GLint,
                                           0 + vertex_stride * offset);
-                gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint,
+                gl.vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint,
                                           4,
                                           gl::UNSIGNED_BYTE,
                                           true,
                                           vertex_stride as gl::GLint,
                                           8 + vertex_stride * offset);
-                gl::vertex_attrib_pointer(VertexAttribute::ColorTexCoord as gl::GLuint,
+                gl.vertex_attrib_pointer(VertexAttribute::ColorTexCoord as gl::GLuint,
                                           2,
                                           gl::FLOAT,
                                           false,
                                           vertex_stride as gl::GLint,
                                           12 + vertex_stride * offset);
             }
             VertexFormat::DebugColor => {
-                gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
-                gl::enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint);
+                gl.enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
+                gl.enable_vertex_attrib_array(VertexAttribute::Color as gl::GLuint);
 
-                gl::vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
-                gl::vertex_attrib_divisor(VertexAttribute::Color as gl::GLuint, 0);
+                gl.vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
+                gl.vertex_attrib_divisor(VertexAttribute::Color as gl::GLuint, 0);
 
                 let vertex_stride = mem::size_of::<DebugColorVertex>() as gl::GLuint;
 
-                gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
+                gl.vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
                                           2,
                                           gl::FLOAT,
                                           false,
                                           vertex_stride as gl::GLint,
                                           0 + vertex_stride * offset);
-                gl::vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint,
+                gl.vertex_attrib_pointer(VertexAttribute::Color as gl::GLuint,
                                           4,
                                           gl::UNSIGNED_BYTE,
                                           true,
                                           vertex_stride as gl::GLint,
                                           8 + vertex_stride * offset);
             }
             VertexFormat::Rectangles |
             VertexFormat::Triangles => {
                 let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
-                gl::enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
-                gl::vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
+                gl.enable_vertex_attrib_array(VertexAttribute::Position as gl::GLuint);
+                gl.vertex_attrib_divisor(VertexAttribute::Position as gl::GLuint, 0);
 
-                gl::vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
+                gl.vertex_attrib_pointer(VertexAttribute::Position as gl::GLuint,
                                           2,
                                           gl::FLOAT,
                                           false,
                                           vertex_stride as gl::GLint,
                                           0);
 
-                instance.bind();
+                instance.bind(gl);
                 let mut offset = 0;
 
                 for &attrib in [VertexAttribute::GlobalPrimId,
                                 VertexAttribute::PrimitiveAddress,
                                 VertexAttribute::TaskIndex,
                                 VertexAttribute::ClipTaskIndex,
                                 VertexAttribute::LayerIndex,
                                 VertexAttribute::ElementIndex,
                                 VertexAttribute::ZIndex,
                                ].into_iter() {
-                    gl::enable_vertex_attrib_array(attrib as gl::GLuint);
-                    gl::vertex_attrib_divisor(attrib as gl::GLuint, 1);
-                    gl::vertex_attrib_i_pointer(attrib as gl::GLuint,
+                    gl.enable_vertex_attrib_array(attrib as gl::GLuint);
+                    gl.vertex_attrib_divisor(attrib as gl::GLuint, 1);
+                    gl.vertex_attrib_i_pointer(attrib as gl::GLuint,
                                                 1,
                                                 gl::INT,
                                                 instance_stride,
                                                 offset);
                     offset += 4;
                 }
 
-                gl::enable_vertex_attrib_array(VertexAttribute::UserData as gl::GLuint);
-                gl::vertex_attrib_divisor(VertexAttribute::UserData as gl::GLuint, 1);
-                gl::vertex_attrib_i_pointer(VertexAttribute::UserData as gl::GLuint,
+                gl.enable_vertex_attrib_array(VertexAttribute::UserData as gl::GLuint);
+                gl.vertex_attrib_divisor(VertexAttribute::UserData as gl::GLuint, 1);
+                gl.vertex_attrib_i_pointer(VertexAttribute::UserData as gl::GLuint,
                                             2,
                                             gl::INT,
                                             instance_stride,
                                             offset);
             }
             VertexFormat::Clear => {
                 let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
-                gl::enable_vertex_attrib_array(ClearAttribute::Position as gl::GLuint);
-                gl::vertex_attrib_divisor(ClearAttribute::Position as gl::GLuint, 0);
+                gl.enable_vertex_attrib_array(ClearAttribute::Position as gl::GLuint);
+                gl.vertex_attrib_divisor(ClearAttribute::Position as gl::GLuint, 0);
 
-                gl::vertex_attrib_pointer(ClearAttribute::Position as gl::GLuint,
+                gl.vertex_attrib_pointer(ClearAttribute::Position as gl::GLuint,
                                           2,
                                           gl::FLOAT,
                                           false,
                                           vertex_stride as gl::GLint,
                                           0);
 
-                instance.bind();
+                instance.bind(gl);
 
-                gl::enable_vertex_attrib_array(ClearAttribute::Rectangle as gl::GLuint);
-                gl::vertex_attrib_divisor(ClearAttribute::Rectangle as gl::GLuint, 1);
-                gl::vertex_attrib_i_pointer(ClearAttribute::Rectangle as gl::GLuint,
+                gl.enable_vertex_attrib_array(ClearAttribute::Rectangle as gl::GLuint);
+                gl.vertex_attrib_divisor(ClearAttribute::Rectangle as gl::GLuint, 1);
+                gl.vertex_attrib_i_pointer(ClearAttribute::Rectangle as gl::GLuint,
                                             4,
                                             gl::INT,
                                             instance_stride,
                                             0);
             }
             VertexFormat::Blur => {
                 let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
-                gl::enable_vertex_attrib_array(BlurAttribute::Position as gl::GLuint);
-                gl::vertex_attrib_divisor(BlurAttribute::Position as gl::GLuint, 0);
+                gl.enable_vertex_attrib_array(BlurAttribute::Position as gl::GLuint);
+                gl.vertex_attrib_divisor(BlurAttribute::Position as gl::GLuint, 0);
 
-                gl::vertex_attrib_pointer(BlurAttribute::Position as gl::GLuint,
+                gl.vertex_attrib_pointer(BlurAttribute::Position as gl::GLuint,
                                           2,
                                           gl::FLOAT,
                                           false,
                                           vertex_stride as gl::GLint,
                                           0);
 
-                instance.bind();
+                instance.bind(gl);
 
                 for (i, &attrib) in [BlurAttribute::RenderTaskIndex,
                                      BlurAttribute::SourceTaskIndex,
                                      BlurAttribute::Direction,
                                     ].into_iter().enumerate() {
-                    gl::enable_vertex_attrib_array(attrib as gl::GLuint);
-                    gl::vertex_attrib_divisor(attrib as gl::GLuint, 1);
-                    gl::vertex_attrib_i_pointer(attrib as gl::GLuint,
+                    gl.enable_vertex_attrib_array(attrib as gl::GLuint);
+                    gl.vertex_attrib_divisor(attrib as gl::GLuint, 1);
+                    gl.vertex_attrib_i_pointer(attrib as gl::GLuint,
                                                 1,
                                                 gl::INT,
                                                 instance_stride,
                                                 (i * 4) as gl::GLuint);
                 }
             }
             VertexFormat::Clip => {
                 let vertex_stride = mem::size_of::<PackedVertex>() as gl::GLuint;
-                gl::enable_vertex_attrib_array(ClipAttribute::Position as gl::GLuint);
-                gl::vertex_attrib_divisor(ClipAttribute::Position as gl::GLuint, 0);
+                gl.enable_vertex_attrib_array(ClipAttribute::Position as gl::GLuint);
+                gl.vertex_attrib_divisor(ClipAttribute::Position as gl::GLuint, 0);
 
-                gl::vertex_attrib_pointer(ClipAttribute::Position as gl::GLuint,
+                gl.vertex_attrib_pointer(ClipAttribute::Position as gl::GLuint,
                                           2,
                                           gl::FLOAT,
                                           false,
                                           vertex_stride as gl::GLint,
                                           0);
 
-                instance.bind();
+                instance.bind(gl);
 
                 for (i, &attrib) in [ClipAttribute::RenderTaskIndex,
                                      ClipAttribute::LayerIndex,
                                      ClipAttribute::DataIndex,
                                      ClipAttribute::SegmentIndex,
                                     ].into_iter().enumerate() {
-                    gl::enable_vertex_attrib_array(attrib as gl::GLuint);
-                    gl::vertex_attrib_divisor(attrib as gl::GLuint, 1);
-                    gl::vertex_attrib_i_pointer(attrib as gl::GLuint,
+                    gl.enable_vertex_attrib_array(attrib as gl::GLuint);
+                    gl.vertex_attrib_divisor(attrib as gl::GLuint, 1);
+                    gl.vertex_attrib_i_pointer(attrib as gl::GLuint,
                                                 1,
                                                 gl::INT,
                                                 instance_stride,
                                                 (i * 4) as gl::GLuint);
                 }
             }
         }
     }
 }
 
 impl TextureId {
-    pub fn bind(&self) {
-        gl::bind_texture(self.target, self.name);
+    pub fn bind(&self, gl: &gl::Gl) {
+        gl.bind_texture(self.target, self.name);
     }
 
     pub fn new(name: gl::GLuint) -> TextureId {
         TextureId {
             name: name,
             target: gl::TEXTURE_2D,
         }
     }
@@ -298,167 +317,170 @@ impl TextureId {
             target: gl::TEXTURE_2D,
         }
     }
 
     pub fn is_valid(&self) -> bool { *self != TextureId::invalid() }
 }
 
 impl ProgramId {
-    fn bind(&self) {
-        gl::use_program(self.0);
+    fn bind(&self, gl: &gl::Gl) {
+        gl.use_program(self.0);
     }
 }
 
 impl VBOId {
-    fn bind(&self) {
-        gl::bind_buffer(gl::ARRAY_BUFFER, self.0);
+    fn bind(&self, gl: &gl::Gl) {
+        gl.bind_buffer(gl::ARRAY_BUFFER, self.0);
     }
 }
 
 impl IBOId {
-    fn bind(&self) {
-        gl::bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.0);
+    fn bind(&self, gl: &gl::Gl) {
+        gl.bind_buffer(gl::ELEMENT_ARRAY_BUFFER, self.0);
     }
 }
 
 impl UBOId {
-    fn _bind(&self) {
-        gl::bind_buffer(gl::UNIFORM_BUFFER, self.0);
+    fn _bind(&self, gl: &gl::Gl) {
+        gl.bind_buffer(gl::UNIFORM_BUFFER, self.0);
     }
 }
 
 impl FBOId {
-    fn bind(&self, target: FBOTarget) {
+    fn bind(&self, gl: &gl::Gl, target: FBOTarget) {
         let target = match target {
             FBOTarget::Read => gl::READ_FRAMEBUFFER,
             FBOTarget::Draw => gl::DRAW_FRAMEBUFFER,
         };
-        gl::bind_framebuffer(target, self.0);
+        gl.bind_framebuffer(target, self.0);
     }
 }
 
 struct Texture {
+    gl: Rc<gl::Gl>,
     id: gl::GLuint,
     format: ImageFormat,
     width: u32,
     height: u32,
     filter: TextureFilter,
     mode: RenderTargetMode,
     fbo_ids: Vec<FBOId>,
 }
 
 impl Drop for Texture {
     fn drop(&mut self) {
         if !self.fbo_ids.is_empty() {
             let fbo_ids: Vec<_> = self.fbo_ids.iter().map(|&FBOId(fbo_id)| fbo_id).collect();
-            gl::delete_framebuffers(&fbo_ids[..]);
+            self.gl.delete_framebuffers(&fbo_ids[..]);
         }
-        gl::delete_textures(&[self.id]);
+        self.gl.delete_textures(&[self.id]);
     }
 }
 
 struct Program {
+    gl: Rc<gl::Gl>,
     id: gl::GLuint,
     u_transform: gl::GLint,
     u_device_pixel_ratio: gl::GLint,
     name: String,
     vs_source: String,
     fs_source: String,
     prefix: Option<String>,
     vs_id: Option<gl::GLuint>,
     fs_id: Option<gl::GLuint>,
 }
 
 impl Program {
     fn attach_and_bind_shaders(&mut self,
                                vs_id: gl::GLuint,
                                fs_id: gl::GLuint,
                                vertex_format: VertexFormat) -> Result<(), ShaderError> {
-        gl::attach_shader(self.id, vs_id);
-        gl::attach_shader(self.id, fs_id);
+        self.gl.attach_shader(self.id, vs_id);
+        self.gl.attach_shader(self.id, fs_id);
 
         match vertex_format {
             VertexFormat::Triangles | VertexFormat::Rectangles |
             VertexFormat::DebugFont |  VertexFormat::DebugColor => {
-                gl::bind_attrib_location(self.id, VertexAttribute::Position as gl::GLuint, "aPosition");
-                gl::bind_attrib_location(self.id, VertexAttribute::Color as gl::GLuint, "aColor");
-                gl::bind_attrib_location(self.id, VertexAttribute::ColorTexCoord as gl::GLuint, "aColorTexCoord");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::Position as gl::GLuint, "aPosition");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::Color as gl::GLuint, "aColor");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::ColorTexCoord as gl::GLuint, "aColorTexCoord");
 
-                gl::bind_attrib_location(self.id, VertexAttribute::GlobalPrimId as gl::GLuint, "aGlobalPrimId");
-                gl::bind_attrib_location(self.id, VertexAttribute::PrimitiveAddress as gl::GLuint, "aPrimitiveAddress");
-                gl::bind_attrib_location(self.id, VertexAttribute::TaskIndex as gl::GLuint, "aTaskIndex");
-                gl::bind_attrib_location(self.id, VertexAttribute::ClipTaskIndex as gl::GLuint, "aClipTaskIndex");
-                gl::bind_attrib_location(self.id, VertexAttribute::LayerIndex as gl::GLuint, "aLayerIndex");
-                gl::bind_attrib_location(self.id, VertexAttribute::ElementIndex as gl::GLuint, "aElementIndex");
-                gl::bind_attrib_location(self.id, VertexAttribute::UserData as gl::GLuint, "aUserData");
-                gl::bind_attrib_location(self.id, VertexAttribute::ZIndex as gl::GLuint, "aZIndex");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::GlobalPrimId as gl::GLuint, "aGlobalPrimId");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::PrimitiveAddress as gl::GLuint, "aPrimitiveAddress");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::TaskIndex as gl::GLuint, "aTaskIndex");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::ClipTaskIndex as gl::GLuint, "aClipTaskIndex");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::LayerIndex as gl::GLuint, "aLayerIndex");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::ElementIndex as gl::GLuint, "aElementIndex");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::UserData as gl::GLuint, "aUserData");
+                self.gl.bind_attrib_location(self.id, VertexAttribute::ZIndex as gl::GLuint, "aZIndex");
             }
             VertexFormat::Clear => {
-                gl::bind_attrib_location(self.id, ClearAttribute::Position as gl::GLuint, "aPosition");
-                gl::bind_attrib_location(self.id, ClearAttribute::Rectangle as gl::GLuint, "aClearRectangle");
+                self.gl.bind_attrib_location(self.id, ClearAttribute::Position as gl::GLuint, "aPosition");
+                self.gl.bind_attrib_location(self.id, ClearAttribute::Rectangle as gl::GLuint, "aClearRectangle");
             }
             VertexFormat::Blur => {
-                gl::bind_attrib_location(self.id, BlurAttribute::Position as gl::GLuint, "aPosition");
-                gl::bind_attrib_location(self.id, BlurAttribute::RenderTaskIndex as gl::GLuint, "aBlurRenderTaskIndex");
-                gl::bind_attrib_location(self.id, BlurAttribute::SourceTaskIndex as gl::GLuint, "aBlurSourceTaskIndex");
-                gl::bind_attrib_location(self.id, BlurAttribute::Direction as gl::GLuint, "aBlurDirection");
+                self.gl.bind_attrib_location(self.id, BlurAttribute::Position as gl::GLuint, "aPosition");
+                self.gl.bind_attrib_location(self.id, BlurAttribute::RenderTaskIndex as gl::GLuint, "aBlurRenderTaskIndex");
+                self.gl.bind_attrib_location(self.id, BlurAttribute::SourceTaskIndex as gl::GLuint, "aBlurSourceTaskIndex");
+                self.gl.bind_attrib_location(self.id, BlurAttribute::Direction as gl::GLuint, "aBlurDirection");
             }
             VertexFormat::Clip => {
-                gl::bind_attrib_location(self.id, ClipAttribute::Position as gl::GLuint, "aPosition");
-                gl::bind_attrib_location(self.id, ClipAttribute::RenderTaskIndex as gl::GLuint, "aClipRenderTaskIndex");
-                gl::bind_attrib_location(self.id, ClipAttribute::LayerIndex as gl::GLuint, "aClipLayerIndex");
-                gl::bind_attrib_location(self.id, ClipAttribute::DataIndex as gl::GLuint, "aClipDataIndex");
-                gl::bind_attrib_location(self.id, ClipAttribute::SegmentIndex as gl::GLuint, "aClipSegmentIndex");
+                self.gl.bind_attrib_location(self.id, ClipAttribute::Position as gl::GLuint, "aPosition");
+                self.gl.bind_attrib_location(self.id, ClipAttribute::RenderTaskIndex as gl::GLuint, "aClipRenderTaskIndex");
+                self.gl.bind_attrib_location(self.id, ClipAttribute::LayerIndex as gl::GLuint, "aClipLayerIndex");
+                self.gl.bind_attrib_location(self.id, ClipAttribute::DataIndex as gl::GLuint, "aClipDataIndex");
+                self.gl.bind_attrib_location(self.id, ClipAttribute::SegmentIndex as gl::GLuint, "aClipSegmentIndex");
             }
         }
 
-        gl::link_program(self.id);
-        if gl::get_program_iv(self.id, gl::LINK_STATUS) == (0 as gl::GLint) {
-            let error_log = gl::get_program_info_log(self.id);
+        self.gl.link_program(self.id);
+        if self.gl.get_program_iv(self.id, gl::LINK_STATUS) == (0 as gl::GLint) {
+            let error_log = self.gl.get_program_info_log(self.id);
             println!("Failed to link shader program: {}", error_log);
-            gl::detach_shader(self.id, vs_id);
-            gl::detach_shader(self.id, fs_id);
+            self.gl.detach_shader(self.id, vs_id);
+            self.gl.detach_shader(self.id, fs_id);
             return Err(ShaderError::Link(error_log));
         }
 
         Ok(())
     }
 }
 
 impl Drop for Program {
     fn drop(&mut self) {
-        gl::delete_program(self.id);
+        self.gl.delete_program(self.id);
     }
 }
 
 struct VAO {
+    gl: Rc<gl::Gl>,
     id: gl::GLuint,
     ibo_id: IBOId,
     main_vbo_id: VBOId,
     instance_vbo_id: VBOId,
     instance_stride: gl::GLint,
     owns_indices: bool,
     owns_vertices: bool,
     owns_instances: bool,
 }
 
 impl Drop for VAO {
     fn drop(&mut self) {
-        gl::delete_vertex_arrays(&[self.id]);
+        self.gl.delete_vertex_arrays(&[self.id]);
 
         if self.owns_indices {
             // todo(gw): maybe make these their own type with hashmap?
-            gl::delete_buffers(&[self.ibo_id.0]);
+            self.gl.delete_buffers(&[self.ibo_id.0]);
         }
         if self.owns_vertices {
-            gl::delete_buffers(&[self.main_vbo_id.0]);
+            self.gl.delete_buffers(&[self.main_vbo_id.0]);
         }
         if self.owns_instances {
-            gl::delete_buffers(&[self.instance_vbo_id.0])
+            self.gl.delete_buffers(&[self.instance_vbo_id.0])
         }
     }
 }
 
 #[derive(PartialEq, Eq, Hash, PartialOrd, Ord, Debug, Copy, Clone)]
 pub struct TextureId {
     name: gl::GLuint,
     target: gl::GLuint,
@@ -491,142 +513,167 @@ pub trait NamedTag {
 
 #[derive(Debug, Clone)]
 pub struct GpuSample<T> {
     pub tag: T,
     pub time_ns: u64,
 }
 
 pub struct GpuFrameProfile<T> {
+    gl: Rc<gl::Gl>,
     queries: Vec<gl::GLuint>,
     samples: Vec<GpuSample<T>>,
     next_query: usize,
     pending_query: gl::GLuint,
     frame_id: FrameId,
 }
 
 impl<T> GpuFrameProfile<T> {
-    #[cfg(not(target_os = "android"))]
-    fn new() -> GpuFrameProfile<T> {
-        let queries = gl::gen_queries(MAX_EVENTS_PER_FRAME as gl::GLint);
-
-        GpuFrameProfile {
-            queries: queries,
-            samples: Vec::new(),
-            next_query: 0,
-            pending_query: 0,
-            frame_id: FrameId(0),
-        }
-    }
-
-    #[cfg(target_os = "android")]
-    fn new() -> GpuFrameProfile<T> {
-        GpuFrameProfile {
-            queries: Vec::new(),
-            samples: Vec::new(),
-            next_query: 0,
-            pending_query: 0,
-            frame_id: FrameId(0),
+    fn new(gl: Rc<gl::Gl>) -> GpuFrameProfile<T> {
+        match gl.get_type() {
+            gl::GlType::Gl => {
+                let queries = gl.gen_queries(MAX_EVENTS_PER_FRAME as gl::GLint);
+                GpuFrameProfile {
+                    gl: gl,
+                    queries: queries,
+                    samples: Vec::new(),
+                    next_query: 0,
+                    pending_query: 0,
+                    frame_id: FrameId(0),
+                }
+            }
+            gl::GlType::Gles => {
+                GpuFrameProfile {
+                    gl: gl,
+                    queries: Vec::new(),
+                    samples: Vec::new(),
+                    next_query: 0,
+                    pending_query: 0,
+                    frame_id: FrameId(0),
+                }
+            }
         }
     }
 
     fn begin_frame(&mut self, frame_id: FrameId) {
         self.frame_id = frame_id;
         self.next_query = 0;
         self.pending_query = 0;
         self.samples.clear();
     }
 
-    #[cfg(not(target_os = "android"))]
     fn end_frame(&mut self) {
-        if self.pending_query != 0 {
-            gl::end_query(gl::TIME_ELAPSED);
+        match self.gl.get_type() {
+            gl::GlType::Gl => {
+                if self.pending_query != 0 {
+                    self.gl.end_query(gl::TIME_ELAPSED);
+                }
+            }
+            gl::GlType::Gles => {},
         }
     }
 
-    #[cfg(target_os = "android")]
-    fn end_frame(&mut self) {
+    fn add_marker(&mut self, tag: T) -> GpuMarker
+    where T: NamedTag {
+        match self.gl.get_type() {
+            gl::GlType::Gl => {
+                self.add_marker_gl(tag)
+            }
+            gl::GlType::Gles => {
+                self.add_marker_gles(tag)
+            }
+        }
     }
 
-    #[cfg(not(target_os = "android"))]
-    fn add_marker(&mut self, tag: T) -> GpuMarker
+    fn add_marker_gl(&mut self, tag: T) -> GpuMarker
     where T: NamedTag {
         if self.pending_query != 0 {
-            gl::end_query(gl::TIME_ELAPSED);
+            self.gl.end_query(gl::TIME_ELAPSED);
         }
 
-        let marker = GpuMarker::new(tag.get_label());
+        let marker = GpuMarker::new(&self.gl, tag.get_label());
 
         if self.next_query < MAX_EVENTS_PER_FRAME {
             self.pending_query = self.queries[self.next_query];
-            gl::begin_query(gl::TIME_ELAPSED, self.pending_query);
+            self.gl.begin_query(gl::TIME_ELAPSED, self.pending_query);
             self.samples.push(GpuSample {
                 tag: tag,
                 time_ns: 0,
             });
         } else {
             self.pending_query = 0;
         }
 
         self.next_query += 1;
         marker
     }
 
-    #[cfg(target_os = "android")]
-    fn add_marker(&mut self, tag: T) {
+    fn add_marker_gles(&mut self, tag: T) -> GpuMarker
+    where T: NamedTag {
+        let marker = GpuMarker::new(&self.gl, tag.get_label());
         self.samples.push(GpuSample {
             tag: tag,
             time_ns: 0,
         });
+        marker
     }
 
     fn is_valid(&self) -> bool {
         self.next_query > 0 && self.next_query <= MAX_EVENTS_PER_FRAME
     }
 
-    #[cfg(not(target_os = "android"))]
     fn build_samples(&mut self) -> Vec<GpuSample<T>> {
+        match self.gl.get_type() {
+            gl::GlType::Gl => {
+                self.build_samples_gl()
+            }
+            gl::GlType::Gles => {
+                self.build_samples_gles()
+            }
+        }
+    }
+
+    fn build_samples_gl(&mut self) -> Vec<GpuSample<T>> {
         for (index, sample) in self.samples.iter_mut().enumerate() {
-            sample.time_ns = gl::get_query_object_ui64v(self.queries[index], gl::QUERY_RESULT)
+            sample.time_ns = self.gl.get_query_object_ui64v(self.queries[index], gl::QUERY_RESULT)
         }
 
         mem::replace(&mut self.samples, Vec::new())
     }
 
-    #[cfg(target_os = "android")]
-    fn build_samples(&mut self) -> Vec<GpuSample<T>> {
+    fn build_samples_gles(&mut self) -> Vec<GpuSample<T>> {
         mem::replace(&mut self.samples, Vec::new())
     }
 }
 
 impl<T> Drop for GpuFrameProfile<T> {
-    #[cfg(not(target_os = "android"))]
     fn drop(&mut self) {
-        gl::delete_queries(&self.queries);
-    }
-
-    #[cfg(target_os = "android")]
-    fn drop(&mut self) {
+        match self.gl.get_type() {
+            gl::GlType::Gl =>  {
+                self.gl.delete_queries(&self.queries);
+            }
+            gl::GlType::Gles => {},
+        }
     }
 }
 
 pub struct GpuProfiler<T> {
     frames: [GpuFrameProfile<T>; MAX_PROFILE_FRAMES],
     next_frame: usize,
 }
 
 impl<T> GpuProfiler<T> {
-    pub fn new() -> GpuProfiler<T> {
+    pub fn new(gl: &Rc<gl::Gl>) -> GpuProfiler<T> {
         GpuProfiler {
             next_frame: 0,
             frames: [
-                      GpuFrameProfile::new(),
-                      GpuFrameProfile::new(),
-                      GpuFrameProfile::new(),
-                      GpuFrameProfile::new(),
+                      GpuFrameProfile::new(gl.clone()),
+                      GpuFrameProfile::new(gl.clone()),
+                      GpuFrameProfile::new(gl.clone()),
+                      GpuFrameProfile::new(gl.clone()),
                     ],
         }
     }
 
     pub fn build_samples(&mut self) -> Option<(FrameId, Vec<GpuSample<T>>)> {
         let frame = &mut self.frames[self.next_frame];
         if frame.is_valid() {
             Some((frame.frame_id, frame.build_samples()))
@@ -641,57 +688,63 @@ impl<T> GpuProfiler<T> {
     }
 
     pub fn end_frame(&mut self) {
         let frame = &mut self.frames[self.next_frame];
         frame.end_frame();
         self.next_frame = (self.next_frame + 1) % MAX_PROFILE_FRAMES;
     }
 
-    #[cfg(not(target_os = "android"))]
     pub fn add_marker(&mut self, tag: T) -> GpuMarker
     where T: NamedTag {
         self.frames[self.next_frame].add_marker(tag)
     }
-
-    #[cfg(target_os = "android")]
-    pub fn add_marker(&mut self, tag: T) {
-        self.frames[self.next_frame].add_marker(tag)
-    }
 }
 
 #[must_use]
-pub struct GpuMarker(());
-
-#[cfg(any(target_arch="arm", target_arch="aarch64"))]
-impl GpuMarker {
-    pub fn new(_: &str) -> GpuMarker {
-        GpuMarker(())
-    }
-
-    pub fn fire(_: &str) {}
+pub struct GpuMarker{
+    gl: Rc<gl::Gl>,
 }
 
-
-#[cfg(not(any(target_arch="arm", target_arch="aarch64")))]
 impl GpuMarker {
-    pub fn new(message: &str) -> GpuMarker {
-       gl::push_group_marker_ext(message);
-       GpuMarker(())
+    pub fn new(gl: &Rc<gl::Gl>, message: &str) -> GpuMarker {
+        match gl.get_type() {
+            gl::GlType::Gl =>  {
+                gl.push_group_marker_ext(message);
+                GpuMarker{
+                    gl: gl.clone(),
+                }
+            }
+            gl::GlType::Gles => {
+                GpuMarker{
+                    gl: gl.clone(),
+                }
+            }
+        }
     }
 
-    pub fn fire(message: &str) {
-        gl::insert_event_marker_ext(message);
+    pub fn fire(gl: &gl::Gl, message: &str) {
+        match gl.get_type() {
+            gl::GlType::Gl =>  {
+                gl.insert_event_marker_ext(message);
+            }
+            gl::GlType::Gles => {},
+        }
     }
 }
 
 #[cfg(not(any(target_arch="arm", target_arch="aarch64")))]
 impl Drop for GpuMarker {
     fn drop(&mut self) {
-        gl::pop_group_marker_ext();
+        match self.gl.get_type() {
+            gl::GlType::Gl =>  {
+                self.gl.pop_group_marker_ext();
+            }
+            gl::GlType::Gles => {},
+        }
     }
 }
 
 #[derive(Debug, Copy, Clone)]
 pub enum VertexUsageHint {
     Static,
     Dynamic,
     Stream,
@@ -792,16 +845,17 @@ pub struct Capabilities {
 
 #[derive(Clone, Debug)]
 pub enum ShaderError {
     Compilation(String, String), // name, error mssage
     Link(String), // error message
 }
 
 pub struct Device {
+    gl: Rc<gl::Gl>,
     // device state
     bound_textures: [TextureId; 16],
     bound_program: ProgramId,
     bound_vao: VAOId,
     bound_read_fbo: FBOId,
     bound_draw_fbo: FBOId,
     default_read_fbo: gl::GLuint,
     default_draw_fbo: gl::GLuint,
@@ -830,32 +884,37 @@ pub struct Device {
     max_texture_size: u32,
 
     // Frame counter. This is used to map between CPU
     // frames and GPU frames.
     frame_id: FrameId,
 }
 
 impl Device {
-    pub fn new(resource_override_path: Option<PathBuf>,
+    pub fn new(gl: Rc<gl::Gl>,
+               resource_override_path: Option<PathBuf>,
                _file_changed_handler: Box<FileWatcherHandler>) -> Device {
         //let file_watcher = FileWatcherThread::new(file_changed_handler);
 
         let shader_preamble = get_shader_source(SHADER_PREAMBLE, &resource_override_path);
         //file_watcher.add_watch(resource_path);
 
+        let max_ubo_size = gl.get_integer_v(gl::MAX_UNIFORM_BLOCK_SIZE) as usize;
+        let max_texture_size = gl.get_integer_v(gl::MAX_TEXTURE_SIZE) as u32;
+
         Device {
+            gl: gl,
             resource_override_path: resource_override_path,
             // This is initialized to 1 by default, but it is set
             // every frame by the call to begin_frame().
             device_pixel_ratio: 1.0,
             inside_frame: false,
 
             capabilities: Capabilities {
-                max_ubo_size: gl::get_integer_v(gl::MAX_UNIFORM_BLOCK_SIZE) as usize,
+                max_ubo_size: max_ubo_size,
                 supports_multisampling: false, //TODO
             },
 
             bound_textures: [ TextureId::invalid(); 16 ],
             bound_program: ProgramId(0),
             bound_vao: VAOId(0),
             bound_read_fbo: FBOId(0),
             bound_draw_fbo: FBOId(0),
@@ -866,179 +925,189 @@ impl Device {
             programs: HashMap::with_hasher(Default::default()),
             vaos: HashMap::with_hasher(Default::default()),
 
             shader_preamble: shader_preamble,
 
             next_vao_id: 1,
             //file_watcher: file_watcher,
 
-            max_texture_size: gl::get_integer_v(gl::MAX_TEXTURE_SIZE) as u32,
+            max_texture_size: max_texture_size,
             frame_id: FrameId(0),
         }
     }
 
+    pub fn gl(&self) -> &gl::Gl {
+        &*self.gl
+    }
+
+    pub fn rc_gl(&self) -> &Rc<gl::Gl> {
+        &self.gl
+    }
+
     pub fn max_texture_size(&self) -> u32 {
         self.max_texture_size
     }
 
     pub fn get_capabilities(&self) -> &Capabilities {
         &self.capabilities
     }
 
-    pub fn compile_shader(name: &str,
+    pub fn compile_shader(gl: &gl::Gl,
+                          name: &str,
                           source_str: &str,
                           shader_type: gl::GLenum,
                           shader_preamble: &[String])
                           -> Result<gl::GLuint, ShaderError> {
         debug!("compile {:?}", name);
 
         let mut s = String::new();
-        s.push_str(SHADER_VERSION);
+        s.push_str(get_shader_version(gl));
         for prefix in shader_preamble {
             s.push_str(&prefix);
         }
         s.push_str(source_str);
 
-        let id = gl::create_shader(shader_type);
+        let id = gl.create_shader(shader_type);
         let mut source = Vec::new();
         source.extend_from_slice(s.as_bytes());
-        gl::shader_source(id, &[&source[..]]);
-        gl::compile_shader(id);
-        let log = gl::get_shader_info_log(id);
-        if gl::get_shader_iv(id, gl::COMPILE_STATUS) == (0 as gl::GLint) {
+        gl.shader_source(id, &[&source[..]]);
+        gl.compile_shader(id);
+        let log = gl.get_shader_info_log(id);
+        if gl.get_shader_iv(id, gl::COMPILE_STATUS) == (0 as gl::GLint) {
             println!("Failed to compile shader: {:?}\n{}", name, log);
             Err(ShaderError::Compilation(name.to_string(), log))
         } else {
             if !log.is_empty() {
                 println!("Warnings detected on shader: {:?}\n{}", name, log);
             }
             Ok(id)
         }
     }
 
     pub fn begin_frame(&mut self, device_pixel_ratio: f32) -> FrameId {
         debug_assert!(!self.inside_frame);
         self.inside_frame = true;
         self.device_pixel_ratio = device_pixel_ratio;
 
         // Retrive the currently set FBO.
-        let default_read_fbo = gl::get_integer_v(gl::READ_FRAMEBUFFER_BINDING);
+        let default_read_fbo = self.gl.get_integer_v(gl::READ_FRAMEBUFFER_BINDING);
         self.default_read_fbo = default_read_fbo as gl::GLuint;
-        let default_draw_fbo = gl::get_integer_v(gl::DRAW_FRAMEBUFFER_BINDING);
+        let default_draw_fbo = self.gl.get_integer_v(gl::DRAW_FRAMEBUFFER_BINDING);
         self.default_draw_fbo = default_draw_fbo as gl::GLuint;
 
         // Texture state
         for i in 0..self.bound_textures.len() {
             self.bound_textures[i] = TextureId::invalid();
-            gl::active_texture(gl::TEXTURE0 + i as gl::GLuint);
-            gl::bind_texture(gl::TEXTURE_2D, 0);
+            self.gl.active_texture(gl::TEXTURE0 + i as gl::GLuint);
+            self.gl.bind_texture(gl::TEXTURE_2D, 0);
         }
 
         // Shader state
         self.bound_program = ProgramId(0);
-        gl::use_program(0);
+        self.gl.use_program(0);
 
         // Vertex state
         self.bound_vao = VAOId(0);
         self.clear_vertex_array();
 
         // FBO state
         self.bound_read_fbo = FBOId(self.default_read_fbo);
         self.bound_draw_fbo = FBOId(self.default_draw_fbo);
 
         // Pixel op state
-        gl::pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
+        self.gl.pixel_store_i(gl::UNPACK_ALIGNMENT, 1);
 
         // Default is sampler 0, always
-        gl::active_texture(gl::TEXTURE0);
+        self.gl.active_texture(gl::TEXTURE0);
 
         self.frame_id
     }
 
     pub fn bind_texture(&mut self,
                         sampler: TextureSampler,
                         texture_id: TextureId) {
         debug_assert!(self.inside_frame);
 
         let sampler_index = sampler as usize;
         if self.bound_textures[sampler_index] != texture_id {
             self.bound_textures[sampler_index] = texture_id;
-            gl::active_texture(gl::TEXTURE0 + sampler_index as gl::GLuint);
-            texture_id.bind();
-            gl::active_texture(gl::TEXTURE0);
+            self.gl.active_texture(gl::TEXTURE0 + sampler_index as gl::GLuint);
+            texture_id.bind(self.gl());
+            self.gl.active_texture(gl::TEXTURE0);
         }
     }
 
     pub fn bind_read_target(&mut self, texture_id: Option<(TextureId, i32)>) {
         debug_assert!(self.inside_frame);
 
         let fbo_id = texture_id.map_or(FBOId(self.default_read_fbo), |texture_id| {
             self.textures.get(&texture_id.0).unwrap().fbo_ids[texture_id.1 as usize]
         });
 
         if self.bound_read_fbo != fbo_id {
             self.bound_read_fbo = fbo_id;
-            fbo_id.bind(FBOTarget::Read);
+            fbo_id.bind(self.gl(), FBOTarget::Read);
         }
     }
 
     pub fn bind_draw_target(&mut self,
                             texture_id: Option<(TextureId, i32)>,
                             dimensions: Option<DeviceUintSize>) {
         debug_assert!(self.inside_frame);
 
         let fbo_id = texture_id.map_or(FBOId(self.default_draw_fbo), |texture_id| {
             self.textures.get(&texture_id.0).unwrap().fbo_ids[texture_id.1 as usize]
         });
 
         if self.bound_draw_fbo != fbo_id {
             self.bound_draw_fbo = fbo_id;
-            fbo_id.bind(FBOTarget::Draw);
+            fbo_id.bind(self.gl(), FBOTarget::Draw);
         }
 
         if let Some(dimensions) = dimensions {
-            gl::viewport(0, 0, dimensions.width as gl::GLint, dimensions.height as gl::GLint);
+            self.gl.viewport(0, 0, dimensions.width as gl::GLint, dimensions.height as gl::GLint);
         }
     }
 
     pub fn bind_program(&mut self,
                         program_id: ProgramId,
                         projection: &Matrix4D<f32>) {
         debug_assert!(self.inside_frame);
 
         if self.bound_program != program_id {
             self.bound_program = program_id;
-            program_id.bind();
+            program_id.bind(&*self.gl);
         }
 
         let program = self.programs.get(&program_id).unwrap();
         self.set_uniforms(program,
                           projection,
                           self.device_pixel_ratio);
     }
 
     pub fn create_texture_ids(&mut self,
                               count: i32,
                               target: TextureTarget) -> Vec<TextureId> {
-        let id_list = gl::gen_textures(count);
+        let id_list = self.gl.gen_textures(count);
         let mut texture_ids = Vec::new();
 
         let target = match target {
             TextureTarget::Default => gl::TEXTURE_2D,
             TextureTarget::Array => gl::TEXTURE_2D_ARRAY,
         };
 
         for id in id_list {
             let texture_id = TextureId {
                 name: id,
                 target: target,
             };
 
             let texture = Texture {
+                gl: self.gl.clone(),
                 id: id,
                 width: 0,
                 height: 0,
                 format: ImageFormat::Invalid,
                 filter: TextureFilter::Nearest,
                 mode: RenderTargetMode::None,
                 fbo_ids: vec![],
             };
@@ -1062,39 +1131,39 @@ impl Device {
             TextureFilter::Nearest => {
                 gl::NEAREST
             }
             TextureFilter::Linear => {
                 gl::LINEAR
             }
         };
 
-        gl::tex_parameter_i(target, gl::TEXTURE_MAG_FILTER, filter as gl::GLint);
-        gl::tex_parameter_i(target, gl::TEXTURE_MIN_FILTER, filter as gl::GLint);
+        self.gl.tex_parameter_i(target, gl::TEXTURE_MAG_FILTER, filter as gl::GLint);
+        self.gl.tex_parameter_i(target, gl::TEXTURE_MIN_FILTER, filter as gl::GLint);
 
-        gl::tex_parameter_i(target, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as gl::GLint);
-        gl::tex_parameter_i(target, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as gl::GLint);
+        self.gl.tex_parameter_i(target, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as gl::GLint);
+        self.gl.tex_parameter_i(target, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as gl::GLint);
     }
 
     fn upload_texture_image(&mut self,
                             target: gl::GLuint,
                             width: u32,
                             height: u32,
                             internal_format: u32,
                             format: u32,
                             type_: u32,
                             pixels: Option<&[u8]>) {
-        gl::tex_image_2d(target,
-                         0,
-                         internal_format as gl::GLint,
-                         width as gl::GLint, height as gl::GLint,
-                         0,
-                         format,
-                         type_,
-                         pixels);
+        self.gl.tex_image_2d(target,
+                              0,
+                              internal_format as gl::GLint,
+                              width as gl::GLint, height as gl::GLint,
+                              0,
+                              format,
+                              type_,
+                              pixels);
     }
 
     pub fn init_texture(&mut self,
                         texture_id: TextureId,
                         width: u32,
                         height: u32,
                         format: ImageFormat,
                         filter: TextureFilter,
@@ -1106,17 +1175,17 @@ impl Device {
             let texture = self.textures.get_mut(&texture_id).expect("Didn't find texture!");
             texture.format = format;
             texture.width = width;
             texture.height = height;
             texture.filter = filter;
             texture.mode = mode;
         }
 
-        let (internal_format, gl_format) = gl_texture_formats_for_image_format(format);
+        let (internal_format, gl_format) = gl_texture_formats_for_image_format(self.gl(), format);
         let type_ = gl_type_for_texture_format(format);
 
         match mode {
             RenderTargetMode::SimpleRenderTarget => {
                 self.bind_texture(DEFAULT_TEXTURE, texture_id);
                 self.set_texture_parameters(texture_id.target, filter);
                 self.upload_texture_image(texture_id.target,
                                           width,
@@ -1171,79 +1240,79 @@ impl Device {
                 // If we have enough layers allocated already, just use them.
                 // TODO(gw): Probably worth removing some after a while if
                 //           there is a surplus?
                 let current_layer_count = texture.fbo_ids.len() as i32;
                 if current_layer_count >= layer_count {
                     return;
                 }
 
-                let (internal_format, gl_format) = gl_texture_formats_for_image_format(texture.format);
+                let (internal_format, gl_format) = gl_texture_formats_for_image_format(&*self.gl, texture.format);
                 let type_ = gl_type_for_texture_format(texture.format);
 
-                gl::tex_image_3d(texture_id.target,
-                                 0,
-                                 internal_format as gl::GLint,
-                                 texture.width as gl::GLint,
-                                 texture.height as gl::GLint,
-                                 layer_count,
-                                 0,
-                                 gl_format,
-                                 type_,
-                                 None);
+                self.gl.tex_image_3d(texture_id.target,
+                                      0,
+                                      internal_format as gl::GLint,
+                                      texture.width as gl::GLint,
+                                      texture.height as gl::GLint,
+                                      layer_count,
+                                      0,
+                                      gl_format,
+                                      type_,
+                                      None);
 
                 let needed_layer_count = layer_count - current_layer_count;
-                let new_fbos = gl::gen_framebuffers(needed_layer_count);
+                let new_fbos = self.gl.gen_framebuffers(needed_layer_count);
                 texture.fbo_ids.extend(new_fbos.into_iter().map(|id| FBOId(id)));
 
                 for (fbo_index, fbo_id) in texture.fbo_ids.iter().enumerate() {
-                    gl::bind_framebuffer(gl::FRAMEBUFFER, fbo_id.0);
-                    gl::framebuffer_texture_layer(gl::FRAMEBUFFER,
-                                                  gl::COLOR_ATTACHMENT0,
-                                                  texture_id.name,
-                                                  0,
-                                                  fbo_index as gl::GLint);
+                    self.gl.bind_framebuffer(gl::FRAMEBUFFER, fbo_id.0);
+                    self.gl.framebuffer_texture_layer(gl::FRAMEBUFFER,
+                                                       gl::COLOR_ATTACHMENT0,
+                                                       texture_id.name,
+                                                       0,
+                                                       fbo_index as gl::GLint);
 
                     // TODO(gw): Share depth render buffer between FBOs to
                     //           save memory!
                     // TODO(gw): Free these renderbuffers on exit!
-                    let renderbuffer_ids = gl::gen_renderbuffers(1);
+                    let renderbuffer_ids = self.gl.gen_renderbuffers(1);
                     let depth_rb = renderbuffer_ids[0];
-                    gl::bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
-                    gl::renderbuffer_storage(gl::RENDERBUFFER,
-                                             gl::DEPTH_COMPONENT24,
-                                             texture.width as gl::GLsizei,
-                                             texture.height as gl::GLsizei);
-                    gl::framebuffer_renderbuffer(gl::FRAMEBUFFER,
-                                                 gl::DEPTH_ATTACHMENT,
-                                                 gl::RENDERBUFFER,
-                                                 depth_rb);
+                    self.gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
+                    self.gl.renderbuffer_storage(gl::RENDERBUFFER,
+                                                  gl::DEPTH_COMPONENT24,
+                                                  texture.width as gl::GLsizei,
+                                                  texture.height as gl::GLsizei);
+                    self.gl.framebuffer_renderbuffer(gl::FRAMEBUFFER,
+                                                      gl::DEPTH_ATTACHMENT,
+                                                      gl::RENDERBUFFER,
+                                                      depth_rb);
                 }
             }
             None => {
                 debug_assert!(texture.fbo_ids.len() == 0 || texture.fbo_ids.len() == 1);
                 if texture.fbo_ids.is_empty() {
-                    let new_fbo = gl::gen_framebuffers(1)[0];
+                    let new_fbo = self.gl.gen_framebuffers(1)[0];
 
-                    gl::bind_framebuffer(gl::FRAMEBUFFER, new_fbo);
+                    self.gl.bind_framebuffer(gl::FRAMEBUFFER, new_fbo);
 
-                    gl::framebuffer_texture_2d(gl::FRAMEBUFFER,
-                                               gl::COLOR_ATTACHMENT0,
-                                               texture_id.target,
-                                               texture_id.name,
-                                               0);
+                    self.gl.framebuffer_texture_2d(gl::FRAMEBUFFER,
+                                                    gl::COLOR_ATTACHMENT0,
+                                                    texture_id.target,
+                                                    texture_id.name,
+                                                    0);
 
                     texture.fbo_ids.push(FBOId(new_fbo));
                 }
             }
         }
 
         // TODO(gw): Hack! Modify the code above to use the normal binding interfaces the device exposes.
-        gl::bind_framebuffer(gl::READ_FRAMEBUFFER, self.bound_read_fbo.0);
-        gl::bind_framebuffer(gl::DRAW_FRAMEBUFFER, self.bound_draw_fbo.0);
+        self.gl.bind_framebuffer(gl::READ_FRAMEBUFFER, self.bound_read_fbo.0);
+        self.gl.bind_framebuffer(gl::DRAW_FRAMEBUFFER, self.bound_draw_fbo.0);
     }
 
     pub fn blit_render_target(&mut self,
                               src_texture: Option<(TextureId, i32)>,
                               src_rect: Option<DeviceIntRect>,
                               dest_rect: DeviceIntRect) {
         debug_assert!(self.inside_frame);
 
@@ -1251,26 +1320,26 @@ impl Device {
             let texture = self.textures.get(&src_texture.unwrap().0).expect("unknown texture id!");
             DeviceIntRect::new(DeviceIntPoint::zero(),
                                DeviceIntSize::new(texture.width as gl::GLint,
                                                   texture.height as gl::GLint))
         });
 
         self.bind_read_target(src_texture);
 
-        gl::blit_framebuffer(src_rect.origin.x,
-                             src_rect.origin.y,
-                             src_rect.origin.x + src_rect.size.width,
-                             src_rect.origin.y + src_rect.size.height,
-                             dest_rect.origin.x,
-                             dest_rect.origin.y,
-                             dest_rect.origin.x + dest_rect.size.width,
-                             dest_rect.origin.y + dest_rect.size.height,
-                             gl::COLOR_BUFFER_BIT,
-                             gl::LINEAR);
+        self.gl.blit_framebuffer(src_rect.origin.x,
+                                  src_rect.origin.y,
+                                  src_rect.origin.x + src_rect.size.width,
+                                  src_rect.origin.y + src_rect.size.height,
+                                  dest_rect.origin.x,
+                                  dest_rect.origin.y,
+                                  dest_rect.origin.x + dest_rect.size.width,
+                                  dest_rect.origin.y + dest_rect.size.height,
+                                  gl::COLOR_BUFFER_BIT,
+                                  gl::LINEAR);
     }
 
     pub fn resize_texture(&mut self,
                           texture_id: TextureId,
                           new_width: u32,
                           new_height: u32,
                           format: ImageFormat,
                           filter: TextureFilter,
@@ -1281,66 +1350,66 @@ impl Device {
 
         let temp_texture_id = self.create_texture_ids(1, TextureTarget::Default)[0];
         self.init_texture(temp_texture_id, old_size.width, old_size.height, format, filter, mode, None);
         self.create_fbo_for_texture_if_necessary(temp_texture_id, None);
 
         self.bind_read_target(Some((texture_id, 0)));
         self.bind_texture(DEFAULT_TEXTURE, temp_texture_id);
 
-        gl::copy_tex_sub_image_2d(temp_texture_id.target,
-                                  0,
-                                  0,
-                                  0,
-                                  0,
-                                  0,
-                                  old_size.width as i32,
-                                  old_size.height as i32);
+        self.gl.copy_tex_sub_image_2d(temp_texture_id.target,
+                                       0,
+                                       0,
+                                       0,
+                                       0,
+                                       0,
+                                       old_size.width as i32,
+                                       old_size.height as i32);
 
         self.deinit_texture(texture_id);
         self.init_texture(texture_id, new_width, new_height, format, filter, mode, None);
         self.create_fbo_for_texture_if_necessary(texture_id, None);
         self.bind_read_target(Some((temp_texture_id, 0)));
         self.bind_texture(DEFAULT_TEXTURE, texture_id);
 
-        gl::copy_tex_sub_image_2d(texture_id.target,
-                                  0,
-                                  0,
-                                  0,
-                                  0,
-                                  0,
-                                  old_size.width as i32,
-                                  old_size.height as i32);
+        self.gl.copy_tex_sub_image_2d(texture_id.target,
+                                       0,
+                                       0,
+                                       0,
+                                       0,
+                                       0,
+                                       old_size.width as i32,
+                                       old_size.height as i32);
 
         self.bind_read_target(None);
         self.deinit_texture(temp_texture_id);
     }
 
     pub fn deinit_texture(&mut self, texture_id: TextureId) {
         debug_assert!(self.inside_frame);
 
         self.bind_texture(DEFAULT_TEXTURE, texture_id);
 
         let texture = self.textures.get_mut(&texture_id).unwrap();
-        let (internal_format, gl_format) = gl_texture_formats_for_image_format(texture.format);
+        let (internal_format, gl_format) = gl_texture_formats_for_image_format(&*self.gl, texture.format);
         let type_ = gl_type_for_texture_format(texture.format);
 
-        gl::tex_image_2d(texture_id.target,
-                         0,
-                         internal_format,
-                         0,
-                         0,
-                         0,
-                         gl_format,
-                         type_,
-                         None);
+        self.gl.tex_image_2d(texture_id.target,
+                              0,
+                              internal_format,
+                              0,
+                              0,
+                              0,
+                              gl_format,
+                              type_,
+                              None);
 
         if !texture.fbo_ids.is_empty() {
             let fbo_ids: Vec<_> = texture.fbo_ids.iter().map(|&FBOId(fbo_id)| fbo_id).collect();
-            gl::delete_framebuffers(&fbo_ids[..]);
+            self.gl.delete_framebuffers(&fbo_ids[..]);
         }
 
         texture.format = ImageFormat::Invalid;
         texture.width = 0;
         texture.height = 0;
         texture.fbo_ids.clear();
     }
 
@@ -1353,17 +1422,17 @@ impl Device {
 
     pub fn create_program_with_prefix(&mut self,
                                       base_filename: &str,
                                       include_filenames: &[&str],
                                       prefix: Option<String>,
                                       vertex_format: VertexFormat) -> Result<ProgramId, ShaderError> {
         debug_assert!(self.inside_frame);
 
-        let pid = gl::create_program();
+        let pid = self.gl.create_program();
 
         let mut vs_name = String::from(base_filename);
         vs_name.push_str(".vs");
         let mut fs_name = String::from(base_filename);
         fs_name.push_str(".fs");
 
         let mut include = format!("// Base shader: {}\n", base_filename);
         for inc_filename in include_filenames {
@@ -1371,16 +1440,17 @@ impl Device {
             include.push_str(&src);
         }
 
         if let Some(shared_src) = get_optional_shader_source(base_filename, &self.resource_override_path) {
             include.push_str(&shared_src);
         }
 
         let program = Program {
+            gl: self.gl.clone(),
             name: base_filename.to_owned(),
             id: pid,
             u_transform: -1,
             u_device_pixel_ratio: -1,
             vs_source: get_shader_source(&vs_name, &self.resource_override_path),
             fs_source: get_shader_source(&fs_name, &self.resource_override_path),
             prefix: prefix,
             vs_id: None,
@@ -1418,121 +1488,123 @@ impl Device {
 
         vs_preamble.push(self.shader_preamble.to_owned());
         fs_preamble.push(self.shader_preamble.to_owned());
 
         vs_preamble.push(include.clone());
         fs_preamble.push(include);
 
         // todo(gw): store shader ids so they can be freed!
-        let vs_id = try!{ Device::compile_shader(&program.name,
+        let vs_id = try!{ Device::compile_shader(&*self.gl,
+                                                 &program.name,
                                                  &program.vs_source,
                                                  gl::VERTEX_SHADER,
                                                  &vs_preamble) };
-        let fs_id = try!{ Device::compile_shader(&program.name,
+        let fs_id = try!{ Device::compile_shader(&*self.gl,
+                                                 &program.name,
                                                  &program.fs_source,
                                                  gl::FRAGMENT_SHADER,
                                                  &fs_preamble) };
 
         if let Some(vs_id) = program.vs_id {
-            gl::detach_shader(program.id, vs_id);
+            self.gl.detach_shader(program.id, vs_id);
         }
 
         if let Some(fs_id) = program.fs_id {
-            gl::detach_shader(program.id, fs_id);
+            self.gl.detach_shader(program.id, fs_id);
         }
 
         if let Err(bind_error) = program.attach_and_bind_shaders(vs_id, fs_id, vertex_format) {
             if let (Some(vs_id), Some(fs_id)) = (program.vs_id, program.fs_id) {
                 try! { program.attach_and_bind_shaders(vs_id, fs_id, vertex_format) };
             } else {
                return Err(bind_error);
             }
         } else {
             if let Some(vs_id) = program.vs_id {
-                gl::delete_shader(vs_id);
+                self.gl.delete_shader(vs_id);
             }
 
             if let Some(fs_id) = program.fs_id {
-                gl::delete_shader(fs_id);
+                self.gl.delete_shader(fs_id);
             }
 
             program.vs_id = Some(vs_id);
             program.fs_id = Some(fs_id);
         }
 
-        program.u_transform = gl::get_uniform_location(program.id, "uTransform");
-        program.u_device_pixel_ratio = gl::get_uniform_location(program.id, "uDevicePixelRatio");
+        program.u_transform = self.gl.get_uniform_location(program.id, "uTransform");
+        program.u_device_pixel_ratio = self.gl.get_uniform_location(program.id, "uDevicePixelRatio");
 
-        program_id.bind();
-        let u_color_0 = gl::get_uniform_location(program.id, "sColor0");
+        program_id.bind(&*self.gl);
+        let u_color_0 = self.gl.get_uniform_location(program.id, "sColor0");
         if u_color_0 != -1 {
-            gl::uniform_1i(u_color_0, TextureSampler::Color0 as i32);
+            self.gl.uniform_1i(u_color_0, TextureSampler::Color0 as i32);
         }
-        let u_color1 = gl::get_uniform_location(program.id, "sColor1");
+        let u_color1 = self.gl.get_uniform_location(program.id, "sColor1");
         if u_color1 != -1 {
-            gl::uniform_1i(u_color1, TextureSampler::Color1 as i32);
+            self.gl.uniform_1i(u_color1, TextureSampler::Color1 as i32);
         }
-        let u_color_2 = gl::get_uniform_location(program.id, "sColor2");
+        let u_color_2 = self.gl.get_uniform_location(program.id, "sColor2");
         if u_color_2 != -1 {
-            gl::uniform_1i(u_color_2, TextureSampler::Color2 as i32);
+            self.gl.uniform_1i(u_color_2, TextureSampler::Color2 as i32);
         }
-        let u_mask = gl::get_uniform_location(program.id, "sMask");
+        let u_mask = self.gl.get_uniform_location(program.id, "sMask");
         if u_mask != -1 {
-            gl::uniform_1i(u_mask, TextureSampler::Mask as i32);
+            self.gl.uniform_1i(u_mask, TextureSampler::Mask as i32);
         }
 
-        let u_cache = gl::get_uniform_location(program.id, "sCache");
+        let u_cache = self.gl.get_uniform_location(program.id, "sCache");
         if u_cache != -1 {
-            gl::uniform_1i(u_cache, TextureSampler::Cache as i32);
+            self.gl.uniform_1i(u_cache, TextureSampler::Cache as i32);
         }
 
-        let u_layers = gl::get_uniform_location(program.id, "sLayers");
+        let u_layers = self.gl.get_uniform_location(program.id, "sLayers");
         if u_layers != -1 {
-            gl::uniform_1i(u_layers, TextureSampler::Layers as i32);
+            self.gl.uniform_1i(u_layers, TextureSampler::Layers as i32);
         }
 
-        let u_tasks = gl::get_uniform_location(program.id, "sRenderTasks");
+        let u_tasks = self.gl.get_uniform_location(program.id, "sRenderTasks");
         if u_tasks != -1 {
-            gl::uniform_1i(u_tasks, TextureSampler::RenderTasks as i32);
+            self.gl.uniform_1i(u_tasks, TextureSampler::RenderTasks as i32);
         }
 
-        let u_prim_geom = gl::get_uniform_location(program.id, "sPrimGeometry");
+        let u_prim_geom = self.gl.get_uniform_location(program.id, "sPrimGeometry");
         if u_prim_geom != -1 {
-            gl::uniform_1i(u_prim_geom, TextureSampler::Geometry as i32);
+            self.gl.uniform_1i(u_prim_geom, TextureSampler::Geometry as i32);
         }
 
-        let u_data16 = gl::get_uniform_location(program.id, "sData16");
+        let u_data16 = self.gl.get_uniform_location(program.id, "sData16");
         if u_data16 != -1 {
-            gl::uniform_1i(u_data16, TextureSampler::Data16 as i32);
+            self.gl.uniform_1i(u_data16, TextureSampler::Data16 as i32);
         }
 
-        let u_data32 = gl::get_uniform_location(program.id, "sData32");
+        let u_data32 = self.gl.get_uniform_location(program.id, "sData32");
         if u_data32 != -1 {
-            gl::uniform_1i(u_data32, TextureSampler::Data32 as i32);
+            self.gl.uniform_1i(u_data32, TextureSampler::Data32 as i32);
         }
 
-        let u_data64 = gl::get_uniform_location(program.id, "sData64");
+        let u_data64 = self.gl.get_uniform_location(program.id, "sData64");
         if u_data64 != -1 {
-            gl::uniform_1i(u_data64, TextureSampler::Data64 as i32);
+            self.gl.uniform_1i(u_data64, TextureSampler::Data64 as i32);
         }
 
-        let u_data128 = gl::get_uniform_location(program.id, "sData128");
+        let u_data128 = self.gl.get_uniform_location(program.id, "sData128");
         if u_data128 != -1 {
-            gl::uniform_1i(u_data128, TextureSampler::Data128    as i32);
+            self.gl.uniform_1i(u_data128, TextureSampler::Data128    as i32);
         }
 
-        let u_resource_rects = gl::get_uniform_location(program.id, "sResourceRects");
+        let u_resource_rects = self.gl.get_uniform_location(program.id, "sResourceRects");
         if u_resource_rects != -1 {
-            gl::uniform_1i(u_resource_rects, TextureSampler::ResourceRects as i32);
+            self.gl.uniform_1i(u_resource_rects, TextureSampler::ResourceRects as i32);
         }
 
-        let u_gradients = gl::get_uniform_location(program.id, "sGradients");
+        let u_gradients = self.gl.get_uniform_location(program.id, "sGradients");
         if u_gradients != -1 {
-            gl::uniform_1i(u_gradients, TextureSampler::Gradients as i32);
+            self.gl.uniform_1i(u_gradients, TextureSampler::Gradients as i32);
         }
 
         Ok(())
     }
 
 /*
     pub fn refresh_shader(&mut self, path: PathBuf) {
         let mut vs_preamble_path = self.resource_path.clone();
@@ -1567,51 +1639,51 @@ impl Device {
 
         for program_id in programs_to_update {
             self.load_program(program_id, false);
         }
     }*/
 
     pub fn get_uniform_location(&self, program_id: ProgramId, name: &str) -> UniformLocation {
         let ProgramId(program_id) = program_id;
-        UniformLocation(gl::get_uniform_location(program_id, name))
+        UniformLocation(self.gl.get_uniform_location(program_id, name))
     }
 
     pub fn set_uniform_2f(&self, uniform: UniformLocation, x: f32, y: f32) {
         debug_assert!(self.inside_frame);
         let UniformLocation(location) = uniform;
-        gl::uniform_2f(location, x, y);
+        self.gl.uniform_2f(location, x, y);
     }
 
     fn set_uniforms(&self,
                     program: &Program,
                     transform: &Matrix4D<f32>,
                     device_pixel_ratio: f32) {
         debug_assert!(self.inside_frame);
-        gl::uniform_matrix_4fv(program.u_transform,
+        self.gl.uniform_matrix_4fv(program.u_transform,
                                false,
                                &transform.to_row_major_array());
-        gl::uniform_1f(program.u_device_pixel_ratio, device_pixel_ratio);
+        self.gl.uniform_1f(program.u_device_pixel_ratio, device_pixel_ratio);
     }
 
     fn update_image_for_2d_texture(&mut self,
                                    target: gl::GLuint,
                                    x0: gl::GLint,
                                    y0: gl::GLint,
                                    width: gl::GLint,
                                    height: gl::GLint,
                                    format: gl::GLuint,
                                    data: &[u8]) {
-        gl::tex_sub_image_2d(target,
-                             0,
-                             x0, y0,
-                             width, height,
-                             format,
-                             gl::UNSIGNED_BYTE,
-                             data);
+        self.gl.tex_sub_image_2d(target,
+                                  0,
+                                  x0, y0,
+                                  width, height,
+                                  format,
+                                  gl::UNSIGNED_BYTE,
+                                  data);
     }
 
     pub fn update_texture(&mut self,
                           texture_id: TextureId,
                           x0: u32,
                           y0: u32,
                           width: u32,
                           height: u32,
@@ -1625,131 +1697,132 @@ impl Device {
             ImageFormat::A8 => {
                 if cfg!(any(target_arch="arm", target_arch="aarch64")) {
                     for byte in data {
                         expanded_data.push(*byte);
                         expanded_data.push(*byte);
                         expanded_data.push(*byte);
                         expanded_data.push(*byte);
                     }
-                    (GL_FORMAT_BGRA, 4, expanded_data.as_slice())
+                    (get_gl_format_bgra(self.gl()), 4, expanded_data.as_slice())
                 } else {
                     (GL_FORMAT_A, 1, data)
                 }
             }
             ImageFormat::RGB8 => (gl::RGB, 3, data),
-            ImageFormat::RGBA8 => (GL_FORMAT_BGRA, 4, data),
+            ImageFormat::RGBA8 => (get_gl_format_bgra(self.gl()), 4, data),
             ImageFormat::Invalid | ImageFormat::RGBAF32 => unreachable!(),
         };
 
         let row_length = match stride {
             Some(value) => value / bpp,
             None => width,
         };
 
         // Take the stride into account for all rows, except the last one.
         let len = bpp * row_length * (height - 1)
                 + width * bpp;
 
         assert!(data.len() as u32 >= len);
         let data = &data[0..len as usize];
 
         if let Some(..) = stride {
-            gl::pixel_store_i(gl::UNPACK_ROW_LENGTH, row_length as gl::GLint);
+            self.gl.pixel_store_i(gl::UNPACK_ROW_LENGTH, row_length as gl::GLint);
         }
 
         self.bind_texture(DEFAULT_TEXTURE, texture_id);
         self.update_image_for_2d_texture(texture_id.target,
                                          x0 as gl::GLint,
                                          y0 as gl::GLint,
                                          width as gl::GLint,
                                          height as gl::GLint,
                                          gl_format,
                                          data);
 
         // Reset row length to 0, otherwise the stride would apply to all texture uploads.
         if let Some(..) = stride {
-            gl::pixel_store_i(gl::UNPACK_ROW_LENGTH, 0 as gl::GLint);
+            self.gl.pixel_store_i(gl::UNPACK_ROW_LENGTH, 0 as gl::GLint);
         }
     }
 
     fn clear_vertex_array(&mut self) {
         debug_assert!(self.inside_frame);
-        gl::bind_vertex_array(0);
+        self.gl.bind_vertex_array(0);
     }
 
     pub fn bind_vao(&mut self, vao_id: VAOId) {
         debug_assert!(self.inside_frame);
 
         if self.bound_vao != vao_id {
             self.bound_vao = vao_id;
 
             let VAOId(id) = vao_id;
-            gl::bind_vertex_array(id);
+            self.gl.bind_vertex_array(id);
         }
     }
 
     fn create_vao_with_vbos(&mut self,
                             format: VertexFormat,
                             main_vbo_id: VBOId,
                             instance_vbo_id: VBOId,
                             ibo_id: IBOId,
                             vertex_offset: gl::GLuint,
                             instance_stride: gl::GLint,
                             owns_vertices: bool,
                             owns_instances: bool,
                             owns_indices: bool)
                             -> VAOId {
         debug_assert!(self.inside_frame);
 
-        let vao_ids = gl::gen_vertex_arrays(1);
+        let vao_ids = self.gl.gen_vertex_arrays(1);
         let vao_id = vao_ids[0];
 
-        gl::bind_vertex_array(vao_id);
+        self.gl.bind_vertex_array(vao_id);
 
-        format.bind(main_vbo_id, instance_vbo_id, vertex_offset, instance_stride);
-        ibo_id.bind(); // force it to be a part of VAO
+        format.bind(self.gl(), main_vbo_id, instance_vbo_id, vertex_offset, instance_stride);
+        ibo_id.bind(self.gl()); // force it to be a part of VAO
 
         let vao = VAO {
+            gl: self.gl.clone(),
             id: vao_id,
             ibo_id: ibo_id,
             main_vbo_id: main_vbo_id,
             instance_vbo_id: instance_vbo_id,
             instance_stride: instance_stride,
             owns_indices: owns_indices,
             owns_vertices: owns_vertices,
             owns_instances: owns_instances,
         };
 
-        gl::bind_vertex_array(0);
+        self.gl.bind_vertex_array(0);
 
         let vao_id = VAOId(vao_id);
 
         debug_assert!(!self.vaos.contains_key(&vao_id));
         self.vaos.insert(vao_id, vao);
 
         vao_id
     }
 
     pub fn create_vao(&mut self, format: VertexFormat, inst_stride: gl::GLint) -> VAOId {
         debug_assert!(self.inside_frame);
 
-        let buffer_ids = gl::gen_buffers(3);
+        let buffer_ids = self.gl.gen_buffers(3);
         let ibo_id = IBOId(buffer_ids[0]);
         let main_vbo_id = VBOId(buffer_ids[1]);
         let intance_vbo_id = VBOId(buffer_ids[2]);
 
         self.create_vao_with_vbos(format, main_vbo_id, intance_vbo_id, ibo_id, 0, inst_stride, true, true, true)
     }
 
     pub fn create_vao_with_new_instances(&mut self, format: VertexFormat, inst_stride: gl::GLint,
                                          base_vao: VAOId) -> VAOId {
         debug_assert!(self.inside_frame);
 
-        let buffer_ids = gl::gen_buffers(1);
+        let buffer_ids = self.gl.gen_buffers(1);
         let intance_vbo_id = VBOId(buffer_ids[0]);
         let (main_vbo_id, ibo_id) = {
             let vao = self.vaos.get(&base_vao).unwrap();
             (vao.main_vbo_id, vao.ibo_id)
         };
 
         self.create_vao_with_vbos(format, main_vbo_id, intance_vbo_id, ibo_id, 0, inst_stride, false, true, false)
     }
@@ -1758,270 +1831,273 @@ impl Device {
                                        vao_id: VAOId,
                                        vertices: &[V],
                                        usage_hint: VertexUsageHint) {
         debug_assert!(self.inside_frame);
 
         let vao = self.vaos.get(&vao_id).unwrap();
         debug_assert_eq!(self.bound_vao, vao_id);
 
-        vao.main_vbo_id.bind();
-        gl::buffer_data(gl::ARRAY_BUFFER, &vertices, usage_hint.to_gl());
+        vao.main_vbo_id.bind(self.gl());
+        gl::buffer_data(self.gl(), gl::ARRAY_BUFFER, &vertices, usage_hint.to_gl());
     }
 
     pub fn update_vao_instances<V>(&mut self,
                                    vao_id: VAOId,
                                    instances: &[V],
                                    usage_hint: VertexUsageHint) {
         debug_assert!(self.inside_frame);
 
         let vao = self.vaos.get(&vao_id).unwrap();
         debug_assert_eq!(self.bound_vao, vao_id);
         debug_assert_eq!(vao.instance_stride as usize, mem::size_of::<V>());
 
-        vao.instance_vbo_id.bind();
-        gl::buffer_data(gl::ARRAY_BUFFER, &instances, usage_hint.to_gl());
+        vao.instance_vbo_id.bind(self.gl());
+        gl::buffer_data(self.gl(), gl::ARRAY_BUFFER, &instances, usage_hint.to_gl());
     }
 
     pub fn update_vao_indices<I>(&mut self,
                                  vao_id: VAOId,
                                  indices: &[I],
                                  usage_hint: VertexUsageHint) {
         debug_assert!(self.inside_frame);
 
         let vao = self.vaos.get(&vao_id).unwrap();
         debug_assert_eq!(self.bound_vao, vao_id);
 
-        vao.ibo_id.bind();
-        gl::buffer_data(gl::ELEMENT_ARRAY_BUFFER, &indices, usage_hint.to_gl());
+        vao.ibo_id.bind(self.gl());
+        gl::buffer_data(self.gl(), gl::ELEMENT_ARRAY_BUFFER, &indices, usage_hint.to_gl());
     }
 
     pub fn draw_triangles_u16(&mut self, first_vertex: i32, index_count: i32) {
         debug_assert!(self.inside_frame);
-        gl::draw_elements(gl::TRIANGLES,
-                          index_count,
-                          gl::UNSIGNED_SHORT,
-                          first_vertex as u32 * 2);
+        self.gl.draw_elements(gl::TRIANGLES,
+                               index_count,
+                               gl::UNSIGNED_SHORT,
+                               first_vertex as u32 * 2);
     }
 
     pub fn draw_triangles_u32(&mut self, first_vertex: i32, index_count: i32) {
         debug_assert!(self.inside_frame);
-        gl::draw_elements(gl::TRIANGLES,
-                          index_count,
-                          gl::UNSIGNED_INT,
-                          first_vertex as u32 * 4);
+        self.gl.draw_elements(gl::TRIANGLES,
+                               index_count,
+                               gl::UNSIGNED_INT,
+                               first_vertex as u32 * 4);
     }
 
     pub fn draw_nonindexed_lines(&mut self, first_vertex: i32, vertex_count: i32) {
         debug_assert!(self.inside_frame);
-        gl::draw_arrays(gl::LINES,
-                          first_vertex,
-                          vertex_count);
+        self.gl.draw_arrays(gl::LINES,
+                             first_vertex,
+                             vertex_count);
     }
 
     pub fn draw_indexed_triangles_instanced_u16(&mut self,
                                                 index_count: i32,
                                                 instance_count: i32) {
         debug_assert!(self.inside_frame);
-        gl::draw_elements_instanced(gl::TRIANGLES, index_count, gl::UNSIGNED_SHORT, 0, instance_count);
+        self.gl.draw_elements_instanced(gl::TRIANGLES, index_count, gl::UNSIGNED_SHORT, 0, instance_count);
     }
 
     pub fn end_frame(&mut self) {
         self.bind_draw_target(None, None);
         self.bind_read_target(None);
 
         debug_assert!(self.inside_frame);
         self.inside_frame = false;
 
-        gl::bind_texture(gl::TEXTURE_2D, 0);
-        gl::use_program(0);
+        self.gl.bind_texture(gl::TEXTURE_2D, 0);
+        self.gl.use_program(0);
 
         for i in 0..self.bound_textures.len() {
-            gl::active_texture(gl::TEXTURE0 + i as gl::GLuint);
-            gl::bind_texture(gl::TEXTURE_2D, 0);
+            self.gl.active_texture(gl::TEXTURE0 + i as gl::GLuint);
+            self.gl.bind_texture(gl::TEXTURE_2D, 0);
         }
 
-        gl::active_texture(gl::TEXTURE0);
+        self.gl.active_texture(gl::TEXTURE0);
 
         self.frame_id.0 += 1;
     }
 
     pub fn assign_ubo_binding(&self, program_id: ProgramId, name: &str, value: u32) -> u32 {
-        let index = gl::get_uniform_block_index(program_id.0, name);
-        gl::uniform_block_binding(program_id.0, index, value);
+        let index = self.gl.get_uniform_block_index(program_id.0, name);
+        self.gl.uniform_block_binding(program_id.0, index, value);
         index
     }
 
     pub fn create_ubo<T>(&self, data: &[T], binding: u32) -> UBOId {
-        let ubo = gl::gen_buffers(1)[0];
-        gl::bind_buffer(gl::UNIFORM_BUFFER, ubo);
-        gl::buffer_data(gl::UNIFORM_BUFFER, data, gl::STATIC_DRAW);
-        gl::bind_buffer_base(gl::UNIFORM_BUFFER, binding, ubo);
+        let ubo = self.gl.gen_buffers(1)[0];
+        self.gl.bind_buffer(gl::UNIFORM_BUFFER, ubo);
+        gl::buffer_data(self.gl(), gl::UNIFORM_BUFFER, data, gl::STATIC_DRAW);
+        self.gl.bind_buffer_base(gl::UNIFORM_BUFFER, binding, ubo);
         UBOId(ubo)
     }
 
     pub fn reset_ubo(&self, binding: u32) {
-        gl::bind_buffer(gl::UNIFORM_BUFFER, 0);
-        gl::bind_buffer_base(gl::UNIFORM_BUFFER, binding, 0);
+        self.gl.bind_buffer(gl::UNIFORM_BUFFER, 0);
+        self.gl.bind_buffer_base(gl::UNIFORM_BUFFER, binding, 0);
     }
 
     pub fn delete_buffer(&self, buffer: UBOId) {
-        gl::delete_buffers(&[buffer.0]);
+        self.gl.delete_buffers(&[buffer.0]);
     }
 
     #[cfg(target_os = "android")]
     pub fn set_multisample(&self, enable: bool) {
     }
 
     #[cfg(not(target_os = "android"))]
     pub fn set_multisample(&self, enable: bool) {
         if self.capabilities.supports_multisampling {
             if enable {
-                gl::enable(gl::MULTISAMPLE);
+                self.gl.enable(gl::MULTISAMPLE);
             } else {
-                gl::disable(gl::MULTISAMPLE);
+                self.gl.disable(gl::MULTISAMPLE);
             }
         }
     }
 
     pub fn clear_target(&self,
                         color: Option<[f32; 4]>,
                         depth: Option<f32>) {
         let mut clear_bits = 0;
 
         if let Some(color) = color {
-            gl::clear_color(color[0], color[1], color[2], color[3]);
+            self.gl.clear_color(color[0], color[1], color[2], color[3]);
             clear_bits |= gl::COLOR_BUFFER_BIT;
         }
 
         if let Some(depth) = depth {
-            gl::clear_depth(depth as f64);
+            self.gl.clear_depth(depth as f64);
             clear_bits |= gl::DEPTH_BUFFER_BIT;
         }
 
         if clear_bits != 0 {
-            gl::clear(clear_bits);
+            self.gl.clear(clear_bits);
         }
     }
 
     pub fn clear_target_rect(&self,
                              color: Option<[f32; 4]>,
                              depth: Option<f32>,
                              rect: DeviceIntRect) {
         let mut clear_bits = 0;
 
         if let Some(color) = color {
-            gl::clear_color(color[0], color[1], color[2], color[3]);
+            self.gl.clear_color(color[0], color[1], color[2], color[3]);
             clear_bits |= gl::COLOR_BUFFER_BIT;
         }
 
         if let Some(depth) = depth {
-            gl::clear_depth(depth as f64);
+            self.gl.clear_depth(depth as f64);
             clear_bits |= gl::DEPTH_BUFFER_BIT;
         }
 
         if clear_bits != 0 {
-            gl::enable(gl::SCISSOR_TEST);
-            gl::scissor(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
-            gl::clear(clear_bits);
-            gl::disable(gl::SCISSOR_TEST);
+            self.gl.enable(gl::SCISSOR_TEST);
+            self.gl.scissor(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+            self.gl.clear(clear_bits);
+            self.gl.disable(gl::SCISSOR_TEST);
         }
     }
 
     pub fn enable_depth(&self) {
-        gl::enable(gl::DEPTH_TEST);
+        self.gl.enable(gl::DEPTH_TEST);
     }
 
     pub fn disable_depth(&self) {
-        gl::disable(gl::DEPTH_TEST);
+        self.gl.disable(gl::DEPTH_TEST);
     }
 
     pub fn set_depth_func(&self, depth_func: DepthFunction) {
-        gl::depth_func(depth_func as gl::GLuint);
+        self.gl.depth_func(depth_func as gl::GLuint);
     }
 
     pub fn enable_depth_write(&self) {
-        gl::depth_mask(true);
+        self.gl.depth_mask(true);
     }
 
     pub fn disable_depth_write(&self) {
-        gl::depth_mask(false);
+        self.gl.depth_mask(false);
     }
 
     pub fn disable_stencil(&self) {
-        gl::disable(gl::STENCIL_TEST);
+        self.gl.disable(gl::STENCIL_TEST);
     }
 
     pub fn disable_scissor(&self) {
-        gl::disable(gl::SCISSOR_TEST);
+        self.gl.disable(gl::SCISSOR_TEST);
     }
 
     pub fn set_blend(&self, enable: bool) {
         if enable {
-            gl::enable(gl::BLEND);
+            self.gl.enable(gl::BLEND);
         } else {
-            gl::disable(gl::BLEND);
+            self.gl.disable(gl::BLEND);
         }
     }
 
     pub fn set_blend_mode_premultiplied_alpha(&self) {
-        gl::blend_func(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
-        gl::blend_equation(gl::FUNC_ADD);
+        self.gl.blend_func(gl::ONE, gl::ONE_MINUS_SRC_ALPHA);
+        self.gl.blend_equation(gl::FUNC_ADD);
     }
 
     pub fn set_blend_mode_alpha(&self) {
-        //gl::blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
-        gl::blend_func_separate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA,
-                                gl::ONE, gl::ONE);
-        gl::blend_equation(gl::FUNC_ADD);
+        //self.gl.blend_func(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
+        self.gl.blend_func_separate(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA,
+                                     gl::ONE, gl::ONE);
+        self.gl.blend_equation(gl::FUNC_ADD);
     }
 
     pub fn set_blend_mode_subpixel(&self, color: ColorF) {
-        gl::blend_color(color.r, color.g, color.b, color.a);
-        gl::blend_func(gl::CONSTANT_COLOR, gl::ONE_MINUS_SRC_COLOR);
+        self.gl.blend_color(color.r, color.g, color.b, color.a);
+        self.gl.blend_func(gl::CONSTANT_COLOR, gl::ONE_MINUS_SRC_COLOR);
     }
 
     pub fn set_blend_mode_multiply(&self) {
-        gl::blend_func_separate(gl::ZERO, gl::SRC_COLOR,
-                                gl::ZERO, gl::SRC_ALPHA);
-        gl::blend_equation(gl::FUNC_ADD);
+        self.gl.blend_func_separate(gl::ZERO, gl::SRC_COLOR,
+                                     gl::ZERO, gl::SRC_ALPHA);
+        self.gl.blend_equation(gl::FUNC_ADD);
     }
     pub fn set_blend_mode_max(&self) {
-        gl::blend_func_separate(gl::ONE, gl::ONE,
-                                gl::ONE, gl::ONE);
-        gl::blend_equation_separate(gl::MAX, gl::FUNC_ADD);
+        self.gl.blend_func_separate(gl::ONE, gl::ONE,
+                                     gl::ONE, gl::ONE);
+        self.gl.blend_equation_separate(gl::MAX, gl::FUNC_ADD);
     }
     pub fn set_blend_mode_min(&self) {
-        gl::blend_func_separate(gl::ONE, gl::ONE,
-                                gl::ONE, gl::ONE);
-        gl::blend_equation_separate(gl::MIN, gl::FUNC_ADD);
+        self.gl.blend_func_separate(gl::ONE, gl::ONE,
+                                     gl::ONE, gl::ONE);
+        self.gl.blend_equation_separate(gl::MIN, gl::FUNC_ADD);
     }
 }
 
 impl Drop for Device {
     fn drop(&mut self) {
         //self.file_watcher.exit();
     }
 }
 
-fn gl_texture_formats_for_image_format(format: ImageFormat) -> (gl::GLint, gl::GLuint) {
+fn gl_texture_formats_for_image_format(gl: &gl::Gl, format: ImageFormat) -> (gl::GLint, gl::GLuint) {
     match format {
         ImageFormat::A8 => {
             if cfg!(any(target_arch="arm", target_arch="aarch64")) {
-                (GL_FORMAT_BGRA as gl::GLint, GL_FORMAT_BGRA)
+                (get_gl_format_bgra(gl) as gl::GLint, get_gl_format_bgra(gl))
             } else {
                 (GL_FORMAT_A as gl::GLint, GL_FORMAT_A)
             }
         },
         ImageFormat::RGB8 => (gl::RGB as gl::GLint, gl::RGB),
         ImageFormat::RGBA8 => {
-            if cfg!(any(target_arch="arm", target_arch="aarch64")) {
-                (GL_FORMAT_BGRA as gl::GLint, GL_FORMAT_BGRA)
-            } else {
-                (gl::RGBA as gl::GLint, GL_FORMAT_BGRA)
+            match gl.get_type() {
+                gl::GlType::Gl =>  {
+                    (gl::RGBA as gl::GLint, get_gl_format_bgra(gl))
+                }
+                gl::GlType::Gles => {
+                    (get_gl_format_bgra(gl) as gl::GLint, get_gl_format_bgra(gl))
+                }
             }
         }
         ImageFormat::RGBAF32 => (gl::RGBA32F as gl::GLint, gl::RGBA),
         ImageFormat::Invalid => unreachable!(),
     }
 }
 
 fn gl_type_for_texture_format(format: ImageFormat) -> gl::GLuint {
--- a/gfx/webrender/src/frame.rs
+++ b/gfx/webrender/src/frame.rs
@@ -15,18 +15,18 @@ use resource_cache::ResourceCache;
 use scene::{Scene, SceneProperties};
 use std::collections::HashMap;
 use std::hash::BuildHasherDefault;
 use tiling::{AuxiliaryListsMap, CompositeOps, PrimitiveFlags};
 use webrender_traits::{AuxiliaryLists, ClipDisplayItem, ClipRegion, ColorF, DeviceUintRect};
 use webrender_traits::{DeviceUintSize, DisplayItem, Epoch, FilterOp, ImageDisplayItem, LayerPoint};
 use webrender_traits::{LayerRect, LayerSize, LayerToScrollTransform, LayoutTransform};
 use webrender_traits::{MixBlendMode, PipelineId, ScrollEventPhase, ScrollLayerId};
-use webrender_traits::{ScrollLayerState, ScrollLocation, ScrollPolicy, ServoScrollRootId};
-use webrender_traits::{SpecificDisplayItem, StackingContext, TileOffset, WorldPoint};
+use webrender_traits::{ScrollLayerState, ScrollLocation, ScrollPolicy, SpecificDisplayItem};
+use webrender_traits::{StackingContext, TileOffset, WorldPoint};
 
 #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
 pub struct FrameId(pub u32);
 
 static DEFAULT_SCROLLBAR_COLOR: ColorF = ColorF { r: 0.3, g: 0.3, b: 0.3, a: 0.6 };
 
 struct FlattenContext<'a> {
     scene: &'a Scene,
@@ -226,22 +226,18 @@ impl Frame {
         self.clip_scroll_tree.drain()
     }
 
     pub fn get_scroll_node_state(&self) -> Vec<ScrollLayerState> {
         self.clip_scroll_tree.get_scroll_node_state()
     }
 
     /// Returns true if any nodes actually changed position or false otherwise.
-    pub fn scroll_nodes(&mut self,
-                        origin: LayerPoint,
-                        pipeline_id: PipelineId,
-                        scroll_root_id: ServoScrollRootId)
-                         -> bool {
-        self.clip_scroll_tree.scroll_nodes(origin, pipeline_id, scroll_root_id)
+    pub fn scroll_nodes(&mut self, origin: LayerPoint, id: ScrollLayerId) -> bool {
+        self.clip_scroll_tree.scroll_nodes(origin, id)
     }
 
     /// Returns true if any nodes actually changed position or false otherwise.
     pub fn scroll(&mut self,
                   scroll_location: ScrollLocation,
                   cursor: WorldPoint,
                   phase: ScrollEventPhase)
                   -> bool {
@@ -344,17 +340,16 @@ impl Frame {
                         reference_frame_relative_offset: LayerPoint,
                         clip: &ClipRegion) {
         let clip_rect = clip.main.translate(&reference_frame_relative_offset);
         context.builder.add_clip_scroll_node(item.id,
                                              parent_id,
                                              pipeline_id,
                                              &clip_rect,
                                              &item.content_size,
-                                             item.scroll_root_id,
                                              clip,
                                              &mut self.clip_scroll_tree);
 
     }
 
     fn flatten_stacking_context<'a>(&mut self,
                                     traversal: &mut DisplayListTraversal<'a>,
                                     pipeline_id: PipelineId,
@@ -517,17 +512,16 @@ impl Frame {
 
         let iframe_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
         context.builder.add_clip_scroll_node(
             iframe_scroll_layer_id,
             iframe_reference_frame_id,
             pipeline_id,
             &LayerRect::new(LayerPoint::zero(), iframe_rect.size),
             &iframe_clip.main.size,
-            Some(ServoScrollRootId(0)),
             iframe_clip,
             &mut self.clip_scroll_tree);
 
         let mut traversal = DisplayListTraversal::new_skipping_first(display_list);
         self.flatten_stacking_context(&mut traversal,
                                       pipeline_id,
                                       context,
                                       iframe_scroll_layer_id,
--- a/gfx/webrender/src/frame_builder.rs
+++ b/gfx/webrender/src/frame_builder.rs
@@ -28,18 +28,17 @@ use tiling::{PackedLayer, PackedLayerInd
 use tiling::{RenderTargetContext, RenderTaskCollection, ScrollbarPrimitive, StackingContext};
 use util::{self, pack_as_float, rect_from_points_f, subtract_rect};
 use util::{RectHelpers, TransformedRectKind};
 use webrender_traits::{BorderDetails, BorderDisplayItem, BorderSide, BorderStyle};
 use webrender_traits::{BoxShadowClipMode, ClipRegion, ColorF, DeviceIntPoint, DeviceIntRect};
 use webrender_traits::{DeviceIntSize, DeviceUintRect, DeviceUintSize, ExtendMode, FontKey};
 use webrender_traits::{FontRenderMode, GlyphOptions, ImageKey, ImageRendering, ItemRange};
 use webrender_traits::{LayerPoint, LayerRect, LayerSize, LayerToScrollTransform, PipelineId};
-use webrender_traits::{RepeatMode, ScrollLayerId, ServoScrollRootId, TileOffset, WebGLContextId};
-use webrender_traits::YuvColorSpace;
+use webrender_traits::{RepeatMode, ScrollLayerId, TileOffset, WebGLContextId, YuvColorSpace};
 
 #[derive(Debug, Clone)]
 struct ImageBorderSegment {
     geom_rect: LayerRect,
     sub_rect: TexelRect,
     stretch_size: LayerSize,
     tile_spacing: LayerSize,
 }
@@ -304,35 +303,32 @@ impl FrameBuilder {
 
         let topmost_scroll_layer_id = ScrollLayerId::root_scroll_layer(pipeline_id);
         clip_scroll_tree.topmost_scroll_layer_id = topmost_scroll_layer_id;
         self.add_clip_scroll_node(topmost_scroll_layer_id,
                                    clip_scroll_tree.root_reference_frame_id,
                                    pipeline_id,
                                    &viewport_rect,
                                    content_size,
-                                   Some(ServoScrollRootId(0)),
                                    &ClipRegion::simple(&viewport_rect),
                                    clip_scroll_tree);
         topmost_scroll_layer_id
     }
 
     pub fn add_clip_scroll_node(&mut self,
                                 new_node_id: ScrollLayerId,
                                 parent_id: ScrollLayerId,
                                 pipeline_id: PipelineId,
                                 local_viewport_rect: &LayerRect,
                                 content_size: &LayerSize,
-                                scroll_root_id: Option<ServoScrollRootId>,
                                 clip_region: &ClipRegion,
                                 clip_scroll_tree: &mut ClipScrollTree) {
         let clip_info = ClipInfo::new(clip_region,
                                       &mut self.prim_store.gpu_data32,
-                                      PackedLayerIndex(self.packed_layers.len()),
-                                      scroll_root_id);
+                                      PackedLayerIndex(self.packed_layers.len()));
         let node = ClipScrollNode::new(pipeline_id,
                                        parent_id,
                                        local_viewport_rect,
                                        *content_size,
                                        clip_info);
 
         clip_scroll_tree.add_node(node, new_node_id);
         self.packed_layers.push(PackedLayer::empty());
--- a/gfx/webrender/src/internal_types.rs
+++ b/gfx/webrender/src/internal_types.rs
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use app_units::Au;
 use device::TextureFilter;
 use euclid::{TypedPoint2D, UnknownUnit};
 use fnv::FnvHasher;
+use gleam::gl;
 use offscreen_gl_context::{NativeGLContext, NativeGLContextHandle};
 use offscreen_gl_context::{GLContext, NativeGLContextMethods, GLContextDispatcher};
 use offscreen_gl_context::{OSMesaContext, OSMesaContextHandle};
 use offscreen_gl_context::{ColorAttachmentType, GLContextAttributes, GLLimits};
 use profiler::BackendProfileCounters;
 use std::collections::{HashMap, HashSet};
 use std::f32;
 use std::hash::BuildHasherDefault;
@@ -69,24 +70,26 @@ impl GLContextHandleWrapper {
                        size: DeviceIntSize,
                        attributes: GLContextAttributes,
                        dispatcher: Option<Box<GLContextDispatcher>>) -> Result<GLContextWrapper, &'static str> {
         match *self {
             GLContextHandleWrapper::Native(ref handle) => {
                 let ctx = GLContext::<NativeGLContext>::new_shared_with_dispatcher(size.to_untyped(),
                                                                                    attributes,
                                                                                    ColorAttachmentType::Texture,
+                                                                                   gl::GlType::default(),
                                                                                    Some(handle),
                                                                                    dispatcher);
                 ctx.map(GLContextWrapper::Native)
             }
             GLContextHandleWrapper::OSMesa(ref handle) => {
                 let ctx = GLContext::<OSMesaContext>::new_shared_with_dispatcher(size.to_untyped(),
                                                                                  attributes,
                                                                                  ColorAttachmentType::Texture,
+                                                                                 gl::GlType::default(),
                                                                                  Some(handle),
                                                                                  dispatcher);
                 ctx.map(GLContextWrapper::OSMesa)
             }
         }
     }
 }
 
--- a/gfx/webrender/src/profiler.rs
+++ b/gfx/webrender/src/profiler.rs
@@ -1,14 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use debug_render::DebugRenderer;
-use device::{GpuMarker, GpuSample, NamedTag};
+use device::{Device, GpuMarker, GpuSample, NamedTag};
 use euclid::{Point2D, Size2D, Rect};
 use std::collections::vec_deque::VecDeque;
 use std::f32;
 use std::mem;
 use webrender_traits::ColorF;
 use time::precise_time_ns;
 
 const GRAPH_WIDTH: f32 = 1024.0;
@@ -634,23 +634,24 @@ impl Profiler {
         if left {
             self.y_left = new_y;
         } else {
             self.y_right = new_y;
         }
     }
 
     pub fn draw_profile(&mut self,
+                        device: &mut Device,
                         frame_profile: &FrameProfileCounters,
                         backend_profile: &BackendProfileCounters,
                         renderer_profile: &RendererProfileCounters,
                         renderer_timers: &mut RendererProfileTimers,
                         debug_renderer: &mut DebugRenderer) {
 
-        let _gm = GpuMarker::new("profile");
+        let _gm = GpuMarker::new(device.rc_gl(), "profile");
         self.x_left = 20.0;
         self.y_left = 40.0;
         self.x_right = 400.0;
         self.y_right = 40.0;
 
         self.draw_counters(&[
             &renderer_profile.frame_counter,
             &renderer_profile.frame_time,
--- a/gfx/webrender/src/render_backend.rs
+++ b/gfx/webrender/src/render_backend.rs
@@ -255,22 +255,22 @@ impl RenderBackend {
                             match frame {
                                 Some(frame) => {
                                     self.publish_frame(frame, &mut profile_counters);
                                     self.notify_compositor_of_new_scroll_frame(true)
                                 }
                                 None => self.notify_compositor_of_new_scroll_frame(false),
                             }
                         }
-                        ApiMsg::ScrollLayersWithScrollId(origin, pipeline_id, scroll_root_id) => {
-                            profile_scope!("ScrollLayersWithScrollId");
+                        ApiMsg::ScrollLayerWithId(origin, id) => {
+                            profile_scope!("ScrollLayerWithScrollId");
                             let frame = {
                                 let counters = &mut profile_counters.texture_cache;
                                 profile_counters.total_time.profile(|| {
-                                    if self.frame.scroll_nodes(origin, pipeline_id, scroll_root_id) {
+                                    if self.frame.scroll_nodes(origin, id) {
                                         Some(self.render(counters))
                                     } else {
                                         None
                                     }
                                 })
                             };
 
                             match frame {
--- a/gfx/webrender/src/renderer.rs
+++ b/gfx/webrender/src/renderer.rs
@@ -11,16 +11,17 @@
 
 use debug_colors;
 use debug_render::DebugRenderer;
 use device::{DepthFunction, Device, FrameId, ProgramId, TextureId, VertexFormat, GpuMarker, GpuProfiler};
 use device::{GpuSample, TextureFilter, VAOId, VertexUsageHint, FileWatcherHandler, TextureTarget, ShaderError};
 use euclid::Matrix4D;
 use fnv::FnvHasher;
 use frame_builder::FrameBuilderConfig;
+use gleam::gl;
 use gpu_store::{GpuStore, GpuStoreLayout};
 use internal_types::{CacheTextureId, RendererFrame, ResultMsg, TextureUpdateOp};
 use internal_types::{ExternalImageUpdateList, TextureUpdateList, PackedVertex, RenderTargetMode};
 use internal_types::{ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE, SourceTexture};
 use internal_types::{BatchTextures, TextureSampler, GLContextHandleWrapper};
 use prim_store::GradientData;
 use profiler::{Profiler, BackendProfileCounters};
 use profiler::{GpuProfileTag, RendererProfileTimers, RendererProfileCounters};
@@ -30,16 +31,17 @@ use render_task::RenderTaskData;
 use std;
 use std::cmp;
 use std::collections::{HashMap, VecDeque};
 use std::f32;
 use std::hash::BuildHasherDefault;
 use std::marker::PhantomData;
 use std::mem;
 use std::path::PathBuf;
+use std::rc::Rc;
 use std::sync::{Arc, Mutex};
 use std::sync::mpsc::{channel, Receiver, Sender};
 use std::thread;
 use texture_cache::TextureCache;
 use threadpool::ThreadPool;
 use tiling::{AlphaBatchKind, BlurCommand, Frame, PrimitiveBatch, PrimitiveBatchData};
 use tiling::{CacheClipInstance, PrimitiveInstance, RenderTarget};
 use time::precise_time_ns;
@@ -555,32 +557,34 @@ impl Renderer {
     /// let opts = webrender::RendererOptions {
     ///    device_pixel_ratio: 1.0,
     ///    resource_override_path: None,
     ///    enable_aa: false,
     ///    enable_profiler: false,
     /// };
     /// let (renderer, sender) = Renderer::new(opts);
     /// ```
-    pub fn new(mut options: RendererOptions,
+    pub fn new(gl: Rc<gl::Gl>,
+               mut options: RendererOptions,
                initial_window_size: DeviceUintSize) -> Result<(Renderer, RenderApiSender), InitError> {
         let (api_tx, api_rx) = try!{ channel::msg_channel() };
         let (payload_tx, payload_rx) = try!{ channel::payload_channel() };
         let (result_tx, result_rx) = channel();
 
         register_thread_with_profiler("Compositor".to_owned());
 
         let notifier = Arc::new(Mutex::new(None));
 
         let file_watch_handler = FileWatcher {
             result_tx: result_tx.clone(),
             notifier: notifier.clone(),
         };
 
-        let mut device = Device::new(options.resource_override_path.clone(),
+        let mut device = Device::new(gl,
+                                     options.resource_override_path.clone(),
                                      Box::new(file_watch_handler));
         // device-pixel ratio doesn't matter here - we are just creating resources.
         device.begin_frame(1.0);
 
         let cs_box_shadow = try!{
             LazilyCompiledShader::new(ShaderKind::Cache(VertexFormat::Triangles),
                                       "cs_box_shadow",
                                       &[],
@@ -853,16 +857,18 @@ impl Renderer {
                                                  recorder,
                                                  backend_main_thread_dispatcher,
                                                  blob_image_renderer,
                                                  backend_vr_compositor,
                                                  initial_window_size);
             backend.run(backend_profile_counters);
         })};
 
+        let gpu_profile = GpuProfiler::new(device.rc_gl());
+
         let renderer = Renderer {
             result_rx: result_rx,
             device: device,
             current_frame: None,
             pending_texture_updates: Vec::new(),
             pending_shader_updates: Vec::new(),
             cs_box_shadow: cs_box_shadow,
             cs_text_run: cs_text_run,
@@ -891,17 +897,17 @@ impl Renderer {
             profile_counters: RendererProfileCounters::new(),
             profiler: Profiler::new(),
             enable_profiler: options.enable_profiler,
             max_recorded_profiles: options.max_recorded_profiles,
             clear_framebuffer: options.clear_framebuffer,
             clear_color: options.clear_color,
             last_time: 0,
             render_targets: Vec::new(),
-            gpu_profile: GpuProfiler::new(),
+            gpu_profile: gpu_profile,
             prim_vao_id: prim_vao_id,
             blur_vao_id: blur_vao_id,
             clip_vao_id: clip_vao_id,
             gdt_index: 0,
             gpu_data_textures: gpu_data_textures,
             pipeline_epoch_map: HashMap::with_hasher(Default::default()),
             main_thread_dispatcher: main_thread_dispatcher,
             cache_texture_id_map: Vec::new(),
@@ -912,16 +918,20 @@ impl Renderer {
             cpu_profiles: VecDeque::new(),
             gpu_profiles: VecDeque::new(),
         };
 
         let sender = RenderApiSender::new(api_tx, payload_tx);
         Ok((renderer, sender))
     }
 
+    pub fn gl(&self) -> &gl::Gl {
+        self.device.gl()
+    }
+
     /// Sets the new RenderNotifier.
     ///
     /// The RenderNotifier will be called when processing e.g. of a (scrolling) frame is done,
     /// and therefore the screen should be updated.
     pub fn set_render_notifier(&self, notifier: Box<RenderNotifier>) {
         let mut notifier_arc = self.notifier.lock().unwrap();
         *notifier_arc = Some(notifier);
     }
@@ -1072,17 +1082,18 @@ impl Renderer {
                     }
                     let cpu_profile = CpuProfile::new(cpu_frame_id,
                                                       profile_timers.cpu_time.get(),
                                                       self.profile_counters.draw_calls.get());
                     self.cpu_profiles.push_back(cpu_profile);
                 }
 
                 if self.enable_profiler {
-                    self.profiler.draw_profile(&frame.profile_counters,
+                    self.profiler.draw_profile(&mut self.device,
+                                               &frame.profile_counters,
                                                &self.backend_profile_counters,
                                                &self.profile_counters,
                                                &mut profile_timers,
                                                &mut self.debug);
                 }
 
                 self.profile_counters.reset();
                 self.profile_counters.frame_counter.inc();
@@ -1117,17 +1128,17 @@ impl Renderer {
 
         if update_uniforms {
             self.update_uniform_locations();
         }
     }
 */
 
     fn update_texture_cache(&mut self) {
-        let _gm = GpuMarker::new("texture cache update");
+        let _gm = GpuMarker::new(self.device.rc_gl(), "texture cache update");
         let mut pending_texture_updates = mem::replace(&mut self.pending_texture_updates, vec![]);
         for update_list in pending_texture_updates.drain(..) {
             for update in update_list.updates {
                 match update.op {
                     TextureUpdateOp::Create { width, height, format, filter, mode, data } => {
                         let CacheTextureId(cache_texture_index) = update.id;
                         if self.cache_texture_id_map.len() == cache_texture_index {
                             // Create a new native texture, as requested by the texture cache.
@@ -1508,27 +1519,27 @@ impl Renderer {
         {
             let _gm = self.gpu_profile.add_marker(GPU_TAG_CACHE_CLIP);
             let vao = self.clip_vao_id;
             // switch to multiplicative blending
             self.device.set_blend(true);
             self.device.set_blend_mode_multiply();
             // draw rounded cornered rectangles
             if !target.clip_batcher.rectangles.is_empty() {
-                let _gm2 = GpuMarker::new("clip rectangles");
+                let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip rectangles");
                 let shader = self.cs_clip_rectangle.get(&mut self.device).unwrap();
                 self.draw_instanced_batch(&target.clip_batcher.rectangles,
                                           vao,
                                           shader,
                                           &BatchTextures::no_texture(),
                                           &projection);
             }
             // draw image masks
             for (mask_texture_id, items) in target.clip_batcher.images.iter() {
-                let _gm2 = GpuMarker::new("clip images");
+                let _gm2 = GpuMarker::new(self.device.rc_gl(), "clip images");
                 let texture_id = self.resolve_source_texture(mask_texture_id);
                 self.device.bind_texture(TextureSampler::Mask, texture_id);
                 let shader = self.cs_clip_image.get(&mut self.device).unwrap();
                 self.draw_instanced_batch(items,
                                           vao,
                                           shader,
                                           &BatchTextures::no_texture(),
                                           &projection);
@@ -1551,17 +1562,17 @@ impl Renderer {
 
             self.draw_instanced_batch(&target.text_run_cache_prims,
                                       vao,
                                       shader,
                                       &target.text_run_textures,
                                       &projection);
         }
 
-        let _gm2 = GpuMarker::new("alpha batches");
+        let _gm2 = GpuMarker::new(self.device.rc_gl(), "alpha batches");
         self.device.set_blend(false);
         let mut prev_blend_mode = BlendMode::None;
 
         self.device.set_depth_func(DepthFunction::Less);
         self.device.enable_depth();
         self.device.enable_depth_write();
 
         for batch in &target.alpha_batcher.opaque_batches {
@@ -1615,17 +1626,17 @@ impl Renderer {
         // custom item. Then we patch the resource_rects structure
         // here before it's uploaded to the GPU.
         if !frame.deferred_resolves.is_empty() {
             let handler = self.external_image_handler
                               .as_mut()
                               .expect("Found external image, but no handler set!");
 
             for deferred_resolve in &frame.deferred_resolves {
-                GpuMarker::fire("deferred resolve");
+                GpuMarker::fire(self.device.gl(), "deferred resolve");
                 let props = &deferred_resolve.image_properties;
                 let external_id = props.external_id
                                        .expect("BUG: Deferred resolves must be external images!");
                 let image = handler.lock(external_id);
 
                 let texture_id = match image.source {
                     ExternalImageSource::NativeTexture(texture_id) => TextureId::new(texture_id),
                     _ => panic!("No native texture found."),
@@ -1662,17 +1673,17 @@ impl Renderer {
                 handler.release(external_id);
             }
         }
     }
 
     fn draw_tile_frame(&mut self,
                        frame: &mut Frame,
                        framebuffer_size: &DeviceUintSize) {
-        let _gm = GpuMarker::new("tile frame draw");
+        let _gm = GpuMarker::new(self.device.rc_gl(), "tile frame draw");
         self.update_deferred_resolves(frame);
 
         // Some tests use a restricted viewport smaller than the main screen size.
         // Ensure we clear the framebuffer in these tests.
         // TODO(gw): Find a better solution for this?
         let needs_clear = frame.window_size.width < framebuffer_size.width ||
                           frame.window_size.height < framebuffer_size.height;
 
--- a/gfx/webrender/src/resource_cache.rs
+++ b/gfx/webrender/src/resource_cache.rs
@@ -653,23 +653,58 @@ impl ResourceCache {
             image_template.data.clone()
         });
 
         match image_template.data {
             ImageData::ExternalHandle(..) => {
                 // external handle doesn't need to update the texture_cache.
             }
             ImageData::Raw(..) | ImageData::ExternalBuffer(..) | ImageData::Blob(..) => {
+                let descriptor = if let Some(tile) = request.tile {
+                    let tile_size = image_template.tiling.unwrap() as u32;
+                    let image_descriptor = &image_template.descriptor;
+                    let stride = image_descriptor.compute_stride();
+                    let bpp = image_descriptor.format.bytes_per_pixel().unwrap();
+
+                    // Storage for the tiles on the right and bottom edges is shrunk to
+                    // fit the image data (See decompose_tiled_image in frame.rs).
+                    let actual_width = if (tile.x as u32) < image_descriptor.width / tile_size {
+                        tile_size
+                    } else {
+                        image_descriptor.width % tile_size
+                    };
+
+                    let actual_height = if (tile.y as u32) < image_descriptor.height / tile_size {
+                        tile_size
+                    } else {
+                        image_descriptor.height % tile_size
+                    };
+
+                    let offset = image_descriptor.offset + tile.y as u32 * tile_size * stride
+                                                         + tile.x as u32 * tile_size * bpp;
+
+                    ImageDescriptor {
+                        width: actual_width,
+                        height: actual_height,
+                        stride: Some(stride),
+                        offset: offset,
+                        format: image_descriptor.format,
+                        is_opaque: image_descriptor.is_opaque,
+                    }
+                } else {
+                    image_template.descriptor.clone()
+                };
+
                 match self.cached_images.entry(request.clone(), self.current_frame_id) {
                     Occupied(entry) => {
                         let image_id = entry.get().texture_cache_id;
 
                         if entry.get().epoch != image_template.epoch {
                             self.texture_cache.update(image_id,
-                                                      image_template.descriptor,
+                                                      descriptor,
                                                       image_data);
 
                             // Update the cached epoch
                             *entry.into_mut() = CachedImageInfo {
                                 texture_cache_id: image_id,
                                 epoch: image_template.epoch,
                             };
                         }
@@ -677,60 +712,21 @@ impl ResourceCache {
                     Vacant(entry) => {
                         let image_id = self.texture_cache.new_item_id();
 
                         let filter = match request.rendering {
                             ImageRendering::Pixelated => TextureFilter::Nearest,
                             ImageRendering::Auto | ImageRendering::CrispEdges => TextureFilter::Linear,
                         };
 
-                        if let Some(tile) = request.tile {
-                            let tile_size = image_template.tiling.unwrap() as u32;
-                            let image_descriptor = image_template.descriptor.clone();
-                            let stride = image_descriptor.compute_stride();
-                            let bpp = image_descriptor.format.bytes_per_pixel().unwrap();
-
-                            // Storage for the tiles on the right and bottom edges is shrunk to
-                            // fit the image data (See decompose_tiled_image in frame.rs).
-                            let actual_width = if (tile.x as u32) < image_descriptor.width / tile_size {
-                                tile_size
-                            } else {
-                                image_descriptor.width % tile_size
-                            };
-
-                            let actual_height = if (tile.y as u32) < image_descriptor.height / tile_size {
-                                tile_size
-                            } else {
-                                image_descriptor.height % tile_size
-                            };
-
-                            let offset = image_descriptor.offset + tile.y as u32 * tile_size * stride
-                                                                 + tile.x as u32 * tile_size * bpp;
-
-                            let tile_descriptor = ImageDescriptor {
-                                width: actual_width,
-                                height: actual_height,
-                                stride: Some(stride),
-                                offset: offset,
-                                format: image_descriptor.format,
-                                is_opaque: image_descriptor.is_opaque,
-                            };
-
-                            self.texture_cache.insert(image_id,
-                                                      tile_descriptor,
-                                                      filter,
-                                                      image_data,
-                                                      texture_cache_profile);
-                        } else {
-                            self.texture_cache.insert(image_id,
-                                                      image_template.descriptor,
-                                                      filter,
-                                                      image_data,
-                                                      texture_cache_profile);
-                        }
+                        self.texture_cache.insert(image_id,
+                                                  descriptor,
+                                                  filter,
+                                                  image_data,
+                                                  texture_cache_profile);
 
                         entry.insert(CachedImageInfo {
                             texture_cache_id: image_id,
                             epoch: image_template.epoch,
                         });
                     }
                 }
             }
--- a/gfx/webrender_bindings/Cargo.toml
+++ b/gfx/webrender_bindings/Cargo.toml
@@ -1,16 +1,16 @@
 [package]
 name = "webrender_bindings"
 version = "0.1.0"
 authors = ["The Mozilla Project Developers"]
 license = "MPL-2.0"
 
 [dependencies]
-webrender_traits = {path = "../webrender_traits", version = "0.25.0"}
+webrender_traits = {path = "../webrender_traits", version = "0.26.0"}
 euclid = "0.11"
 app_units = "0.4"
-gleam = "0.2"
+gleam = "0.4"
 
 [dependencies.webrender]
 path = "../webrender"
-version = "0.24.0"
+version = "0.25.0"
 default-features = false
--- a/gfx/webrender_bindings/RendererOGL.h
+++ b/gfx/webrender_bindings/RendererOGL.h
@@ -71,16 +71,18 @@ public:
               layers::CompositorBridgeParentBase* aBridge);
 
   layers::CompositorBridgeParentBase* GetCompositorBridge() { return mBridge; }
 
   WrRenderedEpochs* FlushRenderedEpochs();
 
   RenderTextureHost* GetRenderTexture(uint64_t aExternalImageId);
 
+  WrRenderer* GetWrRenderer() { return mWrRenderer; }
+
 protected:
 
   RefPtr<RenderThread> mThread;
   RefPtr<gl::GLContext> mGL;
   RefPtr<widget::CompositorWidget> mWidget;
   WrRenderer* mWrRenderer;
   layers::CompositorBridgeParentBase* mBridge;
   wr::WindowId mWindowId;
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
@@ -223,17 +223,18 @@ WebRenderAPI::Readback(gfx::IntSize size
             ~Readback()
             {
                 MOZ_COUNT_DTOR(Readback);
             }
 
             virtual void Run(RenderThread& aRenderThread, WindowId aWindowId) override
             {
                 aRenderThread.UpdateAndRender(aWindowId);
-                wr_renderer_readback(mSize.width, mSize.height, mBuffer, mBufferSize);
+                wr_renderer_readback(aRenderThread.GetRenderer(aWindowId)->GetWrRenderer(),
+                                     mSize.width, mSize.height, mBuffer, mBufferSize);
                 layers::AutoCompleteTask complete(mTask);
             }
 
             layers::SynchronousTask* mTask;
             gfx::IntSize mSize;
             uint8_t *mBuffer;
             uint32_t mBufferSize;
     };
--- a/gfx/webrender_bindings/WebRenderTypes.h
+++ b/gfx/webrender_bindings/WebRenderTypes.h
@@ -196,16 +196,26 @@ static inline WrPoint ToWrPoint(const La
 static inline WrSize ToWrSize(const LayerSize size)
 {
   WrSize ls;
   ls.width = size.width;
   ls.height = size.height;
   return ls;
 }
 
+static inline WrBorderRadius ToWrUniformBorderRadius(const LayerSize& aSize)
+{
+  WrBorderRadius br;
+  br.top_left = ToWrSize(aSize);
+  br.top_right = ToWrSize(aSize);
+  br.bottom_left = ToWrSize(aSize);
+  br.bottom_right = ToWrSize(aSize);
+  return br;
+}
+
 static inline WrBorderRadius ToWrBorderRadius(const LayerSize& topLeft, const LayerSize& topRight,
                                               const LayerSize& bottomLeft, const LayerSize& bottomRight)
 {
   WrBorderRadius br;
   br.top_left = ToWrSize(topLeft);
   br.top_right = ToWrSize(topRight);
   br.bottom_left = ToWrSize(bottomLeft);
   br.bottom_right = ToWrSize(bottomRight);
@@ -282,16 +292,26 @@ static inline WrRect ToWrRect(const gfx:
 }
 
 template<class T>
 static inline WrRect ToWrRect(const gfx::IntRectTyped<T>& rect)
 {
   return ToWrRect(IntRectToRect(rect));
 }
 
+template<class T>
+static inline WrComplexClipRegion ToWrComplexClipRegion(const gfx::RectTyped<T>& rect,
+                                                        const LayerSize& size)
+{
+  WrComplexClipRegion complex_clip;
+  complex_clip.rect = wr::ToWrRect(rect);
+  complex_clip.radii = wr::ToWrUniformBorderRadius(size);
+  return complex_clip;
+}
+
 static inline WrPoint ToWrPoint(const gfx::Point& point)
 {
   WrPoint p;
   p.x = point.x;
   p.y = point.y;
   return p;
 }
 
--- a/gfx/webrender_bindings/src/bindings.rs
+++ b/gfx/webrender_bindings/src/bindings.rs
@@ -1,27 +1,24 @@
 use std::ffi::CString;
 use std::{mem, slice};
 use std::path::PathBuf;
 use std::os::raw::{c_void, c_char};
 use gleam::gl;
 
-use webrender_traits::{BorderSide, BorderStyle, BorderRadius};
-use webrender_traits::{BorderWidths, BorderDetails, NormalBorder};
-use webrender_traits::{RepeatMode, ImageBorder, NinePatchDescriptor};
-use webrender_traits::{PipelineId, ComplexClipRegion, ClipRegion, PropertyBinding};
-use webrender_traits::{Epoch, ExtendMode, ColorF, GlyphInstance, GradientStop, ImageDescriptor};
-use webrender_traits::{ImageData, ImageFormat, ImageKey, ImageMask, ImageRendering};
-use webrender_traits::{FilterOp, MixBlendMode};
-use webrender_traits::{ExternalImageId, RenderApi, FontKey};
-use webrender_traits::{DeviceUintSize, DeviceUintRect, DeviceUintPoint, ExternalEvent};
-use webrender_traits::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform};
-use webrender_traits::{BoxShadowClipMode, LayerPixel, ServoScrollRootId, IdNamespace};
-use webrender_traits::{BuiltDisplayListDescriptor, AuxiliaryListsDescriptor};
-use webrender_traits::{BuiltDisplayList, AuxiliaryLists, ItemRange};
+use webrender_traits::{AuxiliaryLists, AuxiliaryListsDescriptor, BorderDetails, BorderRadius};
+use webrender_traits::{BorderSide, BorderStyle, BorderWidths, BoxShadowClipMode, BuiltDisplayList};
+use webrender_traits::{BuiltDisplayListDescriptor, ClipRegion, ColorF, ComplexClipRegion};
+use webrender_traits::{DeviceUintPoint, DeviceUintRect, DeviceUintSize, Epoch, ExtendMode};
+use webrender_traits::{ExternalEvent, ExternalImageId, FilterOp, FontKey, GlyphInstance};
+use webrender_traits::{GradientStop, IdNamespace, ImageBorder, ImageData, ImageDescriptor};
+use webrender_traits::{ImageFormat, ImageKey, ImageMask, ImageRendering, ItemRange, LayerPixel};
+use webrender_traits::{LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, MixBlendMode};
+use webrender_traits::{NinePatchDescriptor, NormalBorder, PipelineId, PropertyBinding, RenderApi};
+use webrender_traits::RepeatMode;
 use webrender::renderer::{Renderer, RendererOptions};
 use webrender::renderer::{ExternalImage, ExternalImageHandler, ExternalImageSource};
 use webrender::{ApiRecordingReceiver, BinaryRecorder};
 use app_units::Au;
 use euclid::{TypedPoint2D, SideOffsets2D};
 
 extern crate webrender_traits;
 
@@ -53,16 +50,30 @@ check_ffi_type!(_font_key_repr struct Fo
 check_ffi_type!(_epoch_repr struct Epoch as (u32));
 check_ffi_type!(_image_format_repr enum ImageFormat as u32);
 check_ffi_type!(_border_style_repr enum BorderStyle as u32);
 check_ffi_type!(_image_rendering_repr enum ImageRendering as u32);
 check_ffi_type!(_mix_blend_mode_repr enum MixBlendMode as u32);
 check_ffi_type!(_box_shadow_clip_mode_repr enum BoxShadowClipMode as u32);
 check_ffi_type!(_namespace_id_repr struct IdNamespace as (u32));
 
+const GL_FORMAT_BGRA_GL: gl::GLuint = gl::BGRA;
+const GL_FORMAT_BGRA_GLES: gl::GLuint = gl::BGRA_EXT;
+
+fn get_gl_format_bgra(gl: &gl::Gl) -> gl::GLuint {
+    match gl.get_type() {
+        gl::GlType::Gl => {
+            GL_FORMAT_BGRA_GL
+        }
+        gl::GlType::Gles => {
+            GL_FORMAT_BGRA_GLES
+        }
+    }
+}
+
 #[repr(C)]
 pub enum WrGradientExtendMode {
     Clamp,
     Repeat,
 }
 
 impl WrGradientExtendMode {
     pub fn to_gradient_extend_mode(self) -> ExtendMode {
@@ -538,16 +549,17 @@ fn get_proc_address(glcontext_ptr: *mut 
 
     symbol as *const _
 }
 
 extern "C" {
     fn is_in_compositor_thread() -> bool;
     fn is_in_render_thread() -> bool;
     fn is_in_main_thread() -> bool;
+    fn is_glcontext_egl(glcontext_ptr: *mut c_void) -> bool;
 }
 
 struct CppNotifier {
     window_id: WrWindowId,
 }
 
 unsafe impl Send for CppNotifier {}
 
@@ -600,32 +612,33 @@ pub extern "C" fn wr_renderer_update(ren
 
 #[no_mangle]
 pub extern "C" fn wr_renderer_render(renderer: &mut Renderer, width: u32, height: u32) {
     renderer.render(DeviceUintSize::new(width, height));
 }
 
 // Call wr_renderer_render() before calling this function.
 #[no_mangle]
-pub unsafe extern "C" fn wr_renderer_readback(width: u32,
+pub unsafe extern "C" fn wr_renderer_readback(renderer: &mut Renderer,
+                                              width: u32,
                                               height: u32,
                                               dst_buffer: *mut u8,
                                               buffer_size: usize) {
     assert!(is_in_render_thread());
 
-    gl::flush();
+    renderer.gl().flush();
 
     let mut slice = slice::from_raw_parts_mut(dst_buffer, buffer_size);
-    gl::read_pixels_into_buffer(0,
-                                0,
-                                width as gl::GLsizei,
-                                height as gl::GLsizei,
-                                gl::BGRA,
-                                gl::UNSIGNED_BYTE,
-                                slice);
+    renderer.gl().read_pixels_into_buffer(0,
+                                          0,
+                                          width as gl::GLsizei,
+                                          height as gl::GLsizei,
+                                          get_gl_format_bgra(renderer.gl()),
+                                          gl::UNSIGNED_BYTE,
+                                          slice);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_renderer_set_profiler_enabled(renderer: &mut Renderer, enabled: bool) {
     renderer.set_profiler_enabled(enabled);
 }
 
 #[no_mangle]
@@ -685,33 +698,38 @@ pub extern "C" fn wr_window_new(window_i
 
     let recorder: Option<Box<ApiRecordingReceiver>> = if ENABLE_RECORDING {
         let name = format!("wr-record-{}.bin", window_id.0);
         Some(Box::new(BinaryRecorder::new(&PathBuf::from(name))))
     } else {
         None
     };
 
-    gl::load_with(|symbol| get_proc_address(gl_context, symbol));
-    gl::clear_color(0.3, 0.0, 0.0, 1.0);
+    let gl;
+    if unsafe { is_glcontext_egl(gl_context) } {
+      gl = unsafe { gl::GlesFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
+    } else {
+      gl = unsafe { gl::GlFns::load_with(|symbol| get_proc_address(gl_context, symbol)) };
+    }
+    gl.clear_color(0.3, 0.0, 0.0, 1.0);
 
-    let version = gl::get_string(gl::VERSION);
+    let version = gl.get_string(gl::VERSION);
 
     println!("WebRender - OpenGL version new {}", version);
 
     let opts = RendererOptions {
         enable_aa: true,
         enable_subpixel_aa: true,
         enable_profiler: enable_profiler,
         recorder: recorder,
         ..Default::default()
     };
 
     let window_size = DeviceUintSize::new(window_width, window_height);
-    let (renderer, sender) = match Renderer::new(opts, window_size) {
+    let (renderer, sender) = match Renderer::new(gl, opts, window_size) {
         Ok((renderer, sender)) => (renderer, sender),
         Err(e) => {
             println!(" Failed to create a Renderer: {:?}", e);
             return false;
         }
     };
 
     renderer.set_render_notifier(Box::new(CppNotifier { window_id: window_id }));
@@ -1031,19 +1049,17 @@ pub extern "C" fn wr_dp_push_stacking_co
         .push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                bounds,
                                clip_region2,
                                state.z_index,
                                Some(PropertyBinding::Value(*transform)),
                                None,
                                mix_blend_mode,
                                filters);
-    state.frame_builder.dl_builder.push_scroll_layer(clip_region,
-                                                     bounds.size,
-                                                     Some(ServoScrollRootId(1)));
+    state.frame_builder.dl_builder.push_scroll_layer(clip_region, bounds.size, None);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_stacking_context(state: &mut WrState) {
     assert!(unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_scroll_layer();
     state.frame_builder.dl_builder.pop_stacking_context();
     //println!("pop_stacking {:?}", state.pipeline_id);
@@ -1059,19 +1075,17 @@ pub extern "C" fn wr_dp_push_scroll_laye
     let mask = mask.map(|&WrImageMask { image, ref rect, repeat }| {
         ImageMask {
             image: image,
             rect: rect.to_rect(),
             repeat: repeat,
         }
     });
     let clip_region = state.frame_builder.dl_builder.new_clip_region(&overflow, vec![], mask);
-    state.frame_builder.dl_builder.push_scroll_layer(clip_region,
-                                                     bounds.size,
-                                                     Some(ServoScrollRootId(1)));
+    state.frame_builder.dl_builder.push_scroll_layer(clip_region, bounds.size, None);
 }
 
 #[no_mangle]
 pub extern "C" fn wr_dp_pop_scroll_layer(state: &mut WrState) {
     assert!(unsafe { is_in_main_thread() });
     state.frame_builder.dl_builder.pop_scroll_layer();
 }
 
--- a/gfx/webrender_bindings/webrender_ffi.h
+++ b/gfx/webrender_bindings/webrender_ffi.h
@@ -64,16 +64,17 @@ WR_DECL_FFI_2(WrFontKey, uint32_t, uint3
 
 // ----
 // Functions invoked from Rust code
 // ----
 
 bool is_in_compositor_thread();
 bool is_in_main_thread();
 bool is_in_render_thread();
+bool is_glcontext_egl(void* glcontext_ptr);
 void* get_proc_address_from_glcontext(void* glcontext_ptr, const char* procname);
 
 // -----
 // Enums used in C++ code with corresponding enums in Rust code
 // -----
 enum class WrBoxShadowClipMode: uint32_t {
   None,
   Outset,
@@ -479,17 +480,18 @@ WR_FUNC;
 
 WR_INLINE void
 wr_renderer_render(WrRenderer* renderer, uint32_t width, uint32_t height)
 WR_FUNC;
 
 // It is the responsibility of the caller to manage the dst_buffer memory
 // and also free it at the proper time.
 WR_INLINE const uint8_t*
-wr_renderer_readback(uint32_t width, uint32_t height,
+wr_renderer_readback(WrRenderer* renderer,
+                     uint32_t width, uint32_t height,
                      uint8_t* dst_buffer, size_t buffer_length)
 WR_FUNC;
 
 WR_INLINE void
 wr_renderer_set_profiler_enabled(WrRenderer* renderer, bool enabled)
 WR_FUNC;
 
 WR_INLINE bool
--- a/gfx/webrender_traits/Cargo.toml
+++ b/gfx/webrender_traits/Cargo.toml
@@ -1,27 +1,27 @@
 [package]
 name = "webrender_traits"
-version = "0.25.0"
+version = "0.26.0"
 authors = ["Glenn Watson <gw@intuitionlibrary.com>"]
 license = "MPL-2.0"
 repository = "https://github.com/servo/webrender"
 
 [features]
 nightly = ["euclid/unstable", "serde/unstable"]
 ipc = ["ipc-channel"]
 
 [dependencies]
 app_units = "0.4"
 byteorder = "1.0"
 euclid = "0.11"
-gleam = "0.2"
+gleam = "0.4"
 heapsize = "0.3.6"
 ipc-channel = {version = "0.7", optional = true}
-offscreen_gl_context = {version = "0.6", features = ["serde"]}
+offscreen_gl_context = {version = "0.8", features = ["serde"]}
 serde = "0.9"
 serde_derive = "0.9"
 
 [target.'cfg(target_os = "macos")'.dependencies]
 core-graphics = "0.7"
 
 [target.'cfg(target_os = "windows")'.dependencies]
 dwrote = "0.3"
--- a/gfx/webrender_traits/src/api.rs
+++ b/gfx/webrender_traits/src/api.rs
@@ -1,24 +1,22 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use byteorder::{LittleEndian, WriteBytesExt};
 use channel::{self, MsgSender, PayloadHelperMethods, PayloadSender};
 use offscreen_gl_context::{GLContextAttributes, GLLimits};
 use std::cell::Cell;
-use {ColorF, ImageDescriptor};
-use {FontKey, ImageKey, NativeFontHandle, ServoScrollRootId};
-use {GlyphKey, GlyphDimensions, ImageData, WebGLContextId, WebGLCommand};
-use {DeviceIntSize, LayoutPoint, LayoutSize, WorldPoint};
-use {DeviceIntPoint, DeviceUintRect, DeviceUintSize, LayoutTransform};
-use {BuiltDisplayList, BuiltDisplayListDescriptor, AuxiliaryLists, AuxiliaryListsDescriptor};
 use std::fmt;
 use std::marker::PhantomData;
+use {AuxiliaryLists, AuxiliaryListsDescriptor, BuiltDisplayList, BuiltDisplayListDescriptor};
+use {ColorF, DeviceIntPoint, DeviceIntSize, DeviceUintRect, DeviceUintSize, FontKey};
+use {GlyphDimensions, GlyphKey, ImageData, ImageDescriptor, ImageKey, LayoutPoint, LayoutSize};
+use {LayoutTransform, NativeFontHandle, ScrollLayerId, WebGLCommand, WebGLContextId, WorldPoint};
 
 pub type TileSize = u16;
 
 #[derive(Clone, Deserialize, Serialize)]
 pub enum ApiMsg {
     AddRawFont(FontKey, Vec<u8>),
     AddNativeFont(FontKey, NativeFontHandle),
     DeleteFont(FontKey),
@@ -43,17 +41,17 @@ pub enum ApiMsg {
                        AuxiliaryListsDescriptor,
                        bool),
     SetPageZoom(ZoomFactor),
     SetPinchZoom(ZoomFactor),
     SetPan(DeviceIntPoint),
     SetRootPipeline(PipelineId),
     SetWindowParameters(DeviceUintSize, DeviceUintRect),
     Scroll(ScrollLocation, WorldPoint, ScrollEventPhase),
-    ScrollLayersWithScrollId(LayoutPoint, PipelineId, ServoScrollRootId),
+    ScrollLayerWithId(LayoutPoint, ScrollLayerId),
     TickScrollingBounce,
     TranslatePointToLayerSpace(WorldPoint, MsgSender<(LayoutPoint, PipelineId)>),
     GetScrollLayerState(MsgSender<Vec<ScrollLayerState>>),
     RequestWebGLContext(DeviceIntSize, GLContextAttributes, MsgSender<Result<(WebGLContextId, GLLimits), String>>),
     ResizeWebGLContext(WebGLContextId, DeviceIntSize),
     WebGLCommand(WebGLContextId, WebGLCommand),
     GenerateFrame(Option<DynamicProperties>),
     // WebVR commands that must be called in the WebGL render thread.
@@ -74,17 +72,17 @@ impl fmt::Debug for ApiMsg {
             &ApiMsg::GetGlyphDimensions(..) => { write!(f, "ApiMsg::GetGlyphDimensions") }
             &ApiMsg::AddImage(..) => { write!(f, "ApiMsg::AddImage") }
             &ApiMsg::UpdateImage(..) => { write!(f, "ApiMsg::UpdateImage") }
             &ApiMsg::DeleteImage(..) => { write!(f, "ApiMsg::DeleteImage") }
             &ApiMsg::CloneApi(..) => { write!(f, "ApiMsg::CloneApi") }
             &ApiMsg::SetRootDisplayList(..) => { write!(f, "ApiMsg::SetRootDisplayList") }
             &ApiMsg::SetRootPipeline(..) => { write!(f, "ApiMsg::SetRootPipeline") }
             &ApiMsg::Scroll(..) => { write!(f, "ApiMsg::Scroll") }
-            &ApiMsg::ScrollLayersWithScrollId(..) => { write!(f, "ApiMsg::ScrollLayersWithScrollId") }
+            &ApiMsg::ScrollLayerWithId(..) => { write!(f, "ApiMsg::ScrollLayerWithId") }
             &ApiMsg::TickScrollingBounce => { write!(f, "ApiMsg::TickScrollingBounce") }
             &ApiMsg::TranslatePointToLayerSpace(..) => { write!(f, "ApiMsg::TranslatePointToLayerSpace") }
             &ApiMsg::GetScrollLayerState(..) => { write!(f, "ApiMsg::GetScrollLayerState") }
             &ApiMsg::RequestWebGLContext(..) => { write!(f, "ApiMsg::RequestWebGLContext") }
             &ApiMsg::ResizeWebGLContext(..) => { write!(f, "ApiMsg::ResizeWebGLContext") }
             &ApiMsg::WebGLCommand(..) => { write!(f, "ApiMsg::WebGLCommand") }
             &ApiMsg::GenerateFrame(..) => { write!(f, "ApiMsg::GenerateFrame") }
             &ApiMsg::VRCompositorCommand(..) => { write!(f, "ApiMsg::VRCompositorCommand") }
@@ -305,21 +303,18 @@ impl RenderApi {
     ///
     /// Webrender looks for the layer closest to the user
     /// which has `ScrollPolicy::Scrollable` set.
     pub fn scroll(&self, scroll_location: ScrollLocation, cursor: WorldPoint, phase: ScrollEventPhase) {
         let msg = ApiMsg::Scroll(scroll_location, cursor, phase);
         self.api_sender.send(msg).unwrap();
     }
 
-    pub fn scroll_layers_with_scroll_root_id(&self,
-                                             new_scroll_origin: LayoutPoint,
-                                             pipeline_id: PipelineId,
-                                             scroll_root_id: ServoScrollRootId) {
-        let msg = ApiMsg::ScrollLayersWithScrollId(new_scroll_origin, pipeline_id, scroll_root_id);
+    pub fn scroll_layer_with_id(&self, new_scroll_origin: LayoutPoint, id: ScrollLayerId) {
+        let msg = ApiMsg::ScrollLayerWithId(new_scroll_origin, id);
         self.api_sender.send(msg).unwrap();
     }
 
     pub fn set_page_zoom(&self, page_zoom: ZoomFactor) {
         let msg = ApiMsg::SetPageZoom(page_zoom);
         self.api_sender.send(msg).unwrap();
     }
 
@@ -431,18 +426,17 @@ pub enum ScrollEventPhase {
     /// down, if a touchpad is in use. (If false, the event is a touchpad fling.)
     Move(bool),
     /// The user ended scrolling.
     End,
 }
 
 #[derive(Clone, Deserialize, Serialize)]
 pub struct ScrollLayerState {
-    pub pipeline_id: PipelineId,
-    pub scroll_root_id: ServoScrollRootId,
+    pub id: ScrollLayerId,
     pub scroll_offset: LayoutPoint,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, Serialize)]
 pub enum ScrollLocation {
     /// Scroll by a certain amount.
     Delta(LayoutPoint),
     /// Scroll to very top of element.
--- a/gfx/webrender_traits/src/display_item.rs
+++ b/gfx/webrender_traits/src/display_item.rs
@@ -41,17 +41,16 @@ pub struct ItemRange {
     pub length: usize,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct ClipDisplayItem {
     pub content_size: LayoutSize,
     pub id: ScrollLayerId,
     pub parent_id: ScrollLayerId,
-    pub scroll_root_id: Option<ServoScrollRootId>,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct RectangleDisplayItem {
     pub color: ColorF,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
@@ -81,16 +80,17 @@ pub struct WebGLDisplayItem {
 pub struct NormalBorder {
     pub left: BorderSide,
     pub right: BorderSide,
     pub top: BorderSide,
     pub bottom: BorderSide,
     pub radius: BorderRadius,
 }
 
+#[repr(u32)]
 #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)]
 pub enum RepeatMode {
     Stretch,
     Repeat,
     Round,
     Space,
 }
 
@@ -188,16 +188,17 @@ pub struct BoxShadowDisplayItem {
     pub offset: LayoutPoint,
     pub color: ColorF,
     pub blur_radius: f32,
     pub spread_radius: f32,
     pub border_radius: f32,
     pub clip_mode: BoxShadowClipMode,
 }
 
+#[repr(u32)]
 #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, Ord, PartialOrd)]
 pub enum ExtendMode {
     Clamp,
     Repeat,
 }
 
 #[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)]
 pub struct Gradient {
@@ -246,17 +247,16 @@ pub struct StackingContext {
     pub bounds: LayoutRect,
     pub z_index: i32,
     pub transform: Option<PropertyBinding<LayoutTransform>>,
     pub perspective: Option<LayoutTransform>,
     pub mix_blend_mode: MixBlendMode,
     pub filters: ItemRange,
 }
 
-#[repr(C)]
 #[repr(u32)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
 pub enum ScrollPolicy {
     Scrollable  = 0,
     Fixed       = 1,
 }
 
 known_heap_size!(0, ScrollPolicy);
@@ -504,53 +504,50 @@ impl ComplexClipRegion {
         if xl <= xr && yt <= yb {
             Some(LayoutRect::new(LayoutPoint::new(xl, yt), LayoutSize::new(xr-xl, yb-yt)))
         } else {
             None
         }
     }
 }
 
-#[repr(C)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
-pub struct ServoScrollRootId(pub usize);
-
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
-pub struct ScrollLayerId {
-    pub pipeline_id: PipelineId,
-    pub info: ScrollLayerInfo,
+pub enum ScrollLayerId {
+    Clip(usize, PipelineId),
+    ClipExternalId(usize, PipelineId),
+    ReferenceFrame(usize, PipelineId),
 }
 
 impl ScrollLayerId {
     pub fn root_scroll_layer(pipeline_id: PipelineId) -> ScrollLayerId {
-        ScrollLayerId {
-            pipeline_id: pipeline_id,
-            info: ScrollLayerInfo::Scrollable(0),
-        }
+        ScrollLayerId::Clip(0, pipeline_id)
     }
 
     pub fn root_reference_frame(pipeline_id: PipelineId) -> ScrollLayerId {
-        ScrollLayerId {
-            pipeline_id: pipeline_id,
-            info: ScrollLayerInfo::ReferenceFrame(0),
+        ScrollLayerId::ReferenceFrame(0, pipeline_id)
+    }
+
+    pub fn new(id: usize, pipeline_id: PipelineId) -> ScrollLayerId {
+        ScrollLayerId::ClipExternalId(id, pipeline_id)
+    }
+
+    pub fn pipeline_id(&self) -> PipelineId {
+        match *self {
+            ScrollLayerId::Clip(_, pipeline_id) => pipeline_id,
+            ScrollLayerId::ClipExternalId(_, pipeline_id) => pipeline_id,
+            ScrollLayerId::ReferenceFrame(_, pipeline_id) => pipeline_id,
         }
     }
 
     pub fn is_reference_frame(&self) -> bool {
-        match self.info {
-            ScrollLayerInfo::Scrollable(..) => false,
-            ScrollLayerInfo::ReferenceFrame(..) => true,
+        match *self {
+            ScrollLayerId::ReferenceFrame(..) => true,
+            _ => false,
         }
     }
 
-    pub fn new(pipeline_id: PipelineId, index: usize) -> ScrollLayerId {
-        ScrollLayerId {
-            pipeline_id: pipeline_id,
-            info: ScrollLayerInfo::Scrollable(index),
+    pub fn external_id(&self) -> Option<usize> {
+        match *self {
+            ScrollLayerId::ClipExternalId(id, _) => Some(id),
+            _ => None,
         }
     }
 }
-
-#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
-pub enum ScrollLayerInfo {
-    Scrollable(usize),
-    ReferenceFrame(usize),
-}
--- a/gfx/webrender_traits/src/display_list.rs
+++ b/gfx/webrender_traits/src/display_list.rs
@@ -6,18 +6,18 @@ use app_units::Au;
 use std::mem;
 use std::slice;
 use {BorderDetails, BorderDisplayItem, BorderWidths, BoxShadowClipMode, BoxShadowDisplayItem};
 use {ClipDisplayItem, ClipRegion, ColorF, ComplexClipRegion, DisplayItem, ExtendMode, FilterOp};
 use {FontKey, GlyphInstance, GlyphOptions, Gradient, GradientDisplayItem, GradientStop};
 use {IframeDisplayItem, ImageDisplayItem, ImageKey, ImageMask, ImageRendering, ItemRange};
 use {LayoutPoint, LayoutRect, LayoutSize, LayoutTransform, MixBlendMode, PipelineId};
 use {PropertyBinding, PushStackingContextDisplayItem, RadialGradient, RadialGradientDisplayItem};
-use {RectangleDisplayItem, ScrollLayerId, ScrollPolicy, ServoScrollRootId, SpecificDisplayItem};
-use {StackingContext, TextDisplayItem, WebGLContextId, WebGLDisplayItem, YuvColorSpace};
+use {RectangleDisplayItem, ScrollLayerId, ScrollPolicy, SpecificDisplayItem, StackingContext};
+use {TextDisplayItem, WebGLContextId, WebGLDisplayItem, YuvColorSpace};
 use YuvImageDisplayItem;
 
 #[derive(Clone, Deserialize, Serialize)]
 pub struct AuxiliaryLists {
     /// The concatenation of: gradient stops, complex clip regions, filters, and glyph instances,
     /// in that order.
     data: Vec<u8>,
     descriptor: AuxiliaryListsDescriptor,
@@ -336,38 +336,41 @@ impl DisplayListBuilder {
 
     pub fn pop_stacking_context(&mut self) {
         self.push_new_empty_item(SpecificDisplayItem::PopStackingContext);
     }
 
     pub fn define_clip(&mut self,
                        clip: ClipRegion,
                        content_size: LayoutSize,
-                       scroll_root_id: Option<ServoScrollRootId>)
+                       id: Option<ScrollLayerId>)
                        -> ScrollLayerId {
-        let scroll_layer_id = self.next_scroll_layer_id;
-        self.next_scroll_layer_id += 1;
+        let id = match id {
+            Some(id) => id,
+            None => {
+                self.next_scroll_layer_id += 1;
+                ScrollLayerId::Clip(self.next_scroll_layer_id - 1, self.pipeline_id)
+            }
+        };
 
-        let id = ScrollLayerId::new(self.pipeline_id, scroll_layer_id);
         let item = SpecificDisplayItem::Clip(ClipDisplayItem {
             content_size: content_size,
             id: id,
             parent_id: *self.clip_stack.last().unwrap(),
-            scroll_root_id: scroll_root_id,
         });
 
         self.push_item(item, clip.main, clip);
         id
     }
 
     pub fn push_scroll_layer(&mut self,
                              clip: ClipRegion,
                              content_size: LayoutSize,
-                             scroll_root_id: Option<ServoScrollRootId>) {
-        let id = self.define_clip(clip, content_size, scroll_root_id);
+                             id: Option<ScrollLayerId>) {
+        let id = self.define_clip(clip, content_size, id);
         self.clip_stack.push(id);
     }
 
     pub fn push_clip_id(&mut self, id: ScrollLayerId) {
         self.clip_stack.push(id);
     }
 
     pub fn pop_clip_id(&mut self) {
@@ -409,16 +412,17 @@ impl DisplayListBuilder {
                 }
                 Iframe(_) | Clip(_) => {
                     // We don't support relocating these
                     panic!();
                 }
                 _ => {}
             }
             i.clip.complex = self.auxiliary_lists_builder.add_complex_clip_regions(aux.complex_clip_regions(&i.clip.complex));
+            i.scroll_layer_id = *self.clip_stack.last().unwrap();
             self.list.push(i);
         }
     }
 
     pub fn new_clip_region(&mut self,
                            rect: &LayoutRect,
                            complex: Vec<ComplexClipRegion>,
                            image_mask: Option<ImageMask>)
--- a/gfx/webrender_traits/src/image.rs
+++ b/gfx/webrender_traits/src/image.rs
@@ -15,17 +15,16 @@ impl ImageKey {
 }
 
 /// An arbitrary identifier for an external image provided by the
 /// application. It must be a unique identifier for each external
 /// image.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
 pub struct ExternalImageId(pub u64);
 
-#[repr(C)]
 #[repr(u32)]
 #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
 pub enum ImageFormat {
     Invalid  = 0,
     A8       = 1,
     RGB8     = 2,
     RGBA8    = 3,
     RGBAF32  = 4,
@@ -103,16 +102,17 @@ pub trait BlobImageRenderer: Send {
                             descriptor: &BlobImageDescriptor);
     fn resolve_blob_image(&mut self, key: ImageKey) -> BlobImageResult;
 }
 
 pub type BlobImageData = Vec<u8>;
 
 pub type BlobImageResult = Result<RasterizedBlobImage, BlobImageError>;
 
+#[repr(C)]
 #[derive(Copy, Clone, Debug)]
 pub struct BlobImageDescriptor {
     pub width: u32,
     pub height: u32,
     pub format: ImageFormat,
     pub scale_factor: f32,
 }
 
--- a/gfx/webrender_traits/src/webgl.rs
+++ b/gfx/webrender_traits/src/webgl.rs
@@ -380,283 +380,287 @@ impl fmt::Debug for WebGLCommand {
 
 impl WebGLCommand {
     /// NOTE: This method consumes the command
     pub fn apply<Native: NativeGLContextMethods>(self, ctx: &GLContext<Native>) {
         match self {
             WebGLCommand::GetContextAttributes(sender) =>
                 sender.send(*ctx.borrow_attributes()).unwrap(),
             WebGLCommand::ActiveTexture(target) =>
-                gl::active_texture(target),
+                ctx.gl().active_texture(target),
             WebGLCommand::AttachShader(program_id, shader_id) =>
-                gl::attach_shader(program_id.get(), shader_id.get()),
+                ctx.gl().attach_shader(program_id.get(), shader_id.get()),
             WebGLCommand::DetachShader(program_id, shader_id) =>
-                gl::detach_shader(program_id.get(), shader_id.get()),
+                ctx.gl().detach_shader(program_id.get(), shader_id.get()),
             WebGLCommand::BindAttribLocation(program_id, index, name) =>
-                gl::bind_attrib_location(program_id.get(), index, &name),
+                ctx.gl().bind_attrib_location(program_id.get(), index, &name),
             WebGLCommand::BlendColor(r, g, b, a) =>
-                gl::blend_color(r, g, b, a),
+                ctx.gl().blend_color(r, g, b, a),
             WebGLCommand::BlendEquation(mode) =>
-                gl::blend_equation(mode),
+                ctx.gl().blend_equation(mode),
             WebGLCommand::BlendEquationSeparate(mode_rgb, mode_alpha) =>
-                gl::blend_equation_separate(mode_rgb, mode_alpha),
+                ctx.gl().blend_equation_separate(mode_rgb, mode_alpha),
             WebGLCommand::BlendFunc(src, dest) =>
-                gl::blend_func(src, dest),
+                ctx.gl().blend_func(src, dest),
             WebGLCommand::BlendFuncSeparate(src_rgb, dest_rgb, src_alpha, dest_alpha) =>
-                gl::blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha),
+                ctx.gl().blend_func_separate(src_rgb, dest_rgb, src_alpha, dest_alpha),
             WebGLCommand::BufferData(buffer_type, data, usage) =>
-                gl::buffer_data(buffer_type, &data, usage),
+                gl::buffer_data(ctx.gl(), buffer_type, &data, usage),
             WebGLCommand::BufferSubData(buffer_type, offset, data) =>
-                gl::buffer_sub_data(buffer_type, offset, &data),
+                gl::buffer_sub_data(ctx.gl(), buffer_type, offset, &data),
             WebGLCommand::Clear(mask) =>
-                gl::clear(mask),
+                ctx.gl().clear(mask),
             WebGLCommand::ClearColor(r, g, b, a) =>
-                gl::clear_color(r, g, b, a),
+                ctx.gl().clear_color(r, g, b, a),
             WebGLCommand::ClearDepth(depth) =>
-                gl::clear_depth(depth),
+                ctx.gl().clear_depth(depth),
             WebGLCommand::ClearStencil(stencil) =>
-                gl::clear_stencil(stencil),
+                ctx.gl().clear_stencil(stencil),
             WebGLCommand::ColorMask(r, g, b, a) =>
-                gl::color_mask(r, g, b, a),
+                ctx.gl().color_mask(r, g, b, a),
             WebGLCommand::CopyTexImage2D(target, level, internal_format, x, y, width, height, border) =>
-                gl::copy_tex_image_2d(target, level, internal_format, x, y, width, height, border),
+                ctx.gl().copy_tex_image_2d(target, level, internal_format, x, y, width, height, border),
             WebGLCommand::CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height) =>
-                gl::copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height),
+                ctx.gl().copy_tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height),
             WebGLCommand::CullFace(mode) =>
-                gl::cull_face(mode),
+                ctx.gl().cull_face(mode),
             WebGLCommand::DepthFunc(func) =>
-                gl::depth_func(func),
+                ctx.gl().depth_func(func),
             WebGLCommand::DepthMask(flag) =>
-                gl::depth_mask(flag),
+                ctx.gl().depth_mask(flag),
             WebGLCommand::DepthRange(near, far) =>
-                gl::depth_range(near, far),
+                ctx.gl().depth_range(near, far),
             WebGLCommand::Disable(cap) =>
-                gl::disable(cap),
+                ctx.gl().disable(cap),
             WebGLCommand::Enable(cap) =>
-                gl::enable(cap),
+                ctx.gl().enable(cap),
             WebGLCommand::FramebufferRenderbuffer(target, attachment, renderbuffertarget, rb) =>
-                gl::framebuffer_renderbuffer(target, attachment, renderbuffertarget, rb.map_or(0, WebGLRenderbufferId::get)),
+                ctx.gl().framebuffer_renderbuffer(target, attachment, renderbuffertarget, rb.map_or(0, WebGLRenderbufferId::get)),
             WebGLCommand::FramebufferTexture2D(target, attachment, textarget, texture, level) =>
-                gl::framebuffer_texture_2d(target, attachment, textarget, texture.map_or(0, WebGLTextureId::get), level),
+                ctx.gl().framebuffer_texture_2d(target, attachment, textarget, texture.map_or(0, WebGLTextureId::get), level),
             WebGLCommand::FrontFace(mode) =>
-                gl::front_face(mode),
+                ctx.gl().front_face(mode),
             WebGLCommand::DisableVertexAttribArray(attrib_id) =>
-                gl::disable_vertex_attrib_array(attrib_id),
+                ctx.gl().disable_vertex_attrib_array(attrib_id),
             WebGLCommand::DrawArrays(mode, first, count) =>
-                gl::draw_arrays(mode, first, count),
+                ctx.gl().draw_arrays(mode, first, count),
             WebGLCommand::DrawElements(mode, count, type_, offset) =>
-                gl::draw_elements(mode, count, type_, offset as u32),
+                ctx.gl().draw_elements(mode, count, type_, offset as u32),
             WebGLCommand::EnableVertexAttribArray(attrib_id) =>
-                gl::enable_vertex_attrib_array(attrib_id),
+                ctx.gl().enable_vertex_attrib_array(attrib_id),
             WebGLCommand::Hint(name, val) =>
-                gl::hint(name, val),
+                ctx.gl().hint(name, val),
             WebGLCommand::IsEnabled(cap, chan) =>
-                chan.send(gl::is_enabled(cap) != 0).unwrap(),
+                chan.send(ctx.gl().is_enabled(cap) != 0).unwrap(),
             WebGLCommand::LineWidth(width) =>
-                gl::line_width(width),
+                ctx.gl().line_width(width),
             WebGLCommand::PixelStorei(name, val) =>
-                gl::pixel_store_i(name, val),
+                ctx.gl().pixel_store_i(name, val),
             WebGLCommand::PolygonOffset(factor, units) =>
-                gl::polygon_offset(factor, units),
+                ctx.gl().polygon_offset(factor, units),
             WebGLCommand::ReadPixels(x, y, width, height, format, pixel_type, chan) =>
-                Self::read_pixels(x, y, width, height, format, pixel_type, chan),
+                Self::read_pixels(ctx.gl(), x, y, width, height, format, pixel_type, chan),
             WebGLCommand::RenderbufferStorage(target, format, width, height) =>
-                gl::renderbuffer_storage(target, format, width, height),
+                ctx.gl().renderbuffer_storage(target, format, width, height),
             WebGLCommand::SampleCoverage(value, invert) =>
-                gl::sample_coverage(value, invert),
+                ctx.gl().sample_coverage(value, invert),
             WebGLCommand::Scissor(x, y, width, height) =>
-                gl::scissor(x, y, width, height),
+                ctx.gl().scissor(x, y, width, height),
             WebGLCommand::StencilFunc(func, ref_, mask) =>
-                gl::stencil_func(func, ref_, mask),
+                ctx.gl().stencil_func(func, ref_, mask),
             WebGLCommand::StencilFuncSeparate(face, func, ref_, mask) =>
-                gl::stencil_func_separate(face, func, ref_, mask),
+                ctx.gl().stencil_func_separate(face, func, ref_, mask),
             WebGLCommand::StencilMask(mask) =>
-                gl::stencil_mask(mask),
+                ctx.gl().stencil_mask(mask),
             WebGLCommand::StencilMaskSeparate(face, mask) =>
-                gl::stencil_mask_separate(face, mask),
+                ctx.gl().stencil_mask_separate(face, mask),
             WebGLCommand::StencilOp(fail, zfail, zpass) =>
-                gl::stencil_op(fail, zfail, zpass),
+                ctx.gl().stencil_op(fail, zfail, zpass),
             WebGLCommand::StencilOpSeparate(face, fail, zfail, zpass) =>
-                gl::stencil_op_separate(face, fail, zfail, zpass),
+                ctx.gl().stencil_op_separate(face, fail, zfail, zpass),
             WebGLCommand::GetActiveAttrib(program_id, index, chan) =>
-                Self::active_attrib(program_id, index, chan),
+                Self::active_attrib(ctx.gl(), program_id, index, chan),
             WebGLCommand::GetActiveUniform(program_id, index, chan) =>
-                Self::active_uniform(program_id, index, chan),
+                Self::active_uniform(ctx.gl(), program_id, index, chan),
             WebGLCommand::GetAttribLocation(program_id, name, chan) =>
-                Self::attrib_location(program_id, name, chan),
+                Self::attrib_location(ctx.gl(), program_id, name, chan),
             WebGLCommand::GetVertexAttrib(index, pname, chan) =>
-                Self::vertex_attrib(index, pname, chan),
+                Self::vertex_attrib(ctx.gl(), index, pname, chan),
             WebGLCommand::GetBufferParameter(target, param_id, chan) =>
-                Self::buffer_parameter(target, param_id, chan),
+                Self::buffer_parameter(ctx.gl(), target, param_id, chan),
             WebGLCommand::GetParameter(param_id, chan) =>
-                Self::parameter(param_id, chan),
+                Self::parameter(ctx.gl(), param_id, chan),
             WebGLCommand::GetProgramParameter(program_id, param_id, chan) =>
-                Self::program_parameter(program_id, param_id, chan),
+                Self::program_parameter(ctx.gl(), program_id, param_id, chan),
             WebGLCommand::GetShaderParameter(shader_id, param_id, chan) =>
-                Self::shader_parameter(shader_id, param_id, chan),
+                Self::shader_parameter(ctx.gl(), shader_id, param_id, chan),
             WebGLCommand::GetUniformLocation(program_id, name, chan) =>
-                Self::uniform_location(program_id, name, chan),
+                Self::uniform_location(ctx.gl(), program_id, name, chan),
             WebGLCommand::GetShaderInfoLog(shader_id, chan) =>
-                Self::shader_info_log(shader_id, chan),
+                Self::shader_info_log(ctx.gl(), shader_id, chan),
             WebGLCommand::GetProgramInfoLog(program_id, chan) =>
-                Self::program_info_log(program_id, chan),
+                Self::program_info_log(ctx.gl(), program_id, chan),
             WebGLCommand::CompileShader(shader_id, source) =>
-                Self::compile_shader(shader_id, source),
+                Self::compile_shader(ctx.gl(), shader_id, source),
             WebGLCommand::CreateBuffer(chan) =>
-                Self::create_buffer(chan),
+                Self::create_buffer(ctx.gl(), chan),
             WebGLCommand::CreateFramebuffer(chan) =>
-                Self::create_framebuffer(chan),
+                Self::create_framebuffer(ctx.gl(), chan),
             WebGLCommand::CreateRenderbuffer(chan) =>
-                Self::create_renderbuffer(chan),
+                Self::create_renderbuffer(ctx.gl(), chan),
             WebGLCommand::CreateTexture(chan) =>
-                Self::create_texture(chan),
+                Self::create_texture(ctx.gl(), chan),
             WebGLCommand::CreateProgram(chan) =>
-                Self::create_program(chan),
+                Self::create_program(ctx.gl(), chan),
             WebGLCommand::CreateShader(shader_type, chan) =>
-                Self::create_shader(shader_type, chan),
+                Self::create_shader(ctx.gl(), shader_type, chan),
             WebGLCommand::DeleteBuffer(id) =>
-                gl::delete_buffers(&[id.get()]),
+                ctx.gl().delete_buffers(&[id.get()]),
             WebGLCommand::DeleteFramebuffer(id) =>
-                gl::delete_framebuffers(&[id.get()]),
+                ctx.gl().delete_framebuffers(&[id.get()]),
             WebGLCommand::DeleteRenderbuffer(id) =>
-                gl::delete_renderbuffers(&[id.get()]),
+                ctx.gl().delete_renderbuffers(&[id.get()]),
             WebGLCommand::DeleteTexture(id) =>
-                gl::delete_textures(&[id.get()]),
+                ctx.gl().delete_textures(&[id.get()]),
             WebGLCommand::DeleteProgram(id) =>
-                gl::delete_program(id.get()),
+                ctx.gl().delete_program(id.get()),
             WebGLCommand::DeleteShader(id) =>
-                gl::delete_shader(id.get()),
+                ctx.gl().delete_shader(id.get()),
             WebGLCommand::BindBuffer(target, id) =>
-                gl::bind_buffer(target, id.map_or(0, WebGLBufferId::get)),
+                ctx.gl().bind_buffer(target, id.map_or(0, WebGLBufferId::get)),
             WebGLCommand::BindFramebuffer(target, request) =>
-                Self::bind_framebuffer(target, request, ctx),
+                Self::bind_framebuffer(ctx.gl(), target, request, ctx),
             WebGLCommand::BindRenderbuffer(target, id) =>
-                gl::bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get)),
+                ctx.gl().bind_renderbuffer(target, id.map_or(0, WebGLRenderbufferId::get)),
             WebGLCommand::BindTexture(target, id) =>
-                gl::bind_texture(target, id.map_or(0, WebGLTextureId::get)),
+                ctx.gl().bind_texture(target, id.map_or(0, WebGLTextureId::get)),
             WebGLCommand::LinkProgram(program_id) =>
-                gl::link_program(program_id.get()),
+                ctx.gl().link_program(program_id.get()),
             WebGLCommand::Uniform1f(uniform_id, v) =>
-                gl::uniform_1f(uniform_id, v),
+                ctx.gl().uniform_1f(uniform_id, v),
             WebGLCommand::Uniform1fv(uniform_id, v) =>
-                gl::uniform_1fv(uniform_id, &v),
+                ctx.gl().uniform_1fv(uniform_id, &v),
             WebGLCommand::Uniform1i(uniform_id, v) =>
-                gl::uniform_1i(uniform_id, v),
+                ctx.gl().uniform_1i(uniform_id, v),
             WebGLCommand::Uniform1iv(uniform_id, v) =>
-                gl::uniform_1iv(uniform_id, &v),
+                ctx.gl().uniform_1iv(uniform_id, &v),
             WebGLCommand::Uniform2f(uniform_id, x, y) =>
-                gl::uniform_2f(uniform_id, x, y),
+                ctx.gl().uniform_2f(uniform_id, x, y),
             WebGLCommand::Uniform2fv(uniform_id, v) =>
-                gl::uniform_2fv(uniform_id, &v),
+                ctx.gl().uniform_2fv(uniform_id, &v),
             WebGLCommand::Uniform2i(uniform_id, x, y) =>
-                gl::uniform_2i(uniform_id, x, y),
+                ctx.gl().uniform_2i(uniform_id, x, y),
             WebGLCommand::Uniform2iv(uniform_id, v) =>
-                gl::uniform_2iv(uniform_id, &v),
+                ctx.gl().uniform_2iv(uniform_id, &v),
             WebGLCommand::Uniform3f(uniform_id, x, y, z) =>
-                gl::uniform_3f(uniform_id, x, y, z),
+                ctx.gl().uniform_3f(uniform_id, x, y, z),
             WebGLCommand::Uniform3fv(uniform_id, v) =>
-                gl::uniform_3fv(uniform_id, &v),
+                ctx.gl().uniform_3fv(uniform_id, &v),
             WebGLCommand::Uniform3i(uniform_id, x, y, z) =>
-                gl::uniform_3i(uniform_id, x, y, z),
+                ctx.gl().uniform_3i(uniform_id, x, y, z),
             WebGLCommand::Uniform3iv(uniform_id, v) =>
-                gl::uniform_3iv(uniform_id, &v),
+                ctx.gl().uniform_3iv(uniform_id, &v),
             WebGLCommand::Uniform4f(uniform_id, x, y, z, w) =>
-                gl::uniform_4f(uniform_id, x, y, z, w),
+                ctx.gl().uniform_4f(uniform_id, x, y, z, w),
             WebGLCommand::Uniform4fv(uniform_id, v) =>
-                gl::uniform_4fv(uniform_id, &v),
+                ctx.gl().uniform_4fv(uniform_id, &v),
             WebGLCommand::Uniform4i(uniform_id, x, y, z, w) =>
-                gl::uniform_4i(uniform_id, x, y, z, w),
+                ctx.gl().uniform_4i(uniform_id, x, y, z, w),
             WebGLCommand::Uniform4iv(uniform_id, v) =>
-                gl::uniform_4iv(uniform_id, &v),
+                ctx.gl().uniform_4iv(uniform_id, &v),
             WebGLCommand::UniformMatrix2fv(uniform_id, transpose,  v) =>
-                gl::uniform_matrix_2fv(uniform_id, transpose, &v),
+                ctx.gl().uniform_matrix_2fv(uniform_id, transpose, &v),
             WebGLCommand::UniformMatrix3fv(uniform_id, transpose,  v) =>
-                gl::uniform_matrix_3fv(uniform_id, transpose, &v),
+                ctx.gl().uniform_matrix_3fv(uniform_id, transpose, &v),
             WebGLCommand::UniformMatrix4fv(uniform_id, transpose,  v) =>
-                gl::uniform_matrix_4fv(uniform_id, transpose, &v),
+                ctx.gl().uniform_matrix_4fv(uniform_id, transpose, &v),
             WebGLCommand::UseProgram(program_id) =>
-                gl::use_program(program_id.get()),
+                ctx.gl().use_program(program_id.get()),
             WebGLCommand::ValidateProgram(program_id) =>
-                gl::validate_program(program_id.get()),
+                ctx.gl().validate_program(program_id.get()),
             WebGLCommand::VertexAttrib(attrib_id, x, y, z, w) =>
-                gl::vertex_attrib_4f(attrib_id, x, y, z, w),
+                ctx.gl().vertex_attrib_4f(attrib_id, x, y, z, w),
             WebGLCommand::VertexAttribPointer2f(attrib_id, size, normalized, stride, offset) =>
-                gl::vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset),
+                ctx.gl().vertex_attrib_pointer_f32(attrib_id, size, normalized, stride, offset),
             WebGLCommand::VertexAttribPointer(attrib_id, size, data_type, normalized, stride, offset) =>
-                gl::vertex_attrib_pointer(attrib_id, size, data_type, normalized, stride, offset),
+                ctx.gl().vertex_attrib_pointer(attrib_id, size, data_type, normalized, stride, offset),
             WebGLCommand::Viewport(x, y, width, height) =>
-                gl::viewport(x, y, width, height),
+                ctx.gl().viewport(x, y, width, height),
             WebGLCommand::TexImage2D(target, level, internal, width, height, format, data_type, data) =>
-                gl::tex_image_2d(target, level, internal, width, height, /*border*/0, format, data_type, Some(&data)),
+                ctx.gl().tex_image_2d(target, level, internal, width, height, /*border*/0, format, data_type, Some(&data)),
             WebGLCommand::TexParameteri(target, name, value) =>
-                gl::tex_parameter_i(target, name, value),
+                ctx.gl().tex_parameter_i(target, name, value),
             WebGLCommand::TexParameterf(target, name, value) =>
-                gl::tex_parameter_f(target, name, value),
+                ctx.gl().tex_parameter_f(target, name, value),
             WebGLCommand::TexSubImage2D(target, level, xoffset, yoffset, x, y, width, height, data) =>
-                gl::tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height, &data),
+                ctx.gl().tex_sub_image_2d(target, level, xoffset, yoffset, x, y, width, height, &data),
             WebGLCommand::DrawingBufferWidth(sender) =>
                 sender.send(ctx.borrow_draw_buffer().unwrap().size().width).unwrap(),
             WebGLCommand::DrawingBufferHeight(sender) =>
                 sender.send(ctx.borrow_draw_buffer().unwrap().size().height).unwrap(),
             WebGLCommand::Finish(sender) =>
-                Self::finish(sender),
+                Self::finish(ctx.gl(), sender),
             WebGLCommand::Flush =>
-                gl::flush(),
+                ctx.gl().flush(),
             WebGLCommand::GenerateMipmap(target) =>
-                gl::generate_mipmap(target),
+                ctx.gl().generate_mipmap(target),
         }
 
         // FIXME: Use debug_assertions once tests are run with them
-        let error = gl::get_error();
+        let error = ctx.gl().get_error();
         assert!(error == gl::NO_ERROR, "Unexpected WebGL error: 0x{:x} ({})", error, error);
     }
 
-    fn read_pixels(x: i32, y: i32, width: i32, height: i32, format: u32, pixel_type: u32,
+    fn read_pixels(gl: &gl::Gl, x: i32, y: i32, width: i32, height: i32, format: u32, pixel_type: u32,
                    chan: MsgSender<Vec<u8>>) {
-      let result = gl::read_pixels(x, y, width, height, format, pixel_type);
+      let result = gl.read_pixels(x, y, width, height, format, pixel_type);
       chan.send(result).unwrap()
     }
 
-    fn active_attrib(program_id: WebGLProgramId,
+    fn active_attrib(gl: &gl::Gl,
+                     program_id: WebGLProgramId,
                      index: u32,
                      chan: MsgSender<WebGLResult<(i32, u32, String)>>) {
-        let result = if index >= gl::get_program_iv(program_id.get(), gl::ACTIVE_ATTRIBUTES) as u32 {
+        let result = if index >= gl.get_program_iv(program_id.get(), gl::ACTIVE_ATTRIBUTES) as u32 {
             Err(WebGLError::InvalidValue)
         } else {
-            Ok(gl::get_active_attrib(program_id.get(), index))
+            Ok(gl.get_active_attrib(program_id.get(), index))
         };
         chan.send(result).unwrap();
     }
 
-    fn active_uniform(program_id: WebGLProgramId,
+    fn active_uniform(gl: &gl::Gl,
+                      program_id: WebGLProgramId,
                       index: u32,
                       chan: MsgSender<WebGLResult<(i32, u32, String)>>) {
-        let result = if index >= gl::get_program_iv(program_id.get(), gl::ACTIVE_UNIFORMS) as u32 {
+        let result = if index >= gl.get_program_iv(program_id.get(), gl::ACTIVE_UNIFORMS) as u32 {
             Err(WebGLError::InvalidValue)
         } else {
-            Ok(gl::get_active_uniform(program_id.get(), index))
+            Ok(gl.get_active_uniform(program_id.get(), index))
         };
         chan.send(result).unwrap();
     }
 
-    fn attrib_location(program_id: WebGLProgramId,
+    fn attrib_location(gl: &gl::Gl,
+                       program_id: WebGLProgramId,
                        name: String,
                        chan: MsgSender<Option<i32>> ) {
-        let attrib_location = gl::get_attrib_location(program_id.get(), &name);
+        let attrib_location = gl.get_attrib_location(program_id.get(), &name);
 
         let attrib_location = if attrib_location == -1 {
             None
         } else {
             Some(attrib_location)
         };
 
         chan.send(attrib_location).unwrap();
     }
 
-    fn parameter(param_id: u32,
+    fn parameter(gl: &gl::Gl,
+                 param_id: u32,
                  chan: MsgSender<WebGLResult<WebGLParameter>>) {
         let result = match param_id {
             gl::ACTIVE_TEXTURE |
             //gl::ALPHA_BITS |
             gl::BLEND_DST_ALPHA |
             gl::BLEND_DST_RGB |
             gl::BLEND_EQUATION_ALPHA |
             gl::BLEND_EQUATION_RGB |
@@ -699,36 +703,36 @@ impl WebGLCommand {
             gl::STENCIL_PASS_DEPTH_FAIL |
             gl::STENCIL_PASS_DEPTH_PASS |
             gl::STENCIL_REF |
             gl::STENCIL_VALUE_MASK |
             gl::STENCIL_WRITEMASK |
             gl::SUBPIXEL_BITS |
             gl::UNPACK_ALIGNMENT =>
             //gl::UNPACK_COLORSPACE_CONVERSION_WEBGL =>
-                Ok(WebGLParameter::Int(gl::get_integer_v(param_id))),
+                Ok(WebGLParameter::Int(gl.get_integer_v(param_id))),
 
             gl::BLEND |
             gl::CULL_FACE |
             gl::DEPTH_TEST |
             gl::DEPTH_WRITEMASK |
             gl::DITHER |
             gl::POLYGON_OFFSET_FILL |
             gl::SAMPLE_COVERAGE_INVERT |
             gl::STENCIL_TEST =>
             //gl::UNPACK_FLIP_Y_WEBGL |
             //gl::UNPACK_PREMULTIPLY_ALPHA_WEBGL =>
-                Ok(WebGLParameter::Bool(gl::get_boolean_v(param_id) != 0)),
+                Ok(WebGLParameter::Bool(gl.get_boolean_v(param_id) != 0)),
 
             gl::DEPTH_CLEAR_VALUE |
             gl::LINE_WIDTH |
             gl::POLYGON_OFFSET_FACTOR |
             gl::POLYGON_OFFSET_UNITS |
             gl::SAMPLE_COVERAGE_VALUE =>
-                Ok(WebGLParameter::Float(gl::get_float_v(param_id))),
+                Ok(WebGLParameter::Float(gl.get_float_v(param_id))),
 
             gl::VERSION => Ok(WebGLParameter::String("WebGL 1.0".to_owned())),
             gl::RENDERER |
             gl::VENDOR => Ok(WebGLParameter::String("Mozilla/Servo".to_owned())),
             gl::SHADING_LANGUAGE_VERSION => Ok(WebGLParameter::String("WebGL GLSL ES 1.0".to_owned())),
 
             // TODO(zbarsky, emilio): Implement support for the following valid parameters
             // Float32Array
@@ -768,189 +772,195 @@ impl WebGLCommand {
 
             // Invalid parameters
             _ => Err(WebGLError::InvalidEnum)
         };
 
         chan.send(result).unwrap();
     }
 
-    fn finish(chan: MsgSender<()>) {
-        gl::finish();
+    fn finish(gl: &gl::Gl, chan: MsgSender<()>) {
+        gl.finish();
         chan.send(()).unwrap();
     }
 
-    fn vertex_attrib(index: u32,
+    fn vertex_attrib(gl: &gl::Gl,
+                     index: u32,
                      pname: u32,
                      chan: MsgSender<WebGLResult<WebGLParameter>>) {
-        let result = if index >= gl::get_integer_v(gl::MAX_VERTEX_ATTRIBS) as u32 {
+        let result = if index >= gl.get_integer_v(gl::MAX_VERTEX_ATTRIBS) as u32 {
             Err(WebGLError::InvalidValue)
         } else {
             match pname {
                 gl::VERTEX_ATTRIB_ARRAY_ENABLED |
                 gl::VERTEX_ATTRIB_ARRAY_NORMALIZED =>
-                    Ok(WebGLParameter::Bool(gl::get_vertex_attrib_iv(index, pname) != 0)),
+                    Ok(WebGLParameter::Bool(gl.get_vertex_attrib_iv(index, pname) != 0)),
                 gl::VERTEX_ATTRIB_ARRAY_SIZE |
                 gl::VERTEX_ATTRIB_ARRAY_STRIDE |
                 gl::VERTEX_ATTRIB_ARRAY_TYPE =>
-                    Ok(WebGLParameter::Int(gl::get_vertex_attrib_iv(index, pname))),
+                    Ok(WebGLParameter::Int(gl.get_vertex_attrib_iv(index, pname))),
                 gl::CURRENT_VERTEX_ATTRIB =>
-                    Ok(WebGLParameter::FloatArray(gl::get_vertex_attrib_fv(index, pname))),
+                    Ok(WebGLParameter::FloatArray(gl.get_vertex_attrib_fv(index, pname))),
                 // gl::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING should return WebGLBuffer
                 _ => Err(WebGLError::InvalidEnum),
             }
         };
 
         chan.send(result).unwrap();
     }
 
-    fn buffer_parameter(target: u32,
+    fn buffer_parameter(gl: &gl::Gl,
+                        target: u32,
                         param_id: u32,
                         chan: MsgSender<WebGLResult<WebGLParameter>>) {
         let result = match param_id {
             gl::BUFFER_SIZE |
             gl::BUFFER_USAGE =>
-                Ok(WebGLParameter::Int(gl::get_buffer_parameter_iv(target, param_id))),
+                Ok(WebGLParameter::Int(gl.get_buffer_parameter_iv(target, param_id))),
             _ => Err(WebGLError::InvalidEnum),
         };
 
         chan.send(result).unwrap();
     }
 
-    fn program_parameter(program_id: WebGLProgramId,
+    fn program_parameter(gl: &gl::Gl,
+                         program_id: WebGLProgramId,
                          param_id: u32,
                          chan: MsgSender<WebGLResult<WebGLParameter>>) {
         let result = match param_id {
             gl::DELETE_STATUS |
             gl::LINK_STATUS |
             gl::VALIDATE_STATUS =>
-                Ok(WebGLParameter::Bool(gl::get_program_iv(program_id.get(), param_id) != 0)),
+                Ok(WebGLParameter::Bool(gl.get_program_iv(program_id.get(), param_id) != 0)),
             gl::ATTACHED_SHADERS |
             gl::ACTIVE_ATTRIBUTES |
             gl::ACTIVE_UNIFORMS =>
-                Ok(WebGLParameter::Int(gl::get_program_iv(program_id.get(), param_id))),
+                Ok(WebGLParameter::Int(gl.get_program_iv(program_id.get(), param_id))),
             _ => Err(WebGLError::InvalidEnum),
         };
 
         chan.send(result).unwrap();
     }
 
-    fn shader_parameter(shader_id: WebGLShaderId,
+    fn shader_parameter(gl: &gl::Gl,
+                        shader_id: WebGLShaderId,
                         param_id: u32,
                         chan: MsgSender<WebGLResult<WebGLParameter>>) {
         let result = match param_id {
             gl::SHADER_TYPE =>
-                Ok(WebGLParameter::Int(gl::get_shader_iv(shader_id.get(), param_id))),
+                Ok(WebGLParameter::Int(gl.get_shader_iv(shader_id.get(), param_id))),
             gl::DELETE_STATUS |
             gl::COMPILE_STATUS =>
-                Ok(WebGLParameter::Bool(gl::get_shader_iv(shader_id.get(), param_id) != 0)),
+                Ok(WebGLParameter::Bool(gl.get_shader_iv(shader_id.get(), param_id) != 0)),
             _ => Err(WebGLError::InvalidEnum),
         };
 
         chan.send(result).unwrap();
     }
 
-    fn uniform_location(program_id: WebGLProgramId,
+    fn uniform_location(gl: &gl::Gl,
+                        program_id: WebGLProgramId,
                         name: String,
                         chan: MsgSender<Option<i32>>) {
-        let location = gl::get_uniform_location(program_id.get(), &name);
+        let location = gl.get_uniform_location(program_id.get(), &name);
         let location = if location == -1 {
             None
         } else {
             Some(location)
         };
 
         chan.send(location).unwrap();
     }
 
 
-    fn shader_info_log(shader_id: WebGLShaderId, chan: MsgSender<String>) {
-        let log = gl::get_shader_info_log(shader_id.get());
+    fn shader_info_log(gl: &gl::Gl, shader_id: WebGLShaderId, chan: MsgSender<String>) {
+        let log = gl.get_shader_info_log(shader_id.get());
         chan.send(log).unwrap();
     }
 
-    fn program_info_log(program_id: WebGLProgramId, chan: MsgSender<String>) {
-        let log = gl::get_program_info_log(program_id.get());
+    fn program_info_log(gl: &gl::Gl, program_id: WebGLProgramId, chan: MsgSender<String>) {
+        let log = gl.get_program_info_log(program_id.get());
         chan.send(log).unwrap();
     }
 
-    fn create_buffer(chan: MsgSender<Option<WebGLBufferId>>) {
-        let buffer = gl::gen_buffers(1)[0];
+    fn create_buffer(gl: &gl::Gl, chan: MsgSender<Option<WebGLBufferId>>) {
+        let buffer = gl.gen_buffers(1)[0];
         let buffer = if buffer == 0 {
             None
         } else {
             Some(unsafe { WebGLBufferId::new(buffer) })
         };
         chan.send(buffer).unwrap();
     }
 
-    fn create_framebuffer(chan: MsgSender<Option<WebGLFramebufferId>>) {
-        let framebuffer = gl::gen_framebuffers(1)[0];
+    fn create_framebuffer(gl: &gl::Gl, chan: MsgSender<Option<WebGLFramebufferId>>) {
+        let framebuffer = gl.gen_framebuffers(1)[0];
         let framebuffer = if framebuffer == 0 {
             None
         } else {
             Some(unsafe { WebGLFramebufferId::new(framebuffer) })
         };
         chan.send(framebuffer).unwrap();
     }
 
 
-    fn create_renderbuffer(chan: MsgSender<Option<WebGLRenderbufferId>>) {
-        let renderbuffer = gl::gen_renderbuffers(1)[0];
+    fn create_renderbuffer(gl: &gl::Gl, chan: MsgSender<Option<WebGLRenderbufferId>>) {
+        let renderbuffer = gl.gen_renderbuffers(1)[0];
         let renderbuffer = if renderbuffer == 0 {
             None
         } else {
             Some(unsafe { WebGLRenderbufferId::new(renderbuffer) })
         };
         chan.send(renderbuffer).unwrap();
     }
 
-    fn create_texture(chan: MsgSender<Option<WebGLTextureId>>) {
-        let texture = gl::gen_textures(1)[0];
+    fn create_texture(gl: &gl::Gl, chan: MsgSender<Option<WebGLTextureId>>) {
+        let texture = gl.gen_textures(1)[0];
         let texture = if texture == 0 {
             None
         } else {
             Some(unsafe { WebGLTextureId::new(texture) })
         };
         chan.send(texture).unwrap();
     }
 
 
-    fn create_program(chan: MsgSender<Option<WebGLProgramId>>) {
-        let program = gl::create_program();
+    fn create_program(gl: &gl::Gl, chan: MsgSender<Option<WebGLProgramId>>) {
+        let program = gl.create_program();
         let program = if program == 0 {
             None
         } else {
             Some(unsafe { WebGLProgramId::new(program) })
         };
         chan.send(program).unwrap();
     }
 
-    fn create_shader(shader_type: u32, chan: MsgSender<Option<WebGLShaderId>>) {
-        let shader = gl::create_shader(shader_type);
+    fn create_shader(gl: &gl::Gl, shader_type: u32, chan: MsgSender<Option<WebGLShaderId>>) {
+        let shader = gl.create_shader(shader_type);
         let shader = if shader == 0 {
             None
         } else {
             Some(unsafe { WebGLShaderId::new(shader) })
         };
         chan.send(shader).unwrap();
     }
 
     #[inline]
-    fn bind_framebuffer<Native: NativeGLContextMethods>(target: u32,
+    fn bind_framebuffer<Native: NativeGLContextMethods>(gl: &gl::Gl,
+                                                        target: u32,
                                                         request: WebGLFramebufferBindingRequest,
                                                         ctx: &GLContext<Native>) {
         let id = match request {
             WebGLFramebufferBindingRequest::Explicit(id) => id.get(),
             WebGLFramebufferBindingRequest::Default =>
                 ctx.borrow_draw_buffer().unwrap().get_framebuffer(),
         };
 
-        gl::bind_framebuffer(target, id);
+        gl.bind_framebuffer(target, id);
     }
 
 
     #[inline]
-    fn compile_shader(shader_id: WebGLShaderId, source: String) {
-        gl::shader_source(shader_id.get(), &[source.as_bytes()]);
-        gl::compile_shader(shader_id.get());
+    fn compile_shader(gl: &gl::Gl, shader_id: WebGLShaderId, source: String) {
+        gl.shader_source(shader_id.get(), &[source.as_bytes()]);
+        gl.compile_shader(shader_id.get());
     }
 }
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -14,17 +14,16 @@
 #include "nsITheme.h"
 #include "nsFrame.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/dom/Element.h"
 #include "Layers.h"
 #include "gfxPrefs.h"
 #include "gfxUtils.h"
 #include "mozilla/layers/WebRenderDisplayItemLayer.h"
-#include "mozilla/layers/WebRenderBorderLayer.h"
 
 #define ACTIVE   "active"
 #define HOVER    "hover"
 #define FOCUS    "focus"
 
 using namespace mozilla;
 using namespace mozilla::image;
 using namespace mozilla::layers;
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -270,16 +270,20 @@ already_AddRefed<Layer>
 nsDisplayCanvasBackgroundColor::BuildLayer(nsDisplayListBuilder* aBuilder,
                                            LayerManager* aManager,
                                            const ContainerLayerParameters& aContainerParameters)
 {
   if (NS_GET_A(mColor) == 0) {
     return nullptr;
   }
 
+  if (aManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
+    return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
+  }
+
   RefPtr<ColorLayer> layer = static_cast<ColorLayer*>
     (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
   if (!layer) {
     layer = aManager->CreateColorLayer();
     if (!layer) {
       return nullptr;
     }
   }
@@ -293,16 +297,37 @@ nsDisplayCanvasBackgroundColor::BuildLay
 
   layer->SetBounds(bgClipRect.ToNearestPixels(appUnitsPerDevPixel));
   layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
                                                       aContainerParameters.mOffset.y, 0));
 
   return layer.forget();
 }
 
+void
+nsDisplayCanvasBackgroundColor::CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                                        nsTArray<WebRenderParentCommand>& aParentCommands,
+                                                        WebRenderDisplayItemLayer* aLayer)
+{
+  nsCanvasFrame* frame = static_cast<nsCanvasFrame*>(mFrame);
+  nsPoint offset = ToReferenceFrame();
+  nsRect bgClipRect = frame->CanvasArea() + offset;
+  int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
+
+  Rect devPxRect(Float(bgClipRect.x / appUnitsPerDevPixel),
+                 Float(bgClipRect.y / appUnitsPerDevPixel),
+                 Float(bgClipRect.width / appUnitsPerDevPixel),
+                 Float(bgClipRect.height / appUnitsPerDevPixel));
+
+  Rect transformedRect = aLayer->RelativeToParent(devPxRect);
+  aBuilder.PushRect(wr::ToWrRect(transformedRect),
+                    aBuilder.BuildClipRegion(wr::ToWrRect(transformedRect)),
+                    wr::ToWrColor(ToDeviceColor(mColor)));
+}
+
 #ifdef MOZ_DUMP_PAINTING
 void
 nsDisplayCanvasBackgroundColor::WriteDebugInfo(std::stringstream& aStream)
 {
   aStream << " (rgba "
           << (int)NS_GET_R(mColor) << ","
           << (int)NS_GET_G(mColor) << ","
           << (int)NS_GET_B(mColor) << ","
--- a/layout/generic/nsCanvasFrame.h
+++ b/layout/generic/nsCanvasFrame.h
@@ -9,16 +9,17 @@
 #define nsCanvasFrame_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/EventForwards.h"
 #include "nsContainerFrame.h"
 #include "nsIScrollPositionListener.h"
 #include "nsDisplayList.h"
 #include "nsIAnonymousContentCreator.h"
+#include "gfxPrefs.h"
 
 class nsPresContext;
 class nsRenderingContext;
 
 /**
  * Root frame class.
  *
  * The root frame is the parent frame for the document element's frame.
@@ -156,29 +157,32 @@ public:
     return frame->CanvasArea() + ToReferenceFrame();
   }
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) override
   {
     // We need to override so we don't consider border-radius.
     aOutFrames->AppendElement(mFrame);
   }
+  virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
+                                             LayerManager* aManager,
+                                             const ContainerLayerParameters& aContainerParameters) override;
+  virtual void CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                       nsTArray<WebRenderParentCommand>& aParentCommands,
+                                       mozilla::layers::WebRenderDisplayItemLayer* aLayer) override;
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override
   {
-    if (ForceActiveLayers()) {
+    if (ForceActiveLayers() || gfxPrefs::LayersAllowCanvasBackgroundColorLayers()) {
       return mozilla::LAYER_ACTIVE;
     }
     return mozilla::LAYER_NONE;
   }
-  virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
-                                             LayerManager* aManager,
-                                             const ContainerLayerParameters& aContainerParameters) override;
   virtual void Paint(nsDisplayListBuilder* aBuilder,
                      nsRenderingContext* aCtx) override;
 
   void SetExtraBackgroundColor(nscolor aColor)
   {
     mColor = aColor;
   }
 
--- a/layout/painting/nsCSSRenderingBorders.cpp
+++ b/layout/painting/nsCSSRenderingBorders.cpp
@@ -3526,16 +3526,34 @@ nsCSSBorderRenderer::DrawBorders()
 
       mDrawTarget->PopClip();
 
       PrintAsStringNewline("---------------- (*)");
     }
   }
 }
 
+bool
+nsCSSBorderRenderer::CanCreateWebrenderCommands()
+{
+  NS_FOR_CSS_SIDES(i) {
+    if (mCompositeColors[i] != nullptr) {
+      return false;
+    }
+
+    if (mBorderStyles[i] == NS_STYLE_BORDER_STYLE_DOUBLE ||
+        mBorderStyles[i] == NS_STYLE_BORDER_STYLE_DOTTED ||
+        mBorderStyles[i] == NS_STYLE_BORDER_STYLE_DASHED) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 void
 nsCSSBorderRenderer::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                                              layers::WebRenderDisplayItemLayer* aLayer)
 {
   Rect outlineTransformedRect = aLayer->RelativeToParent(mOuterRect);
   WrBorderSide side[4];
   NS_FOR_CSS_SIDES(i) {
     side[i] = wr::ToWrBorderSide(ToDeviceColor(mBorderColors[i]), mBorderStyles[i]);
--- a/layout/painting/nsCSSRenderingBorders.h
+++ b/layout/painting/nsCSSRenderingBorders.h
@@ -100,16 +100,17 @@ public:
                       RectCornerRadii& aBorderRadii,
                       const nscolor* aBorderColors,
                       nsBorderColors* const* aCompositeColors,
                       nscolor aBackgroundColor);
 
   // draw the entire border
   void DrawBorders();
 
+  bool CanCreateWebrenderCommands();
   void CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                mozilla::layers::WebRenderDisplayItemLayer* aLayer);
 
   // utility function used for background painting as well as borders
   static void ComputeInnerRadii(const RectCornerRadii& aRadii,
                                 const Float* aBorderSizes,
                                 RectCornerRadii* aInnerRadiiRet);
 
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -4527,41 +4527,29 @@ nsDisplayBorder::GetLayerState(nsDisplay
                                          mFrame,
                                          nsRect(),
                                          nsRect(offset, mFrame->GetSize()),
                                          mFrame->StyleContext(),
                                          mFrame->GetSkipSides());
 
   const nsStyleBorder *styleBorder = mFrame->StyleContext()->StyleBorder();
   const nsStyleImage* image = &styleBorder->mBorderImageSource;
+  mBorderRenderer = Nothing();
   mBorderImageRenderer = Nothing();
   if ((!image || image->GetType() != eStyleImageType_Image) && !br) {
     return LAYER_NONE;
   }
 
   LayersBackend backend = aManager->GetBackendType();
   if (backend == layers::LayersBackend::LAYERS_WR) {
     if (br) {
-      bool hasCompositeColors;
-      br->AllBordersSolid(&hasCompositeColors);
-      if (hasCompositeColors) {
+      if (!br->CanCreateWebrenderCommands()) {
         return LAYER_NONE;
       }
-
-      NS_FOR_CSS_SIDES(i) {
-        mColors[i] = ToDeviceColor(br->mBorderColors[i]);
-        mWidths[i] = br->mBorderWidths[i];
-        mBorderStyles[i] = br->mBorderStyles[i];
-      }
-
-      NS_FOR_CSS_FULL_CORNERS(corner) {
-        mCorners[corner] = LayerSize(br->mBorderRadii[corner].width, br->mBorderRadii[corner].height);
-      }
-
-      mRect = ViewAs<LayerPixel>(br->mOuterRect);
+      mBorderRenderer = br;
     } else {
       if (styleBorder->mBorderImageRepeatH == NS_STYLE_BORDER_IMAGE_REPEAT_ROUND ||
           styleBorder->mBorderImageRepeatH == NS_STYLE_BORDER_IMAGE_REPEAT_SPACE ||
           styleBorder->mBorderImageRepeatV == NS_STYLE_BORDER_IMAGE_REPEAT_ROUND ||
           styleBorder->mBorderImageRepeatV == NS_STYLE_BORDER_IMAGE_REPEAT_SPACE) {
         // WebRender not supports this currently
         return LAYER_NONE;
       }
@@ -4580,16 +4568,20 @@ nsDisplayBorder::GetLayerState(nsDisplay
                                                             mVisibleRect,
                                                             mFrame->GetSkipSides(),
                                                             flags,
                                                             &result);
 
       if (!mBorderImageRenderer) {
         return LAYER_NONE;
       }
+
+      if (!mBorderImageRenderer->mImageRenderer.IsImageContainerAvailable(aManager, flags)) {
+        return LAYER_NONE;
+      }
     }
 
     return LAYER_ACTIVE;
   }
 
   if (!br) {
     return LAYER_NONE;
   }
@@ -4629,42 +4621,41 @@ nsDisplayBorder::GetLayerState(nsDisplay
   return LAYER_ACTIVE;
 }
 
 already_AddRefed<Layer>
 nsDisplayBorder::BuildLayer(nsDisplayListBuilder* aBuilder,
                             LayerManager* aManager,
                             const ContainerLayerParameters& aContainerParameters)
 {
-  if (mBorderImageRenderer) {
+  if (aManager->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
     return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
-  }
-
-  RefPtr<Layer> oldLayer = aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this);
-  RefPtr<BorderLayer> layer = oldLayer ? oldLayer->AsBorderLayer() : nullptr;
-
-  if (!layer) {
-    layer = aManager->CreateBorderLayer();
-    if (!layer)
-      return nullptr;
-  }
-  layer->SetRect(mRect);
-  layer->SetCornerRadii(mCorners);
-  layer->SetColors(mColors);
-  layer->SetWidths(mWidths);
-  layer->SetStyles(mBorderStyles);
-  layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
-                                                      aContainerParameters.mOffset.y, 0));
-  return layer.forget();
+  } else {
+    RefPtr<BorderLayer> layer = static_cast<BorderLayer*>
+      (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
+    if (!layer) {
+      layer = aManager->CreateBorderLayer();
+      if (!layer)
+        return nullptr;
+    }
+    layer->SetRect(mRect);
+    layer->SetCornerRadii(mCorners);
+    layer->SetColors(mColors);
+    layer->SetWidths(mWidths);
+    layer->SetStyles(mBorderStyles);
+    layer->SetBaseTransform(gfx::Matrix4x4::Translation(aContainerParameters.mOffset.x,
+                                                        aContainerParameters.mOffset.y, 0));
+    return layer.forget();
+  }
 }
 
 void
-nsDisplayBorder::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
-                                         nsTArray<WebRenderParentCommand>& aParentCommands,
-                                         WebRenderDisplayItemLayer* aLayer)
+nsDisplayBorder::CreateBorderImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                                    nsTArray<WebRenderParentCommand>& aParentCommands,
+                                                    WebRenderDisplayItemLayer* aLayer)
 {
   // Only support border-image currently
   MOZ_ASSERT(mBorderImageRenderer);
   if (!mBorderImageRenderer->mImageRenderer.IsReady()) {
     return;
   }
 
   nsDisplayListBuilder* builder = aLayer->GetDisplayListBuilder();
@@ -4674,16 +4665,19 @@ nsDisplayBorder::CreateWebRenderCommands
 
   RefPtr<imgIContainer> img = mBorderImageRenderer->mImageRenderer.GetImage();
   RefPtr<layers::ImageContainer> container = img->GetImageContainer(aLayer->WrManager(), flags);
   if (!container) {
     return;
   }
 
   uint64_t externalImageId = aLayer->SendImageContainer(container);
+  if (!externalImageId) {
+    return;
+  }
 
   const int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   Rect destRect =
     NSRectToRect(mBorderImageRenderer->mArea, appUnitsPerDevPixel);
   Rect destRectTransformed = aLayer->RelativeToParent(destRect);
   IntRect dest = RoundedToInt(destRectTransformed);
 
   IntRect clip = dest;
@@ -4716,16 +4710,30 @@ nsDisplayBorder::CreateWebRenderCommands
                              (float)(mBorderImageRenderer->mImageSize.height) / appUnitsPerDevPixel,
                              wr::ToWrSideOffsets2Du32(slice[0], slice[1], slice[2], slice[3])),
                            wr::ToWrSideOffsets2Df32(outset[0], outset[1], outset[2], outset[3]),
                            wr::ToWrRepeatMode(mBorderImageRenderer->mRepeatModeHorizontal),
                            wr::ToWrRepeatMode(mBorderImageRenderer->mRepeatModeVertical));
 }
 
 void
+nsDisplayBorder::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
+                                         nsTArray<WebRenderParentCommand>& aParentCommands,
+                                         WebRenderDisplayItemLayer* aLayer)
+{
+  MOZ_ASSERT(mBorderImageRenderer || mBorderRenderer);
+
+  if (mBorderImageRenderer) {
+    CreateBorderImageWebRenderCommands(aBuilder, aParentCommands, aLayer);
+  } else if (mBorderRenderer) {
+    mBorderRenderer->CreateWebRenderCommands(aBuilder, aLayer);
+  }
+}
+
+void
 nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder,
                        nsRenderingContext* aCtx) {
   nsPoint offset = ToReferenceFrame();
 
   PaintBorderFlags flags = aBuilder->ShouldSyncDecodeImages()
                          ? PaintBorderFlags::SYNC_DECODE_IMAGES
                          : PaintBorderFlags();
 
@@ -4884,110 +4892,171 @@ nsDisplayBoxShadowOuter::ComputeVisibili
   // Store the actual visible region
   mVisibleRegion.And(*aVisibleRegion, mVisibleRect);
   return true;
 }
 
 
 LayerState
 nsDisplayBoxShadowOuter::GetLayerState(nsDisplayListBuilder* aBuilder,
-                                                  LayerManager* aManager,
-                                                  const ContainerLayerParameters& aParameters)
-{
-  if (gfxPrefs::LayersAllowOuterBoxShadow()) {
+                                       LayerManager* aManager,
+                                       const ContainerLayerParameters& aParameters)
+{
+  if (gfxPrefs::LayersAllowOuterBoxShadow() &&
+      CanBuildWebRenderDisplayItems()) {
     return LAYER_ACTIVE;
   }
 
   return LAYER_NONE;
 }
 
 already_AddRefed<Layer>
 nsDisplayBoxShadowOuter::BuildLayer(nsDisplayListBuilder* aBuilder,
                                     LayerManager* aManager,
                                     const ContainerLayerParameters& aContainerParameters)
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
+bool
+nsDisplayBoxShadowOuter::CanBuildWebRenderDisplayItems()
+{
+  nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
+  if (!shadows) {
+    return false;
+  }
+
+  bool hasBorderRadius;
+  bool nativeTheme =
+      nsCSSRendering::HasBoxShadowNativeTheme(mFrame, hasBorderRadius);
+  nsPoint offset = ToReferenceFrame();
+  nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
+  nsRect frameRect =
+      nsCSSRendering::GetShadowRect(borderRect, nativeTheme, mFrame);
+
+  if (hasBorderRadius) {
+    nscoord twipsRadii[8];
+    nsSize sz = frameRect.Size();
+    hasBorderRadius = mFrame->GetBorderRadii(sz, sz, Sides(), twipsRadii);
+  }
+
+  // WebRender doesn't support clipping properly with a border radius.
+  // We don't support native themed things yet like box shadows around
+  // input buttons.
+  if (hasBorderRadius || nativeTheme) {
+    return false;
+  }
+
+  for (uint32_t j = shadows->Length(); j  > 0; j--) {
+    nsCSSShadowItem* shadow = shadows->ShadowAt(j - 1);
+    // Need WR support for clip out.
+    if (shadow->mRadius <= 0) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 void
 nsDisplayBoxShadowOuter::CreateWebRenderCommands(wr::DisplayListBuilder& aBuilder,
                                                  nsTArray<WebRenderParentCommand>& aParentCommands,
                                                  WebRenderDisplayItemLayer* aLayer)
 {
   int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   nsPoint offset = ToReferenceFrame();
   nsRect borderRect = mFrame->VisualBorderRectRelativeToSelf() + offset;
   //nsPresContext* presContext = mFrame->PresContext();
   AutoTArray<nsRect,10> rects;
   nsRegion visible = aLayer->GetVisibleRegion().ToAppUnits(appUnitsPerDevPixel);
 
   ComputeDisjointRectangles(visible, &rects);
 
-  nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
-  if (!shadows)
-    return;
-
   bool hasBorderRadius;
   bool nativeTheme = nsCSSRendering::HasBoxShadowNativeTheme(mFrame,
                                                              hasBorderRadius);
 
   // Don't need the full size of the shadow rect like we do in
   // nsCSSRendering since WR takes care of calculations for blur
   // and spread radius.
-  nsRect shadowRect = nsCSSRendering::GetShadowRect(borderRect,
+  nsRect frameRect = nsCSSRendering::GetShadowRect(borderRect,
                                                     nativeTheme,
                                                     mFrame);
 
   RectCornerRadii borderRadii;
   if (hasBorderRadius) {
-    hasBorderRadius = nsCSSRendering::GetBorderRadii(shadowRect,
+    hasBorderRadius = nsCSSRendering::GetBorderRadii(frameRect,
                                                      borderRect,
                                                      mFrame,
                                                      borderRadii);
-    MOZ_ASSERT(borderRadii.AreRadiiSame(), "WR only supports uniform borders");
+    MOZ_ASSERT(borderRadii.AreRadiiSame());
   }
 
   // Everything here is in app units, change to device units.
   for (uint32_t i = 0; i < rects.Length(); ++i) {
     Rect clipRect = NSRectToRect(rects[i], appUnitsPerDevPixel);
     nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
+    MOZ_ASSERT(shadows);
 
     for (uint32_t j = shadows->Length(); j  > 0; j--) {
       nsCSSShadowItem* shadow = shadows->ShadowAt(j - 1);
-
+      float blurRadius = float(shadow->mRadius) / float(appUnitsPerDevPixel);
       gfx::Color shadowColor = nsCSSRendering::GetShadowColor(shadow,
                                                               mFrame,
                                                               mOpacity);
-      shadowRect.MoveBy(shadow->mXOffset, shadow->mYOffset);
-
+
+      // We don't move the shadow rect here since WR does it for us
       // Now translate everything to device pixels.
+      nsRect shadowRect = frameRect;
       Point shadowOffset;
       shadowOffset.x = (shadow->mXOffset / appUnitsPerDevPixel);
       shadowOffset.y = (shadow->mYOffset / appUnitsPerDevPixel);
 
       Rect deviceBoxRect = NSRectToRect(shadowRect, appUnitsPerDevPixel);
       deviceBoxRect = aLayer->RelativeToParent(deviceBoxRect);
-
-      Rect deviceClipRect = aLayer->RelativeToParent(clipRect + shadowOffset);
-
-      float blurRadius = float(shadow->mRadius) / float(appUnitsPerDevPixel);
+      deviceBoxRect.Round();
+      Rect deviceClipRect = aLayer->RelativeToParent(clipRect);
+
       // TODO: support non-uniform border radius.
       float borderRadius = hasBorderRadius ? borderRadii.TopLeft().width
                                            : 0.0;
       float spreadRadius = float(shadow->mSpread) / float(appUnitsPerDevPixel);
 
-      aBuilder.PushBoxShadow(wr::ToWrRect(deviceBoxRect),
-                             aBuilder.BuildClipRegion(wr::ToWrRect(deviceClipRect)),
-                             wr::ToWrRect(deviceBoxRect),
-                             wr::ToWrPoint(shadowOffset),
-                             wr::ToWrColor(shadowColor),
-                             blurRadius,
-                             spreadRadius,
-                             borderRadius,
-                             WrBoxShadowClipMode::Outset);
+      if (blurRadius <= 0) {
+        MOZ_ASSERT(false, "WR needs clip out first");
+        // TODO: See nsContextBoxBlur::BlurRectangle. Just need to fill
+        // a rect here with the proper clip in/out, but WR doesn't support
+        // clip out yet
+        if (hasBorderRadius) {
+          LayerSize borderRadiusSize(borderRadius, borderRadius);
+          WrComplexClipRegion roundedRect =
+                                  wr::ToWrComplexClipRegion(deviceBoxRect,
+                                                            borderRadiusSize);
+          nsTArray<WrComplexClipRegion> clips;
+          clips.AppendElement(roundedRect);
+          aBuilder.PushRect(wr::ToWrRect(deviceBoxRect),
+                            aBuilder.BuildClipRegion(wr::ToWrRect(deviceClipRect),
+                                                    clips),
+                            wr::ToWrColor(shadowColor));
+        } else {
+          aBuilder.PushRect(wr::ToWrRect(deviceBoxRect),
+                            aBuilder.BuildClipRegion(wr::ToWrRect(deviceClipRect)),
+                            wr::ToWrColor(shadowColor));
+        }
+      } else {
+        aBuilder.PushBoxShadow(wr::ToWrRect(deviceBoxRect),
+                              aBuilder.BuildClipRegion(wr::ToWrRect(deviceClipRect)),
+                              wr::ToWrRect(deviceBoxRect),
+                              wr::ToWrPoint(shadowOffset),
+                              wr::ToWrColor(shadowColor),
+                              blurRadius,
+                              spreadRadius,
+                              borderRadius,
+                              WrBoxShadowClipMode::Outset);
+      }
     }
   }
 }
 
 void
 nsDisplayBoxShadowOuter::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder,
                                                    const nsDisplayItemGeometry* aGeometry,
                                                    nsRegion* aInvalidRegion)
@@ -5040,16 +5109,39 @@ nsDisplayBoxShadowInner::Paint(nsDisplay
 }
 
 LayerState
 nsDisplayBoxShadowInner::GetLayerState(nsDisplayListBuilder* aBuilder,
                                        LayerManager* aManager,
                                        const ContainerLayerParameters& aParameters)
 {
   if (gfxPrefs::LayersAllowInsetBoxShadow()) {
+    nsPoint offset = ToReferenceFrame();
+    nsRect borderRect = nsRect(offset, mFrame->GetSize());
+    RectCornerRadii innerRadii;
+    bool hasBorderRadius = nsCSSRendering::GetShadowInnerRadii(mFrame,
+                                                               borderRect,
+                                                               innerRadii);
+    if (hasBorderRadius) {
+      return LAYER_NONE;
+    }
+
+    nsCSSShadowArray* shadows = mFrame->StyleEffects()->mBoxShadow;
+    for (uint32_t i = shadows->Length(); i > 0; --i) {
+      nsCSSShadowItem* shadowItem = shadows->ShadowAt(i - 1);
+      if (!shadowItem->mInset) {
+        continue;
+      }
+
+      if (shadowItem->mXOffset <= 0 || shadowItem->mYOffset <= 0) {
+        // Need to wait for WR to support clip out.
+        return LAYER_NONE;
+      }
+    }
+
     return LAYER_ACTIVE;
   }
 
   return LAYER_NONE;
 }
 
 already_AddRefed<Layer>
 nsDisplayBoxShadowInner::BuildLayer(nsDisplayListBuilder* aBuilder,
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -2884,25 +2884,28 @@ public:
 
   virtual nsRegion GetTightBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) override
   {
     *aSnap = true;
     return CalculateBounds(*mFrame->StyleBorder());
   }
 
 protected:
+  void CreateBorderImageWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                                          nsTArray<WebRenderParentCommand>& aParentCommands,
+                                          WebRenderDisplayItemLayer* aLayer);
   nsRegion CalculateBounds(const nsStyleBorder& aStyleBorder);
 
   mozilla::Array<mozilla::gfx::Color, 4> mColors;
   mozilla::Array<mozilla::LayerCoord, 4> mWidths;
   mozilla::Array<mozilla::LayerSize, 4> mCorners;
   mozilla::Array<uint8_t, 4> mBorderStyles;
   mozilla::LayerRect mRect;
 
-  // For border image
+  mozilla::Maybe<nsCSSBorderRenderer> mBorderRenderer;
   mozilla::Maybe<nsCSSBorderImageRenderer> mBorderImageRenderer;
 
   nsRect mBounds;
 };
 
 /**
  * A simple display item that just renders a solid color across the
  * specified bounds. For canvas frames (in the CSS sense) we split off the
@@ -3403,16 +3406,18 @@ public:
   }
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
+
+  bool CanBuildWebRenderDisplayItems();
   virtual void CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
                                        nsTArray<WebRenderParentCommand>& aParentCommands,
                                        WebRenderDisplayItemLayer* aLayer) override;
 
   nsRect GetBoundsInternal();
 
 private:
   nsRegion mVisibleRegion;
--- a/layout/painting/nsImageRenderer.cpp
+++ b/layout/painting/nsImageRenderer.cpp
@@ -849,16 +849,25 @@ nsImageRenderer::GetImage()
   if (mType != eStyleImageType_Image || !mImageContainer) {
     return nullptr;
   }
 
   nsCOMPtr<imgIContainer> image = mImageContainer;
   return image.forget();
 }
 
+bool
+nsImageRenderer::IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags)
+{
+  if (!mImageContainer) {
+    return false;
+  }
+  return mImageContainer->IsImageContainerAvailable(aManager, aFlags);
+}
+
 void
 nsImageRenderer::PurgeCacheForViewportChange(
   const Maybe<nsSize>& aSVGViewportSize, const bool aHasIntrinsicRatio)
 {
   // Check if we should flush the cached data - only vector images need to do
   // the check since they might not have fixed ratio.
   if (mImageContainer &&
       mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) {
--- a/layout/painting/nsImageRenderer.h
+++ b/layout/painting/nsImageRenderer.h
@@ -225,16 +225,17 @@ public:
                            const bool           aHasIntrinsicRatio);
 
   bool IsRasterImage();
   bool IsAnimatedImage();
 
   /// Retrieves the image associated with this nsImageRenderer, if there is one.
   already_AddRefed<imgIContainer> GetImage();
 
+  bool IsImageContainerAvailable(layers::LayerManager* aManager, uint32_t aFlags);
   bool IsReady() const { return mPrepareResult == DrawResult::SUCCESS; }
   DrawResult PrepareResult() const { return mPrepareResult; }
   void SetExtendMode(mozilla::gfx::ExtendMode aMode) { mExtendMode = aMode; }
   void SetMaskOp(uint8_t aMaskOp) { mMaskOp = aMaskOp; }
   void PurgeCacheForViewportChange(const mozilla::Maybe<nsSize>& aSVGViewportSize,
                                    const bool aHasRatio);
 
 private:
--- a/layout/reftests/box-shadow/reftest.list
+++ b/layout/reftests/box-shadow/reftest.list
@@ -4,38 +4,40 @@
 random == boxshadow-blur-2.html boxshadow-blur-2-ref.html # fixedpoint division in blur code makes this fail
 random != boxshadow-blur-2.html boxshadow-blur-2-notref.html # fixedpoint division in blur code makes this fail
 == boxshadow-multiple.html boxshadow-multiple-ref.html
 == boxshadow-spread.html boxshadow-spread-ref.html
 == tableboxshadow-basic.html tableboxshadow-basic-ref.html
 == tableboxshadow-trshadow.html tableboxshadow-trshadow-ref.html
 == tableboxshadow-tdshadow.html tableboxshadow-tdshadow-ref.html
 == boxshadow-rounding.html boxshadow-rounding-ref.html
-fails-if(Android) == boxshadow-button.html boxshadow-button-ref.html
+# One uses old path, one uses WR box shadow.
+fails-if(Android) fuzzy-if(webrender,20,3310) == boxshadow-button.html boxshadow-button-ref.html
+fuzzy-if(OSX==1010,1,24) fuzzy-if(d2d,16,908) fuzzy-if(webrender,18,1680) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649
+
 fails-if(Android) == boxshadow-fileupload.html boxshadow-fileupload-ref.html
 == boxshadow-inner-basic.html boxshadow-inner-basic-ref.svg
 random-if(layersGPUAccelerated) == boxshadow-mixed.html boxshadow-mixed-ref.html
 random-if(d2d) == boxshadow-rounded-spread.html boxshadow-rounded-spread-ref.html
 fuzzy-if(skiaContent,1,50) HTTP(..) == boxshadow-dynamic.xul boxshadow-dynamic-ref.xul
 random-if(d2d) == boxshadow-onecorner.html boxshadow-onecorner-ref.html
 random-if(d2d) == boxshadow-twocorners.html boxshadow-twocorners-ref.html
 random-if(d2d) == boxshadow-threecorners.html boxshadow-threecorners-ref.html
 fuzzy(2,440) == boxshadow-skiprect.html boxshadow-skiprect-ref.html
 == boxshadow-opacity.html boxshadow-opacity-ref.html
 == boxshadow-color-rounding.html boxshadow-color-rounding-ref.html
 == boxshadow-color-rounding-middle.html boxshadow-color-rounding-middle-ref.html
-fuzzy-if(OSX==1010,1,24) fuzzy-if(d2d,16,908) == boxshadow-large-border-radius.html boxshadow-large-border-radius-ref.html # Bug 1209649
 fuzzy(3,500) fuzzy-if(d2d,2,1080) == boxshadow-border-radius-int.html boxshadow-border-radius-int-ref.html
 == boxshadow-inset-neg-spread.html about:blank
 == boxshadow-inset-neg-spread2.html boxshadow-inset-neg-spread2-ref.html
 fuzzy(26,3610) == boxshadow-rotated.html boxshadow-rotated-ref.html # Bug 1211264
 == boxshadow-inset-large-border-radius.html boxshadow-inset-large-border-radius-ref.html
 
 # fuzzy due to blur going inside, but as long as it's essentially black instead of a light gray its ok.
-fuzzy(12,9445) fuzzy-if(d2d,13,10926) == boxshadow-inset-large-offset.html boxshadow-inset-large-offset-ref.html
+fuzzy(13,9445) fuzzy-if(d2d,13,10926) fuzzy-if(webrender,13,13612) == boxshadow-inset-large-offset.html boxshadow-inset-large-offset-ref.html
 
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref.html
 == overflow-not-scrollable-1.html overflow-not-scrollable-1-ref2.html
 == overflow-not-scrollable-2.html overflow-not-scrollable-2-ref.html
 == 611574-1.html 611574-1-ref.html
 == 611574-2.html 611574-2-ref.html
 fuzzy-if(winWidget,5,30) fuzzy-if(skiaContent,16,10) == fieldset.html fieldset-ref.html # minor anti-aliasing problem on Windows
 fuzzy-if(winWidget,5,30) fuzzy-if(skiaContent,16,10) == fieldset-inset.html fieldset-inset-ref.html # minor anti-aliasing problem on Windows
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1647,17 +1647,17 @@ HTTP(..) == 621253-2-externalFilter.html
 random-if(winWidget) == 621918-1.svg 621918-1-ref.svg # 1-pixel diacritic positioning discrepancy in rotated text (may depend on platform fonts)
 random-if(winWidget) HTTP(..) == 621918-2.svg 621918-2-ref.svg # same 1px issue as above, and HTTP(..) for filters.svg, used to mask antialiasing issues where glyphs touch
 fuzzy-if(d2d,5,1) == 622585-1.html 622585-1-ref.html # bug 789402
 fuzzy-if(Android,8,300) fuzzy-if(skiaContent,1,40000) == 625409-1.html 625409-1-ref.html
 == 627393-1.html about:blank
 fuzzy-if(skiaContent,1,500) == 630835-1.html about:blank
 == 631352-1.html 631352-1-ref.html
 skip-if(!haveTestPlugin) fails-if(Android) fuzzy-if(winWidget&&!layersGPUAccelerated,102,535) fuzzy-if(skiaContent&&!Android,102,11000) == 632423-1.html 632423-1-ref.html
-skip-if(Android) random-if(winWidget||OSX==1010) skip-if(webrender) == 632781-verybig.html 632781-ref.html  # see bug 1322816 for webrender
+skip-if(Android) random-if(winWidget||OSX==1010) fails-if(webrender) == 632781-verybig.html 632781-ref.html
 == 632781-normalsize.html 632781-ref.html
 fuzzy-if(d2d&&/^Windows\x20NT\x206\.2/.test(http.oscpu),1,559) fuzzy-if(!isDebugBuild&&gtkWidget&&/^Linux\x20i686/.test(http.oscpu),102,140) == 633344-1.html 633344-1-ref.html # bug 1103623, Linux32 from GCC update
 fuzzy-if(skiaContent,1,500) == 634232-1.html 634232-1-ref.html
 fuzzy-if(skiaContent,3,120000) fails-if(webrender) == 635302-1.html 635302-1-ref.html
 fuzzy(1,68) fuzzy-if(gtkWidget,1,70) fails-if(Android) fuzzy-if(skiaContent&&!Android,1,300) fails-if(webrender) == 635373-1.html 635373-1-ref.html
 random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,118) fuzzy-if(skiaContent&&!Android,2,550) fails-if(webrender) == 635373-2.html 635373-2-ref.html
 random-if(d2d) fails-if(Android) fuzzy-if(winWidget&&!d2d,20,116) fuzzy-if(skiaContent&&!Android,2,650) fails-if(webrender) == 635373-3.html 635373-3-ref.html
 HTTP(..) == 635639-1.html 635639-1-ref.html
@@ -1820,17 +1820,18 @@ fuzzy-if(skiaContent,1,123) == 978911-1.
 == 983084-2.html 983084-2-ref.html
 == 983084-3.html 983084-1-ref.html
 == 983691-1.html 983691-ref.html
 HTTP(..) == 983985-1.html 983985-1-ref.html
 HTTP(..) == 983985-2.html 983985-2-ref.html
 == 985303-1a.html 985303-1-ref.html
 == 985303-1b.html 985303-1-ref.html
 == 987680-1.html 987680-1-ref.html
-fuzzy-if(d2d,1,601) == 991046-1.html 991046-1-ref.html
+# Fuzzy on WR due to alpha blending
+fuzzy-if(d2d,1,601) fuzzy-if(webrender,1,1185) == 991046-1.html 991046-1-ref.html
 pref(layout.css.overflow-clip-box.enabled,true) fuzzy-if(skiaContent,2,845) == 992447.html 992447-ref.html
 == 1003425-1.html 1003425-1-ref.html
 == 1003425-2.html 1003425-2-ref.html
 == 1005405-1.html 1005405-1-ref.html
 == 1012640-1.html 1012640-1-ref.html
 == 1013054-1.html 1013054-1-ref.html
 == 1018522-1.html 1018522-1-ref.html
 == 1021564-1.html 1021564-ref.html
--- a/layout/reftests/canvas/reftest.list
+++ b/layout/reftests/canvas/reftest.list
@@ -1,10 +1,10 @@
 == default-size.html default-size-ref.html
-fuzzy-if(Android,8,1000) skip-if(webrender) == size-1.html size-1-ref.html # see bug 1322816 for webrender
+fuzzy-if(Android,8,1000) == size-1.html size-1-ref.html
 
 == empty-transaction-1.html empty-transaction-1-ref.html
 
 == image-rendering-test.html image-rendering-ref.html
 == image-shadow.html image-shadow-ref.html
 
 asserts-if(cocoaWidget,0-2) == size-change-1.html size-change-1-ref.html
 
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -75,17 +75,17 @@ fuzzy-if(cocoaWidget,128,9) == animate-p
 fails-if(webrender) == 1245450-1.html green-rect.html
 fuzzy(1,2000) fails-if(webrender) == opacity-preserve3d-1.html opacity-preserve3d-1-ref.html
 fuzzy(1,15000) == opacity-preserve3d-2.html opacity-preserve3d-2-ref.html
 fuzzy(1,10000) == opacity-preserve3d-3.html opacity-preserve3d-3-ref.html
 fuzzy(1,10000) == opacity-preserve3d-4.html opacity-preserve3d-4-ref.html
 == opacity-preserve3d-5.html opacity-preserve3d-5-ref.html
 fails-if(webrender) == snap-perspective-1.html snap-perspective-1-ref.html
 fails-if(webrender) == mask-layer-1.html mask-layer-ref.html
-skip-if(webrender) == mask-layer-2.html mask-layer-ref.html
-skip-if(webrender) == mask-layer-3.html mask-layer-ref.html
+fails-if(webrender) == mask-layer-2.html mask-layer-ref.html
+fails-if(webrender) == mask-layer-3.html mask-layer-ref.html
 fails-if(webrender) == split-intersect1.html split-intersect1-ref.html
 fuzzy(255,150) fails-if(webrender) == split-intersect2.html split-intersect2-ref.html
 fuzzy(255,100) fails-if(webrender) == split-non-ortho1.html split-non-ortho1-ref.html
 fuzzy-if(winWidget,150,120) fails-if(webrender) == component-alpha-1.html component-alpha-1-ref.html
 fails-if(webrender) == nested-transform-1.html nested-transform-1-ref.html
 fails-if(webrender) == transform-geometry-1.html transform-geometry-1-ref.html
 fails-if(webrender) == intermediate-1.html intermediate-1-ref.html
--- a/layout/reftests/transform/reftest.list
+++ b/layout/reftests/transform/reftest.list
@@ -132,12 +132,12 @@ pref(svg.transform-box.enabled,true) == 
 pref(svg.transform-box.enabled,true) == transform-box-svg-3a.svg pass.svg
 == transform-origin-svg-1a.svg transform-origin-svg-1-ref.svg
 == transform-origin-svg-1b.svg transform-origin-svg-1-ref.svg
 == transform-origin-svg-2a.svg transform-origin-svg-2-ref.svg
 == transform-origin-svg-2b.svg transform-origin-svg-2-ref.svg
 # Bug 1122526
 == animate-layer-scale-inherit-1.html animate-layer-scale-inherit-1-ref.html
 == animate-layer-scale-inherit-2.html animate-layer-scale-inherit-2-ref.html
-random-if(webrender) == animate-layer-scale-inherit-3.html animate-layer-scale-inherit-1-ref.html
+== animate-layer-scale-inherit-3.html animate-layer-scale-inherit-1-ref.html
 # Bug 1301500
 == dynamic-add-without-change-cb-1.html dynamic-add-without-change-cb-1-ref.html
 fuzzy-if(d2d,1,5) == table-overflowed-by-animation.html table-overflowed-by-animation-ref.html
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5640,11 +5640,12 @@ pref("dom.timeout.max_consecutive_callba
 #ifdef FUZZING
 pref("fuzzing.enabled", false);
 #endif
 
 // Set advanced layers preferences here.
 pref("layers.advanced.border-layers", false);
 #ifdef MOZ_ENABLE_WEBRENDER
 pref("layers.advanced.caret-layers", true);
+pref("layers.advanced.boxshadow-outer-layers", false);
 #else
 pref("layers.advanced.caret-layers", false);
 #endif
--- 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;
+        }
+    }