merge mozilla-inbound to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 29 Oct 2014 13:19:08 +0100
changeset 212832 fe5c1cb8075a9773b86ee001e41c0181519ea04a
parent 212790 366d06412304c16c2c8cdafed6afecb5576c92cd (current diff)
parent 212831 a347286d9669f3489462b365d574f0e2f3575a3c (diff)
child 212843 e5e6847c29885e473fb3747198117579102d5019
push id27730
push usercbook@mozilla.com
push dateWed, 29 Oct 2014 12:26:03 +0000
treeherdermozilla-central@fe5c1cb8075a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone36.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 mozilla-inbound to mozilla-central a=merge
build/unix/abs2rel.pl
config/module2dir.pl
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,12 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Updating CLOBBER for Bug 1084342
-
-There are some refactored files in in dom/bluetooth. Updating CLOBBER to not
-leave artifacts from older builds.
+Backing out bug 1087560 needs a CLOBBER
--- a/b2g/components/test/mochitest/test_permission_deny.html
+++ b/b2g/components/test/mochitest/test_permission_deny.html
@@ -38,17 +38,17 @@ function runNext() {
   if (gTests.length > 0) {
     // Put the requested permission in query string
     let requestedType = gTests.shift();
     info('getUserMedia for ' + JSON.stringify(requestedType));
     navigator.mozGetUserMedia(requestedType, function success() {
       ok(false, 'unexpected success, permission request should be denied');
       runNext();
     }, function failure(err) {
-      is(err.toLowerCase(), 'permission denied', 'expected permission denied');
+      is(err.name, 'PermissionDeniedError', 'expected permission denied');
       runNext();
     });
   } else {
     info('test finished, teardown');
     gScript.sendAsyncMessage('teardown', '');
     gScript.destroy();
     SimpleTest.finish();
   }
--- a/browser/base/content/test/general/browser_devices_get_user_media.js
+++ b/browser/base/content/test/general/browser_devices_get_user_media.js
@@ -218,16 +218,18 @@ function checkNotSharing() {
   is(getMediaCaptureState(), "none", "expected nothing to be shared");
 
   ok(!PopupNotifications.getNotification("webRTC-sharingDevices"),
      "no webRTC-sharingDevices popup notification");
 
   assertWebRTCIndicatorStatus(null);
 }
 
+const permissionError = "error: PermissionDeniedError: The user did not grant permission for the operation.";
+
 let gTests = [
 
 {
   desc: "getUserMedia audio+video",
   run: function checkAudioVideo() {
     yield promisePopupNotificationShown("webRTC-shareDevices", () => {
       info("requesting devices");
       content.wrappedJSObject.requestDevice(true, true);
@@ -376,17 +378,17 @@ let gTests = [
     });
     expectObserverCalled("getUserMedia:request");
     checkDeviceSelectors(true, true);
 
     // disable the camera and microphone
     enableDevice("Camera", false);
     enableDevice("Microphone", false);
 
-    yield promiseMessage("error: PERMISSION_DENIED", () => {
+    yield promiseMessage(permissionError, () => {
       PopupNotifications.panel.firstChild.button.click();
     });
 
     // reset the menuitems to have no impact on the following tests.
     enableDevice("Camera", true);
     enableDevice("Microphone", true);
 
     expectObserverCalled("getUserMedia:response:deny");
@@ -400,17 +402,17 @@ let gTests = [
   run: function checkDontShare() {
     yield promisePopupNotificationShown("webRTC-shareDevices", () => {
       info("requesting devices");
       content.wrappedJSObject.requestDevice(true, true);
     });
     expectObserverCalled("getUserMedia:request");
     checkDeviceSelectors(true, true);
 
-    yield promiseMessage("error: PERMISSION_DENIED", () => {
+    yield promiseMessage(permissionError, () => {
       activateSecondaryAction(kActionDeny);
     });
 
     expectObserverCalled("getUserMedia:response:deny");
     expectObserverCalled("recording-window-ended");
     checkNotSharing();
   }
 },
@@ -477,17 +479,17 @@ let gTests = [
 
       let noVideo = aAllowVideo === undefined;
       is(elt("webRTC-selectCamera").hidden, noVideo,
          "camera selector expected to be " + (noVideo ? "hidden" : "visible"));
       if (!noVideo)
         enableDevice("Camera", aAllowVideo || aNever);
 
       let expectedMessage =
-        (aAllowVideo || aAllowAudio) ? "ok" : "error: PERMISSION_DENIED";
+        (aAllowVideo || aAllowAudio) ? "ok" : permissionError;
       yield promiseMessage(expectedMessage, () => {
         activateSecondaryAction(aNever ? kActionNever : kActionAlways);
       });
       let expected = [];
       if (expectedMessage == "ok") {
         expectObserverCalled("getUserMedia:response:allow");
         expectObserverCalled("recording-device-events");
         if (aAllowVideo)
@@ -582,24 +584,24 @@ let gTests = [
       };
 
       if (aExpectStream === undefined) {
         // Check that we get a prompt.
         yield promisePopupNotificationShown("webRTC-shareDevices", gum);
         expectObserverCalled("getUserMedia:request");
 
         // Deny the request to cleanup...
-        yield promiseMessage("error: PERMISSION_DENIED", () => {
+        yield promiseMessage(permissionError, () => {
           activateSecondaryAction(kActionDeny);
         });
         expectObserverCalled("getUserMedia:response:deny");
         expectObserverCalled("recording-window-ended");
       }
       else {
-        let expectedMessage = aExpectStream ? "ok" : "error: PERMISSION_DENIED";
+        let expectedMessage = aExpectStream ? "ok" : permissionError;
         yield promiseMessage(expectedMessage, gum);
 
         if (expectedMessage == "ok") {
           expectObserverCalled("getUserMedia:request");
           yield promiseNoPopupNotification("webRTC-shareDevices");
           expectObserverCalled("getUserMedia:response:allow");
           expectObserverCalled("recording-device-events");
 
--- a/browser/modules/ContentWebRTC.jsm
+++ b/browser/modules/ContentWebRTC.jsm
@@ -59,17 +59,17 @@ function handleRequest(aSubject, aTopic,
 
   contentWindow.navigator.mozGetUserMediaDevices(
     constraints,
     function (devices) {
       prompt(contentWindow, aSubject.windowID, aSubject.callID,
              constraints, devices, secure);
     },
     function (error) {
-      // bug 827146 -- In the future, the UI should catch NO_DEVICES_FOUND
+      // bug 827146 -- In the future, the UI should catch NotFoundError
       // and allow the user to plug in a device, instead of immediately failing.
       denyRequest({callID: aSubject.callID}, error);
     },
     aSubject.innerWindowID);
 }
 
 function prompt(aContentWindow, aWindowID, aCallID, aConstraints, aDevices, aSecure) {
   let audioDevices = [];
@@ -103,17 +103,17 @@ function prompt(aContentWindow, aWindowI
 
   let requestTypes = [];
   if (videoDevices.length)
     requestTypes.push(sharingScreen ? "Screen" : "Camera");
   if (audioDevices.length)
     requestTypes.push("Microphone");
 
   if (!requestTypes.length) {
-    denyRequest({callID: aCallID}, "NO_DEVICES_FOUND");
+    denyRequest({callID: aCallID}, "NotFoundError");
     return;
   }
 
   if (!aContentWindow.pendingGetUserMediaRequests)
     aContentWindow.pendingGetUserMediaRequests = new Map();
   aContentWindow.pendingGetUserMediaRequests.set(aCallID, devices);
 
   let request = {
--- a/build/autoconf/android.m4
+++ b/build/autoconf/android.m4
@@ -235,17 +235,16 @@ if test "$OS_TARGET" = "Android" -a -z "
                 # android-ndk-r5c, android-ndk-r6, android-ndk-r6b
                 STLPORT_CPPFLAGS="-I$android_ndk/sources/cxx-stl/gnu-libstdc++/include -I$android_ndk/sources/cxx-stl/gnu-libstdc++/libs/$ANDROID_CPU_ARCH/include"
                 STLPORT_LIBS="-L$android_ndk/sources/cxx-stl/gnu-libstdc++/libs/$ANDROID_CPU_ARCH/ -lstdc++"
             else
                 AC_MSG_ERROR([Couldn't find path to gnu-libstdc++ in the android ndk])
             fi
         else
             STLPORT_CPPFLAGS="-isystem $_topsrcdir/build/stlport/stlport -isystem $_topsrcdir/build/stlport/overrides -isystem $android_ndk/sources/cxx-stl/system/include"
-            STLPORT_LIBS="$_objdir/build/stlport/libstlport_static.a -static-libstdc++"
         fi
     fi
     CXXFLAGS="$CXXFLAGS $STLPORT_CPPFLAGS"
 fi
 AC_SUBST([MOZ_ANDROID_LIBSTDCXX])
 AC_SUBST([STLPORT_LIBS])
 
 ])
--- a/build/stlport/moz.build
+++ b/build/stlport/moz.build
@@ -1,15 +1,21 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
-Library('stlport_static')
+Library('stlport')
+# Keep the same name as the NDK-provided library, while using a shorter
+# name for the Library for convenience in moz.build.
+STATIC_LIBRARY_NAME = 'stlport_static'
+
+if not CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
+    OS_LIBS += ['-static-libstdc++']
 
 FORCE_STATIC_LIB = True
 
 SOURCES += [
     'src/allocators.cpp',
     'src/bitset.cpp',
     'src/codecvt.cpp',
     'src/collate.cpp',
--- a/build/templates.mozbuild
+++ b/build/templates.mozbuild
@@ -1,68 +1,80 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 @template
-def StdCppCompat():
-    '''Template for libstdc++ compatibility for target binaries.'''
+def Binary():
+    '''Generic template for target binaries. Meant to be used by other
+    templates.'''
 
     if CONFIG['MOZ_LIBSTDCXX_TARGET_VERSION']:
         USE_LIBS += ['stdc++compat']
 
+    # Ideally, we'd support not adding this to the LIB_IS_C_ONLY case,
+    # but that variable is actually only set in db/sqlite/src, which
+    # doesn't build a shared library on the relevant platforms anyways.
+    # Eventually, though, we should detect LIB_IS_C_ONLY based on the
+    # associated SOURCES (and there might actually be places where we
+    # haven't set it but should have).
+    if CONFIG['STLPORT_LIBS']:
+        OS_LIBS += [CONFIG['STLPORT_LIBS']]
+    elif CONFIG['OS_TARGET'] == 'Android':
+        USE_LIBS += ['stlport']
+
 
 @template
 def Program(name):
     '''Template for program executables.'''
     PROGRAM = name
 
-    StdCppCompat()
+    Binary()
 
 
 @template
 def SimplePrograms(names, ext='.cpp'):
     '''Template for simple program executables.
 
     Those have a single source with the same base name as the executable.
     '''
     SIMPLE_PROGRAMS += names
     SOURCES += ['%s%s' % (name, ext) for name in names]
 
-    StdCppCompat()
+    Binary()
 
 
 @template
 def CppUnitTests(names, ext='.cpp'):
     '''Template for C++ unit tests.
 
     Those have a single source with the same base name as the executable.
     '''
     CPP_UNIT_TESTS += names
     SOURCES += ['%s%s' % (name, ext) for name in names]
 
-    StdCppCompat()
+    Binary()
 
 
 @template
 def Library(name):
     '''Template for libraries.'''
     LIBRARY_NAME = name
 
 
 @template
 def SharedLibrary(name):
     '''Template for shared libraries.'''
     Library(name)
 
     FORCE_SHARED_LIB = True
 
-    StdCppCompat()
+    Binary()
 
 
 @template
 def Framework(name):
     '''Template for OSX Frameworks.'''
     SharedLibrary(name)
 
     IS_FRAMEWORK = True
deleted file mode 100644
--- a/build/unix/abs2rel.pl
+++ /dev/null
@@ -1,35 +0,0 @@
-#!env perl
-
-# 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 File::Spec::Unix;
-use strict;
-
-print "Usage: $0 dest_path start_path\n" if ($#ARGV+1 != 2);
-my $finish = my_canonpath(shift);
-my $start = my_canonpath(shift);
-
-my $res = File::Spec::Unix->abs2rel($finish, $start);
-
-#print STDERR "abs2rel($finish,$start) = $res\n";
-print "$res\n";
-
-sub my_canonpath($) {
-    my ($file) = @_;
-    my (@inlist, @outlist, $dir);
-
-    # Do what File::Spec::Unix->no_upwards should do
-    my @inlist = split(/\//, File::Spec::Unix->canonpath($file));
-    foreach $dir (@inlist) {
-	if ($dir eq '..') {
-	    pop @outlist;
-	} else {
-	    push @outlist, $dir;
-	}
-    }
-    $file = join '/',@outlist;
-    return $file;
-}
-
--- a/caps/nsIScriptSecurityManager.idl
+++ b/caps/nsIScriptSecurityManager.idl
@@ -14,17 +14,17 @@ interface nsILoadContext;
 
 %{ C++
 #include "jspubtd.h"
 %}
 
 [ptr] native JSContextPtr(JSContext);
 [ptr] native JSObjectPtr(JSObject);
 
-[scriptable, uuid(3b021962-975e-43b5-8a93-9fc2d20346e9)]
+[scriptable, uuid(f649959d-dae3-4027-83fd-5b7f8c8a8815)]
 interface nsIScriptSecurityManager : nsISupports
 {
     /**
      * For each of these hooks returning NS_OK means 'let the action continue'.
      * Returning an error code means 'veto the action'. XPConnect will return
      * false to the js engine if the action is vetoed. The implementor of this
      * interface is responsible for setting a JS exception into the JSContext
      * if that is appropriate.
@@ -174,23 +174,16 @@ interface nsIScriptSecurityManager : nsI
     /**
      * Legacy name for getNoAppCodebasePrincipal.
      *
      * @deprecated use getNoAppCodebasePrincipal instead.
      */
     [deprecated] nsIPrincipal getCodebasePrincipal(in nsIURI uri);
 
     /**
-     * Returns OK if aJSContext and target have the same "origin"
-     * (scheme, host, and port).
-     */
-    [noscript] void checkSameOrigin(in JSContextPtr aJSContext,
-                                    in nsIURI aTargetURI);
-
-    /**
      * Returns OK if aSourceURI and target have the same "origin"
      * (scheme, host, and port).
      * ReportError flag suppresses error reports for functions that
      * don't need reporting.
      */
     void checkSameOriginURI(in nsIURI aSourceURI,
                             in nsIURI aTargetURI,
                             in boolean reportError);
--- a/caps/nsPrincipal.cpp
+++ b/caps/nsPrincipal.cpp
@@ -341,16 +341,27 @@ nsPrincipal::CheckMayLoad(nsIURI* aURI, 
    if (aAllowIfInheritsPrincipal) {
     // If the caller specified to allow loads of URIs that inherit
     // our principal, allow the load if this URI inherits its principal
     if (nsPrincipal::IsPrincipalInherited(aURI)) {
       return NS_OK;
     }
   }
 
+  // See if aURI is something like a Blob URI that is actually associated with
+  // a principal.
+  nsCOMPtr<nsIURIWithPrincipal> uriWithPrin = do_QueryInterface(aURI);
+  nsCOMPtr<nsIPrincipal> uriPrin;
+  if (uriWithPrin) {
+    uriWithPrin->GetPrincipal(getter_AddRefs(uriPrin));
+  }
+  if (uriPrin && nsIPrincipal::Subsumes(uriPrin)) {
+      return NS_OK;
+  }
+
   if (nsScriptSecurityManager::SecurityCompareURIs(mCodebase, aURI)) {
     return NS_OK;
   }
 
   // If strict file origin policy is in effect, local files will always fail
   // SecurityCompareURIs unless they are identical. Explicitly check file origin
   // policy, in that case.
   if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -437,49 +437,16 @@ nsScriptSecurityManager::ContentSecurity
 bool
 nsScriptSecurityManager::JSPrincipalsSubsume(JSPrincipals *first,
                                              JSPrincipals *second)
 {
     return nsJSPrincipals::get(first)->Subsumes(nsJSPrincipals::get(second));
 }
 
 NS_IMETHODIMP
-nsScriptSecurityManager::CheckSameOrigin(JSContext* cx,
-                                         nsIURI* aTargetURI)
-{
-    MOZ_ASSERT_IF(cx, cx == nsContentUtils::GetCurrentJSContext());
-
-    // Get a principal from the context
-    nsIPrincipal* sourcePrincipal = nsContentUtils::SubjectPrincipal();
-    if (sourcePrincipal == mSystemPrincipal)
-    {
-        // This is a system (chrome) script, so allow access
-        return NS_OK;
-    }
-
-    // Get the original URI from the source principal.
-    // This has the effect of ignoring any change to document.domain
-    // which must be done to avoid DNS spoofing (bug 154930)
-    nsCOMPtr<nsIURI> sourceURI;
-    sourcePrincipal->GetDomain(getter_AddRefs(sourceURI));
-    if (!sourceURI) {
-      sourcePrincipal->GetURI(getter_AddRefs(sourceURI));
-      NS_ENSURE_TRUE(sourceURI, NS_ERROR_FAILURE);
-    }
-
-    // Compare origins
-    if (!SecurityCompareURIs(sourceURI, aTargetURI))
-    {
-         ReportError(cx, NS_LITERAL_STRING("CheckSameOriginError"), sourceURI, aTargetURI);
-         return NS_ERROR_DOM_BAD_URI;
-    }
-    return NS_OK;
-}
-
-NS_IMETHODIMP
 nsScriptSecurityManager::CheckSameOriginURI(nsIURI* aSourceURI,
                                             nsIURI* aTargetURI,
                                             bool reportError)
 {
     if (!SecurityCompareURIs(aSourceURI, aTargetURI))
     {
          if (reportError) {
             ReportError(nullptr, NS_LITERAL_STRING("CheckSameOriginError"),
deleted file mode 100755
--- a/config/module2dir.pl
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/perl -w
-# 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/.
-
-
-#
-# Create a mapping from symbolic component name to directory name(s).
-#
-# Tue Oct 16 16:48:36 PDT 2001
-# <mcafee@netscape.com>
-
-use strict;
-
-# For --option1, --option2, ...
-use Getopt::Long;
-Getopt::Long::Configure("bundling_override");
-Getopt::Long::Configure("auto_abbrev");
-
-# Globals
-my $list_only_mode = 0;
-my $opt_list_only;
-my $mapfile = "";
-my %map;
-
-sub PrintUsage {
-  die <<END_USAGE
-  Prints out directories needed for a given list of components.
-  usage: module2dir.pl [--list-only] [--mapfile mapfile] <component-name1> <component-name2> ...
-END_USAGE
-}
-
-sub parse_map_file($) {
-    my ($mapfile) = @_;
-    my (%mod_map, $tmp, $dir, $mod, @mod_list);
-
-    undef %mod_map;
-    open (MAPFILE, "$mapfile") || die ("$mapfile: $!\n");
-    while ($tmp=<MAPFILE>) {
-	chomp ($tmp);
-	($dir, $mod, @mod_list) = split(/:/, $tmp, 3);
-	$mod =~ s/[\s]*(\S+)[\s]*/$1/;
-	$mod_map{$mod} .= "$dir ";
-    }
-    close(MAPFILE);
-    foreach $mod (sort(keys %mod_map)) {
-	my (@dirlist, @trimlist, $found, $tdir);
-	@dirlist = split(/\s+/, $mod_map{$mod});
-	$mod_map{$mod} = "";
-	foreach $dir (@dirlist) {
-	    $found = 0; 
-	    foreach $tdir (@trimlist) {
-		$found++, last if ($dir =~ m/^$tdir\// || $dir eq $tdir);
-	    }
-	    push @trimlist, $dir if (!$found);
-        }
-	$map{$mod} = join(" ", @trimlist);
-	#print "$mod: $map{$mod}\n";
-    }
-}
-
-sub dir_for_required_component {
-  my ($component) = @_;
-  my $rv;
-  my $dir;
-
-  $dir = $map{$component};
-  if($dir) {
-	# prepend "mozilla/" in front of directory names.
-	$rv = "mozilla/$dir";
-	$rv =~ s/\s+/ mozilla\//g;  # Hack for 2 or more directories.
-  } else {
-	$rv = 0;
-  }
-  return $rv;
-}
-
-{
-
-  # Add stdin to the commandline.  This makes commandline-only mode hang,
-  # call it a bug.  Not sure how to get around this.
-  push (@ARGV, split(' ',<STDIN>));
-
-  PrintUsage() if !GetOptions('list-only' => \$opt_list_only,
-			      'mapfile=s' => \$mapfile);
-
-  # Pick up arguments, if any.
-  if($opt_list_only) {
-  	$list_only_mode = 1;
-  }
-
-  &parse_map_file($mapfile);
-
-  my $arg;
-  my $dir;
-  while ($arg = shift @ARGV) {
-	$dir = dir_for_required_component($arg);
-	if($dir) {
-      if($list_only_mode) {
-		print $dir, " ";
-	  } else {
-		print "$arg: ", $dir, "\n";
-	  }
-	} else {
-	  # do nothing
-	}
-  }
-  if($dir && $list_only_mode) {
-	print "\n";
-  }
-}
--- a/config/recurse.mk
+++ b/config/recurse.mk
@@ -150,18 +150,13 @@ endif
 # Note some others are hardcoded or "guessed" in recursivemake.py and emitter.py
 ifeq ($(MOZ_WIDGET_TOOLKIT),gtk3)
 toolkit/library/target: widget/gtk/mozgtk/gtk3/target
 endif
 ifdef MOZ_LDAP_XPCOM
 ldap/target: config/external/nss/target mozglue/build/target
 toolkit/library/target: ldap/target
 endif
-ifndef MOZ_FOLD_LIBS
-ifndef MOZ_NATIVE_SQLITE
-config/external/nss/target: db/sqlite3/src/target
-endif
-endif
 ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library)
-mozglue/build/target: memory/replace/dummy/target
+mozglue/build/target memory/replace/logalloc/replay/target: memory/replace/dummy/target
 endif
 
 endif
--- a/config/rules.mk
+++ b/config/rules.mk
@@ -691,17 +691,17 @@ ifdef MSMANIFEST_TOOL
 	fi
 endif	# MSVC with manifest tool
 ifdef MOZ_PROFILE_GENERATE
 # touch it a few seconds into the future to work around FAT's
 # 2-second granularity
 	touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
 endif
 else # !WINNT || GNU_CC
-	$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
+	$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
@@ -747,17 +747,17 @@ ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
 	$(EXPAND_LD) -nologo -out:$@ -pdb:$(LINK_PDBFILE) $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(MOZ_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS)
 ifdef MSMANIFEST_TOOL
 	@if test -f $@.manifest; then \
 		mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;1; \
 		rm -f $@.manifest; \
 	fi
 endif	# MSVC with manifest tool
 else
-	$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
+	$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS)
 	$(call CHECK_BINARY,$@)
 endif # WINNT && !GNU_CC
 
 ifdef ENABLE_STRIP
 	$(STRIP) $(STRIP_FLAGS) $@
 endif
 ifdef MOZ_POST_PROGRAM_COMMAND
 	$(MOZ_POST_PROGRAM_COMMAND) $@
@@ -829,20 +829,20 @@ endif
 	$(REPORT_BUILD)
 ifndef INCREMENTAL_LINKER
 	$(RM) $@
 endif
 ifdef DTRACE_LIB_DEPENDENT
 ifndef XP_MACOSX
 	dtrace -G -C -s $(MOZILLA_DTRACE_SRC) -o  $(DTRACE_PROBE_OBJ) $(shell $(EXPAND_LIBS) $(MOZILLA_PROBE_LIBS))
 endif
-	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(MOZILLA_PROBE_LIBS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE) $(if $(LIB_IS_C_ONLY),,$(STLPORT_LIBS))
+	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(DTRACE_PROBE_OBJ) $(MOZILLA_PROBE_LIBS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE)
 	@$(RM) $(DTRACE_PROBE_OBJ)
 else # ! DTRACE_LIB_DEPENDENT
-	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE) $(if $(LIB_IS_C_ONLY),,$(STLPORT_LIBS))
+	$(EXPAND_MKSHLIB) $(SHLIB_LDSTARTFILE) $(OBJS) $(SUB_SHLOBJS) $(RESFILE) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_DSO_LDOPTS) $(MOZ_GLUE_LDFLAGS) $(EXTRA_LIBS) $(OS_LIBS) $(SHLIB_LDENDFILE)
 endif # DTRACE_LIB_DEPENDENT
 	$(call CHECK_BINARY,$@)
 
 ifeq (_WINNT,$(GNU_CC)_$(OS_ARCH))
 ifdef MSMANIFEST_TOOL
 ifdef EMBED_MANIFEST_AT
 	@if test -f $@.manifest; then \
 		mt.exe -NOLOGO -MANIFEST $@.manifest -OUTPUTRESOURCE:$@\;$(EMBED_MANIFEST_AT); \
--- a/configure.in
+++ b/configure.in
@@ -224,17 +224,16 @@ if test -n "$gonkdir" ; then
     RANLIB="$gonk_toolchain_prefix"ranlib
     STRIP="$gonk_toolchain_prefix"strip
     OBJCOPY="$gonk_toolchain_prefix"objcopy
 
     if ! test -e "$gonkdir/ndk/sources/cxx-stl/stlport/src/iostream.cpp"; then
         AC_MSG_ERROR([Couldn't find path to stlport sources in the gonk tree])
     fi
     STLPORT_CPPFLAGS="-I$_topsrcdir/build/stlport/stlport -I$gonkdir/ndk/sources/cxx-stl/system/include"
-    STLPORT_LIBS="$_objdir/build/stlport/libstlport_static.a"
 
     case "$target_cpu" in
     arm)
         ARCH_DIR=arch-arm
         ;;
     i?86)
         ARCH_DIR=arch-x86
         ;;
@@ -9055,18 +9054,16 @@ HAVE_STATVFS
 HAVE_STATFS64
 HAVE_STATFS
 HAVE_SYS_STATVFS_H
 HAVE_SYS_STATFS_H
 HAVE_SYS_VFS_H
 HAVE_SYS_MOUNT_H
 "
 
-AC_SUBST(STLPORT_LIBS)
-
 dnl ========================================================
 dnl ICU Support
 dnl ========================================================
 
 # Internationalization isn't built or exposed by default in non-desktop
 # builds.  Bugs to enable:
 #
 #   Android:  bug 864843
--- a/docshell/test/chrome/bug113934_window.xul
+++ b/docshell/test/chrome/bug113934_window.xul
@@ -48,18 +48,19 @@
     $("f2").setAttribute("src", doc2);
     $("f3").setAttribute("src", doc2);
 
     function doTheTest() {
       var s1 = snapshotWindow($("f1").contentWindow);
       var s2 = snapshotWindow($("f2").contentWindow);
       var s3 = snapshotWindow($("f3").contentWindow);
 
-      ok(!compareSnapshots(s2, s3, true)[0],
-         "Should look different due to different sizing");
+      // This test is broken - see bug 1090274
+      //ok(!compareSnapshots(s2, s3, true)[0],
+      //   "Should look different due to different sizing");
 
       function getDOM(id) {
         return $(id).contentDocument.documentElement.innerHTML;
       }
 
       var dom1 = getDOM("f1");
 
       var dom2 = getDOM("f2");
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -64,16 +64,17 @@
 #include "nsIDOMNavigatorSystemMessages.h"
 #include "nsStreamUtils.h"
 #include "nsIAppsService.h"
 #include "mozIApplication.h"
 #include "WidgetUtils.h"
 #include "mozIThirdPartyUtil.h"
 
 #ifdef MOZ_MEDIA_NAVIGATOR
+#include "mozilla/dom/MediaDevices.h"
 #include "MediaManager.h"
 #endif
 #ifdef MOZ_B2G_BT
 #include "BluetoothManager.h"
 #endif
 #include "DOMCameraManager.h"
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
@@ -1208,16 +1209,31 @@ Navigator::SendBeacon(const nsAString& a
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return false;
   }
   return true;
 }
 
 #ifdef MOZ_MEDIA_NAVIGATOR
+MediaDevices*
+Navigator::GetMediaDevices(ErrorResult& aRv)
+{
+  if (!mMediaDevices) {
+    if (!mWindow ||
+        !mWindow->GetOuterWindow() ||
+        mWindow->GetOuterWindow()->GetCurrentInnerWindow() != mWindow) {
+      aRv.Throw(NS_ERROR_NOT_AVAILABLE);
+      return nullptr;
+    }
+    mMediaDevices = new MediaDevices(mWindow);
+  }
+  return mMediaDevices;
+}
+
 void
 Navigator::MozGetUserMedia(const MediaStreamConstraints& aConstraints,
                            NavigatorUserMediaSuccessCallback& aOnSuccess,
                            NavigatorUserMediaErrorCallback& aOnError,
                            ErrorResult& aRv)
 {
   CallbackObjectHolder<NavigatorUserMediaSuccessCallback,
                        nsIDOMGetUserMediaSuccessCallback> holder1(&aOnSuccess);
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -27,16 +27,17 @@ class nsDOMCameraManager;
 class nsDOMDeviceStorage;
 class nsIPrincipal;
 class nsIURI;
 
 namespace mozilla {
 namespace dom {
 class Geolocation;
 class systemMessageCallback;
+class MediaDevices;
 struct MediaStreamConstraints;
 class WakeLock;
 class ArrayBufferViewOrBlobOrStringOrFormData;
 struct MobileIdOptions;
 class ServiceWorkerContainer;
 }
 }
 
@@ -219,16 +220,17 @@ public:
                          ErrorResult& aRv);
   DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
   CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
   MobileMessageManager* GetMozMobileMessage();
   Telephony* GetMozTelephony(ErrorResult& aRv);
   Voicemail* GetMozVoicemail(ErrorResult& aRv);
   network::Connection* GetConnection(ErrorResult& aRv);
   nsDOMCameraManager* GetMozCameras(ErrorResult& aRv);
+  MediaDevices* GetMediaDevices(ErrorResult& aRv);
   void MozSetMessageHandler(const nsAString& aType,
                             systemMessageCallback* aCallback,
                             ErrorResult& aRv);
   bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv);
 #ifdef MOZ_B2G
   already_AddRefed<Promise> GetMobileIdAssertion(const MobileIdOptions& options,
                                                  ErrorResult& aRv);
 #endif
@@ -339,16 +341,17 @@ private:
 #endif
 #ifdef MOZ_B2G_BT
   nsRefPtr<bluetooth::BluetoothManager> mBluetooth;
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   nsRefPtr<system::AudioChannelManager> mAudioChannelManager;
 #endif
   nsRefPtr<nsDOMCameraManager> mCameraManager;
+  nsRefPtr<MediaDevices> mMediaDevices;
   nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
   nsTArray<nsRefPtr<nsDOMDeviceStorage> > mDeviceStorageStores;
   nsRefPtr<time::TimeManager> mTimeManager;
   nsRefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
   nsCOMPtr<nsPIDOMWindow> mWindow;
 
   // Hashtable for saving cached objects newresolve created, so we don't create
   // the object twice if asked for it twice, whether due to use of "delete" or
--- a/dom/indexedDB/ActorsParent.cpp
+++ b/dom/indexedDB/ActorsParent.cpp
@@ -41,17 +41,16 @@
 #include "mozilla/dom/indexedDB/PBackgroundIDBTransactionParent.h"
 #include "mozilla/dom/indexedDB/PBackgroundIDBVersionChangeTransactionParent.h"
 #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestParent.h"
 #include "mozilla/dom/ipc/BlobParent.h"
 #include "mozilla/dom/quota/Client.h"
 #include "mozilla/dom/quota/FileStreams.h"
 #include "mozilla/dom/quota/OriginOrPatternString.h"
 #include "mozilla/dom/quota/QuotaManager.h"
-#include "mozilla/dom/quota/StoragePrivilege.h"
 #include "mozilla/dom/quota/UsageInfo.h"
 #include "mozilla/ipc/BackgroundParent.h"
 #include "mozilla/ipc/BackgroundUtils.h"
 #include "mozilla/ipc/InputStreamParams.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/ipc/PBackground.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsClassHashtable.h"
@@ -3880,17 +3879,16 @@ protected:
 
   nsTArray<MaybeBlockedDatabaseInfo> mMaybeBlockedDatabases;
 
   const CommonFactoryRequestParams mCommonParams;
   nsCString mGroup;
   nsCString mOrigin;
   nsCString mDatabaseId;
   State mState;
-  StoragePrivilege mStoragePrivilege;
   bool mEnforcingQuota;
   const bool mDeleting;
   bool mBlockedQuotaManager;
   bool mChromeWriteAccessAllowed;
 
 public:
   void
   NoteDatabaseBlocked(Database* aDatabase);
@@ -8585,24 +8583,24 @@ Cursor::RecvContinue(const CursorRequest
 
 /*******************************************************************************
  * FileManager
  ******************************************************************************/
 
 FileManager::FileManager(PersistenceType aPersistenceType,
                          const nsACString& aGroup,
                          const nsACString& aOrigin,
-                         StoragePrivilege aPrivilege,
-                         const nsAString& aDatabaseName)
+                         const nsAString& aDatabaseName,
+                         bool aEnforcingQuota)
   : mPersistenceType(aPersistenceType)
   , mGroup(aGroup)
   , mOrigin(aOrigin)
-  , mPrivilege(aPrivilege)
   , mDatabaseName(aDatabaseName)
   , mLastFileId(0)
+  , mEnforcingQuota(aEnforcingQuota)
   , mInvalidated(false)
 { }
 
 FileManager::~FileManager()
 { }
 
 nsresult
 FileManager::Init(nsIFile* aDirectory,
@@ -10431,17 +10429,16 @@ AutoSetProgressHandler::Register(
 FactoryOp::FactoryOp(Factory* aFactory,
                      already_AddRefed<ContentParent> aContentParent,
                      const CommonFactoryRequestParams& aCommonParams,
                      bool aDeleting)
   : mFactory(aFactory)
   , mContentParent(Move(aContentParent))
   , mCommonParams(aCommonParams)
   , mState(State_Initial)
-  , mStoragePrivilege(mozilla::dom::quota::Content)
   , mEnforcingQuota(true)
   , mDeleting(aDeleting)
   , mBlockedQuotaManager(false)
   , mChromeWriteAccessAllowed(false)
 {
   AssertIsOnBackgroundThread();
   MOZ_ASSERT(aFactory);
   MOZ_ASSERT(!QuotaClient::IsShuttingDownOnNonMainThread());
@@ -10730,19 +10727,17 @@ FactoryOp::CheckPermission(ContentParent
       }
 
       mChromeWriteAccessAllowed = canWrite;
     } else {
       mChromeWriteAccessAllowed = true;
     }
 
     if (State_Initial == mState) {
-      QuotaManager::GetInfoForChrome(&mGroup, &mOrigin, &mStoragePrivilege,
-                                     nullptr);
-      MOZ_ASSERT(mStoragePrivilege == mozilla::dom::quota::Chrome);
+      QuotaManager::GetInfoForChrome(&mGroup, &mOrigin, nullptr, nullptr);
       mEnforcingQuota = false;
     }
 
     *aPermission = PermissionRequestBase::kPermissionAllowed;
     return NS_OK;
   }
 
   MOZ_ASSERT(principalInfo.type() == PrincipalInfo::TContentPrincipalInfo);
@@ -10784,22 +10779,20 @@ FactoryOp::CheckPermission(ContentParent
         return rv;
       }
     }
   }
 
   if (permission != PermissionRequestBase::kPermissionDenied &&
       State_Initial == mState) {
     rv = QuotaManager::GetInfoFromPrincipal(principal, &mGroup, &mOrigin,
-                                            &mStoragePrivilege, nullptr);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
-
-    MOZ_ASSERT(mStoragePrivilege != mozilla::dom::quota::Chrome);
+                                            nullptr, nullptr);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
   }
 
   if (permission == PermissionRequestBase::kPermissionAllowed &&
       mEnforcingQuota)
   {
     // If we're running from a window then we should check the quota permission
     // as well.
     uint32_t quotaPermission = CheckQuotaHelper::GetQuotaPermission(principal);
@@ -11321,18 +11314,18 @@ OpenDatabaseOp::DoDatabaseWork()
   MOZ_ASSERT(mgr);
 
   nsRefPtr<FileManager> fileManager =
     mgr->GetFileManager(persistenceType, mOrigin, databaseName);
   if (!fileManager) {
     fileManager = new FileManager(persistenceType,
                                   mGroup,
                                   mOrigin,
-                                  mStoragePrivilege,
-                                  databaseName);
+                                  databaseName,
+                                  mEnforcingQuota);
 
     rv = fileManager->Init(fmDirectory, connection);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
     mgr->AddFileManager(fileManager);
   }
@@ -12699,29 +12692,29 @@ VersionChangeOp::RunOnIOThread()
     mDeleteDatabaseOp->mCommonParams.metadata().persistenceType();
 
   QuotaManager* quotaManager = QuotaManager::Get();
   MOZ_ASSERT(quotaManager);
 
   if (exists) {
     int64_t fileSize;
 
-    if (mDeleteDatabaseOp->mStoragePrivilege != Chrome) {
+    if (mDeleteDatabaseOp->mEnforcingQuota) {
       rv = dbFile->GetFileSize(&fileSize);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
 
     rv = dbFile->Remove(false);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    if (mDeleteDatabaseOp->mStoragePrivilege != Chrome) {
+    if (mDeleteDatabaseOp->mEnforcingQuota) {
       quotaManager->DecreaseUsageForOrigin(persistenceType,
                                            mDeleteDatabaseOp->mGroup,
                                            mDeleteDatabaseOp->mOrigin,
                                            fileSize);
     }
   }
 
   nsCOMPtr<nsIFile> dbJournalFile;
@@ -12776,29 +12769,29 @@ VersionChangeOp::RunOnIOThread()
 
     if (NS_WARN_IF(!isDirectory)) {
       IDB_REPORT_INTERNAL_ERR();
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     uint64_t usage = 0;
 
-    if (mDeleteDatabaseOp->mStoragePrivilege != Chrome) {
+    if (mDeleteDatabaseOp->mEnforcingQuota) {
       rv = FileManager::GetUsage(fmDirectory, &usage);
       if (NS_WARN_IF(NS_FAILED(rv))) {
         return rv;
       }
     }
 
     rv = fmDirectory->Remove(true);
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return rv;
     }
 
-    if (mDeleteDatabaseOp->mStoragePrivilege != Chrome) {
+    if (mDeleteDatabaseOp->mEnforcingQuota) {
       quotaManager->DecreaseUsageForOrigin(persistenceType,
                                            mDeleteDatabaseOp->mGroup,
                                            mDeleteDatabaseOp->mOrigin,
                                            usage);
     }
   }
 
   IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
@@ -14420,22 +14413,24 @@ ObjectStoreAddOrPutRequestOp::CopyFileDa
     }
 
     if (NS_WARN_IF(numWrite != numRead)) {
       rv = NS_ERROR_FAILURE;
       break;
     }
   } while (true);
 
-  nsresult rv2 = aOutputStream->Flush();
-  if (NS_WARN_IF(NS_FAILED(rv2))) {
-    return NS_SUCCEEDED(rv) ? rv2 : rv;
-  }
-
-  rv2 = aOutputStream->Close();
+  if (NS_SUCCEEDED(rv)) {
+    rv = aOutputStream->Flush();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  nsresult rv2 = aOutputStream->Close();
   if (NS_WARN_IF(NS_FAILED(rv2))) {
     return NS_SUCCEEDED(rv) ? rv2 : rv;
   }
 
   return rv;
 }
 
 bool
@@ -14799,19 +14794,41 @@ ObjectStoreAddOrPutRequestOp::DoDatabase
           rv = CopyFileData(inputStream, outputStream);
           if (NS_FAILED(rv) &&
               NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) {
             IDB_REPORT_INTERNAL_ERR();
             rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
           }
           if (NS_WARN_IF(NS_FAILED(rv))) {
             // Try to remove the file if the copy failed.
-            if (NS_FAILED(diskFile->Remove(false))) {
-              NS_WARNING("Failed to remove file after copying failed!");
+            nsresult rv2;
+            int64_t fileSize;
+
+            if (mFileManager->EnforcingQuota()) {
+              rv2 = diskFile->GetFileSize(&fileSize);
+              if (NS_WARN_IF(NS_FAILED(rv2))) {
+                return rv;
+              }
             }
+
+            rv2 = diskFile->Remove(false);
+            if (NS_WARN_IF(NS_FAILED(rv2))) {
+              return rv;
+            }
+
+            if (mFileManager->EnforcingQuota()) {
+              QuotaManager* quotaManager = QuotaManager::Get();
+              MOZ_ASSERT(quotaManager);
+
+              quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
+                                                   mFileManager->Group(),
+                                                   mFileManager->Origin(),
+                                                   fileSize);
+            }
+
             return rv;
           }
 
           storedFileInfo.mCopiedSuccessfully = true;
         }
       }
 
       if (index) {
--- a/dom/indexedDB/FileManager.h
+++ b/dom/indexedDB/FileManager.h
@@ -4,17 +4,16 @@
  * 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 mozilla_dom_indexeddb_filemanager_h__
 #define mozilla_dom_indexeddb_filemanager_h__
 
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/quota/PersistenceType.h"
-#include "mozilla/dom/quota/StoragePrivilege.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsISupportsImpl.h"
 
 class nsIFile;
 class mozIStorageConnection;
 
 namespace mozilla {
@@ -24,32 +23,31 @@ namespace indexedDB {
 class FileInfo;
 
 // Implemented in ActorsParent.cpp.
 class FileManager MOZ_FINAL
 {
   friend class FileInfo;
 
   typedef mozilla::dom::quota::PersistenceType PersistenceType;
-  typedef mozilla::dom::quota::StoragePrivilege StoragePrivilege;
 
   PersistenceType mPersistenceType;
   nsCString mGroup;
   nsCString mOrigin;
-  StoragePrivilege mPrivilege;
   nsString mDatabaseName;
 
   nsString mDirectoryPath;
   nsString mJournalDirectoryPath;
 
   int64_t mLastFileId;
 
   // Protected by IndexedDatabaseManager::FileMutex()
   nsDataHashtable<nsUint64HashKey, FileInfo*> mFileInfos;
 
+  const bool mEnforcingQuota;
   bool mInvalidated;
 
 public:
   static already_AddRefed<nsIFile>
   GetFileForId(nsIFile* aDirectory, int64_t aId);
 
   static nsresult
   InitDirectory(nsIFile* aDirectory,
@@ -59,18 +57,18 @@ public:
                 const nsACString& aOrigin);
 
   static nsresult
   GetUsage(nsIFile* aDirectory, uint64_t* aUsage);
 
   FileManager(PersistenceType aPersistenceType,
               const nsACString& aGroup,
               const nsACString& aOrigin,
-              StoragePrivilege aPrivilege,
-              const nsAString& aDatabaseName);
+              const nsAString& aDatabaseName,
+              bool aEnforcingQuota);
 
   PersistenceType
   Type() const
   {
     return mPersistenceType;
   }
 
   const nsACString&
@@ -80,29 +78,29 @@ public:
   }
 
   const nsACString&
   Origin() const
   {
     return mOrigin;
   }
 
-  const StoragePrivilege&
-  Privilege() const
-  {
-    return mPrivilege;
-  }
-
   const nsAString&
   DatabaseName() const
   {
     return mDatabaseName;
   }
 
   bool
+  EnforcingQuota() const
+  {
+    return mEnforcingQuota;
+  }
+
+  bool
   Invalidated() const
   {
     return mInvalidated;
   }
 
   nsresult
   Init(nsIFile* aDirectory, mozIStorageConnection* aConnection);
 
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -843,25 +843,25 @@ AsyncDeleteFileRunnable::Run()
   NS_ENSURE_TRUE(directory, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIFile> file = mFileManager->GetFileForId(directory, mFileId);
   NS_ENSURE_TRUE(file, NS_ERROR_FAILURE);
 
   nsresult rv;
   int64_t fileSize;
 
-  if (mFileManager->Privilege() != Chrome) {
+  if (mFileManager->EnforcingQuota()) {
     rv = file->GetFileSize(&fileSize);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
   }
 
   rv = file->Remove(false);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
-  if (mFileManager->Privilege() != Chrome) {
+  if (mFileManager->EnforcingQuota()) {
     QuotaManager* quotaManager = QuotaManager::Get();
     NS_ASSERTION(quotaManager, "Shouldn't be null!");
 
     quotaManager->DecreaseUsageForOrigin(mFileManager->Type(),
                                          mFileManager->Group(),
                                          mFileManager->Origin(), fileSize);
   }
 
--- a/dom/indexedDB/SerializationHelpers.h
+++ b/dom/indexedDB/SerializationHelpers.h
@@ -7,36 +7,28 @@
 
 #include "ipc/IPCMessageUtils.h"
 
 #include "mozilla/dom/indexedDB/Key.h"
 #include "mozilla/dom/indexedDB/KeyPath.h"
 #include "mozilla/dom/indexedDB/IDBCursor.h"
 #include "mozilla/dom/indexedDB/IDBTransaction.h"
 #include "mozilla/dom/quota/PersistenceType.h"
-#include "mozilla/dom/quota/StoragePrivilege.h"
 
 namespace IPC {
 
 template <>
 struct ParamTraits<mozilla::dom::quota::PersistenceType> :
   public ContiguousEnumSerializer<
                                mozilla::dom::quota::PersistenceType,
                                mozilla::dom::quota::PERSISTENCE_TYPE_PERSISTENT,
                                mozilla::dom::quota::PERSISTENCE_TYPE_INVALID>
 { };
 
 template <>
-struct ParamTraits<mozilla::dom::quota::StoragePrivilege> :
-  public ContiguousEnumSerializer<mozilla::dom::quota::StoragePrivilege,
-                                  mozilla::dom::quota::Chrome,
-                                  mozilla::dom::quota::Invalid>
-{ };
-
-template <>
 struct ParamTraits<mozilla::dom::indexedDB::Key>
 {
   typedef mozilla::dom::indexedDB::Key paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
     WriteParam(aMsg, aParam.mBuffer);
   }
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -28,17 +28,22 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMMe
 
 NS_IMPL_ADDREF_INHERITED(DOMMediaStream, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(DOMMediaStream, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMMediaStream)
   NS_INTERFACE_MAP_ENTRY(DOMMediaStream)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
-NS_IMPL_ISUPPORTS_INHERITED0(DOMLocalMediaStream, DOMMediaStream)
+NS_IMPL_ADDREF_INHERITED(DOMLocalMediaStream, DOMMediaStream)
+NS_IMPL_RELEASE_INHERITED(DOMLocalMediaStream, DOMMediaStream)
+
+NS_INTERFACE_MAP_BEGIN(DOMLocalMediaStream)
+  NS_INTERFACE_MAP_ENTRY(DOMLocalMediaStream)
+NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream,
                                    mStreamNode)
 
 NS_IMPL_ADDREF_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
 NS_IMPL_RELEASE_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream)
--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -15,25 +15,20 @@
 
 namespace mozilla {
 
 // Un-comment to enable logging of seek bisections.
 //#define SEEK_LOGGING
 
 #ifdef PR_LOGGING
 extern PRLogModuleInfo* gMediaDecoderLog;
-#define DECODER_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
-#ifdef SEEK_LOGGING
-#define SEEK_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
+#define DECODER_LOG(x, ...) \
+  PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, ("Decoder=%p " x, mDecoder, ##__VA_ARGS__))
 #else
-#define SEEK_LOG(type, msg)
-#endif
-#else
-#define DECODER_LOG(type, msg)
-#define SEEK_LOG(type, msg)
+#define DECODER_LOG(x, ...)
 #endif
 
 class VideoQueueMemoryFunctor : public nsDequeFunctor {
 public:
   VideoQueueMemoryFunctor() : mSize(0) {}
 
   MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf);
 
@@ -134,16 +129,30 @@ MediaDecoderReader::GetBuffered(mozilla:
   {
     ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
     durationUs = mDecoder->GetMediaDuration();
   }
   GetEstimatedBufferedTimeRanges(stream, durationUs, aBuffered);
   return NS_OK;
 }
 
+int64_t
+MediaDecoderReader::ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio)
+{
+  int64_t startTime = std::min<int64_t>(aAudio ? aAudio->mTime : INT64_MAX,
+                                        aVideo ? aVideo->mTime : INT64_MAX);
+  if (startTime == INT64_MAX) {
+    startTime = 0;
+  }
+  DECODER_LOG("ComputeStartTime first video frame start %lld", aVideo ? aVideo->mTime : -1);
+  DECODER_LOG("ComputeStartTime first audio frame start %lld", aAudio ? aAudio->mTime : -1);
+  MOZ_ASSERT(startTime >= 0);
+  return startTime;
+}
+
 class RequestVideoWithSkipTask : public nsRunnable {
 public:
   RequestVideoWithSkipTask(MediaDecoderReader* aReader,
                            int64_t aTimeThreshold)
     : mReader(aReader)
     , mTimeThreshold(aTimeThreshold)
   {
   }
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -143,16 +143,18 @@ public:
   // is that it's a fast approximation, which does not perform any I/O.
   //
   // The OggReader relies on this base implementation not performing I/O,
   // since in FirefoxOS we can't do I/O on the main thread, where this is
   // called.
   virtual nsresult GetBuffered(dom::TimeRanges* aBuffered,
                                int64_t aStartTime);
 
+  virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio);
+
   // Returns the number of bytes of memory allocated by structures/frames in
   // the video queue.
   size_t SizeOfVideoQueueInBytes() const;
 
   // Returns the number of bytes of memory allocated by structures/frames in
   // the audio queue.
   size_t SizeOfAudioQueueInBytes() const;
 
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -2011,28 +2011,19 @@ MediaDecoderStateMachine::FinishDecodeMe
   NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
   DECODER_LOG("FinishDecodeMetadata");
 
   if (mState == DECODER_STATE_SHUTDOWN) {
     return NS_ERROR_FAILURE;
   }
 
   if (!mScheduler->IsRealTime() && !mDecodingFrozenAtStateMetadata) {
-
     const VideoData* v = VideoQueue().PeekFront();
     const AudioData* a = AudioQueue().PeekFront();
-
-    int64_t startTime = std::min<int64_t>(a ? a->mTime : INT64_MAX,
-                                          v ? v->mTime : INT64_MAX);
-    if (startTime == INT64_MAX) {
-      startTime = 0;
-    }
-    DECODER_LOG("DecodeMetadata first video frame start %lld", v ? v->mTime : -1);
-    DECODER_LOG("DecodeMetadata first audio frame start %lld", a ? a->mTime : -1);
-    SetStartTime(startTime);
+    SetStartTime(mReader->ComputeStartTime(v, a));
     if (VideoQueue().GetSize()) {
       ReentrantMonitorAutoExit exitMon(mDecoder->GetReentrantMonitor());
       RenderVideoFrame(VideoQueue().PeekFront(), TimeStamp::Now());
     }
   }
 
   NS_ASSERTION(mStartTime != -1, "Must have start time");
   MOZ_ASSERT((!HasVideo() && !HasAudio()) ||
new file mode 100644
--- /dev/null
+++ b/dom/media/MediaDevices.cpp
@@ -0,0 +1,97 @@
+/* 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 "mozilla/dom/MediaDevices.h"
+#include "mozilla/dom/MediaStreamBinding.h"
+#include "mozilla/dom/MediaDevicesBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/MediaManager.h"
+#include "nsIEventTarget.h"
+#include "nsIScriptGlobalObject.h"
+#include "nsPIDOMWindow.h"
+
+namespace mozilla {
+namespace dom {
+
+class MediaDevices::GumResolver : public nsIDOMGetUserMediaSuccessCallback
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  explicit GumResolver(Promise* aPromise) : mPromise(aPromise) {}
+
+  NS_IMETHOD
+  OnSuccess(nsISupports* aStream) MOZ_OVERRIDE
+  {
+    nsRefPtr<DOMLocalMediaStream> stream = do_QueryObject(aStream);
+    if (!stream) {
+      return NS_ERROR_FAILURE;
+    }
+    mPromise->MaybeResolve(stream);
+    return NS_OK;
+  }
+
+private:
+  virtual ~GumResolver() {}
+  nsRefPtr<Promise> mPromise;
+};
+
+class MediaDevices::GumRejecter : public nsIDOMGetUserMediaErrorCallback
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  explicit GumRejecter(Promise* aPromise) : mPromise(aPromise) {}
+
+  NS_IMETHOD
+  OnError(nsISupports* aError) MOZ_OVERRIDE
+  {
+    nsRefPtr<MediaStreamError> error = do_QueryObject(aError);
+    if (!error) {
+      return NS_ERROR_FAILURE;
+    }
+    mPromise->MaybeReject(error);
+    return NS_OK;
+  }
+
+private:
+  virtual ~GumRejecter() {}
+  nsRefPtr<Promise> mPromise;
+};
+
+NS_IMPL_ISUPPORTS(MediaDevices::GumResolver, nsIDOMGetUserMediaSuccessCallback)
+NS_IMPL_ISUPPORTS(MediaDevices::GumRejecter, nsIDOMGetUserMediaErrorCallback)
+
+already_AddRefed<Promise>
+MediaDevices::GetUserMedia(const MediaStreamConstraints& aConstraints,
+                           ErrorResult &aRv)
+{
+  ErrorResult rv;
+  nsPIDOMWindow* window = GetOwner();
+  nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(window);
+  nsRefPtr<Promise> p = Promise::Create(go, aRv);
+  NS_ENSURE_TRUE(!rv.Failed(), nullptr);
+
+  nsRefPtr<GumResolver> resolver = new GumResolver(p);
+  nsRefPtr<GumRejecter> rejecter = new GumRejecter(p);
+
+  aRv = MediaManager::Get()->GetUserMedia(window, aConstraints,
+                                          resolver, rejecter);
+  return p.forget();
+}
+
+NS_IMPL_ADDREF_INHERITED(MediaDevices, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(MediaDevices, DOMEventTargetHelper)
+NS_INTERFACE_MAP_BEGIN(MediaDevices)
+  NS_INTERFACE_MAP_ENTRY(MediaDevices)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+JSObject*
+MediaDevices::WrapObject(JSContext* aCx)
+{
+  return MediaDevicesBinding::Wrap(aCx, this);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/MediaDevices.h
@@ -0,0 +1,50 @@
+/* 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 MediaDevices_h__
+#define MediaDevices_h__
+
+#include "mozilla/ErrorResult.h"
+#include "nsISupportsImpl.h"
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/BindingUtils.h"
+#include "nsPIDOMWindow.h"
+
+namespace mozilla {
+namespace dom {
+
+class Promise;
+struct MediaStreamConstraints;
+
+#define MOZILLA_DOM_MEDIADEVICES_IMPLEMENTATION_IID \
+{ 0x2f784d8a, 0x7485, 0x4280, \
+ { 0x9a, 0x36, 0x74, 0xa4, 0xd6, 0x71, 0xa6, 0xc8 } }
+
+class MediaDevices MOZ_FINAL : public DOMEventTargetHelper
+{
+public:
+  MediaDevices(nsPIDOMWindow* aWindow) : DOMEventTargetHelper(aWindow) {}
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_MEDIADEVICES_IMPLEMENTATION_IID)
+
+  JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
+
+  already_AddRefed<Promise>
+  GetUserMedia(const MediaStreamConstraints& aConstraints, ErrorResult &aRv);
+
+private:
+  class GumResolver;
+  class GumRejecter;
+
+  virtual ~MediaDevices() {}
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(MediaDevices,
+                              MOZILLA_DOM_MEDIADEVICES_IMPLEMENTATION_IID)
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // MediaDevices_h__
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -97,16 +97,17 @@ GetMediaManagerLog()
 #define LOG(msg) PR_LOG(GetMediaManagerLog(), PR_LOG_DEBUG, msg)
 #else
 #define LOG(msg)
 #endif
 
 using dom::MediaStreamConstraints;         // Outside API (contains JSObject)
 using dom::MediaTrackConstraintSet;        // Mandatory or optional constraints
 using dom::MediaTrackConstraints;          // Raw mMandatory (as JSObject)
+using dom::MediaStreamError;
 using dom::GetUserMediaRequest;
 using dom::Sequence;
 using dom::OwningBooleanOrMediaTrackConstraints;
 using dom::SupportedAudioConstraints;
 using dom::SupportedVideoConstraints;
 
 static bool
 HostInDomain(const nsCString &aHost, const nsCString &aPattern)
@@ -189,116 +190,121 @@ HostHasPermission(nsIURI &docURI)
 
     begin = end + 1;
   } while (end < domainWhiteList.Length());
 
   return false;
 }
 
 ErrorCallbackRunnable::ErrorCallbackRunnable(
-  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
-  const nsAString& aErrorMsg, uint64_t aWindowID)
-  : mErrorMsg(aErrorMsg)
+  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess,
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
+  MediaMgrError& aError,
+  uint64_t aWindowID)
+  : mError(&aError)
   , mWindowID(aWindowID)
   , mManager(MediaManager::GetInstance())
 {
-  mSuccess.swap(aSuccess);
-  mError.swap(aError);
+  mOnSuccess.swap(aOnSuccess);
+  mOnFailure.swap(aOnFailure);
 }
 
 ErrorCallbackRunnable::~ErrorCallbackRunnable()
 {
-  MOZ_ASSERT(!mSuccess && !mError);
+  MOZ_ASSERT(!mOnSuccess && !mOnFailure);
 }
 
 NS_IMETHODIMP
 ErrorCallbackRunnable::Run()
 {
   // Only run if the window is still active.
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
-  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success = mSuccess.forget();
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget();
+  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess = mOnSuccess.forget();
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
 
   if (!(mManager->IsWindowStillActive(mWindowID))) {
     return NS_OK;
   }
   // This is safe since we're on main-thread, and the windowlist can only
   // be invalidated from the main-thread (see OnNavigation)
-  error->OnError(mErrorMsg);
+  nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+  if (window) {
+    nsRefPtr<MediaStreamError> error = new MediaStreamError(window, *mError);
+    onFailure->OnError(error);
+  }
   return NS_OK;
 }
 
 /**
  * Invoke the "onSuccess" callback in content. The callback will take a
  * DOMBlob in the case of {picture:true}, and a MediaStream in the case of
  * {audio:true} or {video:true}. There is a constructor available for each
  * form. Do this only on the main thread.
  */
 class SuccessCallbackRunnable : public nsRunnable
 {
 public:
   SuccessCallbackRunnable(
-    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
-    nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
+    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess,
+    nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
     nsIDOMFile* aFile, uint64_t aWindowID)
     : mFile(aFile)
     , mWindowID(aWindowID)
     , mManager(MediaManager::GetInstance())
   {
-    mSuccess.swap(aSuccess);
-    mError.swap(aError);
+    mOnSuccess.swap(aOnSuccess);
+    mOnFailure.swap(aOnFailure);
   }
 
   NS_IMETHOD
   Run()
   {
     // Only run if the window is still active.
     NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
-    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success = mSuccess.forget();
-    nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget();
+    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess = mOnSuccess.forget();
+    nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
 
     if (!(mManager->IsWindowStillActive(mWindowID))) {
       return NS_OK;
     }
     // This is safe since we're on main-thread, and the windowlist can only
     // be invalidated from the main-thread (see OnNavigation)
-    success->OnSuccess(mFile);
+    onSuccess->OnSuccess(mFile);
     return NS_OK;
   }
 
 private:
-  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess;
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
   nsCOMPtr<nsIDOMFile> mFile;
   uint64_t mWindowID;
   nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
 };
 
 /**
  * Invoke the GetUserMediaDevices success callback. Wrapped in a runnable
  * so that it may be called on the main thread. The error callback is also
  * passed so it can be released correctly.
  */
 class DeviceSuccessCallbackRunnable: public nsRunnable
 {
 public:
   DeviceSuccessCallbackRunnable(
     uint64_t aWindowID,
-    nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback>& aSuccess,
-    nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
+    nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback>& aOnSuccess,
+    nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
     nsTArray<nsRefPtr<MediaDevice>>* aDevices)
     : mDevices(aDevices)
     , mWindowID(aWindowID)
     , mManager(MediaManager::GetInstance())
   {
-    mSuccess.swap(aSuccess);
-    mError.swap(aError);
+    mOnSuccess.swap(aOnSuccess);
+    mOnFailure.swap(aOnFailure);
   }
 
   NS_IMETHOD
   Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
     // Only run if window is still on our active list.
@@ -310,39 +316,44 @@ public:
       do_CreateInstance("@mozilla.org/variant;1");
 
     int32_t len = mDevices->Length();
     if (len == 0) {
       // XXX
       // We should in the future return an empty array, and dynamically add
       // devices to the dropdowns if things are hotplugged while the
       // requester is up.
-      mError->OnError(NS_LITERAL_STRING("NO_DEVICES_FOUND"));
+      nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+      if (window) {
+        nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
+            NS_LITERAL_STRING("NotFoundError"));
+        mOnFailure->OnError(error);
+      }
       return NS_OK;
     }
 
     nsTArray<nsIMediaDevice*> tmp(len);
     for (int32_t i = 0; i < len; i++) {
       tmp.AppendElement(mDevices->ElementAt(i));
     }
 
     devices->SetAsArray(nsIDataType::VTYPE_INTERFACE,
                         &NS_GET_IID(nsIMediaDevice),
                         mDevices->Length(),
                         const_cast<void*>(
                           static_cast<const void*>(tmp.Elements())
                         ));
 
-    mSuccess->OnSuccess(devices);
+    mOnSuccess->OnSuccess(devices);
     return NS_OK;
   }
 
 private:
-  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
   nsAutoPtr<nsTArray<nsRefPtr<MediaDevice>>> mDevices;
   uint64_t mWindowID;
   nsRefPtr<MediaManager> mManager;
 };
 
 // Handle removing GetUserMediaCallbackMediaStreamListener from main thread
 class GetUserMediaListenerRemove: public nsRunnable
 {
@@ -718,63 +729,63 @@ public:
  * though that would complicate the constructors some.  Currently the
  * GetUserMedia spec does not allow for more than 2 streams to be obtained in
  * one call, to simplify handling of constraints.
  */
 class GetUserMediaStreamRunnable : public nsRunnable
 {
 public:
   GetUserMediaStreamRunnable(
-    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
-    nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
+    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess,
+    nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
     uint64_t aWindowID,
     GetUserMediaCallbackMediaStreamListener* aListener,
     MediaEngineSource* aAudioSource,
     MediaEngineSource* aVideoSource,
     PeerIdentity* aPeerIdentity)
     : mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
     , mWindowID(aWindowID)
     , mListener(aListener)
     , mPeerIdentity(aPeerIdentity)
     , mManager(MediaManager::GetInstance())
   {
-    mSuccess.swap(aSuccess);
-    mError.swap(aError);
+    mOnSuccess.swap(aOnSuccess);
+    mOnFailure.swap(aOnFailure);
   }
 
   ~GetUserMediaStreamRunnable() {}
 
   class TracksAvailableCallback : public DOMMediaStream::OnTracksAvailableCallback
   {
   public:
     TracksAvailableCallback(MediaManager* aManager,
                             nsIDOMGetUserMediaSuccessCallback* aSuccess,
                             uint64_t aWindowID,
                             DOMMediaStream* aStream)
-      : mWindowID(aWindowID), mSuccess(aSuccess), mManager(aManager),
+      : mWindowID(aWindowID), mOnSuccess(aSuccess), mManager(aManager),
         mStream(aStream) {}
     virtual void NotifyTracksAvailable(DOMMediaStream* aStream) MOZ_OVERRIDE
     {
       // We're in the main thread, so no worries here.
       if (!(mManager->IsWindowStillActive(mWindowID))) {
         return;
       }
 
       // Start currentTime from the point where this stream was successfully
       // returned.
       aStream->SetLogicalStreamStartTime(aStream->GetStream()->GetCurrentTime());
 
       // This is safe since we're on main-thread, and the windowlist can only
       // be invalidated from the main-thread (see OnNavigation)
       LOG(("Returning success for getUserMedia()"));
-      mSuccess->OnSuccess(aStream);
+      mOnSuccess->OnSuccess(aStream);
     }
     uint64_t mWindowID;
-    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
+    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess;
     nsRefPtr<MediaManager> mManager;
     // Keep the DOMMediaStream alive until the NotifyTracksAvailable callback
     // has fired, otherwise we might immediately destroy the DOMMediaStream and
     // shut down the underlying MediaStream prematurely.
     // This creates a cycle which is broken when NotifyTracksAvailable
     // is fired (which will happen unless the browser shuts down,
     // since we only add this callback when we've successfully appended
     // the desired tracks in the MediaStreamGraph) or when
@@ -825,19 +836,26 @@ public:
       }
     }
 #endif
     // Create a media stream.
     nsRefPtr<nsDOMUserMediaStream> trackunion =
       nsDOMUserMediaStream::CreateTrackUnionStream(window, mListener,
                                                    mAudioSource, mVideoSource);
     if (!trackunion) {
-      nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget();
+      nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
       LOG(("Returning error for getUserMedia() - no stream"));
-      error->OnError(NS_LITERAL_STRING("NO_STREAM"));
+
+      nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+      if (window) {
+        nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
+            NS_LITERAL_STRING("InternalError"),
+            NS_LITERAL_STRING("No stream."));
+        onFailure->OnError(error);
+      }
       return NS_OK;
     }
     trackunion->AudioConfig(aec_on, (uint32_t) aec,
                             agc_on, (uint32_t) agc,
                             noise_on, (uint32_t) noise,
                             playout_delay);
 
 
@@ -869,41 +887,41 @@ public:
     // The listener was added at the beginning in an inactive state.
     // Activate our listener. We'll call Start() on the source when get a callback
     // that the MediaStream has started consuming. The listener is freed
     // when the page is invalidated (on navigation or close).
     mListener->Activate(stream.forget(), mAudioSource, mVideoSource);
 
     // Note: includes JS callbacks; must be released on MainThread
     TracksAvailableCallback* tracksAvailableCallback =
-      new TracksAvailableCallback(mManager, mSuccess, mWindowID, trackunion);
+      new TracksAvailableCallback(mManager, mOnSuccess, mWindowID, trackunion);
 
     mListener->AudioConfig(aec_on, (uint32_t) aec,
                            agc_on, (uint32_t) agc,
                            noise_on, (uint32_t) noise,
                            playout_delay);
 
     // Dispatch to the media thread to ask it to start the sources,
     // because that can take a while.
     // Pass ownership of trackunion to the MediaOperationTask
     // to ensure it's kept alive until the MediaOperationTask runs (at least).
     MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
       new MediaOperationTask(MEDIA_START, mListener, trackunion,
                              tracksAvailableCallback,
                              mAudioSource, mVideoSource, false, mWindowID,
-                             mError.forget()));
+                             mOnFailure.forget()));
 
-    // We won't need mError now.
-    mError = nullptr;
+    // We won't need mOnFailure now.
+    mOnFailure = nullptr;
     return NS_OK;
   }
 
 private:
-  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess;
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
   nsRefPtr<MediaEngineSource> mAudioSource;
   nsRefPtr<MediaEngineSource> mVideoSource;
   uint64_t mWindowID;
   nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
   nsAutoPtr<PeerIdentity> mPeerIdentity;
   nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
 };
 
@@ -1051,73 +1069,75 @@ static void
  * Do not run this on the main thread. The success and error callbacks *MUST*
  * be dispatched on the main thread!
  */
 class GetUserMediaTask : public Task
 {
 public:
   GetUserMediaTask(
     const MediaStreamConstraints& aConstraints,
-    already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
-    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
+    already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aOnSuccess,
+    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aOnFailure,
     uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
     MediaEnginePrefs &aPrefs)
     : mConstraints(aConstraints)
-    , mSuccess(aSuccess)
-    , mError(aError)
+    , mOnSuccess(aOnSuccess)
+    , mOnFailure(aOnFailure)
     , mWindowID(aWindowID)
     , mListener(aListener)
     , mPrefs(aPrefs)
     , mDeviceChosen(false)
     , mBackend(nullptr)
     , mManager(MediaManager::GetInstance())
   {}
 
   /**
    * The caller can also choose to provide their own backend instead of
    * using the one provided by MediaManager::GetBackend.
    */
   GetUserMediaTask(
     const MediaStreamConstraints& aConstraints,
-    already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aSuccess,
-    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
+    already_AddRefed<nsIDOMGetUserMediaSuccessCallback> aOnSuccess,
+    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aOnFailure,
     uint64_t aWindowID, GetUserMediaCallbackMediaStreamListener *aListener,
     MediaEnginePrefs &aPrefs,
     MediaEngine* aBackend)
     : mConstraints(aConstraints)
-    , mSuccess(aSuccess)
-    , mError(aError)
+    , mOnSuccess(aOnSuccess)
+    , mOnFailure(aOnFailure)
     , mWindowID(aWindowID)
     , mListener(aListener)
     , mPrefs(aPrefs)
     , mDeviceChosen(false)
     , mBackend(aBackend)
     , mManager(MediaManager::GetInstance())
   {}
 
   ~GetUserMediaTask() {
   }
 
   void
-  Fail(const nsAString& aMessage) {
+  Fail(const nsAString& aName,
+       const nsAString& aMessage = EmptyString()) {
+    nsRefPtr<MediaMgrError> error = new MediaMgrError(aName, aMessage);
     nsRefPtr<ErrorCallbackRunnable> runnable =
-      new ErrorCallbackRunnable(mSuccess, mError, aMessage, mWindowID);
+      new ErrorCallbackRunnable(mOnSuccess, mOnFailure, *error, mWindowID);
     // These should be empty now
-    MOZ_ASSERT(!mSuccess);
-    MOZ_ASSERT(!mError);
+    MOZ_ASSERT(!mOnSuccess);
+    MOZ_ASSERT(!mOnFailure);
 
     NS_DispatchToMainThread(runnable);
   }
 
   void
   Run()
   {
     NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
-    MOZ_ASSERT(mSuccess);
-    MOZ_ASSERT(mError);
+    MOZ_ASSERT(mOnSuccess);
+    MOZ_ASSERT(mOnFailure);
 
     MediaEngine* backend = mBackend;
     // Was a backend provided?
     if (!backend) {
       backend = mManager->GetBackend(mWindowID);
     }
 
     // Was a device provided?
@@ -1131,44 +1151,50 @@ public:
     // There's a bug in the permission code that can leave us with mAudio but no audio device
     ProcessGetUserMedia(((IsOn(mConstraints.mAudio) && mAudioDevice) ?
                          mAudioDevice->GetSource() : nullptr),
                         ((IsOn(mConstraints.mVideo) && mVideoDevice) ?
                          mVideoDevice->GetSource() : nullptr));
   }
 
   nsresult
-  Denied(const nsAString& aErrorMsg)
+  Denied(const nsAString& aName,
+         const nsAString& aMessage = EmptyString())
   {
-    MOZ_ASSERT(mSuccess);
-    MOZ_ASSERT(mError);
+    MOZ_ASSERT(mOnSuccess);
+    MOZ_ASSERT(mOnFailure);
 
     // We add a disabled listener to the StreamListeners array until accepted
     // If this was the only active MediaStream, remove the window from the list.
     if (NS_IsMainThread()) {
       // This is safe since we're on main-thread, and the window can only
       // be invalidated from the main-thread (see OnNavigation)
-      nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success = mSuccess.forget();
-      nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error = mError.forget();
-      error->OnError(aErrorMsg);
+      nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess = mOnSuccess.forget();
+      nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure = mOnFailure.forget();
 
+      nsGlobalWindow* window = nsGlobalWindow::GetInnerWindowWithId(mWindowID);
+      if (window) {
+        nsRefPtr<MediaStreamError> error = new MediaStreamError(window,
+                                                                aName, aMessage);
+        onFailure->OnError(error);
+      }
       // Should happen *after* error runs for consistency, but may not matter
       nsRefPtr<MediaManager> manager(MediaManager::GetInstance());
       manager->RemoveFromWindowList(mWindowID, mListener);
     } else {
       // This will re-check the window being alive on main-thread
       // Note: we must remove the listener on MainThread as well
-      Fail(aErrorMsg);
+      Fail(aName, aMessage);
 
       // MUST happen after ErrorCallbackRunnable Run()s, as it checks the active window list
       NS_DispatchToMainThread(new GetUserMediaListenerRemove(mWindowID, mListener));
     }
 
-    MOZ_ASSERT(!mSuccess);
-    MOZ_ASSERT(!mError);
+    MOZ_ASSERT(!mOnSuccess);
+    MOZ_ASSERT(!mOnFailure);
 
     return NS_OK;
   }
 
   nsresult
   SetContraints(const MediaStreamConstraints& aConstraints)
   {
     mConstraints = aConstraints;
@@ -1189,38 +1215,38 @@ public:
     mVideoDevice = aVideoDevice;
     mDeviceChosen = true;
     return NS_OK;
   }
 
   nsresult
   SelectDevice(MediaEngine* backend)
   {
-    MOZ_ASSERT(mSuccess);
-    MOZ_ASSERT(mError);
+    MOZ_ASSERT(mOnSuccess);
+    MOZ_ASSERT(mOnFailure);
     if (IsOn(mConstraints.mVideo)) {
       VideoTrackConstraintsN constraints(GetInvariant(mConstraints.mVideo));
       nsTArray<nsRefPtr<VideoDevice>> sources;
       GetSources(backend, constraints, &MediaEngine::EnumerateVideoDevices, sources);
 
       if (!sources.Length()) {
-        Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND"));
+        Fail(NS_LITERAL_STRING("NotFoundError"));
         return NS_ERROR_FAILURE;
       }
       // Pick the first available device.
       mVideoDevice = sources[0];
       LOG(("Selected video device"));
     }
     if (IsOn(mConstraints.mAudio)) {
       AudioTrackConstraintsN constraints(GetInvariant(mConstraints.mAudio));
       nsTArray<nsRefPtr<AudioDevice>> sources;
       GetSources(backend, constraints, &MediaEngine::EnumerateAudioDevices, sources);
 
       if (!sources.Length()) {
-        Fail(NS_LITERAL_STRING("NO_DEVICES_FOUND"));
+        Fail(NS_LITERAL_STRING("NotFoundError"));
         return NS_ERROR_FAILURE;
       }
       // Pick the first available device.
       mAudioDevice = sources[0];
       LOG(("Selected audio device"));
     }
 
     return NS_OK;
@@ -1229,59 +1255,61 @@ public:
   /**
    * Allocates a video or audio device and returns a MediaStream via
    * a GetUserMediaStreamRunnable. Runs off the main thread.
    */
   void
   ProcessGetUserMedia(MediaEngineAudioSource* aAudioSource,
                       MediaEngineVideoSource* aVideoSource)
   {
-    MOZ_ASSERT(mSuccess);
-    MOZ_ASSERT(mError);
+    MOZ_ASSERT(mOnSuccess);
+    MOZ_ASSERT(mOnFailure);
     nsresult rv;
     if (aAudioSource) {
       rv = aAudioSource->Allocate(GetInvariant(mConstraints.mAudio), mPrefs);
       if (NS_FAILED(rv)) {
         LOG(("Failed to allocate audiosource %d",rv));
-        Fail(NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"));
+        Fail(NS_LITERAL_STRING("SourceUnavailableError"),
+             NS_LITERAL_STRING("Failed to allocate audiosource"));
         return;
       }
     }
     if (aVideoSource) {
       rv = aVideoSource->Allocate(GetInvariant(mConstraints.mVideo), mPrefs);
       if (NS_FAILED(rv)) {
         LOG(("Failed to allocate videosource %d\n",rv));
         if (aAudioSource) {
           aAudioSource->Deallocate();
         }
-        Fail(NS_LITERAL_STRING("HARDWARE_UNAVAILABLE"));
+        Fail(NS_LITERAL_STRING("SourceUnavailableError"),
+             NS_LITERAL_STRING("Failed to allocate videosource"));
         return;
       }
     }
     PeerIdentity* peerIdentity = nullptr;
     if (!mConstraints.mPeerIdentity.IsEmpty()) {
       peerIdentity = new PeerIdentity(mConstraints.mPeerIdentity);
     }
 
     NS_DispatchToMainThread(new GetUserMediaStreamRunnable(
-      mSuccess, mError, mWindowID, mListener, aAudioSource, aVideoSource,
+      mOnSuccess, mOnFailure, mWindowID, mListener, aAudioSource, aVideoSource,
       peerIdentity
     ));
 
-    MOZ_ASSERT(!mSuccess);
-    MOZ_ASSERT(!mError);
+    MOZ_ASSERT(!mOnSuccess);
+    MOZ_ASSERT(!mOnFailure);
 
     return;
   }
 
 private:
   MediaStreamConstraints mConstraints;
 
-  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess;
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
   uint64_t mWindowID;
   nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener;
   nsRefPtr<AudioDevice> mAudioDevice;
   nsRefPtr<VideoDevice> mVideoDevice;
   MediaEnginePrefs mPrefs;
 
   bool mDeviceChosen;
 
@@ -1317,23 +1345,23 @@ private:
  * wraps them up in nsIMediaDevice objects and returns it to the success
  * callback.
  */
 class GetUserMediaDevicesTask : public Task
 {
 public:
   GetUserMediaDevicesTask(
     const MediaStreamConstraints& aConstraints,
-    already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aSuccess,
-    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError,
+    already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> aOnSuccess,
+    already_AddRefed<nsIDOMGetUserMediaErrorCallback> aOnFailure,
     uint64_t aWindowId, nsACString& aAudioLoopbackDev,
     nsACString& aVideoLoopbackDev)
     : mConstraints(aConstraints)
-    , mSuccess(aSuccess)
-    , mError(aError)
+    , mOnSuccess(aOnSuccess)
+    , mOnFailure(aOnFailure)
     , mManager(MediaManager::GetInstance())
     , mWindowId(aWindowId)
     , mLoopbackAudioDevice(aAudioLoopbackDev)
     , mLoopbackVideoDevice(aVideoLoopbackDev) {}
 
   void // NS_IMETHOD
   Run()
   {
@@ -1363,26 +1391,26 @@ public:
       GetSources(backend, constraints, &MediaEngine::EnumerateAudioDevices, s,
                  mLoopbackAudioDevice.get());
       for (uint32_t i = 0; i < s.Length(); i++) {
         final->AppendElement(s[i]);
       }
     }
 
     NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mWindowId,
-                                                              mSuccess, mError,
+                                                              mOnSuccess, mOnFailure,
                                                               final.forget()));
     // DeviceSuccessCallbackRunnable should have taken these.
-    MOZ_ASSERT(!mSuccess && !mError);
+    MOZ_ASSERT(!mOnSuccess && !mOnFailure);
   }
 
 private:
   MediaStreamConstraints mConstraints;
-  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mOnSuccess;
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
   nsRefPtr<MediaManager> mManager;
   uint64_t mWindowId;
   const nsString mCallId;
   // Audio & Video loopback devices to be used based on
   // the preference settings. This is currently used for
   // automated media tests only.
   nsCString mLoopbackAudioDevice;
   nsCString mLoopbackVideoDevice;
@@ -1539,28 +1567,28 @@ MediaManager::NotifyRecordingStatusChang
  * The entry point for this file. A call from Navigator::mozGetUserMedia
  * will end up here. MediaManager is a singleton that is responsible
  * for handling all incoming getUserMedia calls from every window.
  */
 nsresult
 MediaManager::GetUserMedia(
   nsPIDOMWindow* aWindow, const MediaStreamConstraints& aConstraints,
   nsIDOMGetUserMediaSuccessCallback* aOnSuccess,
-  nsIDOMGetUserMediaErrorCallback* aOnError)
+  nsIDOMGetUserMediaErrorCallback* aOnFailure)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
   NS_ENSURE_TRUE(aWindow, NS_ERROR_NULL_POINTER);
-  NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aOnFailure, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
 
   bool privileged = nsContentUtils::IsChromeDoc(aWindow->GetExtantDoc());
 
   nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess(aOnSuccess);
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError);
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
 
   MediaStreamConstraints c(aConstraints); // copy
 
   static bool created = false;
   if (!created) {
     // Force MediaManager to startup before we try to access it from other threads
     // Hack: should init singleton earlier unless it's expensive (mem or CPU)
     (void) MediaManager::Get();
@@ -1635,35 +1663,35 @@ MediaManager::GetUserMedia(
     }
   }
 
   // Pass callbacks and MediaStreamListener along to GetUserMediaTask.
   nsAutoPtr<GetUserMediaTask> task;
   if (c.mFake) {
     // Fake stream from default backend.
     task = new GetUserMediaTask(c, onSuccess.forget(),
-      onError.forget(), windowID, listener, mPrefs, new MediaEngineDefault());
+      onFailure.forget(), windowID, listener, mPrefs, new MediaEngineDefault());
   } else {
     // Stream from default device from WebRTC backend.
     task = new GetUserMediaTask(c, onSuccess.forget(),
-      onError.forget(), windowID, listener, mPrefs);
+      onFailure.forget(), windowID, listener, mPrefs);
   }
 
   nsIURI* docURI = aWindow->GetDocumentURI();
 
   if (c.mVideo.IsMediaTrackConstraints()) {
     auto& tc = c.mVideo.GetAsMediaTrackConstraints();
     // deny screensharing request if support is disabled
     if (tc.mMediaSource != dom::MediaSourceEnum::Camera) {
       if (tc.mMediaSource == dom::MediaSourceEnum::Browser) {
         if (!Preferences::GetBool("media.getusermedia.browser.enabled", false)) {
-          return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
+          return task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
         }
       } else if (!Preferences::GetBool("media.getusermedia.screensharing.enabled", false)) {
-        return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
+        return task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
       }
       /* Deny screensharing if the requesting document is not from a host
        on the whitelist. */
       // Block screen/window sharing on Mac OSX 10.6 and WinXP until proved that they work
       if (
 #if defined(XP_MACOSX) || defined(XP_WIN)
           (
             !Preferences::GetBool("media.getusermedia.screensharing.allow_on_old_platforms", false) &&
@@ -1671,17 +1699,17 @@ MediaManager::GetUserMedia(
             !nsCocoaFeatures::OnLionOrLater()
 #endif
 #if defined (XP_WIN)
             !IsVistaOrLater()
 #endif
            ) ||
 #endif
           (!privileged && !HostHasPermission(*docURI))) {
-        return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
+        return task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
       }
     }
   }
 
 #ifdef MOZ_B2G_CAMERA
   if (mCameraManager == nullptr) {
     mCameraManager = nsDOMCameraManager::CreateInstance(aWindow);
   }
@@ -1725,17 +1753,17 @@ MediaManager::GetUserMedia(
     if (IsOn(c.mVideo)) {
       rv = permManager->TestExactPermissionFromPrincipal(
         aWindow->GetExtantDoc()->NodePrincipal(), "camera", &videoPerm);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     if ((!IsOn(c.mAudio) || audioPerm == nsIPermissionManager::DENY_ACTION) &&
         (!IsOn(c.mVideo) || videoPerm == nsIPermissionManager::DENY_ACTION)) {
-      return task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
+      return task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
     }
 
     // Ask for user permission, and dispatch task (or not) when a response
     // is received via an observer notification. Each call is paired with its
     // task by a GUID.
     nsCOMPtr<nsIUUIDGenerator> uuidgen =
       do_GetService("@mozilla.org/uuid-generator;1", &rv);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1773,36 +1801,36 @@ MediaManager::GetUserMedia(
 
   return NS_OK;
 }
 
 nsresult
 MediaManager::GetUserMediaDevices(nsPIDOMWindow* aWindow,
   const MediaStreamConstraints& aConstraints,
   nsIGetUserMediaDevicesSuccessCallback* aOnSuccess,
-  nsIDOMGetUserMediaErrorCallback* aOnError,
+  nsIDOMGetUserMediaErrorCallback* aOnFailure,
   uint64_t aInnerWindowID)
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
-  NS_ENSURE_TRUE(aOnError, NS_ERROR_NULL_POINTER);
+  NS_ENSURE_TRUE(aOnFailure, NS_ERROR_NULL_POINTER);
   NS_ENSURE_TRUE(aOnSuccess, NS_ERROR_NULL_POINTER);
 
   nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess(aOnSuccess);
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError(aOnError);
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onFailure(aOnFailure);
 
   // Check if the preference for using loopback devices is enabled.
   nsAdoptingCString loopbackAudioDevice =
     Preferences::GetCString("media.audio_loopback_dev");
   nsAdoptingCString loopbackVideoDevice =
     Preferences::GetCString("media.video_loopback_dev");
 
   MediaManager::GetMessageLoop()->PostTask(FROM_HERE,
     new GetUserMediaDevicesTask(
-      aConstraints, onSuccess.forget(), onError.forget(),
+      aConstraints, onSuccess.forget(), onFailure.forget(),
       (aInnerWindowID ? aInnerWindowID : aWindow->WindowID()),
       loopbackAudioDevice, loopbackVideoDevice));
 
   return NS_OK;
 }
 
 MediaEngine*
 MediaManager::GetBackend(uint64_t aWindowId)
@@ -2015,17 +2043,17 @@ MediaManager::Observe(nsISupports* aSubj
       // NOTE: does not allow setting a device to null; assumes nullptr
       nsCOMPtr<nsISupportsArray> array(do_QueryInterface(aSubject));
       MOZ_ASSERT(array);
       uint32_t len = 0;
       array->Count(&len);
       MOZ_ASSERT(len);
       if (!len) {
         // neither audio nor video were selected
-        task->Denied(NS_LITERAL_STRING("PERMISSION_DENIED"));
+        task->Denied(NS_LITERAL_STRING("PermissionDeniedError"));
         return NS_OK;
       }
       for (uint32_t i = 0; i < len; i++) {
         nsCOMPtr<nsISupports> supports;
         array->GetElementAt(i,getter_AddRefs(supports));
         nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supports));
         MOZ_ASSERT(device); // shouldn't be returning anything else...
         if (device) {
@@ -2042,24 +2070,24 @@ MediaManager::Observe(nsISupports* aSubj
       }
     }
 
     // Reuse the same thread to save memory.
     MediaManager::GetMessageLoop()->PostTask(FROM_HERE, task.forget());
     return NS_OK;
 
   } else if (!strcmp(aTopic, "getUserMedia:response:deny")) {
-    nsString errorMessage(NS_LITERAL_STRING("PERMISSION_DENIED"));
+    nsString errorMessage(NS_LITERAL_STRING("PermissionDeniedError"));
 
     if (aSubject) {
       nsCOMPtr<nsISupportsString> msg(do_QueryInterface(aSubject));
       MOZ_ASSERT(msg);
       msg->GetData(errorMessage);
       if (errorMessage.IsEmpty())
-        errorMessage.AssignLiteral(MOZ_UTF16("UNKNOWN_ERROR"));
+        errorMessage.AssignLiteral(MOZ_UTF16("InternalError"));
     }
 
     nsString key(aData);
     nsAutoPtr<GetUserMediaTask> task;
     mActiveCallbacks.RemoveAndForget(key, task);
     if (task) {
       task->Denied(errorMessage);
     }
--- a/dom/media/MediaManager.h
+++ b/dom/media/MediaManager.h
@@ -21,16 +21,17 @@
 #include "nsPIDOMWindow.h"
 #include "nsIDOMNavigatorUserMedia.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/dom/MediaStreamBinding.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
+#include "mozilla/dom/MediaStreamError.h"
 #include "prlog.h"
 #include "DOMMediaStream.h"
 
 #ifdef MOZ_WEBRTC
 #include "mtransport/runnable_utils.h"
 #endif
 
 // Note, these suck in Windows headers, unfortunately.
@@ -263,64 +264,64 @@ class GetUserMediaNotificationEvent: pub
 
     GetUserMediaNotificationEvent(GetUserMediaStatus aStatus,
                                   already_AddRefed<DOMMediaStream> aStream,
                                   DOMMediaStream::OnTracksAvailableCallback* aOnTracksAvailableCallback,
                                   bool aIsAudio, bool aIsVideo, uint64_t aWindowID,
                                   already_AddRefed<nsIDOMGetUserMediaErrorCallback> aError)
     : mStream(aStream), mOnTracksAvailableCallback(aOnTracksAvailableCallback),
       mStatus(aStatus), mIsAudio(aIsAudio), mIsVideo(aIsVideo), mWindowID(aWindowID),
-      mError(aError) {}
+      mOnFailure(aError) {}
     virtual ~GetUserMediaNotificationEvent()
     {
 
     }
 
     NS_IMETHOD Run() MOZ_OVERRIDE;
 
   protected:
     nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
     nsRefPtr<DOMMediaStream> mStream;
     nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
     GetUserMediaStatus mStatus;
     bool mIsAudio;
     bool mIsVideo;
     uint64_t mWindowID;
-    nsRefPtr<nsIDOMGetUserMediaErrorCallback> mError;
+    nsRefPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
 };
 
 typedef enum {
   MEDIA_START,
   MEDIA_STOP,
   MEDIA_STOP_TRACK,
   MEDIA_DIRECT_LISTENERS
 } MediaOperation;
 
 class MediaManager;
 class GetUserMediaTask;
 
 /**
- * Send an error back to content. The error is the form a string.
- * Do this only on the main thread. The success callback is also passed here
+ * Send an error back to content.
+ * Do this only on the main thread. The onSuccess callback is also passed here
  * so it can be released correctly.
  */
 class ErrorCallbackRunnable : public nsRunnable
 {
 public:
   ErrorCallbackRunnable(
-    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aSuccess,
-    nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aError,
-    const nsAString& aErrorMsg, uint64_t aWindowID);
+    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback>& aOnSuccess,
+    nsCOMPtr<nsIDOMGetUserMediaErrorCallback>& aOnFailure,
+    MediaMgrError& aError, uint64_t aWindowID);
   NS_IMETHOD Run();
 private:
   ~ErrorCallbackRunnable();
 
-  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mSuccess;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
-  const nsString mErrorMsg;
+  nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> mOnSuccess;
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
+  nsRefPtr<MediaMgrError> mError;
   uint64_t mWindowID;
   nsRefPtr<MediaManager> mManager; // get ref to this when creating the runnable
 };
 
 class ReleaseMediaOperationResource : public nsRunnable
 {
 public:
   ReleaseMediaOperationResource(already_AddRefed<DOMMediaStream> aStream,
@@ -352,36 +353,38 @@ public:
     : mType(aType)
     , mStream(aStream)
     , mOnTracksAvailableCallback(aOnTracksAvailableCallback)
     , mAudioSource(aAudioSource)
     , mVideoSource(aVideoSource)
     , mListener(aListener)
     , mBool(aBool)
     , mWindowID(aWindowID)
-    , mError(aError)
+    , mOnFailure(aError)
   {}
 
   ~MediaOperationTask()
   {
     // MediaStreams can be released on any thread.
   }
 
   void
   ReturnCallbackError(nsresult rv, const char* errorLog)
   {
     MM_LOG(("%s , rv=%d", errorLog, rv));
     NS_DispatchToMainThread(new ReleaseMediaOperationResource(mStream.forget(),
           mOnTracksAvailableCallback.forget()));
     nsString log;
 
-    log.AssignASCII(errorLog, strlen(errorLog));
-    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> success;
-    NS_DispatchToMainThread(new ErrorCallbackRunnable(success, mError,
-      log, mWindowID));
+    log.AssignASCII(errorLog);
+    nsCOMPtr<nsIDOMGetUserMediaSuccessCallback> onSuccess;
+    nsRefPtr<MediaMgrError> error = new MediaMgrError(
+        NS_LITERAL_STRING("InternalError"), log);
+    NS_DispatchToMainThread(new ErrorCallbackRunnable(onSuccess, mOnFailure,
+        *error, mWindowID));
   }
 
   void
   Run()
   {
     SourceMediaStream *source = mListener->GetSourceStream();
     // No locking between these is required as all the callbacks for the
     // same MediaStream will occur on the same thread.
@@ -423,17 +426,17 @@ public:
           // because mOnTracksAvailableCallback needs to be added to mStream
           // on the main thread.
           nsIRunnable *event =
             new GetUserMediaNotificationEvent(GetUserMediaNotificationEvent::STARTING,
                                               mStream.forget(),
                                               mOnTracksAvailableCallback.forget(),
                                               mAudioSource != nullptr,
                                               mVideoSource != nullptr,
-                                              mWindowID, mError.forget());
+                                              mWindowID, mOnFailure.forget());
           // event must always be released on mainthread due to the JS callbacks
           // in the TracksAvailableCallback
           NS_DispatchToMainThread(event);
         }
         break;
 
       case MEDIA_STOP:
       case MEDIA_STOP_TRACK:
@@ -485,17 +488,17 @@ private:
   MediaOperation mType;
   nsRefPtr<DOMMediaStream> mStream;
   nsAutoPtr<DOMMediaStream::OnTracksAvailableCallback> mOnTracksAvailableCallback;
   nsRefPtr<MediaEngineSource> mAudioSource; // threadsafe
   nsRefPtr<MediaEngineSource> mVideoSource; // threadsafe
   nsRefPtr<GetUserMediaCallbackMediaStreamListener> mListener; // threadsafe
   bool mBool;
   uint64_t mWindowID;
-  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
+  nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mOnFailure;
 };
 
 typedef nsTArray<nsRefPtr<GetUserMediaCallbackMediaStreamListener> > StreamListeners;
 typedef nsClassHashtable<nsUint64HashKey, StreamListeners> WindowTable;
 
 class MediaDevice : public nsIMediaDevice
 {
 public:
--- a/dom/media/MediaPermissionGonk.cpp
+++ b/dom/media/MediaPermissionGonk.cpp
@@ -12,16 +12,17 @@
 #include "nsIStringEnumerator.h"
 #include "nsISupportsArray.h"
 #include "nsJSUtils.h"
 #include "nsPIDOMWindow.h"
 #include "nsTArray.h"
 #include "GetUserMediaRequest.h"
 #include "mozilla/dom/PBrowserChild.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
+#include "mozilla/dom/MediaStreamError.h"
 #include "nsISupportsPrimitives.h"
 #include "nsServiceManagerUtils.h"
 #include "nsArrayUtils.h"
 #include "nsContentPermissionHelper.h"
 #include "mozilla/dom/PermissionMessageUtils.h"
 
 #define AUDIO_PERMISSION_NAME "audio-capture"
 #define VIDEO_PERMISSION_NAME "video-capture"
@@ -219,17 +220,17 @@ MediaPermissionRequest::GetElement(nsIDO
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaPermissionRequest::Cancel()
 {
   nsString callID;
   mRequest->GetCallID(callID);
-  NotifyPermissionDeny(callID, NS_LITERAL_STRING("Permission Denied"));
+  NotifyPermissionDeny(callID, NS_LITERAL_STRING("PermissionDeniedError"));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 MediaPermissionRequest::Allow(JS::HandleValue aChoices)
 {
   // check if JS object
   if (!aChoices.isObject()) {
@@ -388,19 +389,27 @@ protected:
 private:
   const nsString mCallID;
 };
 
 NS_IMPL_ISUPPORTS(MediaDeviceErrorCallback, nsIDOMGetUserMediaErrorCallback)
 
 // nsIDOMGetUserMediaErrorCallback method
 NS_IMETHODIMP
-MediaDeviceErrorCallback::OnError(const nsAString &aError)
+MediaDeviceErrorCallback::OnError(nsISupports* aError)
 {
-  return NotifyPermissionDeny(mCallID, aError);
+  MediaStreamError *error = nullptr;
+  nsresult rv = CallQueryInterface(aError, &error);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+
+  nsString name;
+  error->GetName(name);
+  return NotifyPermissionDeny(mCallID, name);
 }
 
 } // namespace anonymous
 
 // MediaPermissionManager
 NS_IMPL_ISUPPORTS(MediaPermissionManager, nsIObserver)
 
 MediaPermissionManager*
new file mode 100644
--- /dev/null
+++ b/dom/media/MediaStreamError.cpp
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "MediaStreamError.h"
+#include "mozilla/dom/MediaStreamErrorBinding.h"
+#include "nsContentUtils.h"
+
+namespace mozilla {
+
+BaseMediaMgrError::BaseMediaMgrError(const nsAString& aName,
+                                     const nsAString& aMessage,
+                                     const nsAString& aConstraintName)
+  : mName(aName)
+  , mMessage(aMessage)
+  , mConstraintName(aConstraintName)
+{
+  if (mMessage.IsEmpty()) {
+    if (mName.EqualsLiteral("NotFoundError")) {
+      mMessage.AssignLiteral("The object can not be found here.");
+    } else if (mName.EqualsLiteral("PermissionDeniedError")) {
+      mMessage.AssignLiteral("The user did not grant permission for the operation.");
+    } else if (mName.EqualsLiteral("SourceUnavailableError")) {
+      mMessage.AssignLiteral("The source of the MediaStream could not be "
+          "accessed due to a hardware error (e.g. lock from another process).");
+    } else if (mName.EqualsLiteral("InternalError")) {
+      mMessage.AssignLiteral("Internal error.");
+    }
+  }
+}
+
+
+NS_IMPL_ISUPPORTS0(MediaMgrError)
+
+namespace dom {
+
+MediaStreamError::MediaStreamError(
+    nsPIDOMWindow* aParent,
+    const nsAString& aName,
+    const nsAString& aMessage,
+    const nsAString& aConstraintName)
+  : BaseMediaMgrError(aName, aMessage, aConstraintName)
+  , mParent(aParent) {}
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaStreamError, mParent)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaStreamError)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaStreamError)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaStreamError)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+  NS_INTERFACE_MAP_ENTRY(MediaStreamError)
+NS_INTERFACE_MAP_END
+
+JSObject*
+MediaStreamError::WrapObject(JSContext* aCx)
+{
+  return MediaStreamErrorBinding::Wrap(aCx, this);
+}
+
+void
+MediaStreamError::GetName(nsAString& aName) const
+{
+  aName = mName;
+}
+
+void
+MediaStreamError::GetMessage(nsAString& aMessage) const
+{
+  aMessage = mMessage;
+}
+
+void
+MediaStreamError::GetConstraintName(nsAString& aConstraintName) const
+{
+  aConstraintName = mConstraintName;
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/MediaStreamError.h
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 mozilla_dom_MediaStreamError_h
+#define mozilla_dom_MediaStreamError_h
+
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "nsWrapperCache.h"
+#include "js/TypeDecls.h"
+#include "nsPIDOMWindow.h"
+#include "nsRefPtr.h"
+
+#if defined(XP_WIN) && defined(GetMessage)
+#undef GetMessage
+#endif
+
+namespace mozilla {
+namespace dom {
+
+#define MOZILLA_DOM_MEDIASTREAMERROR_IMPLEMENTATION_IID \
+{ 0x95fa29aa, 0x0cc2, 0x4698, \
+ { 0x9d, 0xa9, 0xf2, 0xeb, 0x03, 0x91, 0x0b, 0xd1 } }
+
+class MediaStreamError;
+}
+
+class BaseMediaMgrError
+{
+  friend class dom::MediaStreamError;
+protected:
+  BaseMediaMgrError(const nsAString& aName,
+                    const nsAString& aMessage,
+                    const nsAString& aConstraintName);
+  const nsString mName;
+  nsString mMessage;
+  const nsString mConstraintName;
+};
+
+class MediaMgrError MOZ_FINAL : public nsISupports,
+                                public BaseMediaMgrError
+{
+public:
+  MediaMgrError(const nsAString& aName,
+                const nsAString& aMessage =  EmptyString(),
+                const nsAString& aConstraintName =  EmptyString())
+  : BaseMediaMgrError(aName, aMessage, aConstraintName) {}
+
+  NS_DECL_THREADSAFE_ISUPPORTS
+
+private:
+  ~MediaMgrError() {}
+};
+
+namespace dom {
+class MediaStreamError MOZ_FINAL : public nsISupports,
+                                   public BaseMediaMgrError,
+                                   public nsWrapperCache
+{
+public:
+  MediaStreamError(nsPIDOMWindow* aParent,
+                   const nsAString& aName,
+                   const nsAString& aMessage = EmptyString(),
+                   const nsAString& aConstraintName =  EmptyString());
+
+  MediaStreamError(nsPIDOMWindow* aParent,
+                   const BaseMediaMgrError& aOther)
+  : BaseMediaMgrError(aOther.mName, aOther.mMessage, aOther.mConstraintName)
+  , mParent(aParent) {}
+
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaStreamError)
+  NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOM_MEDIASTREAMERROR_IMPLEMENTATION_IID)
+
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  nsPIDOMWindow* GetParentObject() const
+  {
+    return mParent;
+  }
+  void GetName(nsAString& aName) const;
+  void GetMessage(nsAString& aMessage) const;
+  void GetConstraintName(nsAString& aConstraintName) const;
+
+private:
+  virtual ~MediaStreamError() {}
+
+  nsRefPtr<nsPIDOMWindow> mParent;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(MediaStreamError,
+                              MOZILLA_DOM_MEDIASTREAMERROR_IMPLEMENTATION_IID)
+} // namespace dom
+} // namespace mozilla
+
+#endif
--- a/dom/media/mediasource/MediaSourceReader.h
+++ b/dom/media/mediasource/MediaSourceReader.h
@@ -65,16 +65,21 @@ public:
     return mInfo.HasVideo();
   }
 
   bool HasAudio() MOZ_OVERRIDE
   {
     return mInfo.HasAudio();
   }
 
+  // We can't compute a proper start time since we won't necessarily
+  // have the first frame of the resource available. This does the same
+  // as chrome/blink and assumes that we always start at t=0.
+  virtual int64_t ComputeStartTime(const VideoData* aVideo, const AudioData* aAudio) MOZ_OVERRIDE { return 0; }
+
   bool IsMediaSeekable() { return true; }
 
   nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) MOZ_OVERRIDE;
   nsresult Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
                 int64_t aCurrentTime) MOZ_OVERRIDE;
 
   already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
 
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -138,16 +138,18 @@ if CONFIG['MOZ_B2G']:
         'MediaPermissionGonk.h',
     ]
 
 EXPORTS.mozilla.dom += [
     'AudioStreamTrack.h',
     'AudioTrack.h',
     'AudioTrackList.h',
     'GetUserMediaRequest.h',
+    'MediaDevices.h',
+    'MediaStreamError.h',
     'MediaStreamTrack.h',
     'TextTrack.h',
     'TextTrackCue.h',
     'TextTrackCueList.h',
     'TextTrackList.h',
     'TextTrackRegion.h',
     'VideoPlaybackQuality.h',
     'VideoStreamTrack.h',
@@ -172,20 +174,22 @@ UNIFIED_SOURCES += [
     'GraphDriver.cpp',
     'Latency.cpp',
     'MediaCache.cpp',
     'MediaData.cpp',
     'MediaDecoder.cpp',
     'MediaDecoderReader.cpp',
     'MediaDecoderStateMachine.cpp',
     'MediaDecoderStateMachineScheduler.cpp',
+    'MediaDevices.cpp',
     'MediaManager.cpp',
     'MediaRecorder.cpp',
     'MediaResource.cpp',
     'MediaShutdownManager.cpp',
+    'MediaStreamError.cpp',
     'MediaStreamGraph.cpp',
     'MediaStreamTrack.cpp',
     'MediaTaskQueue.cpp',
     'MediaTrack.cpp',
     'MediaTrackList.cpp',
     'MP3FrameParser.cpp',
     'RtspMediaResource.cpp',
     'SharedThreadPool.cpp',
--- a/dom/media/nsIDOMNavigatorUserMedia.idl
+++ b/dom/media/nsIDOMNavigatorUserMedia.idl
@@ -29,10 +29,10 @@ interface nsIDOMGetUserMediaSuccessCallb
    * DOMLocalMediaStream if either audio or video are true.
    */
   void onSuccess(in nsISupports value);
 };
 
 [scriptable, function, uuid(2614bbcf-85cc-43e5-8740-964f52bdc7ca)]
 interface nsIDOMGetUserMediaErrorCallback : nsISupports
 {
-  void onError(in DOMString error);
+  void onError(in nsISupports error);
 };
--- a/dom/media/tests/mochitest/constraints.js
+++ b/dom/media/tests/mochitest/constraints.js
@@ -9,29 +9,29 @@
 
   TODO(jib): Merge desktop and mobile version of these tests again.
 */
 var common_tests = [
   // Each test here tests a different constraint or codepath.
   { message: "unknown required constraint on video fails",
     constraints: { video: { somethingUnknown:0, require:["somethingUnknown"] },
                    fake: true },
-    error: "NO_DEVICES_FOUND" },
+    error: "NotFoundError" },
   { message: "unknown required constraint on audio fails",
     constraints: { audio: { somethingUnknown:0, require:["somethingUnknown"] },
                    fake: true },
-    error: "NO_DEVICES_FOUND" },
+    error: "NotFoundError" },
   { message: "video overconstrained by facingMode fails",
     constraints: { video: { facingMode:'left', require:["facingMode"] },
                    fake: true },
-    error: "NO_DEVICES_FOUND" },
+    error: "NotFoundError" },
   { message: "audio overconstrained by facingMode fails",
     constraints: { audio: { facingMode:'left', require:["facingMode"] },
                    fake: true },
-    error: "NO_DEVICES_FOUND" },
+    error: "NotFoundError" },
   { message: "Success-path: optional video facingMode + audio ignoring facingMode",
     constraints: { fake: true,
                    audio: { facingMode:'left',
                             foo:0,
                             advanced: [{ facingMode:'environment' },
                                        { facingMode:'user' },
                                        { bar:0 }] },
                    video: { // TODO: Bug 767924 sequences in unions
@@ -43,34 +43,32 @@ var common_tests = [
                                        { facingMode:'user' },
                                        { bar:0 }] } },
     error: null }
 ];
 
 
 /**
  * Starts the test run by running through each constraint
- * test by verifying that the right callback and error message is fired.
+ * test by verifying that the right resolution and rejection is fired.
  */
 
 function testConstraints(tests) {
-  var i = 0;
-  next();
-
-  function Success() {
-    ok(!tests[i].error, tests[i].message);
-    i++;
-    next();
+  function testgum(p, test) {
+    return p.then(function() {
+      return navigator.mediaDevices.getUserMedia(test.constraints);
+    })
+    .then(function() {
+      is(null, test.error, test.message);
+    }, function(reason) {
+      is(reason.name, test.error, test.message + ": " + reason.message);
+    });
   }
-  function Failure(err) {
-    ok(tests[i].error? (err === tests[i].error) : false,
-       tests[i].message + " (err=" + err + ")");
-    i++;
-    next();
-  }
-  function next() {
-    if (i < tests.length) {
-      navigator.mozGetUserMedia(tests[i].constraints, Success, Failure);
-    } else {
-      SimpleTest.finish();
-    }
-  }
-};
+
+  var p = new Promise(function(resolve) { resolve(); });
+  tests.forEach(function(test) {
+    p = testgum(p, test);
+  });
+  p.catch(function(reason) {
+    ok(false, "Unexpected failure: " + reason.message);
+  })
+  .then(SimpleTest.finish);
+}
--- a/dom/media/tests/mochitest/test_getUserMedia_constraints_mobile.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_constraints_mobile.html
@@ -21,17 +21,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script type="application/javascript">
 /**
   See constraints.js for testConstraints() and common_tests.
   TODO(jib): Merge desktop and mobile version of these tests again (Bug 997365)
 */
 var mobile_tests = [
   { message: "legacy facingMode overconstrains video (mobile)",
     constraints: { video: { mandatory: { facingMode:'left' } }, fake: true },
-    error: "NO_DEVICES_FOUND" },
+    error: "NotFoundError" },
 ];
 
 runTest(function () {
   testConstraints(common_tests.concat(mobile_tests));
 });
 
 
 </script>
--- a/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html
@@ -21,29 +21,30 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script type="application/javascript">
 function theTest() {
   function testPeerIdentityConstraint(withConstraint, done) {
     var config = { audio: true, video: true, fake: true };
     if (withConstraint) {
       config.peerIdentity = 'user@example.com';
     }
     info('getting media with constraints: ' + JSON.stringify(config));
-    navigator.mozGetUserMedia(config, function(stream) {
+    navigator.mediaDevices.getUserMedia(config).then(function(stream) {
       var oneDone = false;
       function checkDone() {
         if (oneDone) {
           done();
         }
         oneDone = true;
       }
       var cancelAudioCheck = audioIsSilence(withConstraint, stream, checkDone);
       var cancelVideoCheck = videoIsBlack(withConstraint, stream, checkDone);
       setTimeout(cancelAudioCheck, 3*60*1000);
       setTimeout(cancelVideoCheck, 3*60*1000);
-    }, function(e) {
+    })
+    .catch(function(e) {
       ok(false, 'gUM error: ' + e);
     });
   };
 
   // without constraint
   testPeerIdentityConstraint(false, function() {
     // with the constraint
     testPeerIdentityConstraint(true, SimpleTest.finish.bind(SimpleTest));
--- a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html
+++ b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html
@@ -32,33 +32,33 @@
     var flowtest = test.chain.remove("PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT");
     test.chain.append(flowtest);
     test.chain.append([["PC_LOCAL_REPLACE_VIDEOTRACK",
       function (test) {
         var stream = test.pcLocal._pc.getLocalStreams()[0];
         var track = stream.getVideoTracks()[0];
         var sender = test.pcLocal._pc.getSenders().find(isSenderOfTrack, track);
         ok(sender, "track has a sender");
-        navigator.mozGetUserMedia({video:true, fake: true}, function(newStream) {
+        navigator.mediaDevices.getUserMedia({video:true, fake: true})
+        .then(function(newStream) {
           var newtrack = newStream.getVideoTracks()[0];
-          sender.replaceTrack(newtrack,
-            function() {
-              ok(true, "replaceTrack success callback is called");
-              is(sender.track, newtrack, "sender.track has been replaced");
-              test.next();
-            },
-            function(err) {
-              ok(false, "replaceTrack failed with error = " + err);
-              test.next();
-            });
-        },
-        function(err) {
-          ok(false, "mozGetUserMedia failed. error = " + err);
-          test.next();
-        });
+          return new Promise(function(resolve, reject) {
+            sender.replaceTrack(newtrack, function() {
+              resolve(newtrack);
+            }, reject);
+          });
+        })
+        .then(function(newtrack) {
+          ok(true, "replaceTrack success callback is called");
+          is(sender.track, newtrack, "sender.track has been replaced");
+        })
+        .catch(function(reason) {
+          ok(false, "unexpected error = " + reason.message);
+        })
+        .then(test.next.bind(test));
       }
     ]]);
     test.chain.append(flowtest);
 
     test.run();
   });
 </script>
 </pre>
--- a/dom/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/dom/media/webspeech/recognition/SpeechRecognition.cpp
@@ -6,28 +6,34 @@
 
 #include "SpeechRecognition.h"
 
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 
 #include "mozilla/dom/SpeechRecognitionBinding.h"
 #include "mozilla/dom/MediaStreamTrackBinding.h"
+#include "mozilla/dom/MediaStreamError.h"
 #include "mozilla/MediaManager.h"
 #include "mozilla/Services.h"
 
 #include "AudioSegment.h"
 #include "endpointer.h"
 
 #include "mozilla/dom/SpeechRecognitionEvent.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 
 #include <algorithm>
 
+// Undo the windows.h damage
+#if defined(XP_WIN) && defined(GetMessage)
+#undef GetMessage
+#endif
+
 namespace mozilla {
 namespace dom {
 
 #define PREFERENCE_DEFAULT_RECOGNITION_SERVICE "media.webspeech.service.default"
 #define DEFAULT_RECOGNITION_SERVICE "google"
 
 #define PREFERENCE_ENDPOINTER_SILENCE_LENGTH "media.webspeech.silence_length"
 #define PREFERENCE_ENDPOINTER_LONG_SILENCE_LENGTH "media.webspeech.long_silence_length"
@@ -940,26 +946,33 @@ SpeechRecognition::GetUserMediaSuccessCa
     mRecognition->StartRecording(localStream);
   }
   return NS_OK;
 }
 
 NS_IMPL_ISUPPORTS(SpeechRecognition::GetUserMediaErrorCallback, nsIDOMGetUserMediaErrorCallback)
 
 NS_IMETHODIMP
-SpeechRecognition::GetUserMediaErrorCallback::OnError(const nsAString& aError)
+SpeechRecognition::GetUserMediaErrorCallback::OnError(nsISupports* aError)
 {
+  nsRefPtr<MediaStreamError> error = do_QueryObject(aError);
+  if (!error) {
+    return NS_OK;
+  }
   SpeechRecognitionErrorCode errorCode;
 
-  if (aError.EqualsLiteral("PERMISSION_DENIED")) {
+  nsString name;
+  error->GetName(name);
+  if (name.EqualsLiteral("PERMISSION_DENIED")) {
     errorCode = SpeechRecognitionErrorCode::Not_allowed;
   } else {
     errorCode = SpeechRecognitionErrorCode::Audio_capture;
   }
 
+  nsString message;
+  error->GetMessage(message);
   mRecognition->DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR, errorCode,
-                              aError);
-
+                              message);
   return NS_OK;
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/promise/Promise.cpp
+++ b/dom/promise/Promise.cpp
@@ -7,16 +7,17 @@
 #include "mozilla/dom/Promise.h"
 
 #include "jsfriendapi.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/OwningNonNull.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/dom/MediaStreamError.h"
 #include "mozilla/CycleCollectedJSRuntime.h"
 #include "mozilla/Preferences.h"
 #include "PromiseCallback.h"
 #include "PromiseNativeHandler.h"
 #include "PromiseWorkerProxy.h"
 #include "nsContentUtils.h"
 #include "WorkerPrivate.h"
 #include "WorkerRunnable.h"
@@ -350,16 +351,21 @@ Promise::MaybeResolve(JSContext* aCx,
 void
 Promise::MaybeReject(JSContext* aCx,
                      JS::Handle<JS::Value> aValue)
 {
   MaybeRejectInternal(aCx, aValue);
 }
 
 void
+Promise::MaybeReject(const nsRefPtr<MediaStreamError>& aArg) {
+  MaybeSomething(aArg, &Promise::MaybeReject);
+}
+
+void
 Promise::PerformMicroTaskCheckpoint()
 {
   CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
   nsTArray<nsRefPtr<nsIRunnable>>& microtaskQueue =
     runtime->GetPromiseMicroTaskQueue();
 
   while (!microtaskQueue.IsEmpty()) {
     nsRefPtr<nsIRunnable> runnable = microtaskQueue.ElementAt(0);
--- a/dom/promise/Promise.h
+++ b/dom/promise/Promise.h
@@ -24,16 +24,17 @@
 
 class nsIGlobalObject;
 
 namespace mozilla {
 namespace dom {
 
 class AnyCallback;
 class DOMError;
+class MediaStreamError;
 class PromiseCallback;
 class PromiseInit;
 class PromiseNativeHandler;
 class PromiseDebugging;
 
 class Promise;
 class PromiseReportRejectFeature : public workers::WorkerFeature
 {
@@ -94,16 +95,19 @@ public:
   void MaybeResolve(const T& aArg) {
     MaybeSomething(aArg, &Promise::MaybeResolve);
   }
 
   inline void MaybeReject(nsresult aArg) {
     MOZ_ASSERT(NS_FAILED(aArg));
     MaybeSomething(aArg, &Promise::MaybeReject);
   }
+
+  void MaybeReject(const nsRefPtr<MediaStreamError>& aArg);
+
   // DO NOT USE MaybeRejectBrokenly with in new code.  Promises should be
   // rejected with Error instances.
   // Note: MaybeRejectBrokenly is a template so we can use it with DOMError
   // without instantiating the DOMError specialization of MaybeSomething in
   // every translation unit that includes this header, because that would
   // require use to include DOMError.h either here or in all those translation
   // units.
   template<typename T>
--- a/dom/quota/QuotaManager.cpp
+++ b/dom/quota/QuotaManager.cpp
@@ -1096,17 +1096,17 @@ QuotaManager::InitQuotaForOrigin(Persist
 }
 
 void
 QuotaManager::DecreaseUsageForOrigin(PersistenceType aPersistenceType,
                                      const nsACString& aGroup,
                                      const nsACString& aOrigin,
                                      int64_t aSize)
 {
-  AssertIsOnIOThread();
+  MOZ_ASSERT(!NS_IsMainThread());
 
   MutexAutoLock lock(mQuotaMutex);
 
   GroupInfoPair* pair;
   if (!mGroupInfoPairs.Get(aGroup, &pair)) {
     return;
   }
 
--- a/dom/svg/SVGCircleElement.cpp
+++ b/dom/svg/SVGCircleElement.cpp
@@ -76,16 +76,44 @@ SVGCircleElement::GetLengthInfo()
 {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               ArrayLength(sLengthInfo));
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
+bool
+SVGCircleElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
+                                    const Matrix& aTransform)
+{
+  float x, y, r;
+  GetAnimatedLengthValues(&x, &y, &r, nullptr);
+
+  if (r <= 0.f) {
+    // Rendering of the element is disabled
+    aBounds->MoveTo(x, y);
+    aBounds->SetEmpty();
+    return true;
+  }
+
+  if (aTransform.IsRectilinear()) {
+    // Optimize the case where we can treat the circle as a rectangle and
+    // still get tight bounds.
+    if (aStrokeWidth > 0.f) {
+      r += aStrokeWidth / 2.f;
+    }
+    Rect rect(x - r, y - r, 2 * r, 2 * r);
+    *aBounds = aTransform.TransformBounds(rect);
+    return true;
+  }
+
+  return false;
+}
+
 TemporaryRef<Path>
 SVGCircleElement::BuildPath(PathBuilder* aBuilder)
 {
   float x, y, r;
   GetAnimatedLengthValues(&x, &y, &r, nullptr);
 
   if (r <= 0.0f) {
     return nullptr;
--- a/dom/svg/SVGCircleElement.h
+++ b/dom/svg/SVGCircleElement.h
@@ -25,16 +25,18 @@ protected:
   friend nsresult (::NS_NewSVGCircleElement(nsIContent **aResult,
                                             already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
+  virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
+                                 const Matrix& aTransform) MOZ_OVERRIDE;
   virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> R();
--- a/dom/svg/SVGEllipseElement.cpp
+++ b/dom/svg/SVGEllipseElement.cpp
@@ -87,16 +87,45 @@ SVGEllipseElement::GetLengthInfo()
 {
   return LengthAttributesInfo(mLengthAttributes, sLengthInfo,
                               ArrayLength(sLengthInfo));
 }
 
 //----------------------------------------------------------------------
 // nsSVGPathGeometryElement methods
 
+bool
+SVGEllipseElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
+                                     const Matrix& aTransform)
+{
+  float x, y, rx, ry;
+  GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
+
+  if (rx <= 0.f || ry <= 0.f) {
+    // Rendering of the element is disabled
+    aBounds->MoveTo(x, y);
+    aBounds->SetEmpty();
+    return true;
+  }
+
+  if (aTransform.IsRectilinear()) {
+    // Optimize the case where we can treat the ellipse as a rectangle and
+    // still get tight bounds.
+    if (aStrokeWidth > 0.f) {
+      rx += aStrokeWidth / 2.f;
+      ry += aStrokeWidth / 2.f;
+    }
+    Rect rect(x - rx, y - ry, 2 * rx, 2 * ry);
+    *aBounds = aTransform.TransformBounds(rect);
+    return true;
+  }
+
+  return false;
+}
+
 TemporaryRef<Path>
 SVGEllipseElement::BuildPath(PathBuilder* aBuilder)
 {
   float x, y, rx, ry;
   GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
 
   if (rx <= 0.0f || ry <= 0.0f) {
     return nullptr;
--- a/dom/svg/SVGEllipseElement.h
+++ b/dom/svg/SVGEllipseElement.h
@@ -25,16 +25,18 @@ protected:
   friend nsresult (::NS_NewSVGEllipseElement(nsIContent **aResult,
                                              already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo));
 
 public:
   // nsSVGSVGElement methods:
   virtual bool HasValidDimensions() const MOZ_OVERRIDE;
 
   // nsSVGPathGeometryElement methods:
+  virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
+                                 const Matrix& aTransform) MOZ_OVERRIDE;
   virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder) MOZ_OVERRIDE;
 
   virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
 
   // WebIDL
   already_AddRefed<SVGAnimatedLength> Cx();
   already_AddRefed<SVGAnimatedLength> Cy();
   already_AddRefed<SVGAnimatedLength> Rx();
--- a/dom/svg/nsSVGPathGeometryElement.h
+++ b/dom/svg/nsSVGPathGeometryElement.h
@@ -65,16 +65,22 @@ public:
    * This could be moved up to a more general class so it can be used for non-leaf
    * elements, but that would require care and for now there's no need.
    */
   bool GeometryDependsOnCoordCtx();
 
   virtual bool IsMarkable();
   virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
 
+  /**
+   * A method that can be faster than using a Moz2D Path and calling GetBounds/
+   * GetStrokedBounds on it.  It also helps us avoid rounding error for simple
+   * shapes and simple transforms where the Moz2D Path backends can fail to
+   * produce the clean integer bounds that content authors expect in some cases.
+   */
   virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
                                  const Matrix& aTransform) {
     return false;
   }
 
   /**
    * For use with GetAsSimplePath.
    */
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -631,16 +631,18 @@ var interfaceNamesInGlobalScope =
     "KeyEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "KeyboardEvent",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "LocalMediaStream",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "Location",
 // IMPORTANT: Do not change this list without review from a DOM peer!
+    "MediaDevices",
+// IMPORTANT: Do not change this list without review from a DOM peer!
     "MediaElementAudioSourceNode",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     "MediaError",
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaKeyError", pref: "media.eme.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaEncryptedEvent", pref: "media.eme.enabled"},
 // IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MediaDevices.webidl
@@ -0,0 +1,23 @@
+/* -*- Mode: IDL; 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/.
+ *
+ * The origin of this IDL file is
+ * http://dev.w3.org/2011/webrtc/editor/getusermedia.html
+ *
+ * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
+ * liability, trademark and document use rules apply.
+ */
+
+[Func="Navigator::HasUserMediaSupport"]
+interface MediaDevices : EventTarget {
+//    attribute EventHandler ondevicechange;
+//
+//    void enumerateDevices (MediaDeviceInfoCallback resultCallback);
+//
+//  static Dictionary getSupportedConstraints (DOMString kind);
+
+  [Throws, Func="Navigator::HasUserMediaSupport"]
+  Promise<MediaStream> getUserMedia(optional MediaStreamConstraints constraints);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MediaStreamError.webidl
@@ -0,0 +1,21 @@
+/* -*- Mode: IDL; 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/.
+ *
+ * The origin of this IDL file is
+ * http://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaStreamError
+ */
+
+// The future of MediaStreamError is uncertain.
+// https://www.w3.org/Bugs/Public/show_bug.cgi?id=26776
+
+// TODO: This is an 'exception', not an interface, by virtue of needing to be
+// passed as a promise rejection-reason. Revisit if DOMException grows a customArg
+
+[ExceptionClass, NoInterfaceObject]
+interface MediaStreamError {
+  readonly attribute DOMString  name;
+  readonly attribute DOMString? message;
+  readonly attribute DOMString? constraintName;
+};
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -349,20 +349,24 @@ partial interface Navigator {
 partial interface Navigator {
   [Throws]
   readonly attribute AudioChannelManager mozAudioChannelManager;
 };
 #endif // MOZ_AUDIO_CHANNEL_MANAGER
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 callback NavigatorUserMediaSuccessCallback = void (MediaStream stream);
-callback NavigatorUserMediaErrorCallback = void (DOMString error);
+callback NavigatorUserMediaErrorCallback = void (MediaStreamError error);
 
 partial interface Navigator {
   [Throws, Func="Navigator::HasUserMediaSupport"]
+  readonly attribute MediaDevices mediaDevices;
+
+  // Deprecated. Use mediaDevices.getUserMedia instead.
+  [Throws, Func="Navigator::HasUserMediaSupport"]
   void mozGetUserMedia(MediaStreamConstraints constraints,
                        NavigatorUserMediaSuccessCallback successCallback,
                        NavigatorUserMediaErrorCallback errorCallback);
 };
 
 // nsINavigatorUserMedia
 callback MozGetUserMediaDevicesSuccessCallback = void (nsIVariant? devices);
 partial interface Navigator {
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -250,25 +250,27 @@ WEBIDL_FILES = [
     'KeyAlgorithm.webidl',
     'KeyboardEvent.webidl',
     'KeyEvent.webidl',
     'LegacyQueryInterface.webidl',
     'LinkStyle.webidl',
     'ListBoxObject.webidl',
     'LocalMediaStream.webidl',
     'Location.webidl',
+    'MediaDevices.webidl',
     'MediaElementAudioSourceNode.webidl',
     'MediaError.webidl',
     'MediaList.webidl',
     'MediaQueryList.webidl',
     'MediaRecorder.webidl',
     'MediaSource.webidl',
     'MediaStream.webidl',
     'MediaStreamAudioDestinationNode.webidl',
     'MediaStreamAudioSourceNode.webidl',
+    'MediaStreamError.webidl',
     'MediaStreamTrack.webidl',
     'MediaTrackConstraintSet.webidl',
     'MenuBoxObject.webidl',
     'MessageChannel.webidl',
     'MessageEvent.webidl',
     'MessagePort.webidl',
     'MessagePortList.webidl',
     'MimeType.webidl',
--- a/gfx/2d/Helpers.h
+++ b/gfx/2d/Helpers.h
@@ -40,12 +40,58 @@ class AutoRestoreTransform
     }
   }
 
  private:
   RefPtr<DrawTarget> mDrawTarget;
   Matrix mOldTransform;
 };
 
+class AutoPopClips
+{
+public:
+  explicit AutoPopClips(DrawTarget *aTarget)
+    : mDrawTarget(aTarget)
+    , mPushCount(0)
+  {
+    MOZ_ASSERT(mDrawTarget);
+  }
+
+  ~AutoPopClips()
+  {
+    PopAll();
+  }
+
+  void PushClip(const Path *aPath)
+  {
+    mDrawTarget->PushClip(aPath);
+    ++mPushCount;
+  }
+
+  void PushClipRect(const Rect &aRect)
+  {
+    mDrawTarget->PushClipRect(aRect);
+    ++mPushCount;
+  }
+
+  void PopClip()
+  {
+    MOZ_ASSERT(mPushCount > 0);
+    mDrawTarget->PopClip();
+    --mPushCount;
+  }
+
+  void PopAll()
+  {
+    while (mPushCount-- > 0) {
+      mDrawTarget->PopClip();
+    }
+  }
+
+private:
+  RefPtr<DrawTarget> mDrawTarget;
+  int32_t mPushCount;
+};
+
 } // namespace gfx
 } // namespace mozilla
 
 #endif // MOZILLA_GFX_2D_HELPERS_H_
--- a/gfx/2d/PathCG.cpp
+++ b/gfx/2d/PathCG.cpp
@@ -2,16 +2,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/. */
 
 #include "PathCG.h"
 #include <math.h>
 #include "DrawTargetCG.h"
 #include "Logging.h"
+#include "PathHelpers.h"
 
 namespace mozilla {
 namespace gfx {
 
 PathBuilderCG::~PathBuilderCG()
 {
   CGPathRelease(mCGPath);
 }
@@ -63,30 +64,37 @@ PathBuilderCG::Close()
   if (!CGPathIsEmpty(mCGPath))
     CGPathCloseSubpath(mCGPath);
 }
 
 void
 PathBuilderCG::Arc(const Point &aOrigin, Float aRadius, Float aStartAngle,
                  Float aEndAngle, bool aAntiClockwise)
 {
+  // Disabled for now due to a CG bug when using CGPathAddArc with stroke
+  // dashing and rotation transforms that are multiples of 90 degrees. See:
+  // https://bugzilla.mozilla.org/show_bug.cgi?id=949661#c8
+#if 0
   // Core Graphic's initial coordinate system is y-axis up, whereas Moz2D's is
   // y-axis down. Core Graphics therefore considers "clockwise" to mean "sweep
   // in the direction of decreasing angle" whereas Moz2D considers it to mean
   // "sweep in the direction of increasing angle". In other words if this
   // Moz2D method is instructed to sweep anti-clockwise we need to tell
   // CGPathAddArc to sweep clockwise, and vice versa. Hence why we pass the
   // value of aAntiClockwise directly to CGPathAddArc's "clockwise" bool
   // parameter.
   CGPathAddArc(mCGPath, nullptr,
                aOrigin.x, aOrigin.y,
                aRadius,
                aStartAngle,
                aEndAngle,
                aAntiClockwise);
+#endif
+  ArcToBezier(this, aOrigin, Size(aRadius, aRadius), aStartAngle, aEndAngle,
+              aAntiClockwise);
 }
 
 Point
 PathBuilderCG::CurrentPoint() const
 {
   CGPoint pt = CGPathGetCurrentPoint(mCGPath);
   Point ret(pt.x, pt.y);
   return ret;
--- a/gfx/angle/AUTHORS
+++ b/gfx/angle/AUTHORS
@@ -9,28 +9,29 @@
 
 Google Inc.
 TransGaming Inc.
 3DLabs Inc. Ltd.
 
 Adobe Systems Inc.
 Autodesk, Inc.
 BlackBerry Limited
-Borbitsoft
 Cable Television Laboratories, Inc.
 Cloud Party, Inc.
 Intel Corporation
 Mozilla Corporation
 Turbulenz
 Klarälvdalens Datakonsult AB
 Microsoft Open Technologies, Inc.
+NVIDIA Corporation
 
 Jacek Caban
 Mark Callow
 Ginn Chen
+Tibor den Ouden
 James Hauxwell
 Sam Hocevar
 Pierre Leveille
 Jonathan Liu
 Boying Lu
 Aitor Moreno
 Yuri O'Donnell
 Josh Soref
--- a/gfx/angle/CONTRIBUTORS
+++ b/gfx/angle/CONTRIBUTORS
@@ -44,19 +44,16 @@ Google Inc.
 Adobe Systems Inc.
  Alexandru Chiculita
  Steve Minns
  Max Vujovic
 
 Autodesk, Inc.
  Ranger Harke
 
-Borbitsoft
- Tibor den Ouden
-
 Cloud Party, Inc.
  Conor Dickinson
 
 Digia Plc
  Andrew Knight
 
 Intel Corporation
  Jin Yang
@@ -77,12 +74,16 @@ Mozilla Corp.
 
 Turbulenz
  Michael Braithwaite
 
 Ulrik Persson (ddefrostt)
 Mark Banner (standard8mbp)
 David Kilzer
 Jacek Caban
+Tibor den Ouden
 
 Microsoft Open Technologies, Inc.
 Cooper Partin
 Austin Kinross
+
+NVIDIA Corporation
+ Olli Etuaho
--- a/gfx/angle/include/GLSLANG/ShaderLang.h
+++ b/gfx/angle/include/GLSLANG/ShaderLang.h
@@ -241,16 +241,22 @@ typedef struct
     // Set to 1 to enable the extension, else 0.
     int OES_standard_derivatives;
     int OES_EGL_image_external;
     int ARB_texture_rectangle;
     int EXT_draw_buffers;
     int EXT_frag_depth;
     int EXT_shader_texture_lod;
 
+    // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives
+    // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate
+    // EXT_draw_buffers by using it in combination with GLES3.0 glDrawBuffers
+    // function. This applies to Tegra K1 devices.
+    int NV_draw_buffers;
+
     // Set to 1 if highp precision is supported in the fragment language.
     // Default is 0.
     int FragmentPrecisionHigh;
 
     // GLSL ES 3.0 constants.
     int MaxVertexOutputVectors;
     int MaxFragmentInputVectors;
     int MinProgramTexelOffset;
--- a/gfx/angle/include/GLSLANG/ShaderVars.h
+++ b/gfx/angle/include/GLSLANG/ShaderVars.h
@@ -47,60 +47,122 @@ struct COMPILER_EXPORT ShaderVariable
     ~ShaderVariable();
     ShaderVariable(const ShaderVariable &other);
     ShaderVariable &operator=(const ShaderVariable &other);
 
     bool isArray() const { return arraySize > 0; }
     unsigned int elementCount() const { return std::max(1u, arraySize); }
     bool isStruct() const { return !fields.empty(); }
 
+    // All of the shader's variables are described using nested data
+    // structures. This is needed in order to disambiguate similar looking
+    // types, such as two structs containing the same fields, but in
+    // different orders. "findInfoByMappedName" provides an easy query for
+    // users to dive into the data structure and fetch the unique variable
+    // instance corresponding to a dereferencing chain of the top-level
+    // variable.
+    // Given a mapped name like 'a[0].b.c[0]', return the ShaderVariable
+    // that defines 'c' in |leafVar|, and the original name 'A[0].B.C[0]'
+    // in |originalName|, based on the assumption that |this| defines 'a'.
+    // If no match is found, return false.
+    bool findInfoByMappedName(const std::string &mappedFullName,
+                              const ShaderVariable **leafVar,
+                              std::string* originalFullName) const;
+
     GLenum type;
     GLenum precision;
     std::string name;
     std::string mappedName;
     unsigned int arraySize;
     bool staticUse;
     std::vector<ShaderVariable> fields;
     std::string structName;
+
+  protected:
+    bool isSameVariableAtLinkTime(const ShaderVariable &other,
+                                  bool matchPrecision) const;
+
+    bool operator==(const ShaderVariable &other) const;
+    bool operator!=(const ShaderVariable &other) const
+    {
+        return !operator==(other);
+    }
 };
 
 struct COMPILER_EXPORT Uniform : public ShaderVariable
 {
     Uniform();
     ~Uniform();
     Uniform(const Uniform &other);
     Uniform &operator=(const Uniform &other);
+    bool operator==(const Uniform &other) const;
+    bool operator!=(const Uniform &other) const
+    {
+        return !operator==(other);
+    }
+
+    // Decide whether two uniforms are the same at shader link time,
+    // assuming one from vertex shader and the other from fragment shader.
+    // See GLSL ES Spec 3.00.3, sec 4.3.5.
+    bool isSameUniformAtLinkTime(const Uniform &other) const;
 };
 
 struct COMPILER_EXPORT Attribute : public ShaderVariable
 {
     Attribute();
     ~Attribute();
     Attribute(const Attribute &other);
     Attribute &operator=(const Attribute &other);
+    bool operator==(const Attribute &other) const;
+    bool operator!=(const Attribute &other) const
+    {
+        return !operator==(other);
+    }
 
     int location;
 };
 
 struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable
 {
     InterfaceBlockField();
     ~InterfaceBlockField();
     InterfaceBlockField(const InterfaceBlockField &other);
     InterfaceBlockField &operator=(const InterfaceBlockField &other);
+    bool operator==(const InterfaceBlockField &other) const;
+    bool operator!=(const InterfaceBlockField &other) const
+    {
+        return !operator==(other);
+    }
+
+    // Decide whether two InterfaceBlock fields are the same at shader
+    // link time, assuming one from vertex shader and the other from
+    // fragment shader.
+    // See GLSL ES Spec 3.00.3, sec 4.3.7.
+    bool isSameInterfaceBlockFieldAtLinkTime(
+        const InterfaceBlockField &other) const;
 
     bool isRowMajorLayout;
 };
 
 struct COMPILER_EXPORT Varying : public ShaderVariable
 {
     Varying();
     ~Varying();
-    Varying(const Varying &other);
+    Varying(const Varying &otherg);
     Varying &operator=(const Varying &other);
+    bool operator==(const Varying &other) const;
+    bool operator!=(const Varying &other) const
+    {
+        return !operator==(other);
+    }
+
+    // Decide whether two varyings are the same at shader link time,
+    // assuming one from vertex shader and the other from fragment shader.
+    // See GLSL ES Spec 3.00.3, sec 4.3.9.
+    bool isSameVaryingAtLinkTime(const Varying &other) const;
 
     InterpolationType interpolation;
     bool isInvariant;
 };
 
 struct COMPILER_EXPORT InterfaceBlock
 {
     InterfaceBlock();
--- a/gfx/angle/src/commit.h
+++ b/gfx/angle/src/commit.h
@@ -1,3 +1,3 @@
-#define ANGLE_COMMIT_HASH "7a2ba5a15abc"
+#define ANGLE_COMMIT_HASH "f0cacb827771"
 #define ANGLE_COMMIT_HASH_SIZE 12
-#define ANGLE_COMMIT_DATE "2014-10-25 15:19:56 -0400"
+#define ANGLE_COMMIT_DATE "2014-10-28 23:00:12 -0400"
--- a/gfx/angle/src/common/angleutils.cpp
+++ b/gfx/angle/src/common/angleutils.cpp
@@ -1,16 +1,17 @@
 //
 // Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
 
 #include "common/angleutils.h"
 
+#include <stdio.h>
 #include <vector>
 
 std::string FormatString(const char *fmt, va_list vararg)
 {
     static std::vector<char> buffer(512);
 
     // Attempt to just print to the current buffer
     int len = vsnprintf(&buffer[0], buffer.size(), fmt, vararg);
--- a/gfx/angle/src/compiler/translator/Compiler.cpp
+++ b/gfx/angle/src/compiler/translator/Compiler.cpp
@@ -355,17 +355,18 @@ void TCompiler::setResourceString()
               << ":FragmentPrecisionHigh:" << compileResources.FragmentPrecisionHigh
               << ":MaxExpressionComplexity:" << compileResources.MaxExpressionComplexity
               << ":MaxCallStackDepth:" << compileResources.MaxCallStackDepth
               << ":EXT_frag_depth:" << compileResources.EXT_frag_depth
               << ":EXT_shader_texture_lod:" << compileResources.EXT_shader_texture_lod
               << ":MaxVertexOutputVectors:" << compileResources.MaxVertexOutputVectors
               << ":MaxFragmentInputVectors:" << compileResources.MaxFragmentInputVectors
               << ":MinProgramTexelOffset:" << compileResources.MinProgramTexelOffset
-              << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset;
+              << ":MaxProgramTexelOffset:" << compileResources.MaxProgramTexelOffset
+              << ":NV_draw_buffers:" << compileResources.NV_draw_buffers;
 
     builtInResourcesString = strstream.str();
 }
 
 void TCompiler::clearResults()
 {
     arrayBoundsClamper.Cleanup();
     infoSink.info.erase();
--- a/gfx/angle/src/compiler/translator/ShaderLang.cpp
+++ b/gfx/angle/src/compiler/translator/ShaderLang.cpp
@@ -196,16 +196,18 @@ void ShInitBuiltInResources(ShBuiltInRes
     // Extensions.
     resources->OES_standard_derivatives = 0;
     resources->OES_EGL_image_external = 0;
     resources->ARB_texture_rectangle = 0;
     resources->EXT_draw_buffers = 0;
     resources->EXT_frag_depth = 0;
     resources->EXT_shader_texture_lod = 0;
 
+    resources->NV_draw_buffers = 0;
+
     // Disable highp precision in fragment shader by default.
     resources->FragmentPrecisionHigh = 0;
 
     // GLSL ES 3.0 constants.
     resources->MaxVertexOutputVectors = 16;
     resources->MaxFragmentInputVectors = 15;
     resources->MinProgramTexelOffset = -8;
     resources->MaxProgramTexelOffset = 7;
--- a/gfx/angle/src/compiler/translator/ShaderVars.cpp
+++ b/gfx/angle/src/compiler/translator/ShaderVars.cpp
@@ -4,16 +4,18 @@
 // found in the LICENSE file.
 //
 // ShaderVars.cpp:
 //  Methods for GL variable types (varyings, uniforms, etc)
 //
 
 #include <GLSLANG/ShaderLang.h>
 
+#include "compiler/translator/compilerdebug.h"
+
 namespace sh
 {
 
 ShaderVariable::ShaderVariable()
     : type(0),
       precision(0),
       arraySize(0),
       staticUse(false)
@@ -48,32 +50,162 @@ ShaderVariable &ShaderVariable::operator
     mappedName = other.mappedName;
     arraySize = other.arraySize;
     staticUse = other.staticUse;
     fields = other.fields;
     structName = other.structName;
     return *this;
 }
 
+bool ShaderVariable::operator==(const ShaderVariable &other) const
+{
+    if (type != other.type ||
+        precision != other.precision ||
+        name != other.name ||
+        mappedName != other.mappedName ||
+        arraySize != other.arraySize ||
+        staticUse != other.staticUse ||
+        fields.size() != other.fields.size() ||
+        structName != other.structName)
+    {
+        return false;
+    }
+    for (size_t ii = 0; ii < fields.size(); ++ii)
+    {
+        if (fields[ii] != other.fields[ii])
+            return false;
+    }
+    return true;
+}
+
+bool ShaderVariable::findInfoByMappedName(
+    const std::string &mappedFullName,
+    const ShaderVariable **leafVar, std::string *originalFullName) const
+{
+    ASSERT(leafVar && originalFullName);
+    // There are three cases:
+    // 1) the top variable is of struct type;
+    // 2) the top variable is an array;
+    // 3) otherwise.
+    size_t pos = mappedFullName.find_first_of(".[");
+    std::string topName;
+
+    if (pos == std::string::npos)
+    {
+        // Case 3.
+        if (mappedFullName != this->mappedName)
+            return false;
+        *originalFullName = this->name;
+        *leafVar = this;
+        return true;
+    }
+    else
+    {
+        std::string topName = mappedFullName.substr(0, pos);
+        if (topName != this->mappedName)
+            return false;
+        std::string originalName = this->name;
+        std::string remaining;
+        if (mappedFullName[pos] == '[')
+        {
+            // Case 2.
+            size_t closePos = mappedFullName.find_first_of(']');
+            if (closePos < pos || closePos == std::string::npos)
+                return false;
+            // Append '[index]'.
+            originalName += mappedFullName.substr(pos, closePos - pos + 1);
+            if (closePos + 1 == mappedFullName.size())
+            {
+                *originalFullName = originalName;
+                *leafVar = this;
+                return true;
+            }
+            else
+            {
+                // In the form of 'a[0].b', so after ']', '.' is expected.
+                if (mappedFullName[closePos + 1]  != '.')
+                    return false;
+                remaining = mappedFullName.substr(closePos + 2);  // Skip "]."
+            }
+        }
+        else
+        {
+            // Case 1.
+            remaining = mappedFullName.substr(pos + 1);  // Skip "."
+        }
+        for (size_t ii = 0; ii < this->fields.size(); ++ii)
+        {
+            const ShaderVariable *fieldVar = NULL;
+            std::string originalFieldName;
+            bool found = fields[ii].findInfoByMappedName(
+                remaining, &fieldVar, &originalFieldName);
+            if (found)
+            {
+                *originalFullName = originalName + "." + originalFieldName;
+                *leafVar = fieldVar;
+                return true;
+            }
+        }
+        return false;
+    }
+}
+
+bool ShaderVariable::isSameVariableAtLinkTime(
+    const ShaderVariable &other, bool matchPrecision) const
+{
+    if (type != other.type)
+        return false;
+    if (matchPrecision && precision != other.precision)
+        return false;
+    if (name != other.name)
+        return false;
+    ASSERT(mappedName == other.mappedName);
+    if (arraySize != other.arraySize)
+        return false;
+    if (fields.size() != other.fields.size())
+        return false;
+    for (size_t ii = 0; ii < fields.size(); ++ii)
+    {
+        if (!fields[ii].isSameVariableAtLinkTime(other.fields[ii],
+                                                 matchPrecision))
+        {
+            return false;
+        }
+    }
+    if (structName != other.structName)
+        return false;
+    return true;
+}
+
 Uniform::Uniform()
 {}
 
 Uniform::~Uniform()
 {}
 
 Uniform::Uniform(const Uniform &other)
     : ShaderVariable(other)
 {}
 
 Uniform &Uniform::operator=(const Uniform &other)
 {
     ShaderVariable::operator=(other);
     return *this;
 }
 
+bool Uniform::operator==(const Uniform &other) const
+{
+    return ShaderVariable::operator==(other);
+}
+
+bool Uniform::isSameUniformAtLinkTime(const Uniform &other) const
+{
+    return ShaderVariable::isSameVariableAtLinkTime(other, true);
+}
+
 Attribute::Attribute()
     : location(-1)
 {}
 
 Attribute::~Attribute()
 {}
 
 Attribute::Attribute(const Attribute &other)
@@ -83,16 +215,22 @@ Attribute::Attribute(const Attribute &ot
 
 Attribute &Attribute::operator=(const Attribute &other)
 {
     ShaderVariable::operator=(other);
     location = other.location;
     return *this;
 }
 
+bool Attribute::operator==(const Attribute &other) const
+{
+    return (ShaderVariable::operator==(other) &&
+            location == other.location);
+}
+
 InterfaceBlockField::InterfaceBlockField()
     : isRowMajorLayout(false)
 {}
 
 InterfaceBlockField::~InterfaceBlockField()
 {}
 
 InterfaceBlockField::InterfaceBlockField(const InterfaceBlockField &other)
@@ -102,16 +240,29 @@ InterfaceBlockField::InterfaceBlockField
 
 InterfaceBlockField &InterfaceBlockField::operator=(const InterfaceBlockField &other)
 {
     ShaderVariable::operator=(other);
     isRowMajorLayout = other.isRowMajorLayout;
     return *this;
 }
 
+bool InterfaceBlockField::operator==(const InterfaceBlockField &other) const
+{
+    return (ShaderVariable::operator==(other) &&
+            isRowMajorLayout == other.isRowMajorLayout);
+}
+
+bool InterfaceBlockField::isSameInterfaceBlockFieldAtLinkTime(
+    const InterfaceBlockField &other) const
+{
+    return (ShaderVariable::isSameVariableAtLinkTime(other, true) &&
+            isRowMajorLayout == other.isRowMajorLayout);
+}
+
 Varying::Varying()
     : interpolation(INTERPOLATION_SMOOTH),
       isInvariant(false)
 {}
 
 Varying::~Varying()
 {}
 
@@ -124,16 +275,30 @@ Varying::Varying(const Varying &other)
 Varying &Varying::operator=(const Varying &other)
 {
     ShaderVariable::operator=(other);
     interpolation = other.interpolation;
     isInvariant = other.isInvariant;
     return *this;
 }
 
+bool Varying::operator==(const Varying &other) const
+{
+    return (ShaderVariable::operator==(other) &&
+            interpolation == other.interpolation &&
+            isInvariant == other.isInvariant);
+}
+
+bool Varying::isSameVaryingAtLinkTime(const Varying &other) const
+{
+    return (ShaderVariable::isSameVariableAtLinkTime(other, false) &&
+            interpolation == other.interpolation &&
+            isInvariant == other.isInvariant);
+}
+
 InterfaceBlock::InterfaceBlock()
     : arraySize(0),
       layout(BLOCKLAYOUT_PACKED),
       isRowMajorLayout(false),
       staticUse(false)
 {}
 
 InterfaceBlock::~InterfaceBlock()
--- a/gfx/angle/src/compiler/translator/TranslatorESSL.cpp
+++ b/gfx/angle/src/compiler/translator/TranslatorESSL.cpp
@@ -32,13 +32,18 @@ void TranslatorESSL::translate(TIntermNo
 }
 
 void TranslatorESSL::writeExtensionBehavior() {
     TInfoSinkBase& sink = getInfoSink().obj;
     const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
     for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
          iter != extensionBehavior.end(); ++iter) {
         if (iter->second != EBhUndefined) {
-            sink << "#extension " << iter->first << " : "
-                 << getBehaviorString(iter->second) << "\n";
+            if (getResources().NV_draw_buffers && iter->first == "GL_EXT_draw_buffers") {
+                sink << "#extension GL_NV_draw_buffers : "
+                     << getBehaviorString(iter->second) << "\n";
+            } else {
+                sink << "#extension " << iter->first << " : "
+                     << getBehaviorString(iter->second) << "\n";
+            }
         }
     }
 }
--- a/gfx/angle/src/libGLESv2/Context.cpp
+++ b/gfx/angle/src/libGLESv2/Context.cpp
@@ -86,23 +86,23 @@ Context::Context(int clientVersion, cons
     bindArrayBuffer(0);
     bindElementArrayBuffer(0);
 
     bindReadFramebuffer(0);
     bindDrawFramebuffer(0);
     bindRenderbuffer(0);
 
     bindGenericUniformBuffer(0);
-    for (int i = 0; i < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; i++)
+    for (unsigned int i = 0; i < mCaps.maxCombinedUniformBlocks; i++)
     {
         bindIndexedUniformBuffer(0, i, 0, -1);
     }
 
     bindGenericTransformFeedbackBuffer(0);
-    for (int i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+    for (unsigned int i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++)
     {
         bindIndexedTransformFeedbackBuffer(0, i, 0, -1);
     }
 
     bindCopyReadBuffer(0);
     bindCopyWriteBuffer(0);
     bindPixelPackBuffer(0);
     bindPixelUnpackBuffer(0);
@@ -114,18 +114,16 @@ Context::Context(int clientVersion, cons
     mTransformFeedbackZero.set(new TransformFeedback(mRenderer->createTransformFeedback(), 0));
     bindTransformFeedback(0);
 
     mHasBeenCurrent = false;
     mContextLost = false;
     mResetStatus = GL_NO_ERROR;
     mResetStrategy = (notifyResets ? GL_LOSE_CONTEXT_ON_RESET_EXT : GL_NO_RESET_NOTIFICATION_EXT);
     mRobustAccess = robustAccess;
-
-    mState.setContext(this);
 }
 
 Context::~Context()
 {
     GLuint currentProgram = mState.getCurrentProgramId();
     if (currentProgram != 0)
     {
         Program *programObject = mResourceManager->getProgram(currentProgram);
@@ -635,43 +633,54 @@ void Context::useProgram(GLuint program)
 
         if (priorProgram)
         {
             priorProgram->release();
         }
     }
 }
 
-void Context::linkProgram(GLuint program)
+Error Context::linkProgram(GLuint program)
 {
     Program *programObject = mResourceManager->getProgram(program);
 
-    bool linked = programObject->link(getCaps());
+    Error error = programObject->link(getCaps());
+    if (error.isError())
+    {
+        return error;
+    }
 
     // if the current program was relinked successfully we
     // need to install the new executables
-    if (linked && program == mState.getCurrentProgramId())
-    {
-        mState.setCurrentProgramBinary(programObject->getProgramBinary());
-    }
-}
-
-void Context::setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length)
-{
-    Program *programObject = mResourceManager->getProgram(program);
-
-    bool loaded = programObject->setProgramBinary(binaryFormat, binary, length);
-
-    // if the current program was reloaded successfully we
-    // need to install the new executables
-    if (loaded && program == mState.getCurrentProgramId())
+    if (programObject->isLinked() && program == mState.getCurrentProgramId())
     {
         mState.setCurrentProgramBinary(programObject->getProgramBinary());
     }
 
+    return Error(GL_NO_ERROR);
+}
+
+Error Context::setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length)
+{
+    Program *programObject = mResourceManager->getProgram(program);
+
+    Error error = programObject->setProgramBinary(binaryFormat, binary, length);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    // if the current program was reloaded successfully we
+    // need to install the new executables
+    if (programObject->isLinked() && program == mState.getCurrentProgramId())
+    {
+        mState.setCurrentProgramBinary(programObject->getProgramBinary());
+    }
+
+    return Error(GL_NO_ERROR);
 }
 
 void Context::bindTransformFeedback(GLuint transformFeedback)
 {
     mState.setTransformFeedbackBinding(getTransformFeedback(transformFeedback));
 }
 
 Error Context::beginQuery(GLenum target, GLuint query)
@@ -1393,20 +1402,18 @@ Error Context::applyState(GLenum drawMod
     }
 
     return Error(GL_NO_ERROR);
 }
 
 // Applies the shaders and shader constants to the Direct3D 9 device
 Error Context::applyShaders(ProgramBinary *programBinary, bool transformFeedbackActive)
 {
-    const VertexAttribute *vertexAttributes = mState.getVertexArray()->getVertexAttributes();
-
     VertexFormat inputLayout[MAX_VERTEX_ATTRIBS];
-    VertexFormat::GetInputLayout(inputLayout, programBinary, vertexAttributes, mState.getVertexAttribCurrentValues());
+    VertexFormat::GetInputLayout(inputLayout, programBinary, mState);
 
     const Framebuffer *fbo = mState.getDrawFramebuffer();
 
     Error error = mRenderer->applyShaders(programBinary, inputLayout, fbo, mState.getRasterizerState().rasterizerDiscard, transformFeedbackActive);
     if (error.isError())
     {
         return error;
     }
@@ -1579,35 +1586,28 @@ Error Context::applyUniformBuffers()
     return programBinary->applyUniformBuffers(boundBuffers, getCaps());
 }
 
 bool Context::applyTransformFeedbackBuffers()
 {
     TransformFeedback *curTransformFeedback = mState.getCurrentTransformFeedback();
     if (curTransformFeedback && curTransformFeedback->isStarted() && !curTransformFeedback->isPaused())
     {
-        Buffer *transformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
-        GLintptr transformFeedbackOffsets[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
-        for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
-        {
-            transformFeedbackBuffers[i] = mState.getIndexedTransformFeedbackBuffer(i);
-            transformFeedbackOffsets[i] = mState.getIndexedTransformFeedbackBufferOffset(i);
-        }
-        mRenderer->applyTransformFeedbackBuffers(transformFeedbackBuffers, transformFeedbackOffsets);
+        mRenderer->applyTransformFeedbackBuffers(mState);
         return true;
     }
     else
     {
         return false;
     }
 }
 
 void Context::markTransformFeedbackUsage()
 {
-    for (size_t i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+    for (size_t i = 0; i < mCaps.maxTransformFeedbackSeparateAttributes; i++)
     {
         Buffer *buffer = mState.getIndexedTransformFeedbackBuffer(i);
         if (buffer)
         {
             buffer->markTransformFeedbackUsage();
         }
     }
 }
@@ -1766,17 +1766,17 @@ Error Context::drawArrays(GLenum mode, G
     }
 
     error = applyState(mode);
     if (error.isError())
     {
         return error;
     }
 
-    error = mRenderer->applyVertexBuffer(programBinary, mState.getVertexArray()->getVertexAttributes(), mState.getVertexAttribCurrentValues(), first, count, instances);
+    error = mRenderer->applyVertexBuffer(mState, first, count, instances);
     if (error.isError())
     {
         return error;
     }
 
     bool transformFeedbackActive = applyTransformFeedbackBuffers();
 
     error = applyShaders(programBinary, transformFeedbackActive);
@@ -1851,19 +1851,17 @@ Error Context::drawElements(GLenum mode,
     indexInfo.indexRange = indexRange;
     error = mRenderer->applyIndexBuffer(indices, vao->getElementArrayBuffer(), count, mode, type, &indexInfo);
     if (error.isError())
     {
         return error;
     }
 
     GLsizei vertexCount = indexInfo.indexRange.length() + 1;
-    error = mRenderer->applyVertexBuffer(programBinary, vao->getVertexAttributes(),
-                                         mState.getVertexAttribCurrentValues(),
-                                         indexInfo.indexRange.start, vertexCount, instances);
+    error = mRenderer->applyVertexBuffer(mState, indexInfo.indexRange.start, vertexCount, instances);
     if (error.isError())
     {
         return error;
     }
 
     bool transformFeedbackActive = applyTransformFeedbackBuffers();
     // Transform feedback is not allowed for DrawElements, this error should have been caught at the API validation
     // layer.
--- a/gfx/angle/src/libGLESv2/Context.h
+++ b/gfx/angle/src/libGLESv2/Context.h
@@ -125,18 +125,18 @@ class Context
     void bindIndexedUniformBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size);
     void bindGenericTransformFeedbackBuffer(GLuint buffer);
     void bindIndexedTransformFeedbackBuffer(GLuint buffer, GLuint index, GLintptr offset, GLsizeiptr size);
     void bindCopyReadBuffer(GLuint buffer);
     void bindCopyWriteBuffer(GLuint buffer);
     void bindPixelPackBuffer(GLuint buffer);
     void bindPixelUnpackBuffer(GLuint buffer);
     void useProgram(GLuint program);
-    void linkProgram(GLuint program);
-    void setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length);
+    Error linkProgram(GLuint program);
+    Error setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length);
     void bindTransformFeedback(GLuint transformFeedback);
 
     Error beginQuery(GLenum target, GLuint query);
     Error endQuery(GLenum target);
 
     void setFramebufferZero(Framebuffer *framebuffer);
 
     void setRenderbufferStorage(GLsizei width, GLsizei height, GLenum internalformat, GLsizei samples);
--- a/gfx/angle/src/libGLESv2/ImageIndex.cpp
+++ b/gfx/angle/src/libGLESv2/ImageIndex.cpp
@@ -43,16 +43,21 @@ ImageIndex ImageIndex::Make2DArray(GLint
     return ImageIndex(GL_TEXTURE_2D_ARRAY, mipIndex, layerIndex);
 }
 
 ImageIndex ImageIndex::Make3D(GLint mipIndex, GLint layerIndex)
 {
     return ImageIndex(GL_TEXTURE_3D, mipIndex, layerIndex);
 }
 
+ImageIndex ImageIndex::MakeInvalid()
+{
+    return ImageIndex(GL_NONE, -1, -1);
+}
+
 ImageIndex::ImageIndex(GLenum typeIn, GLint mipIndexIn, GLint layerIndexIn)
     : type(typeIn),
       mipIndex(mipIndexIn),
       layerIndex(layerIndexIn)
 {}
 
 ImageIndexIterator ImageIndexIterator::Make2D(GLint minMip, GLint maxMip)
 {
--- a/gfx/angle/src/libGLESv2/ImageIndex.h
+++ b/gfx/angle/src/libGLESv2/ImageIndex.h
@@ -26,16 +26,17 @@ struct ImageIndex
     ImageIndex &operator=(const ImageIndex &other);
 
     bool hasLayer() const { return layerIndex != ENTIRE_LEVEL; }
 
     static ImageIndex Make2D(GLint mipIndex);
     static ImageIndex MakeCube(GLenum target, GLint mipIndex);
     static ImageIndex Make2DArray(GLint mipIndex, GLint layerIndex);
     static ImageIndex Make3D(GLint mipIndex, GLint layerIndex = ENTIRE_LEVEL);
+    static ImageIndex MakeInvalid();
 
     static const GLint ENTIRE_LEVEL = static_cast<GLint>(-1);
 };
 
 class ImageIndexIterator
 {
   public:
     static ImageIndexIterator Make2D(GLint minMip, GLint maxMip);
--- a/gfx/angle/src/libGLESv2/Program.cpp
+++ b/gfx/angle/src/libGLESv2/Program.cpp
@@ -239,28 +239,33 @@ void AttributeBindings::bindAttributeLoc
 void Program::bindAttributeLocation(GLuint index, const char *name)
 {
     mAttributeBindings.bindAttributeLocation(index, name);
 }
 
 // Links the HLSL code of the vertex and pixel shader by matching up their varyings,
 // compiling them into binaries, determining the attribute mappings, and collecting
 // a list of uniforms
-bool Program::link(const Caps &caps)
+Error Program::link(const Caps &caps)
 {
     unlink(false);
 
     mInfoLog.reset();
     resetUniformBlockBindings();
 
     mProgramBinary.set(new ProgramBinary(mRenderer->createProgram()));
-    mLinked = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader,
-                                   mTransformFeedbackVaryings, mTransformFeedbackBufferMode, caps);
+    LinkResult result = mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader,
+                                             mTransformFeedbackVaryings, mTransformFeedbackBufferMode, caps);
+    if (result.error.isError())
+    {
+        return result.error;
+    }
 
-    return mLinked;
+    mLinked = result.linkSuccess;
+    return gl::Error(GL_NO_ERROR);
 }
 
 int AttributeBindings::getAttributeBinding(const std::string &name) const
 {
     for (int location = 0; location < MAX_VERTEX_ATTRIBS; location++)
     {
         if (mAttributeBinding[location].find(name) != mAttributeBinding[location].end())
         {
@@ -298,31 +303,32 @@ bool Program::isLinked()
     return mLinked;
 }
 
 ProgramBinary* Program::getProgramBinary() const
 {
     return mProgramBinary.get();
 }
 
-bool Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length)
+Error Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length)
 {
     unlink(false);
 
     mInfoLog.reset();
 
     mProgramBinary.set(new ProgramBinary(mRenderer->createProgram()));
-    mLinked = mProgramBinary->load(mInfoLog, binaryFormat, binary, length);
-
-    if (!mLinked)
+    LinkResult result = mProgramBinary->load(mInfoLog, binaryFormat, binary, length);
+    if (result.error.isError())
     {
         mProgramBinary.set(NULL);
+        return result.error;
     }
 
-    return mLinked;
+    mLinked = result.linkSuccess;
+    return Error(GL_NO_ERROR);
 }
 
 void Program::release()
 {
     mRefCount--;
 
     if (mRefCount == 0 && mDeleteStatus)
     {
--- a/gfx/angle/src/libGLESv2/Program.h
+++ b/gfx/angle/src/libGLESv2/Program.h
@@ -72,19 +72,19 @@ class Program
     ~Program();
 
     bool attachShader(Shader *shader);
     bool detachShader(Shader *shader);
     int getAttachedShadersCount() const;
 
     void bindAttributeLocation(GLuint index, const char *name);
 
-    bool link(const Caps &caps);
+    Error link(const Caps &caps);
     bool isLinked();
-    bool setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length);
+    Error setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length);
     ProgramBinary *getProgramBinary() const;
 
     int getInfoLogLength() const;
     void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
     void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
 
     void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
     GLint getActiveAttributeCount();
--- a/gfx/angle/src/libGLESv2/ProgramBinary.cpp
+++ b/gfx/angle/src/libGLESv2/ProgramBinary.cpp
@@ -102,16 +102,22 @@ LinkedVarying::LinkedVarying()
 }
 
 LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
                              unsigned int semanticIndex, unsigned int semanticIndexCount)
     : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
 {
 }
 
+LinkResult::LinkResult(bool linkSuccess, const Error &error)
+    : linkSuccess(linkSuccess),
+      error(error)
+{
+}
+
 unsigned int ProgramBinary::mCurrentSerial = 1;
 
 ProgramBinary::ProgramBinary(rx::ProgramImpl *impl)
     : RefCountObject(0),
       mProgram(impl),
       mUsedVertexSamplerRange(0),
       mUsedPixelSamplerRange(0),
       mDirtySamplerMapping(true),
@@ -849,55 +855,55 @@ bool ProgramBinary::linkVaryings(InfoLog
             infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
             return false;
         }
     }
 
     return true;
 }
 
-bool ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length)
+LinkResult ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length)
 {
 #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
-    return false;
+    return LinkResult(false, Error(GL_NO_ERROR));
 #else
     ASSERT(binaryFormat == mProgram->getBinaryFormat());
 
     reset();
 
     BinaryInputStream stream(binary, length);
 
     GLenum format = stream.readInt<GLenum>();
     if (format != mProgram->getBinaryFormat())
     {
         infoLog.append("Invalid program binary format.");
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     int majorVersion = stream.readInt<int>();
     int minorVersion = stream.readInt<int>();
     if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
     {
         infoLog.append("Invalid program binary version.");
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
     stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
     if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
     {
         infoLog.append("Invalid program binary version.");
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     int compileFlags = stream.readInt<int>();
     if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
     {
         infoLog.append("Mismatched compilation flags.");
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
     {
         stream.readInt(&mLinkedAttribute[i].type);
         stream.readString(&mLinkedAttribute[i].name);
         stream.readInt(&mProgram->getShaderAttributes()[i].type);
         stream.readString(&mProgram->getShaderAttributes()[i].name);
@@ -927,17 +933,17 @@ bool ProgramBinary::load(InfoLog &infoLo
 
     stream.readInt(&mUsedVertexSamplerRange);
     stream.readInt(&mUsedPixelSamplerRange);
 
     const unsigned int uniformCount = stream.readInt<unsigned int>();
     if (stream.error())
     {
         infoLog.append("Invalid program binary.");
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     mUniforms.resize(uniformCount);
     for (unsigned int uniformIndex = 0; uniformIndex < uniformCount; uniformIndex++)
     {
         GLenum type = stream.readInt<GLenum>();
         GLenum precision = stream.readInt<GLenum>();
         std::string name = stream.readString();
@@ -960,17 +966,17 @@ bool ProgramBinary::load(InfoLog &infoLo
 
         mUniforms[uniformIndex] = uniform;
     }
 
     unsigned int uniformBlockCount = stream.readInt<unsigned int>();
     if (stream.error())
     {
         infoLog.append("Invalid program binary.");
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     mUniformBlocks.resize(uniformBlockCount);
     for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < uniformBlockCount; ++uniformBlockIndex)
     {
         std::string name = stream.readString();
         unsigned int elementIndex = stream.readInt<unsigned int>();
         unsigned int dataSize = stream.readInt<unsigned int>();
@@ -989,39 +995,40 @@ bool ProgramBinary::load(InfoLog &infoLo
 
         mUniformBlocks[uniformBlockIndex] = uniformBlock;
     }
 
     const unsigned int uniformIndexCount = stream.readInt<unsigned int>();
     if (stream.error())
     {
         infoLog.append("Invalid program binary.");
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     mUniformIndex.resize(uniformIndexCount);
     for (unsigned int uniformIndexIndex = 0; uniformIndexIndex < uniformIndexCount; uniformIndexIndex++)
     {
         stream.readString(&mUniformIndex[uniformIndexIndex].name);
         stream.readInt(&mUniformIndex[uniformIndexIndex].element);
         stream.readInt(&mUniformIndex[uniformIndexIndex].index);
     }
 
-    if (!mProgram->load(infoLog, &stream))
+    LinkResult result = mProgram->load(infoLog, &stream);
+    if (result.error.isError() || !result.linkSuccess)
     {
-        return false;
+        return result;
     }
 
     mProgram->initializeUniformStorage(mUniforms);
 
-    return true;
+    return LinkResult(true, Error(GL_NO_ERROR));
 #endif // #ifdef ANGLE_DISABLE_PROGRAM_BINARY_LOAD
 }
 
-bool ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length)
+Error ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length)
 {
     if (binaryFormat)
     {
         *binaryFormat = mProgram->getBinaryFormat();
     }
 
     BinaryOutputStream stream;
 
@@ -1103,37 +1110,32 @@ bool ProgramBinary::save(GLenum *binaryF
     stream.writeInt(mUniformIndex.size());
     for (size_t i = 0; i < mUniformIndex.size(); ++i)
     {
         stream.writeString(mUniformIndex[i].name);
         stream.writeInt(mUniformIndex[i].element);
         stream.writeInt(mUniformIndex[i].index);
     }
 
-    if (!mProgram->save(&stream))
-    {
-        if (length)
-        {
-            *length = 0;
-        }
-
-        return false;
-    }
+    mProgram->save(&stream);
 
     GLsizei streamLength = stream.length();
     const void *streamData = stream.data();
 
     if (streamLength > bufSize)
     {
         if (length)
         {
             *length = 0;
         }
 
-        return false;
+        // TODO: This should be moved to the validation layer but computing the size of the binary before saving
+        // it causes the save to happen twice.  It may be possible to write the binary to a separate buffer, validate
+        // sizes and then copy it.
+        return Error(GL_INVALID_OPERATION);
     }
 
     if (binary)
     {
         char *ptr = (char*) binary;
 
         memcpy(ptr, streamData, streamLength);
         ptr += streamLength;
@@ -1141,109 +1143,105 @@ bool ProgramBinary::save(GLenum *binaryF
         ASSERT(ptr - streamLength == binary);
     }
 
     if (length)
     {
         *length = streamLength;
     }
 
-    return true;
+    return Error(GL_NO_ERROR);
 }
 
 GLint ProgramBinary::getLength()
 {
     GLint length;
-    if (save(NULL, NULL, INT_MAX, &length))
-    {
-        return length;
-    }
-    else
+    Error error = save(NULL, NULL, INT_MAX, &length);
+    if (error.isError())
     {
         return 0;
     }
+
+    return length;
 }
 
-bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader,
-                         const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps)
+LinkResult ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader,
+                               const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps)
 {
     if (!fragmentShader || !fragmentShader->isCompiled())
     {
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
     ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
 
     if (!vertexShader || !vertexShader->isCompiled())
     {
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
     ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
 
     reset();
 
     mSamplersPS.resize(caps.maxTextureImageUnits);
     mSamplersVS.resize(caps.maxVertexTextureImageUnits);
 
     rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
     rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
 
     int registers;
     std::vector<LinkedVarying> linkedVaryings;
-    if (!mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode,
-                        &registers, &linkedVaryings, &mOutputVariables, caps))
+    LinkResult result = mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode,
+                                       &registers, &linkedVaryings, &mOutputVariables, caps);
+    if (result.error.isError() || !result.linkSuccess)
     {
-        return false;
+        return result;
     }
 
-    bool success = true;
-
     if (!linkAttributes(infoLog, attributeBindings, vertexShader))
     {
-        success = false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     if (!linkUniforms(infoLog, *vertexShader, *fragmentShader, caps))
     {
-        success = false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     // special case for gl_DepthRange, the only built-in uniform (also a struct)
     if (vertexShaderD3D->usesDepthRange() || fragmentShaderD3D->usesDepthRange())
     {
         const sh::BlockMemberInfo &defaultInfo = sh::BlockMemberInfo::getDefaultBlockInfo();
 
         mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0, -1, defaultInfo));
         mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0, -1, defaultInfo));
         mUniforms.push_back(new LinkedUniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0, -1, defaultInfo));
     }
 
     if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, caps))
     {
-        success = false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
     if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
                                                transformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), caps))
     {
-        success = false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
-    if (success)
+    // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
+    // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
+    result = mProgram->compileProgramExecutables(infoLog, fragmentShader, vertexShader, registers);
+    if (result.error.isError() || !result.linkSuccess)
     {
-        // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
-        // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
-        if (!mProgram->compileProgramExecutables(infoLog, fragmentShader, vertexShader, registers))
-        {
-            infoLog.append("Failed to create D3D shaders.");
-            success = false;
-            reset();
-        }
+        infoLog.append("Failed to create D3D shaders.");
+        reset();
+        return result;
     }
 
-    return success;
+    return LinkResult(true, Error(GL_NO_ERROR));
 }
 
 // Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
 bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader)
 {
     const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
 
     unsigned int usedLocations = 0;
--- a/gfx/angle/src/libGLESv2/ProgramBinary.h
+++ b/gfx/angle/src/libGLESv2/ProgramBinary.h
@@ -81,16 +81,24 @@ struct LinkedVarying
     GLsizei size;
 
     // DirectX semantic information
     std::string semanticName;
     unsigned int semanticIndex;
     unsigned int semanticIndexCount;
 };
 
+struct LinkResult
+{
+    bool linkSuccess;
+    Error error;
+
+    LinkResult(bool linkSuccess, const Error &error);
+};
+
 // This is the result of linking a program. It is the state that would be passed to ProgramBinary.
 class ProgramBinary : public RefCountObject
 {
   public:
     explicit ProgramBinary(rx::ProgramImpl *impl);
     ~ProgramBinary();
 
     rx::ProgramImpl *getImplementation() { return mProgram; }
@@ -133,22 +141,23 @@ class ProgramBinary : public RefCountObj
     void getUniformiv(GLint location, GLint *params);
     void getUniformuiv(GLint location, GLuint *params);
 
     void dirtyAllUniforms();
 
     Error applyUniforms();
     Error applyUniformBuffers(const std::vector<Buffer*> boundBuffers, const Caps &caps);
 
-    bool load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length);
-    bool save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length);
+    LinkResult load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length);
+    Error save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length);
     GLint getLength();
 
-    bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader,
-              const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps);
+    LinkResult link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader,
+                    const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
+                    const Caps &caps);
     void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
 
     void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const;
     GLint getActiveAttributeCount() const;
     GLint getActiveAttributeMaxLength() const;
 
     void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const;
     GLint getActiveUniformCount() const;
--- a/gfx/angle/src/libGLESv2/State.cpp
+++ b/gfx/angle/src/libGLESv2/State.cpp
@@ -17,26 +17,29 @@
 #include "libGLESv2/renderer/RenderTarget.h"
 #include "libGLESv2/formatutils.h"
 
 namespace gl
 {
 
 State::State()
 {
+    mMaxDrawBuffers = 0;
+    mMaxCombinedTextureImageUnits = 0;
 }
 
 State::~State()
 {
     reset();
 }
 
 void State::initialize(const Caps& caps, GLuint clientVersion)
 {
-    mContext = NULL;
+    mMaxDrawBuffers = caps.maxDrawBuffers;
+    mMaxCombinedTextureImageUnits = caps.maxCombinedTextureImageUnits;
 
     setClearColor(0.0f, 0.0f, 0.0f, 0.0f);
 
     mDepthClearValue = 1.0f;
     mStencilClearValue = 0;
 
     mRasterizer.rasterizerDiscard = false;
     mRasterizer.cullFace = false;
@@ -106,21 +109,25 @@ void State::initialize(const Caps& caps,
     mBlend.colorMaskRed = true;
     mBlend.colorMaskGreen = true;
     mBlend.colorMaskBlue = true;
     mBlend.colorMaskAlpha = true;
 
     mActiveSampler = 0;
 
     const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f };
-    for (int attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; attribIndex++)
+    mVertexAttribCurrentValues.resize(caps.maxVertexAttributes);
+    for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); ++attribIndex)
     {
         mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues);
     }
 
+    mUniformBuffers.resize(caps.maxCombinedUniformBlocks);
+    mTransformFeedbackBuffers.resize(caps.maxTransformFeedbackSeparateAttributes);
+
     mSamplerTextures[GL_TEXTURE_2D].resize(caps.maxCombinedTextureImageUnits);
     mSamplerTextures[GL_TEXTURE_CUBE_MAP].resize(caps.maxCombinedTextureImageUnits);
     if (clientVersion >= 3)
     {
         // TODO: These could also be enabled via extension
         mSamplerTextures[GL_TEXTURE_2D_ARRAY].resize(caps.maxCombinedTextureImageUnits);
         mSamplerTextures[GL_TEXTURE_3D].resize(caps.maxCombinedTextureImageUnits);
     }
@@ -148,42 +155,36 @@ void State::reset()
             textureVector[textureIdx].set(NULL);
         }
     }
     for (size_t samplerIdx = 0; samplerIdx < mSamplers.size(); samplerIdx++)
     {
         mSamplers[samplerIdx].set(NULL);
     }
 
-    const GLfloat defaultFloatValues[] = { 0.0f, 0.0f, 0.0f, 1.0f };
-    for (int attribIndex = 0; attribIndex < MAX_VERTEX_ATTRIBS; attribIndex++)
-    {
-        mVertexAttribCurrentValues[attribIndex].setFloatValues(defaultFloatValues);
-    }
-
     mArrayBuffer.set(NULL);
     mRenderbuffer.set(NULL);
 
     mTransformFeedback.set(NULL);
 
     for (State::ActiveQueryMap::iterator i = mActiveQueries.begin(); i != mActiveQueries.end(); i++)
     {
         i->second.set(NULL);
     }
 
     mGenericUniformBuffer.set(NULL);
-    for (int i = 0; i < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS; i++)
+    mGenericTransformFeedbackBuffer.set(NULL);
+    for (BufferVector::iterator bufItr = mUniformBuffers.begin(); bufItr != mUniformBuffers.end(); ++bufItr)
     {
-        mUniformBuffers[i].set(NULL);
+        bufItr->set(NULL);
     }
 
-    mGenericTransformFeedbackBuffer.set(NULL);
-    for (int i = 0; i < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+    for (BufferVector::iterator bufItr = mTransformFeedbackBuffers.begin(); bufItr != mTransformFeedbackBuffers.end(); ++bufItr)
     {
-        mTransformFeedbackBuffers[i].set(NULL);
+        bufItr->set(NULL);
     }
 
     mCopyReadBuffer.set(NULL);
     mCopyWriteBuffer.set(NULL);
 
     mPack.pixelBuffer.set(NULL);
     mUnpack.pixelBuffer.set(NULL);
 }
@@ -942,59 +943,64 @@ void State::setGenericUniformBufferBindi
 
 void State::setIndexedUniformBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size)
 {
     mUniformBuffers[index].set(buffer, offset, size);
 }
 
 GLuint State::getIndexedUniformBufferId(GLuint index) const
 {
-    ASSERT(index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS);
+    ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
 
     return mUniformBuffers[index].id();
 }
 
 Buffer *State::getIndexedUniformBuffer(GLuint index) const
 {
-    ASSERT(index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS);
+    ASSERT(static_cast<size_t>(index) < mUniformBuffers.size());
 
     return mUniformBuffers[index].get();
 }
 
 void State::setGenericTransformFeedbackBufferBinding(Buffer *buffer)
 {
     mGenericTransformFeedbackBuffer.set(buffer);
 }
 
 void State::setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size)
 {
     mTransformFeedbackBuffers[index].set(buffer, offset, size);
 }
 
 GLuint State::getIndexedTransformFeedbackBufferId(GLuint index) const
 {
-    ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
+    ASSERT(static_cast<size_t>(index) < mTransformFeedbackBuffers.size());
 
     return mTransformFeedbackBuffers[index].id();
 }
 
 Buffer *State::getIndexedTransformFeedbackBuffer(GLuint index) const
 {
-    ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
+    ASSERT(static_cast<size_t>(index) < mTransformFeedbackBuffers.size());
 
     return mTransformFeedbackBuffers[index].get();
 }
 
 GLuint State::getIndexedTransformFeedbackBufferOffset(GLuint index) const
 {
-    ASSERT(index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
+    ASSERT(static_cast<size_t>(index) < mTransformFeedbackBuffers.size());
 
     return mTransformFeedbackBuffers[index].getOffset();
 }
 
+size_t State::getTransformFeedbackBufferIndexRange() const
+{
+    return mTransformFeedbackBuffers.size();
+}
+
 void State::setCopyReadBufferBinding(Buffer *buffer)
 {
     mCopyReadBuffer.set(buffer);
 }
 
 void State::setCopyWriteBufferBinding(Buffer *buffer)
 {
     mCopyWriteBuffer.set(buffer);
@@ -1028,54 +1034,49 @@ Buffer *State::getTargetBuffer(GLenum ta
 
 void State::setEnableVertexAttribArray(unsigned int attribNum, bool enabled)
 {
     getVertexArray()->enableAttribute(attribNum, enabled);
 }
 
 void State::setVertexAttribf(GLuint index, const GLfloat values[4])
 {
-    ASSERT(index < gl::MAX_VERTEX_ATTRIBS);
+    ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size());
     mVertexAttribCurrentValues[index].setFloatValues(values);
 }
 
 void State::setVertexAttribu(GLuint index, const GLuint values[4])
 {
-    ASSERT(index < gl::MAX_VERTEX_ATTRIBS);
+    ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size());
     mVertexAttribCurrentValues[index].setUnsignedIntValues(values);
 }
 
 void State::setVertexAttribi(GLuint index, const GLint values[4])
 {
-    ASSERT(index < gl::MAX_VERTEX_ATTRIBS);
+    ASSERT(static_cast<size_t>(index) < mVertexAttribCurrentValues.size());
     mVertexAttribCurrentValues[index].setIntValues(values);
 }
 
 void State::setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type, bool normalized,
     bool pureInteger, GLsizei stride, const void *pointer)
 {
     getVertexArray()->setAttributeState(attribNum, boundBuffer, size, type, normalized, pureInteger, stride, pointer);
 }
 
 const VertexAttribute &State::getVertexAttribState(unsigned int attribNum) const
 {
     return getVertexArray()->getVertexAttribute(attribNum);
 }
 
 const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const
 {
-    ASSERT(attribNum < MAX_VERTEX_ATTRIBS);
+    ASSERT(static_cast<size_t>(attribNum) < mVertexAttribCurrentValues.size());
     return mVertexAttribCurrentValues[attribNum];
 }
 
-const VertexAttribCurrentValueData *State::getVertexAttribCurrentValues() const
-{
-    return mVertexAttribCurrentValues;
-}
-
 const void *State::getVertexAttribPointer(unsigned int attribNum) const
 {
     return getVertexArray()->getVertexAttribute(attribNum).pointer;
 }
 
 void State::setPackAlignment(GLint alignment)
 {
     mPack.alignment = alignment;
@@ -1180,17 +1181,17 @@ void State::getFloatv(GLenum pname, GLfl
     }
 }
 
 void State::getIntegerv(GLenum pname, GLint *params)
 {
     if (pname >= GL_DRAW_BUFFER0_EXT && pname <= GL_DRAW_BUFFER15_EXT)
     {
         unsigned int colorAttachment = (pname - GL_DRAW_BUFFER0_EXT);
-        ASSERT(colorAttachment < mContext->getCaps().maxDrawBuffers);
+        ASSERT(colorAttachment < mMaxDrawBuffers);
         Framebuffer *framebuffer = mDrawFramebuffer;
         *params = framebuffer->getDrawBufferState(colorAttachment);
         return;
     }
 
     // Please note: DEPTH_CLEAR_VALUE is not included in our internal getIntegerv implementation
     // because it is stored as a float, despite the fact that the GL ES 2.0 spec names
     // GetIntegerv as its native query function. As it would require conversion in any
@@ -1327,29 +1328,29 @@ void State::getIntegerv(GLenum pname, GL
             }
             else
             {
                 *params = 0;
             }
         }
         break;
       case GL_TEXTURE_BINDING_2D:
-        ASSERT(mActiveSampler < mContext->getCaps().maxCombinedTextureImageUnits);
+        ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits);
         *params = mSamplerTextures.at(GL_TEXTURE_2D)[mActiveSampler].id();
         break;
       case GL_TEXTURE_BINDING_CUBE_MAP:
-        ASSERT(mActiveSampler < mContext->getCaps().maxCombinedTextureImageUnits);
+        ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits);
         *params = mSamplerTextures.at(GL_TEXTURE_CUBE_MAP)[mActiveSampler].id();
         break;
       case GL_TEXTURE_BINDING_3D:
-        ASSERT(mActiveSampler <mContext->getCaps().maxCombinedTextureImageUnits);
+        ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits);
         *params = mSamplerTextures.at(GL_TEXTURE_3D)[mActiveSampler].id();
         break;
       case GL_TEXTURE_BINDING_2D_ARRAY:
-        ASSERT(mActiveSampler < mContext->getCaps().maxCombinedTextureImageUnits);
+        ASSERT(mActiveSampler < mMaxCombinedTextureImageUnits);
         *params = mSamplerTextures.at(GL_TEXTURE_2D_ARRAY)[mActiveSampler].id();
         break;
       case GL_UNIFORM_BUFFER_BINDING:
         *params = mGenericUniformBuffer.id();
         break;
       case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
         *params = mGenericTransformFeedbackBuffer.id();
         break;
@@ -1371,76 +1372,76 @@ void State::getIntegerv(GLenum pname, GL
     }
 }
 
 bool State::getIndexedIntegerv(GLenum target, GLuint index, GLint *data)
 {
     switch (target)
     {
       case GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
-        if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS)
+        if (static_cast<size_t>(index) < mTransformFeedbackBuffers.size())
         {
             *data = mTransformFeedbackBuffers[index].id();
         }
         break;
       case GL_UNIFORM_BUFFER_BINDING:
-        if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS)
+        if (static_cast<size_t>(index) < mUniformBuffers.size())
         {
             *data = mUniformBuffers[index].id();
         }
         break;
       default:
         return false;
     }
 
     return true;
 }
 
 bool State::getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data)
 {
     switch (target)
     {
       case GL_TRANSFORM_FEEDBACK_BUFFER_START:
-        if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS)
+        if (static_cast<size_t>(index) < mTransformFeedbackBuffers.size())
         {
             *data = mTransformFeedbackBuffers[index].getOffset();
         }
         break;
       case GL_TRANSFORM_FEEDBACK_BUFFER_SIZE:
-        if (index < IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS)
+        if (static_cast<size_t>(index) < mTransformFeedbackBuffers.size())
         {
             *data = mTransformFeedbackBuffers[index].getSize();
         }
         break;
       case GL_UNIFORM_BUFFER_START:
-        if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS)
+        if (static_cast<size_t>(index) < mUniformBuffers.size())
         {
             *data = mUniformBuffers[index].getOffset();
         }
         break;
       case GL_UNIFORM_BUFFER_SIZE:
-        if (index < IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS)
+        if (static_cast<size_t>(index) < mUniformBuffers.size())
         {
             *data = mUniformBuffers[index].getSize();
         }
         break;
       default:
         return false;
     }
 
     return true;
 }
 
 bool State::hasMappedBuffer(GLenum target) const
 {
     if (target == GL_ARRAY_BUFFER)
     {
-        for (unsigned int attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; attribIndex++)
+        for (size_t attribIndex = 0; attribIndex < mVertexAttribCurrentValues.size(); attribIndex++)
         {
-            const gl::VertexAttribute &vertexAttrib = getVertexAttribState(attribIndex);
+            const gl::VertexAttribute &vertexAttrib = getVertexAttribState(static_cast<unsigned int>(attribIndex));
             gl::Buffer *boundBuffer = vertexAttrib.buffer.get();
             if (vertexAttrib.enabled && boundBuffer && boundBuffer->isMapped())
             {
                 return true;
             }
         }
 
         return false;
--- a/gfx/angle/src/libGLESv2/State.h
+++ b/gfx/angle/src/libGLESv2/State.h
@@ -30,18 +30,16 @@ class State
 {
   public:
     State();
     ~State();
 
     void initialize(const Caps& caps, GLuint clientVersion);
     void reset();
 
-    void setContext(Context *context) { mContext = context; }
-
     // State chunk getters
     const RasterizerState &getRasterizerState() const;
     const BlendState &getBlendState() const;
     const DepthStencilState &getDepthStencilState() const;
 
     // Clear behavior setters & state parameter block generation function
     void setClearColor(float red, float green, float blue, float alpha);
     void setClearDepth(float depth);
@@ -194,16 +192,17 @@ class State
     Buffer *getIndexedUniformBuffer(GLuint index) const;
 
     // GL_TRANSFORM_FEEDBACK_BUFFER - Both indexed and generic targets
     void setGenericTransformFeedbackBufferBinding(Buffer *buffer);
     void setIndexedTransformFeedbackBufferBinding(GLuint index, Buffer *buffer, GLintptr offset, GLsizeiptr size);
     GLuint getIndexedTransformFeedbackBufferId(GLuint index) const;
     Buffer *getIndexedTransformFeedbackBuffer(GLuint index) const;
     GLuint getIndexedTransformFeedbackBufferOffset(GLuint index) const;
+    size_t getTransformFeedbackBufferIndexRange() const;
 
     // GL_COPY_[READ/WRITE]_BUFFER
     void setCopyReadBufferBinding(Buffer *buffer);
     void setCopyWriteBufferBinding(Buffer *buffer);
 
     // GL_PIXEL[PACK/UNPACK]_BUFFER
     void setPixelPackBufferBinding(Buffer *buffer);
     void setPixelUnpackBufferBinding(Buffer *buffer);
@@ -215,17 +214,16 @@ class State
     void setEnableVertexAttribArray(unsigned int attribNum, bool enabled);
     void setVertexAttribf(GLuint index, const GLfloat values[4]);
     void setVertexAttribu(GLuint index, const GLuint values[4]);
     void setVertexAttribi(GLuint index, const GLint values[4]);
     void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
                               bool normalized, bool pureInteger, GLsizei stride, const void *pointer);
     const VertexAttribute &getVertexAttribState(unsigned int attribNum) const;
     const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const;
-    const VertexAttribCurrentValueData *getVertexAttribCurrentValues() const;
     const void *getVertexAttribPointer(unsigned int attribNum) const;
 
     // Pixel pack state manipulation
     void setPackAlignment(GLint alignment);
     GLint getPackAlignment() const;
     void setPackReverseRowOrder(bool reverseRowOrder);
     bool getPackReverseRowOrder() const;
     const PixelPackState &getPackState() const;
@@ -242,17 +240,19 @@ class State
     bool getIndexedIntegerv(GLenum target, GLuint index, GLint *data);
     bool getIndexedInteger64v(GLenum target, GLuint index, GLint64 *data);
 
     bool hasMappedBuffer(GLenum target) const;
 
   private:
     DISALLOW_COPY_AND_ASSIGN(State);
 
-    Context *mContext;
+    // Cached values from Context's caps
+    GLuint mMaxDrawBuffers;
+    GLuint mMaxCombinedTextureImageUnits;
 
     ColorF mColorClearValue;
     GLclampf mDepthClearValue;
     int mStencilClearValue;
 
     RasterizerState mRasterizer;
     bool mScissorTest;
     Rectangle mScissor;
@@ -278,38 +278,40 @@ class State
 
     BindingPointer<Buffer> mArrayBuffer;
     Framebuffer *mReadFramebuffer;
     Framebuffer *mDrawFramebuffer;
     BindingPointer<Renderbuffer> mRenderbuffer;
     GLuint mCurrentProgramId;
     BindingPointer<ProgramBinary> mCurrentProgramBinary;
 
-    VertexAttribCurrentValueData mVertexAttribCurrentValues[MAX_VERTEX_ATTRIBS]; // From glVertexAttrib
+    typedef std::vector<VertexAttribCurrentValueData> VertexAttribVector;
+    VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib
     VertexArray *mVertexArray;
 
     // Texture and sampler bindings
     size_t mActiveSampler;   // Active texture unit selector - GL_TEXTURE0
 
     typedef std::vector< BindingPointer<Texture> > TextureBindingVector;
     typedef std::map<GLenum, TextureBindingVector> TextureBindingMap;
     TextureBindingMap mSamplerTextures;
 
     typedef std::vector< BindingPointer<Sampler> > SamplerBindingVector;
     SamplerBindingVector mSamplers;
 
     typedef std::map< GLenum, BindingPointer<Query> > ActiveQueryMap;
     ActiveQueryMap mActiveQueries;
 
     BindingPointer<Buffer> mGenericUniformBuffer;
-    OffsetBindingPointer<Buffer> mUniformBuffers[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS];
+    typedef std::vector< OffsetBindingPointer<Buffer> > BufferVector;
+    BufferVector mUniformBuffers;
 
     BindingPointer<TransformFeedback> mTransformFeedback;
     BindingPointer<Buffer> mGenericTransformFeedbackBuffer;
-    OffsetBindingPointer<Buffer> mTransformFeedbackBuffers[IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
+    BufferVector mTransformFeedbackBuffers;
 
     BindingPointer<Buffer> mCopyReadBuffer;
     BindingPointer<Buffer> mCopyWriteBuffer;
 
     PixelUnpackState mUnpack;
     PixelPackState mPack;
 };
 
--- a/gfx/angle/src/libGLESv2/angletypes.cpp
+++ b/gfx/angle/src/libGLESv2/angletypes.cpp
@@ -4,16 +4,18 @@
 // found in the LICENSE file.
 //
 
 // angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2
 
 #include "libGLESv2/angletypes.h"
 #include "libGLESv2/ProgramBinary.h"
 #include "libGLESv2/VertexAttribute.h"
+#include "libGLESv2/State.h"
+#include "libGLESv2/VertexArray.h"
 
 namespace gl
 {
 
 SamplerState::SamplerState()
     : minFilter(GL_NEAREST_MIPMAP_LINEAR),
       magFilter(GL_LINEAR),
       wrapS(GL_REPEAT),
@@ -143,26 +145,26 @@ VertexFormat::VertexFormat(const VertexA
     if (mType == GL_FLOAT || mType == GL_HALF_FLOAT || mType == GL_FIXED)
     {
         mNormalized = GL_FALSE;
     }
 }
 
 void VertexFormat::GetInputLayout(VertexFormat *inputLayout,
                                   ProgramBinary *programBinary,
-                                  const VertexAttribute *attributes,
-                                  const gl::VertexAttribCurrentValueData *currentValues)
+                                  const State &state)
 {
+    const VertexAttribute *vertexAttributes = state.getVertexArray()->getVertexAttributes();
     for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
     {
         int semanticIndex = programBinary->getSemanticIndex(attributeIndex);
 
         if (semanticIndex != -1)
         {
-            inputLayout[semanticIndex] = VertexFormat(attributes[attributeIndex], currentValues[attributeIndex].Type);
+            inputLayout[semanticIndex] = VertexFormat(vertexAttributes[attributeIndex], state.getVertexAttribCurrentValue(attributeIndex).Type);
         }
     }
 }
 
 bool VertexFormat::operator==(const VertexFormat &other) const
 {
     return (mType == other.mType                &&
             mComponents == other.mComponents    &&
--- a/gfx/angle/src/libGLESv2/angletypes.h
+++ b/gfx/angle/src/libGLESv2/angletypes.h
@@ -10,16 +10,17 @@
 #define LIBGLESV2_ANGLETYPES_H_
 
 #include "libGLESv2/Constants.h"
 #include "common/RefCountObject.h"
 
 namespace gl
 {
 class Buffer;
+class State;
 class ProgramBinary;
 struct VertexAttribute;
 struct VertexAttribCurrentValueData;
 
 enum SamplerType
 {
     SAMPLER_PIXEL,
     SAMPLER_VERTEX
@@ -224,18 +225,17 @@ struct VertexFormat
 
     VertexFormat();
     VertexFormat(GLenum type, GLboolean normalized, GLuint components, bool pureInteger);
     explicit VertexFormat(const VertexAttribute &attribute);
     VertexFormat(const VertexAttribute &attribute, GLenum currentValueType);
 
     static void GetInputLayout(VertexFormat *inputLayout,
                                ProgramBinary *programBinary,
-                               const VertexAttribute *attributes,
-                               const gl::VertexAttribCurrentValueData *currentValues);
+                               const State& currentValues);
 
     bool operator==(const VertexFormat &other) const;
     bool operator!=(const VertexFormat &other) const;
     bool operator<(const VertexFormat& other) const;
 };
 
 }
 
--- a/gfx/angle/src/libGLESv2/libGLESv2.cpp
+++ b/gfx/angle/src/libGLESv2/libGLESv2.cpp
@@ -3649,17 +3649,22 @@ void __stdcall glLinkProgram(GLuint prog
             }
             else
             {
                 context->recordError(gl::Error(GL_INVALID_VALUE));
                 return;
             }
         }
 
-        context->linkProgram(program);
+        gl::Error error = context->linkProgram(program);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
+        }
     }
 }
 
 void __stdcall glPixelStorei(GLenum pname, GLint param)
 {
     EVENT("(GLenum pname = 0x%X, GLint param = %d)", pname, param);
 
     gl::Context *context = gl::getNonLostContext();
@@ -8397,19 +8402,20 @@ void __stdcall glGetProgramBinaryOES(GLu
         gl::ProgramBinary *programBinary = programObject->getProgramBinary();
 
         if (!programBinary)
         {
             context->recordError(gl::Error(GL_INVALID_OPERATION));
             return;
         }
 
-        if (!programBinary->save(binaryFormat, binary, bufSize, length))
-        {
-            context->recordError(gl::Error(GL_INVALID_OPERATION));
+        gl::Error error = programBinary->save(binaryFormat, binary, bufSize, length);
+        if (error.isError())
+        {
+            context->recordError(error);
             return;
         }
     }
 }
 
 void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat,
                                   const void *binary, GLint length)
 {
@@ -8428,17 +8434,22 @@ void __stdcall glProgramBinaryOES(GLuint
 
         gl::Program *programObject = context->getProgram(program);
         if (!programObject)
         {
             context->recordError(gl::Error(GL_INVALID_OPERATION));
             return;
         }
 
-        context->setProgramBinary(program, binaryFormat, binary, length);
+        gl::Error error = context->setProgramBinary(program, binaryFormat, binary, length);
+        if (error.isError())
+        {
+            context->recordError(error);
+            return;
+        }
     }
 }
 
 void __stdcall glDrawBuffersEXT(GLsizei n, const GLenum *bufs)
 {
     EVENT("(GLenum n = %d, bufs = 0x%0.8p)", n, bufs);
 
     gl::Context *context = gl::getNonLostContext();
--- a/gfx/angle/src/libGLESv2/renderer/Image.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/Image.cpp
@@ -4,25 +4,41 @@
 // found in the LICENSE file.
 //
 
 // Image.h: Implements the rx::Image class, an abstract base class for the
 // renderer-specific classes which will define the interface to the underlying
 // surfaces or resources.
 
 #include "libGLESv2/renderer/Image.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/main.h"
 
 namespace rx
 {
 
 Image::Image()
 {
     mWidth = 0;
     mHeight = 0;
     mDepth = 0;
     mInternalFormat = GL_NONE;
     mActualFormat = GL_NONE;
     mTarget = GL_NONE;
     mRenderable = false;
     mDirty = false;
 }
 
+void Image::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, gl::Framebuffer *source)
+{
+    gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer();
+
+    if (!colorbuffer)
+    {
+        return gl::error(GL_OUT_OF_MEMORY);
+    }
+
+    RenderTarget *renderTarget = GetAttachmentRenderTarget(colorbuffer);
+    ASSERT(renderTarget);
+    copy(xoffset, yoffset, zoffset, area, renderTarget);
 }
+
+}
--- a/gfx/angle/src/libGLESv2/renderer/Image.h
+++ b/gfx/angle/src/libGLESv2/renderer/Image.h
@@ -14,22 +14,25 @@
 #include "common/debug.h"
 #include "libGLESv2/Error.h"
 
 #include <GLES2/gl2.h>
 
 namespace gl
 {
 class Framebuffer;
+struct Rectangle;
+struct ImageIndex;
 }
 
 namespace rx
 {
-
 class Renderer;
+class RenderTarget;
+class TextureStorage;
 
 class Image
 {
   public:
     Image();
     virtual ~Image() {};
 
     GLsizei getWidth() const { return mWidth; }
@@ -46,17 +49,20 @@ class Image
 
     virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease) = 0;
 
     virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                GLint unpackAlignment, GLenum type, const void *input) = 0;
     virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                          const void *input) = 0;
 
-    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source) = 0;
+    void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, gl::Framebuffer *source);
+    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source) = 0;
+    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
+                      const gl::ImageIndex &sourceIndex, TextureStorage *source) = 0;
 
   protected:
     GLsizei mWidth;
     GLsizei mHeight;
     GLsizei mDepth;
     GLenum mInternalFormat;
     GLenum mActualFormat;
     bool mRenderable;
--- a/gfx/angle/src/libGLESv2/renderer/ProgramImpl.h
+++ b/gfx/angle/src/libGLESv2/renderer/ProgramImpl.h
@@ -27,26 +27,26 @@ public:
 
     virtual bool usesPointSize() const = 0;
     virtual int getShaderVersion() const = 0;
     virtual GLenum getTransformFeedbackBufferMode() const = 0;
     virtual std::vector<gl::LinkedVarying> &getTransformFeedbackLinkedVaryings() = 0;
     virtual sh::Attribute *getShaderAttributes() = 0;
 
     virtual GLenum getBinaryFormat() = 0;
-    virtual bool load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0;
-    virtual bool save(gl::BinaryOutputStream *stream) = 0;
+    virtual gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0;
+    virtual gl::Error save(gl::BinaryOutputStream *stream) = 0;
 
-    virtual bool compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                           int registers) = 0;
+    virtual gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                                     int registers) = 0;
 
-    virtual bool link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                      const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
-                      int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
-                      std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps) = 0;
+    virtual gl::LinkResult link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
+                                int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
+                                std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps) = 0;
 
     virtual void initializeUniformStorage(const std::vector<gl::LinkedUniform*> &uniforms) = 0;
 
     virtual gl::Error applyUniforms(const std::vector<gl::LinkedUniform*> &uniforms) = 0;
     virtual gl::Error applyUniformBuffers(const std::vector<gl::UniformBlock*> uniformBlocks, const std::vector<gl::Buffer*> boundBuffers,
                                      const gl::Caps &caps) = 0;
     virtual bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
                                             unsigned int registerIndex, const gl::Caps &caps) = 0;
--- a/gfx/angle/src/libGLESv2/renderer/Renderer.h
+++ b/gfx/angle/src/libGLESv2/renderer/Renderer.h
@@ -127,20 +127,19 @@ class Renderer
     virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
                              bool ignoreViewport) = 0;
 
     virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer) = 0;
     virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive) = 0;
     virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) = 0;
     virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount) = 0;
-    virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[],
-                                        GLint first, GLsizei count, GLsizei instances) = 0;
+    virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances) = 0;
     virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo) = 0;
-    virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]) = 0;
+    virtual void applyTransformFeedbackBuffers(const gl::State& state) = 0;
 
     virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive) = 0;
     virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
                                    gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances) = 0;
 
     virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer) = 0;
 
     virtual void markAllStateDirty() = 0;
@@ -192,22 +191,23 @@ class Renderer
     virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples) = 0;
 
     // Shader creation
     virtual ShaderImpl *createShader(GLenum type) = 0;
     virtual ProgramImpl *createProgram() = 0;
 
     // Shader operations
     virtual void releaseShaderCompiler() = 0;
-    virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type,
-                                             const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                             bool separatedOutputBuffers) = 0;
-    virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
-                                                  const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                                  bool separatedOutputBuffers, D3DWorkaroundType workaround) = 0;
+    virtual gl::Error loadExecutable(const void *function, size_t length, rx::ShaderType type,
+                                     const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                     bool separatedOutputBuffers, ShaderExecutable **outExecutable) = 0;
+    virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
+                                          const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                          bool separatedOutputBuffers, D3DWorkaroundType workaround,
+                                          ShaderExecutable **outExectuable) = 0;
     virtual UniformStorage *createUniformStorage(size_t storageSize) = 0;
 
     // Image operations
     virtual Image *createImage() = 0;
     virtual void generateMipmap(Image *dest, Image *source) = 0;
     virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain) = 0;
     virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels) = 0;
     virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels) = 0;
--- a/gfx/angle/src/libGLESv2/renderer/Workarounds.h
+++ b/gfx/angle/src/libGLESv2/renderer/Workarounds.h
@@ -21,17 +21,19 @@ enum D3DWorkaroundType
     ANGLE_D3D_WORKAROUND_NONE,
     ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION,
     ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION
 };
 
 struct Workarounds
 {
     Workarounds()
-        : mrtPerfWorkaround(false)
+        : mrtPerfWorkaround(false),
+          setDataFasterThanImageUpload(false)
     {}
 
     bool mrtPerfWorkaround;
+    bool setDataFasterThanImageUpload;
 };
 
 }
 
 #endif // LIBGLESV2_RENDERER_WORKAROUNDS_H_
--- a/gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp
@@ -77,18 +77,18 @@ void HLSLCompiler::release()
     if (mD3DCompilerModule)
     {
         FreeLibrary(mD3DCompilerModule);
         mD3DCompilerModule = NULL;
         mD3DCompileFunc = NULL;
     }
 }
 
-ID3DBlob *HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile,
-                                        const std::vector<CompileConfig> &configs) const
+gl::Error HLSLCompiler::compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile,
+                                        const std::vector<CompileConfig> &configs, ID3DBlob **outCompiledBlob) const
 {
     ASSERT(mD3DCompilerModule && mD3DCompileFunc);
 
     if (gl::perfActive())
     {
         std::string sourcePath = getTempPath();
         std::string sourceText = FormatString("#line 2 \"%s\"\n\n%s", sourcePath.c_str(), hlsl.c_str());
         writeFile(sourcePath.c_str(), sourceText.c_str(), sourceText.size());
@@ -110,30 +110,34 @@ ID3DBlob *HLSLCompiler::compileToBinary(
             TRACE("\n%s", hlsl);
             TRACE("\n%s", message);
 
             SafeRelease(errorMessage);
         }
 
         if (SUCCEEDED(result))
         {
-            return binary;
+            *outCompiledBlob = binary;
+            return gl::Error(GL_NO_ERROR);
         }
         else
         {
             if (result == E_OUTOFMEMORY)
             {
-                return gl::error<ID3DBlob*>(GL_OUT_OF_MEMORY, NULL);
+                *outCompiledBlob = NULL;
+                return gl::Error(GL_OUT_OF_MEMORY, "HLSL compiler had an unexpected failure, result: 0x%X.", result);
             }
 
             infoLog.append("Warning: D3D shader compilation failed with %s flags.", configs[i].name.c_str());
 
             if (i + 1 < configs.size())
             {
                 infoLog.append(" Retrying with %s.\n", configs[i + 1].name.c_str());
             }
         }
     }
 
-    return NULL;
+    // None of the configurations succeeded in compiling this shader but the compiler is still intact
+    *outCompiledBlob = NULL;
+    return gl::Error(GL_NO_ERROR);
 }
 
 }
--- a/gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h
@@ -1,11 +1,13 @@
 #ifndef LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_
 #define LIBGLESV2_RENDERER_HLSL_D3DCOMPILER_H_
 
+#include "libGLESv2/Error.h"
+
 #include "common/angleutils.h"
 #include "common/platform.h"
 
 #include <vector>
 #include <string>
 
 namespace gl
 {
@@ -28,18 +30,20 @@ class HLSLCompiler
 {
   public:
     HLSLCompiler();
     ~HLSLCompiler();
 
     bool initialize();
     void release();
 
-    ID3DBlob *compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile,
-                              const std::vector<CompileConfig> &configs) const;
+    // Attempt to compile a HLSL shader using the supplied configurations, may output a NULL compiled blob
+    // even if no GL errors are returned.
+    gl::Error compileToBinary(gl::InfoLog &infoLog, const std::string &hlsl, const std::string &profile,
+                              const std::vector<CompileConfig> &configs, ID3DBlob **outCompiledBlob) const;
 
   private:
     DISALLOW_COPY_AND_ASSIGN(HLSLCompiler);
 
     HMODULE mD3DCompilerModule;
     pD3DCompile mD3DCompileFunc;
 };
 
--- a/gfx/angle/src/libGLESv2/renderer/d3d/ImageD3D.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/ImageD3D.h
@@ -12,16 +12,18 @@
 #define LIBGLESV2_RENDERER_IMAGED3D_H_
 
 #include "common/debug.h"
 #include "libGLESv2/renderer/Image.h"
 
 namespace gl
 {
 class Framebuffer;
+struct ImageIndex;
+struct Box;
 }
 
 namespace rx
 {
 class TextureStorage;
 
 class ImageD3D : public Image
 {
@@ -32,20 +34,20 @@ class ImageD3D : public Image
     static ImageD3D *makeImageD3D(Image *img);
 
     virtual bool isDirty() const = 0;
 
     virtual void setManagedSurface2D(TextureStorage *storage, int level) {};
     virtual void setManagedSurfaceCube(TextureStorage *storage, int face, int level) {};
     virtual void setManagedSurface3D(TextureStorage *storage, int level) {};
     virtual void setManagedSurface2DArray(TextureStorage *storage, int layer, int level) {};
-    virtual gl::Error copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0;
-    virtual gl::Error copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height) = 0;
-    virtual gl::Error copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth) = 0;
-    virtual gl::Error copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height) = 0;
+    virtual gl::Error copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
+    virtual gl::Error copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
+    virtual gl::Error copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
+    virtual gl::Error copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region) = 0;
 
   private:
     DISALLOW_COPY_AND_ASSIGN(ImageD3D);
 };
 
 }
 
 #endif // LIBGLESV2_RENDERER_IMAGED3D_H_
--- a/gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp
@@ -142,17 +142,17 @@ bool ProgramD3D::usesPointSpriteEmulatio
     return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
 }
 
 bool ProgramD3D::usesGeometryShader() const
 {
     return usesPointSpriteEmulation();
 }
 
-bool ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
+gl::LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
 {
     stream->readInt(&mShaderVersion);
 
     stream->readInt(&mTransformFeedbackBufferMode);
     const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>();
     mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount);
     for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++)
     {
@@ -196,24 +196,32 @@ bool ProgramD3D::load(gl::InfoLog &infoL
             stream->readInt(&vertexInput->mType);
             stream->readInt(&vertexInput->mNormalized);
             stream->readInt(&vertexInput->mComponents);
             stream->readBool(&vertexInput->mPureInteger);
         }
 
         unsigned int vertexShaderSize = stream->readInt<unsigned int>();
         const unsigned char *vertexShaderFunction = binary + stream->offset();
-        ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize,
-                                                                       SHADER_VERTEX,
-                                                                       mTransformFeedbackLinkedVaryings,
-                                                                       (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+
+        ShaderExecutable *shaderExecutable = NULL;
+        gl::Error error = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize,
+                                                    SHADER_VERTEX,
+                                                    mTransformFeedbackLinkedVaryings,
+                                                    (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+                                                    &shaderExecutable);
+        if (error.isError())
+        {
+            return gl::LinkResult(false, error);
+        }
+
         if (!shaderExecutable)
         {
             infoLog.append("Could not create vertex shader.");
-            return false;
+            return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
         }
 
         // generated converted input layout
         GLenum signature[gl::MAX_VERTEX_ATTRIBS];
         getInputLayoutSignature(inputLayout, signature);
 
         // add new binary
         mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable));
@@ -228,65 +236,74 @@ bool ProgramD3D::load(gl::InfoLog &infoL
         std::vector<GLenum> outputs(outputCount);
         for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++)
         {
             stream->readInt(&outputs[outputIndex]);
         }
 
         const size_t pixelShaderSize = stream->readInt<unsigned int>();
         const unsigned char *pixelShaderFunction = binary + stream->offset();
-        ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize,
-                                                                       SHADER_PIXEL,
-                                                                       mTransformFeedbackLinkedVaryings,
-                                                                       (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+        ShaderExecutable *shaderExecutable = NULL;
+        gl::Error error = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize, SHADER_PIXEL,
+                                                    mTransformFeedbackLinkedVaryings,
+                                                    (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+                                                    &shaderExecutable);
+        if (error.isError())
+        {
+            return gl::LinkResult(false, error);
+        }
 
         if (!shaderExecutable)
         {
             infoLog.append("Could not create pixel shader.");
-            return false;
+            return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
         }
 
         // add new binary
         mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable));
 
         stream->skip(pixelShaderSize);
     }
 
     unsigned int geometryShaderSize = stream->readInt<unsigned int>();
 
     if (geometryShaderSize > 0)
     {
         const unsigned char *geometryShaderFunction = binary + stream->offset();
-        mGeometryExecutable = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize,
-                                                        SHADER_GEOMETRY,
-                                                        mTransformFeedbackLinkedVaryings,
-                                                        (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+        gl::Error error = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize, SHADER_GEOMETRY,
+                                                    mTransformFeedbackLinkedVaryings,
+                                                    (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+                                                    &mGeometryExecutable);
+        if (error.isError())
+        {
+            return gl::LinkResult(false, error);
+        }
 
         if (!mGeometryExecutable)
         {
             infoLog.append("Could not create geometry shader.");
-            return false;
+            return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
         }
         stream->skip(geometryShaderSize);
     }
 
     GUID binaryIdentifier = {0};
     stream->readBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID));
 
     GUID identifier = mRenderer->getAdapterIdentifier();
     if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0)
     {
         infoLog.append("Invalid program binary.");
-        return false;
+        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
-    return true;
+    return gl::LinkResult(true, gl::Error(GL_NO_ERROR));
 }
 
-bool ProgramD3D::save(gl::BinaryOutputStream *stream)
+gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
 {
     stream->writeInt(mShaderVersion);
 
     stream->writeInt(mTransformFeedbackBufferMode);
     stream->writeInt(mTransformFeedbackLinkedVaryings.size());
     for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
     {
         const gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
@@ -362,22 +379,22 @@ bool ProgramD3D::save(gl::BinaryOutputSt
 
     if (mGeometryExecutable != NULL && geometryShaderSize > 0)
     {
         const uint8_t *geometryBlob = mGeometryExecutable->getFunction();
         stream->writeBytes(geometryBlob, geometryShaderSize);
     }
 
     GUID binaryIdentifier = mRenderer->getAdapterIdentifier();
-    stream->writeBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier),  sizeof(GUID));
+    stream->writeBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID));
 
-    return true;
+    return gl::Error(GL_NO_ERROR);
 }
 
-ShaderExecutable *ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo)
+gl::Error ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutable **outExecutable)
 {
     std::vector<GLenum> outputs;
 
     const gl::ColorbufferInfo &colorbuffers = fbo->getColorbuffersForRender();
 
     for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
     {
         const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
@@ -387,120 +404,149 @@ ShaderExecutable *ProgramD3D::getPixelEx
             outputs.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding());
         }
         else
         {
             outputs.push_back(GL_NONE);
         }
     }
 
-    return getPixelExecutableForOutputLayout(outputs);
+    return getPixelExecutableForOutputLayout(outputs, outExecutable);
 }
 
-ShaderExecutable *ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature)
+gl::Error ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature, ShaderExecutable **outExectuable)
 {
     for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++)
     {
         if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
         {
-            return mPixelExecutables[executableIndex]->shaderExecutable();
+            *outExectuable = mPixelExecutables[executableIndex]->shaderExecutable();
+            return gl::Error(GL_NO_ERROR);
         }
     }
 
     std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth,
                                                                                      outputSignature);
 
     // Generate new pixel executable
     gl::InfoLog tempInfoLog;
-    ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL, SHADER_PIXEL,
-                                                                       mTransformFeedbackLinkedVaryings,
-                                                                       (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
-                                                                       mPixelWorkarounds);
+    ShaderExecutable *pixelExecutable = NULL;
+    gl::Error error = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL, SHADER_PIXEL,
+                                                     mTransformFeedbackLinkedVaryings,
+                                                     (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+                                                     mPixelWorkarounds, &pixelExecutable);
+    if (error.isError())
+    {
+        return error;
+    }
 
     if (!pixelExecutable)
     {
         std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
         tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
         ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]);
     }
     else
     {
         mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable));
     }
 
-    return pixelExecutable;
+    *outExectuable = pixelExecutable;
+    return gl::Error(GL_NO_ERROR);
 }
 
-ShaderExecutable *ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
+gl::Error ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutable **outExectuable)
 {
     GLenum signature[gl::MAX_VERTEX_ATTRIBS];
     getInputLayoutSignature(inputLayout, signature);
 
     for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
     {
         if (mVertexExecutables[executableIndex]->matchesSignature(signature))
         {
-            return mVertexExecutables[executableIndex]->shaderExecutable();
+            *outExectuable = mVertexExecutables[executableIndex]->shaderExecutable();
+            return gl::Error(GL_NO_ERROR);
         }
     }
 
     // Generate new dynamic layout with attribute conversions
     std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes);
 
     // Generate new vertex executable
     gl::InfoLog tempInfoLog;
-    ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL,
-                                                                        SHADER_VERTEX,
-                                                                        mTransformFeedbackLinkedVaryings,
-                                                                        (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
-                                                                        mVertexWorkarounds);
+    ShaderExecutable *vertexExecutable = NULL;
+    gl::Error error = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL, SHADER_VERTEX,
+                                                     mTransformFeedbackLinkedVaryings,
+                                                     (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+                                                     mVertexWorkarounds, &vertexExecutable);
+    if (error.isError())
+    {
+        return error;
+    }
+
     if (!vertexExecutable)
     {
         std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3);
         tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
         ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
     }
     else
     {
         mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable));
     }
 
-    return vertexExecutable;
+    *outExectuable = vertexExecutable;
+    return gl::Error(GL_NO_ERROR);
 }
 
-bool ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                           int registers)
+gl::LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                                     int registers)
 {
     ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
     ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
 
     gl::VertexFormat defaultInputLayout[gl::MAX_VERTEX_ATTRIBS];
     GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout);
-    ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
+    ShaderExecutable *defaultVertexExecutable = NULL;
+    gl::Error error = getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable);
+    if (error.isError())
+    {
+        return gl::LinkResult(false, error);
+    }
 
     std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey());
-    ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput);
+    ShaderExecutable *defaultPixelExecutable = NULL;
+    error = getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable);
+    if (error.isError())
+    {
+        return gl::LinkResult(false, error);
+    }
 
     if (usesGeometryShader())
     {
         std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D);
 
-        mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL,
-                                                             SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
-                                                             (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
-                                                             ANGLE_D3D_WORKAROUND_NONE);
+
+        error = mRenderer->compileToExecutable(infoLog, geometryHLSL, SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
+                                               (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+                                               ANGLE_D3D_WORKAROUND_NONE, &mGeometryExecutable);
+        if (error.isError())
+        {
+            return gl::LinkResult(false, error);
+        }
     }
 
-    return (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable));
+    bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable));
+    return gl::LinkResult(linkSuccess, gl::Error(GL_NO_ERROR));
 }
 
-bool ProgramD3D::link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                      const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
-                      int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
-                      std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps)
+gl::LinkResult ProgramD3D::link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
+                                int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
+                                std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps)
 {
     ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
     ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
 
     mTransformFeedbackBufferMode = transformFeedbackBufferMode;
 
     mPixelHLSL = fragmentShaderD3D->getTranslatedSource();
     mPixelWorkarounds = fragmentShaderD3D->getD3DWorkarounds();
@@ -510,34 +556,34 @@ bool ProgramD3D::link(gl::InfoLog &infoL
     mShaderVersion = vertexShaderD3D->getShaderVersion();
 
     // Map the varyings to the register file
     VaryingPacking packing = { NULL };
     *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings);
 
     if (*registers < 0)
     {
-        return false;
+        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
     if (!gl::ProgramBinary::linkVaryings(infoLog, fragmentShader, vertexShader))
     {
-        return false;
+        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
     if (!mDynamicHLSL->generateShaderLinkHLSL(infoLog, *registers, packing, mPixelHLSL, mVertexHLSL,
                                               fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings,
                                               linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth))
     {
-        return false;
+        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
     mUsesPointSize = vertexShaderD3D->usesPointSize();
 
-    return true;
+    return gl::LinkResult(true, gl::Error(GL_NO_ERROR));
 }
 
 void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const
 {
     mDynamicHLSL->getInputLayoutSignature(inputLayout, signature);
 }
 
 void ProgramD3D::initializeUniformStorage(const std::vector<gl::LinkedUniform*> &uniforms)
--- a/gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h
@@ -42,31 +42,31 @@ class ProgramD3D : public ProgramImpl
     std::vector<gl::LinkedVarying> &getTransformFeedbackLinkedVaryings() { return mTransformFeedbackLinkedVaryings; }
     sh::Attribute *getShaderAttributes() { return mShaderAttributes; }
 
     bool usesPointSize() const { return mUsesPointSize; }
     bool usesPointSpriteEmulation() const;
     bool usesGeometryShader() const;
 
     GLenum getBinaryFormat() { return GL_PROGRAM_BINARY_ANGLE; }
-    bool load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream);
-    bool save(gl::BinaryOutputStream *stream);
+    gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream);
+    gl::Error save(gl::BinaryOutputStream *stream);
 
-    ShaderExecutable *getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo);
-    ShaderExecutable *getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout);
-    ShaderExecutable *getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]);
+    gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutable **outExectuable);
+    gl::Error getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout, ShaderExecutable **outExectuable);
+    gl::Error getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutable **outExectuable);
     ShaderExecutable *getGeometryExecutable() const { return mGeometryExecutable; }
 
-    bool compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                   int registers);
+    gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                             int registers);
 
-    bool link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-              const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
-              int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
-              std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps);
+    gl::LinkResult link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                        const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
+                        int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
+                        std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps);
 
     void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const;
 
     void initializeUniformStorage(const std::vector<gl::LinkedUniform*> &uniforms);
     gl::Error applyUniforms(const std::vector<gl::LinkedUniform*> &uniforms);
     gl::Error applyUniformBuffers(const std::vector<gl::UniformBlock*> uniformBlocks, const std::vector<gl::Buffer*> boundBuffers,
                              const gl::Caps &caps);
     bool assignUniformBlockRegister(gl::InfoLog &infoLog, gl::UniformBlock *uniformBlock, GLenum shader,
--- a/gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp
@@ -85,81 +85,117 @@ GLint TextureD3D::getBaseLevelDepth() co
 // where in the base of 2D array textures and cube maps there are several. Don't use
 // the base level image for anything except querying texture format and size.
 GLenum TextureD3D::getBaseLevelInternalFormat() const
 {
     const Image *baseImage = getBaseLevelImage();
     return (baseImage ? baseImage->getInternalFormat() : GL_NONE);
 }
 
-gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image)
+gl::Error TextureD3D::setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index)
 {
+    Image *image = getImage(index);
+
     // No-op
     if (image->getWidth() == 0 || image->getHeight() == 0 || image->getDepth() == 0)
     {
         return gl::Error(GL_NO_ERROR);
     }
 
     // We no longer need the "GLenum format" parameter to TexImage to determine what data format "pixels" contains.
     // From our image internal format we know how many channels to expect, and "type" gives the format of pixel's components.
-    const void *pixelData = pixels;
+    const uint8_t *pixelData = NULL;
 
     if (unpack.pixelBuffer.id() != 0)
     {
         // Do a CPU readback here, if we have an unpack buffer bound and the fast GPU path is not supported
         gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
         ptrdiff_t offset = reinterpret_cast<ptrdiff_t>(pixels);
         // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
         // This functionality should be moved into renderer and the getData method of BufferImpl removed.
         const void *bufferData = pixelBuffer->getImplementation()->getData();
-        pixelData = static_cast<const unsigned char *>(bufferData) + offset;
+        pixelData = static_cast<const uint8_t *>(bufferData) + offset;
+    }
+    else
+    {
+        pixelData = static_cast<const uint8_t *>(pixels);
     }
 
     if (pixelData != NULL)
     {
-        gl::Error error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
+        gl::Error error(GL_NO_ERROR);
+
+        gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
+
+        // TODO(jmadill): Handle compressed internal formats
+        if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
+        {
+            gl::Box sourceBox(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth());
+            error = mTexStorage->setData(index, sourceBox, image->getInternalFormat(), type, unpack, pixelData);
+        }
+        else
+        {
+            error = image->loadData(0, 0, 0, image->getWidth(), image->getHeight(), image->getDepth(), unpack.alignment, type, pixelData);
+        }
+
         if (error.isError())
         {
             return error;
         }
 
         mDirtyImages = true;
     }
 
     return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error TextureD3D::subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index)
 {
-    const void *pixelData = pixels;
+    const uint8_t *pixelData = static_cast<const uint8_t *>(pixels);
 
     // CPU readback & copy where direct GPU copy is not supported
     if (unpack.pixelBuffer.id() != 0)
     {
         gl::Buffer *pixelBuffer = unpack.pixelBuffer.get();
         uintptr_t offset = reinterpret_cast<uintptr_t>(pixels);
         // TODO: setImage/subImage is the only place outside of renderer that asks for a buffers raw data.
         // This functionality should be moved into renderer and the getData method of BufferImpl removed.
         const void *bufferData = pixelBuffer->getImplementation()->getData();
-        pixelData = static_cast<const unsigned char *>(bufferData) + offset;
+        pixelData = static_cast<const uint8_t *>(bufferData)+offset;
     }
 
     if (pixelData != NULL)
     {
         Image *image = getImage(index);
         ASSERT(image);
 
+        gl::InternalFormat internalFormat = gl::GetInternalFormatInfo(image->getInternalFormat());
+        gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
+
+        // TODO(jmadill): Handle compressed internal formats
+        if (mTexStorage && mRenderer->getWorkarounds().setDataFasterThanImageUpload && !internalFormat.compressed)
+        {
+            return mTexStorage->setData(index, region, image->getInternalFormat(),
+                                        type, unpack, pixelData);
+        }
+
         gl::Error error = image->loadData(xoffset, yoffset, zoffset, width, height, depth, unpack.alignment,
                                           type, pixelData);
         if (error.isError())
         {
             return error;
         }
 
+        error = commitRegion(index, region);
+        if (error.isError())
+        {
+            return error;
+        }
+
         mDirtyImages = true;
     }
 
     return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error TextureD3D::setCompressedImage(GLsizei imageSize, const void *pixels, Image *image)
 {
@@ -249,41 +285,67 @@ TextureStorage *TextureD3D::getStorage()
 
 Image *TextureD3D::getBaseLevelImage() const
 {
     return getImage(getImageIndex(0, 0));
 }
 
 void TextureD3D::generateMipmaps()
 {
-    // Set up proper image sizes.
+    GLint mipCount = mipLevels();
+
+    if (mipCount == 1)
+    {
+        return; // no-op
+    }
+
+    // Set up proper mipmap chain in our Image array.
     initMipmapsImages();
 
     // We know that all layers have the same dimension, for the texture to be complete
     GLint layerCount = static_cast<GLint>(getLayerCount(0));
-    GLint mipCount = mipLevels();
-
-    // The following will create and initialize the storage, or update it if it exists
-    TextureStorage *storage = getNativeTexture();
-
-    bool renderableStorage = (storage && storage->isRenderTarget());
+
+    // When making mipmaps with the setData workaround enabled, the texture storage has
+    // the image data already. For non-render-target storage, we have to pull it out into
+    // an image layer.
+    if (mRenderer->getWorkarounds().setDataFasterThanImageUpload && mTexStorage)
+    {
+        if (!mTexStorage->isRenderTarget())
+        {
+            // Copy from the storage mip 0 to Image mip 0
+            for (GLint layer = 0; layer < layerCount; ++layer)
+            {
+                gl::ImageIndex srcIndex = getImageIndex(0, layer);
+
+                Image *image = getImage(srcIndex);
+                gl::Rectangle area(0, 0, image->getWidth(), image->getHeight());
+                image->copy(0, 0, 0, area, srcIndex, mTexStorage);
+            }
+        }
+        else
+        {
+            updateStorage();
+        }
+    }
+
+    bool renderableStorage = (mTexStorage && mTexStorage->isRenderTarget());
 
     for (GLint layer = 0; layer < layerCount; ++layer)
     {
         for (GLint mip = 1; mip < mipCount; ++mip)
         {
             ASSERT(getLayerCount(mip) == layerCount);
 
             gl::ImageIndex sourceIndex = getImageIndex(mip - 1, layer);
             gl::ImageIndex destIndex = getImageIndex(mip, layer);
 
             if (renderableStorage)
             {
                 // GPU-side mipmapping
-                storage->generateMipmap(sourceIndex, destIndex);
+                mTexStorage->generateMipmap(sourceIndex, destIndex);
             }
             else
             {
                 // CPU-side mipmapping
                 mRenderer->generateMipmap(getImage(destIndex), getImage(sourceIndex));
             }
         }
     }
@@ -427,21 +489,21 @@ gl::Error TextureD3D_2D::setImage(GLenum
     ASSERT(target == GL_TEXTURE_2D && depth == 1);
 
     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
 
     bool fastUnpacked = false;
 
     redefineImage(level, sizedInternalFormat, width, height);
 
+    gl::ImageIndex index = gl::ImageIndex::Make2D(level);
+
     // Attempt a fast gpu copy of the pixel data to the surface
     if (isFastUnpackable(unpack, sizedInternalFormat) && isLevelComplete(level))
     {
-        gl::ImageIndex index = gl::ImageIndex::Make2D(level);
-
         // Will try to create RT storage if it does not exist
         RenderTarget *destRenderTarget = getRenderTarget(index);
         gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), 1);
 
         if (destRenderTarget)
         {
             gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
             if (error.isError())
@@ -453,17 +515,17 @@ gl::Error TextureD3D_2D::setImage(GLenum
             mImageArray[level]->markClean();
 
             fastUnpacked = true;
         }
     }
 
     if (!fastUnpacked)
     {
-        gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
+        gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
         if (error.isError())
         {
             return error;
         }
     }
 
     return gl::Error(GL_NO_ERROR);
 }
@@ -484,20 +546,20 @@ gl::Error TextureD3D_2D::subImage(GLenum
                                   GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
                                   const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
 
     bool fastUnpacked = false;
 
     gl::ImageIndex index = gl::ImageIndex::Make2D(level);
+    gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
     if (isFastUnpackable(unpack, getInternalFormat(level)) && isLevelComplete(level))
     {
         RenderTarget *renderTarget = getRenderTarget(index);
-        gl::Box destArea(xoffset, yoffset, 0, width, height, 1);
 
         if (renderTarget)
         {
             gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, renderTarget);
             if (error.isError())
             {
                 return error;
             }
@@ -506,29 +568,18 @@ gl::Error TextureD3D_2D::subImage(GLenum
             mImageArray[level]->markClean();
 
             fastUnpacked = true;
         }
     }
 
     if (!fastUnpacked)
     {
-        gl::ImageIndex index = gl::ImageIndex::Make2D(level);
-        gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack,
-                                               pixels, index);
-        if (error.isError())
-        {
-            return error;
-        }
-
-        error = commitRect(level, xoffset, yoffset, width, height);
-        if (error.isError())
-        {
-            return error;
-        }
+        return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type,
+                                    unpack, pixels, index);
     }
 
     return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error TextureD3D_2D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                             GLsizei width, GLsizei height, GLsizei depth, GLenum format,
                                             GLsizei imageSize, const void *pixels)
@@ -536,82 +587,70 @@ gl::Error TextureD3D_2D::subImageCompres
     ASSERT(target == GL_TEXTURE_2D && depth == 1 && zoffset == 0);
 
     gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[level]);
     if (error.isError())
     {
         return error;
     }
 
-    error = commitRect(level, xoffset, yoffset, width, height);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    return gl::Error(GL_NO_ERROR);
+    gl::ImageIndex index = gl::ImageIndex::Make2D(level);
+    gl::Box region(xoffset, yoffset, 0, width, height, 1);
+    return commitRegion(index, region);
 }
 
 void TextureD3D_2D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     ASSERT(target == GL_TEXTURE_2D);
 
     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
     redefineImage(level, sizedInternalFormat, width, height);
 
+    gl::Rectangle sourceRect(x, y, width, height);
+
     if (!mImageArray[level]->isRenderableFormat())
     {
-        mImageArray[level]->copy(0, 0, 0, x, y, width, height, source);
+        mImageArray[level]->copy(0, 0, 0, sourceRect, source);
         mDirtyImages = true;
     }
     else
     {
         ensureRenderTarget();
         mImageArray[level]->markClean();
 
         if (width != 0 && height != 0 && isValidLevel(level))
         {
-            gl::Rectangle sourceRect;
-            sourceRect.x = x;
-            sourceRect.width = width;
-            sourceRect.y = y;
-            sourceRect.height = height;
-
             mRenderer->copyImage2D(source, sourceRect, format, 0, 0, mTexStorage, level);
         }
     }
 }
 
 void TextureD3D_2D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     ASSERT(target == GL_TEXTURE_2D && zoffset == 0);
 
     // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
     // the current level we're copying to is defined (with appropriate format, width & height)
     bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
 
+    gl::Rectangle sourceRect(x, y, width, height);
+
     if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
     {
-        mImageArray[level]->copy(xoffset, yoffset, 0, x, y, width, height, source);
+        mImageArray[level]->copy(xoffset, yoffset, 0, sourceRect, source);
         mDirtyImages = true;
     }
     else
     {
         ensureRenderTarget();
 
         if (isValidLevel(level))
         {
             updateStorageLevel(level);
 
-            gl::Rectangle sourceRect;
-            sourceRect.x = x;
-            sourceRect.width = width;
-            sourceRect.y = y;
-            sourceRect.height = height;
-
             mRenderer->copyImage2D(source, sourceRect,
                                    gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
                                    xoffset, yoffset, mTexStorage, level);
         }
     }
 }
 
 void TextureD3D_2D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
@@ -816,17 +855,19 @@ void TextureD3D_2D::updateStorage()
 
 void TextureD3D_2D::updateStorageLevel(int level)
 {
     ASSERT(level <= (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
     ASSERT(isLevelComplete(level));
 
     if (mImageArray[level]->isDirty())
     {
-        commitRect(level, 0, 0, getWidth(level), getHeight(level));
+        gl::ImageIndex index = gl::ImageIndex::Make2D(level);
+        gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
+        commitRegion(index, region);
     }
 }
 
 void TextureD3D_2D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height)
 {
     // If there currently is a corresponding storage texture image, it has these parameters
     const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
     const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
@@ -849,22 +890,25 @@ void TextureD3D_2D::redefineImage(GLint 
             }
 
             SafeDelete(mTexStorage);
             mDirtyImages = true;
         }
     }
 }
 
-gl::Error TextureD3D_2D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+gl::Error TextureD3D_2D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
 {
+    ASSERT(!index.hasLayer());
+    GLint level = index.mipIndex;
+
     if (isValidLevel(level))
     {
         ImageD3D *image = mImageArray[level];
-        gl::Error error = image->copyToStorage2D(mTexStorage, level, xoffset, yoffset, width, height);
+        gl::Error error = image->copyToStorage2D(mTexStorage, index, region);
         if (error.isError())
         {
             return error;
         }
 
         image->markClean();
     }
 
@@ -944,22 +988,22 @@ bool TextureD3D_Cube::isDepth(GLint leve
 }
 
 gl::Error TextureD3D_Cube::setImage(GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth,
                                     GLenum internalFormat, GLenum format, GLenum type, const gl::PixelUnpackState &unpack,
                                     const void *pixels)
 {
     ASSERT(depth == 1);
 
-    int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
-
-    redefineImage(faceIndex, level, sizedInternalFormat, width, height);
-
-    return TextureD3D::setImage(unpack, type, pixels, mImageArray[faceIndex][level]);
+    gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
+
+    redefineImage(index.layerIndex, level, sizedInternalFormat, width, height);
+
+    return TextureD3D::setImage(unpack, type, pixels, index);
 }
 
 gl::Error TextureD3D_Cube::setCompressedImage(GLenum target, GLint level, GLenum format,
                                               GLsizei width, GLsizei height, GLsizei depth,
                                               GLsizei imageSize, const void *pixels)
 {
     ASSERT(depth == 1);
 
@@ -971,119 +1015,90 @@ gl::Error TextureD3D_Cube::setCompressed
     return TextureD3D::setCompressedImage(imageSize, pixels, mImageArray[faceIndex][level]);
 }
 
 gl::Error TextureD3D_Cube::subImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                     GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type,
                                     const gl::PixelUnpackState &unpack, const void *pixels)
 {
     ASSERT(depth == 1 && zoffset == 0);
-
-    int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
-
     gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
-    gl::Error error = TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels,
-                                           index);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    return gl::Error(GL_NO_ERROR);
+    return TextureD3D::subImage(xoffset, yoffset, 0, width, height, 1, format, type, unpack, pixels, index);
 }
 
 gl::Error TextureD3D_Cube::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                               GLsizei width, GLsizei height, GLsizei depth, GLenum format,
                                               GLsizei imageSize, const void *pixels)
 {
     ASSERT(depth == 1 && zoffset == 0);
 
-    int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
-
-    gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[faceIndex][level]);
+    gl::ImageIndex index = gl::ImageIndex::MakeCube(target, level);
+
+    gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, 0, width, height, 1, format, imageSize, pixels, mImageArray[index.layerIndex][level]);
     if (error.isError())
     {
         return error;
     }
 
-    error = commitRect(faceIndex, level, xoffset, yoffset, width, height);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    return gl::Error(GL_NO_ERROR);
+    gl::Box region(xoffset, yoffset, 0, width, height, 1);
+    return commitRegion(index, region);
 }
 
 void TextureD3D_Cube::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(format, GL_UNSIGNED_BYTE);
 
     redefineImage(faceIndex, level, sizedInternalFormat, width, height);
 
+    gl::Rectangle sourceRect(x, y, width, height);
+
     if (!mImageArray[faceIndex][level]->isRenderableFormat())
     {
-        mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
+        mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
         mDirtyImages = true;
     }
     else
     {
         ensureRenderTarget();
         mImageArray[faceIndex][level]->markClean();
 
         ASSERT(width == height);
 
         if (width > 0 && isValidFaceLevel(faceIndex, level))
         {
-            gl::Rectangle sourceRect;
-            sourceRect.x = x;
-            sourceRect.width = width;
-            sourceRect.y = y;
-            sourceRect.height = height;
-
             mRenderer->copyImageCube(source, sourceRect, format, 0, 0, mTexStorage, target, level);
         }
     }
 }
 
 void TextureD3D_Cube::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     int faceIndex = gl::TextureCubeMap::targetToLayerIndex(target);
 
     // We can only make our texture storage to a render target if the level we're copying *to* is complete
     // and the base level is cube-complete. The base level must be cube complete (common case) because we cannot
     // rely on the "getBaseLevel*" methods reliably otherwise.
     bool canCreateRenderTarget = isFaceLevelComplete(faceIndex, level) && isCubeComplete();
 
+    gl::Rectangle sourceRect(x, y, width, height);
+
     if (!mImageArray[faceIndex][level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
     {
-        mImageArray[faceIndex][level]->copy(0, 0, 0, x, y, width, height, source);
+        mImageArray[faceIndex][level]->copy(0, 0, 0, sourceRect, source);
         mDirtyImages = true;
     }
     else
     {
         ensureRenderTarget();
 
         if (isValidFaceLevel(faceIndex, level))
         {
             updateStorageFaceLevel(faceIndex, level);
 
-            gl::Rectangle sourceRect;
-            sourceRect.x = x;
-            sourceRect.width = width;
-            sourceRect.y = y;
-            sourceRect.height = height;
-
             mRenderer->copyImageCube(source, sourceRect, gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
                                      xoffset, yoffset, mTexStorage, target, level);
         }
     }
 }
 
 void TextureD3D_Cube::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
 {
@@ -1302,17 +1317,20 @@ bool TextureD3D_Cube::isFaceLevelComplet
 
 void TextureD3D_Cube::updateStorageFaceLevel(int faceIndex, int level)
 {
     ASSERT(level >= 0 && faceIndex < 6 && level < (int)ArraySize(mImageArray[faceIndex]) && mImageArray[faceIndex][level] != NULL);
     ImageD3D *image = mImageArray[faceIndex][level];
 
     if (image->isDirty())
     {
-        commitRect(faceIndex, level, 0, 0, image->getWidth(), image->getHeight());
+        GLenum faceTarget = gl::TextureCubeMap::layerIndexToTarget(faceIndex);
+        gl::ImageIndex index = gl::ImageIndex::MakeCube(faceTarget, level);
+        gl::Box region(0, 0, 0, image->getWidth(), image->getHeight(), 1);
+        commitRegion(index, region);
     }
 }
 
 void TextureD3D_Cube::redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height)
 {
     // If there currently is a corresponding storage texture image, it has these parameters
     const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
     const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
@@ -1339,22 +1357,27 @@ void TextureD3D_Cube::redefineImage(int 
 
             SafeDelete(mTexStorage);
 
             mDirtyImages = true;
         }
     }
 }
 
-gl::Error TextureD3D_Cube::commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+gl::Error TextureD3D_Cube::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
 {
+    ASSERT(index.hasLayer());
+
+    GLint level = index.mipIndex;
+    int faceIndex = static_cast<int>(index.layerIndex);
+
     if (isValidFaceLevel(faceIndex, level))
     {
         ImageD3D *image = mImageArray[faceIndex][level];
-        gl::Error error = image->copyToStorageCube(mTexStorage, faceIndex, level, xoffset, yoffset, width, height);
+        gl::Error error = image->copyToStorageCube(mTexStorage, index, region);
         if (error.isError())
         {
             return error;
         }
 
         image->markClean();
     }
 
@@ -1458,21 +1481,22 @@ gl::Error TextureD3D_3D::setImage(GLenum
 {
     ASSERT(target == GL_TEXTURE_3D);
     GLenum sizedInternalFormat = gl::GetSizedInternalFormat(internalFormat, type);
 
     redefineImage(level, sizedInternalFormat, width, height, depth);
 
     bool fastUnpacked = false;
 
+    gl::ImageIndex index = gl::ImageIndex::Make3D(level);
+
     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
     if (isFastUnpackable(unpack, sizedInternalFormat))
     {
         // Will try to create RT storage if it does not exist
-        gl::ImageIndex index = gl::ImageIndex::Make3D(level);
         RenderTarget *destRenderTarget = getRenderTarget(index);
         gl::Box destArea(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
 
         if (destRenderTarget)
         {
             gl::Error error = fastUnpackPixels(unpack, pixels, destArea, sizedInternalFormat, type, destRenderTarget);
             if (error.isError())
             {
@@ -1483,17 +1507,17 @@ gl::Error TextureD3D_3D::setImage(GLenum
             mImageArray[level]->markClean();
 
             fastUnpacked = true;
         }
     }
 
     if (!fastUnpacked)
     {
-        gl::Error error = TextureD3D::setImage(unpack, type, pixels, mImageArray[level]);
+        gl::Error error = TextureD3D::setImage(unpack, type, pixels, index);
         if (error.isError())
         {
             return error;
         }
     }
 
     return gl::Error(GL_NO_ERROR);
 }
@@ -1519,48 +1543,37 @@ gl::Error TextureD3D_3D::subImage(GLenum
     bool fastUnpacked = false;
 
     gl::ImageIndex index = gl::ImageIndex::Make3D(level);
 
     // Attempt a fast gpu copy of the pixel data to the surface if the app bound an unpack buffer
     if (isFastUnpackable(unpack, getInternalFormat(level)))
     {
         RenderTarget *destRenderTarget = getRenderTarget(index);
-        gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
 
         if (destRenderTarget)
         {
+            gl::Box destArea(xoffset, yoffset, zoffset, width, height, depth);
             gl::Error error = fastUnpackPixels(unpack, pixels, destArea, getInternalFormat(level), type, destRenderTarget);
             if (error.isError())
             {
                 return error;
             }
 
             // Ensure we don't overwrite our newly initialized data
             mImageArray[level]->markClean();
 
             fastUnpacked = true;
         }
     }
 
     if (!fastUnpacked)
     {
-        gl::ImageIndex index = gl::ImageIndex::Make3D(level);
-        gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type, unpack,
-                                               pixels, index);
-        if (error.isError())
-        {
-            return error;
-        }
-
-        error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
-        if (error.isError())
-        {
-            return error;
-        }
+        return TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, depth, format, type,
+                                    unpack, pixels, index);
     }
 
     return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error TextureD3D_3D::subImageCompressed(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset,
                                             GLsizei width, GLsizei height, GLsizei depth, GLenum format,
                                             GLsizei imageSize, const void *pixels)
@@ -1569,57 +1582,49 @@ gl::Error TextureD3D_3D::subImageCompres
 
     gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, depth,
                                                      format, imageSize, pixels, mImageArray[level]);
     if (error.isError())
     {
         return error;
     }
 
-    error = commitRect(level, xoffset, yoffset, zoffset, width, height, depth);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    return gl::Error(GL_NO_ERROR);
+    gl::ImageIndex index = gl::ImageIndex::Make3D(level);
+    gl::Box region(xoffset, yoffset, zoffset, width, height, depth);
+    return commitRegion(index, region);
 }
 
 void TextureD3D_3D::copyImage(GLenum target, GLint level, GLenum format, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     UNIMPLEMENTED();
 }
 
 void TextureD3D_3D::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     ASSERT(target == GL_TEXTURE_3D);
 
     // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
     // the current level we're copying to is defined (with appropriate format, width & height)
     bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
 
+    gl::Rectangle sourceRect(x, y, width, height);
+
     if (!mImageArray[level]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
     {
-        mImageArray[level]->copy(xoffset, yoffset, zoffset, x, y, width, height, source);
+        mImageArray[level]->copy(xoffset, yoffset, zoffset, sourceRect, source);
         mDirtyImages = true;
     }
     else
     {
         ensureRenderTarget();
 
         if (isValidLevel(level))
         {
             updateStorageLevel(level);
 
-            gl::Rectangle sourceRect;
-            sourceRect.x = x;
-            sourceRect.width = width;
-            sourceRect.y = y;
-            sourceRect.height = height;
-
             mRenderer->copyImage3D(source, sourceRect,
                                    gl::GetInternalFormatInfo(getBaseLevelInternalFormat()).format,
                                    xoffset, yoffset, zoffset, mTexStorage, level);
         }
     }
 }
 
 void TextureD3D_3D::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
@@ -1811,17 +1816,19 @@ bool TextureD3D_3D::isLevelComplete(int 
 
 void TextureD3D_3D::updateStorageLevel(int level)
 {
     ASSERT(level >= 0 && level < (int)ArraySize(mImageArray) && mImageArray[level] != NULL);
     ASSERT(isLevelComplete(level));
 
     if (mImageArray[level]->isDirty())
     {
-        commitRect(level, 0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
+        gl::ImageIndex index = gl::ImageIndex::Make3D(level);
+        gl::Box region(0, 0, 0, getWidth(level), getHeight(level), getDepth(level));
+        commitRegion(index, region);
     }
 }
 
 void TextureD3D_3D::redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
 {
     // If there currently is a corresponding storage texture image, it has these parameters
     const int storageWidth = std::max(1, getBaseLevelWidth() >> level);
     const int storageHeight = std::max(1, getBaseLevelHeight() >> level);
@@ -1846,22 +1853,25 @@ void TextureD3D_3D::redefineImage(GLint 
             }
 
             SafeDelete(mTexStorage);
             mDirtyImages = true;
         }
     }
 }
 
-gl::Error TextureD3D_3D::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
+gl::Error TextureD3D_3D::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
 {
+    ASSERT(!index.hasLayer());
+    GLint level = index.mipIndex;
+
     if (isValidLevel(level))
     {
         ImageD3D *image = mImageArray[level];
-        gl::Error error = image->copyToStorage3D(mTexStorage, level, xoffset, yoffset, zoffset, width, height, depth);
+        gl::Error error = image->copyToStorage3D(mTexStorage, index, region);
         if (error.isError())
         {
             return error;
         }
 
         image->markClean();
     }
 
@@ -1951,17 +1961,18 @@ gl::Error TextureD3D_2DArray::setImage(G
     redefineImage(level, sizedInternalFormat, width, height, depth);
 
     const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedInternalFormat);
     GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
 
     for (int i = 0; i < depth; i++)
     {
         const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
-        gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, mImageArray[level][i]);
+        gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, i);
+        gl::Error error = TextureD3D::setImage(unpack, type, layerPixels, index);
         if (error.isError())
         {
             return error;
         }
     }
 
     return gl::Error(GL_NO_ERROR);
 }
@@ -2001,24 +2012,18 @@ gl::Error TextureD3D_2DArray::subImage(G
     GLsizei inputDepthPitch = formatInfo.computeDepthPitch(type, width, height, unpack.alignment);
 
     for (int i = 0; i < depth; i++)
     {
         int layer = zoffset + i;
         const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
 
         gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
-        gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type, unpack,
-                                               layerPixels, index);
-        if (error.isError())
-        {
-            return error;
-        }
-
-        error = commitRect(level, xoffset, yoffset, layer, width, height);
+        gl::Error error = TextureD3D::subImage(xoffset, yoffset, zoffset, width, height, 1, format, type,
+                                               unpack, layerPixels, index);
         if (error.isError())
         {
             return error;
         }
     }
 
     return gl::Error(GL_NO_ERROR);
 }
@@ -2038,17 +2043,19 @@ gl::Error TextureD3D_2DArray::subImageCo
         const void *layerPixels = pixels ? (reinterpret_cast<const unsigned char*>(pixels) + (inputDepthPitch * i)) : NULL;
 
         gl::Error error = TextureD3D::subImageCompressed(xoffset, yoffset, zoffset, width, height, 1, format, imageSize, layerPixels, mImageArray[level][layer]);
         if (error.isError())
         {
             return error;
         }
 
-        error = commitRect(level, xoffset, yoffset, layer, width, height);
+        gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
+        gl::Box region(xoffset, yoffset, 0, width, height, 1);
+        error = commitRegion(index, region);
         if (error.isError())
         {
             return error;
         }
     }
 
     return gl::Error(GL_NO_ERROR);
 }
@@ -2061,35 +2068,31 @@ void TextureD3D_2DArray::copyImage(GLenu
 void TextureD3D_2DArray::copySubImage(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
 {
     ASSERT(target == GL_TEXTURE_2D_ARRAY);
 
     // can only make our texture storage to a render target if level 0 is defined (with a width & height) and
     // the current level we're copying to is defined (with appropriate format, width & height)
     bool canCreateRenderTarget = isLevelComplete(level) && isLevelComplete(0);
 
+    gl::Rectangle sourceRect(x, y, width, height);
+
     if (!mImageArray[level][0]->isRenderableFormat() || (!mTexStorage && !canCreateRenderTarget))
     {
-        mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, x, y, width, height, source);
+        mImageArray[level][zoffset]->copy(xoffset, yoffset, 0, sourceRect, source);
         mDirtyImages = true;
     }
     else
     {
         ensureRenderTarget();
 
         if (isValidLevel(level))
         {
             updateStorageLevel(level);
 
-            gl::Rectangle sourceRect;
-            sourceRect.x = x;
-            sourceRect.width = width;
-            sourceRect.y = y;
-            sourceRect.height = height;
-
             mRenderer->copyImage2DArray(source, sourceRect, gl::GetInternalFormatInfo(getInternalFormat(0)).format,
                                         xoffset, yoffset, zoffset, mTexStorage, level);
         }
     }
 }
 
 void TextureD3D_2DArray::storage(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
 {
@@ -2285,17 +2288,19 @@ void TextureD3D_2DArray::updateStorageLe
     ASSERT(level >= 0 && level < (int)ArraySize(mLayerCounts));
     ASSERT(isLevelComplete(level));
 
     for (int layer = 0; layer < mLayerCounts[level]; layer++)
     {
         ASSERT(mImageArray[level] != NULL && mImageArray[level][layer] != NULL);
         if (mImageArray[level][layer]->isDirty())
         {
-            commitRect(level, 0, 0, layer, getWidth(level), getHeight(level));
+            gl::ImageIndex index = gl::ImageIndex::Make2DArray(level, layer);
+            gl::Box region(0, 0, 0, getWidth(level), getHeight(level), 1);
+            commitRegion(index, region);
         }
     }
 }
 
 void TextureD3D_2DArray::deleteImages()
 {
     for (int level = 0; level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; ++level)
     {
@@ -2356,22 +2361,26 @@ void TextureD3D_2DArray::redefineImage(G
 
             delete mTexStorage;
             mTexStorage = NULL;
             mDirtyImages = true;
         }
     }
 }
 
-gl::Error TextureD3D_2DArray::commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height)
+gl::Error TextureD3D_2DArray::commitRegion(const gl::ImageIndex &index, const gl::Box &region)
 {
+    ASSERT(index.hasLayer());
+    GLint level = index.mipIndex;
+    GLint layerTarget = index.layerIndex;
+
     if (isValidLevel(level) && layerTarget < getLayerCount(level))
     {
         ImageD3D *image = mImageArray[level][layerTarget];
-        gl::Error error = image->copyToStorage2DArray(mTexStorage, level, xoffset, yoffset, layerTarget, width, height);
+        gl::Error error = image->copyToStorage2DArray(mTexStorage, index, region);
         if (error.isError())
         {
             return error;
         }
 
         image->markClean();
     }
 
--- a/gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.h
@@ -58,17 +58,17 @@ class TextureD3D : public TextureImpl
     // slices of their depth texures, so 3D textures ignore the layer parameter.
     virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const = 0;
 
     virtual void generateMipmaps();
     TextureStorage *getStorage();
     Image *getBaseLevelImage() const;
 
   protected:
-    gl::Error setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, Image *image);
+    gl::Error setImage(const gl::PixelUnpackState &unpack, GLenum type, const void *pixels, const gl::ImageIndex &index);
     gl::Error subImage(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                        GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const void *pixels, const gl::ImageIndex &index);
     gl::Error setCompressedImage(GLsizei imageSize, const void *pixels, Image *image);
     gl::Error subImageCompressed(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                  GLenum format, GLsizei imageSize, const void *pixels, Image *image);
     bool isFastUnpackable(const gl::PixelUnpackState &unpack, GLenum sizedInternalFormat);
     gl::Error fastUnpackPixels(const gl::PixelUnpackState &unpack, const void *pixels, const gl::Box &destArea,
                                GLenum sizedInternalFormat, GLenum type, RenderTarget *destRenderTarget);
@@ -77,16 +77,17 @@ class TextureD3D : public TextureImpl
     int mipLevels() const;
     virtual void initMipmapsImages() = 0;
     bool isBaseImageZeroSize() const;
 
     virtual bool ensureRenderTarget();
 
     virtual TextureStorage *createCompleteStorage(bool renderTarget) const = 0;
     virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage) = 0;
+    virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region) = 0;
 
     Renderer *mRenderer;
 
     GLenum mUsage;
 
     bool mDirtyImages;
 
     bool mImmutable;
@@ -134,27 +135,27 @@ class TextureD3D_2D : public TextureD3D
     virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
 
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureD3D_2D);
 
     virtual void initializeStorage(bool renderTarget);
     virtual TextureStorage *createCompleteStorage(bool renderTarget) const;
     virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
+    gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region);
 
     virtual void updateStorage();
     virtual void initMipmapsImages();
 
     bool isValidLevel(int level) const;
     bool isLevelComplete(int level) const;
 
     void updateStorageLevel(int level);
 
     void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height);
-    gl::Error commitRect(GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
 
     ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
 };
 
 class TextureD3D_Cube : public TextureD3D
 {
   public:
     TextureD3D_Cube(Renderer *renderer);
@@ -189,27 +190,27 @@ class TextureD3D_Cube : public TextureD3
     virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
 
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureD3D_Cube);
 
     virtual void initializeStorage(bool renderTarget);
     virtual TextureStorage *createCompleteStorage(bool renderTarget) const;
     virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
+    virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region);
 
     virtual void updateStorage();
     virtual void initMipmapsImages();
 
     bool isValidFaceLevel(int faceIndex, int level) const;
     bool isFaceLevelComplete(int faceIndex, int level) const;
     bool isCubeComplete() const;
     void updateStorageFaceLevel(int faceIndex, int level);
 
     void redefineImage(int faceIndex, GLint level, GLenum internalformat, GLsizei width, GLsizei height);
-    gl::Error commitRect(int faceIndex, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
 
     ImageD3D *mImageArray[6][gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
 };
 
 class TextureD3D_3D : public TextureD3D
 {
   public:
     TextureD3D_3D(Renderer *renderer);
@@ -243,26 +244,26 @@ class TextureD3D_3D : public TextureD3D
     virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
 
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureD3D_3D);
 
     virtual void initializeStorage(bool renderTarget);
     virtual TextureStorage *createCompleteStorage(bool renderTarget) const;
     virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
+    virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region);
 
     virtual void updateStorage();
     virtual void initMipmapsImages();
 
     bool isValidLevel(int level) const;
     bool isLevelComplete(int level) const;
     void updateStorageLevel(int level);
 
     void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
-    gl::Error commitRect(GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
 
     ImageD3D *mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
 };
 
 class TextureD3D_2DArray : public TextureD3D
 {
   public:
     TextureD3D_2DArray(Renderer *renderer);
@@ -295,27 +296,27 @@ class TextureD3D_2DArray : public Textur
     virtual gl::ImageIndex getImageIndex(GLint mip, GLint layer) const;
 
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureD3D_2DArray);
 
     virtual void initializeStorage(bool renderTarget);
     virtual TextureStorage *createCompleteStorage(bool renderTarget) const;
     virtual void setCompleteTexStorage(TextureStorage *newCompleteTexStorage);
+    virtual gl::Error commitRegion(const gl::ImageIndex &index, const gl::Box &region);
 
     virtual void updateStorage();
     virtual void initMipmapsImages();
 
     bool isValidLevel(int level) const;
     bool isLevelComplete(int level) const;
     void updateStorageLevel(int level);
 
     void deleteImages();
     void redefineImage(GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
-    gl::Error commitRect(GLint level, GLint xoffset, GLint yoffset, GLint layerTarget, GLsizei width, GLsizei height);
 
     // Storing images as an array of single depth textures since D3D11 treats each array level of a
     // Texture2D object as a separate subresource.  Each layer would have to be looped over
     // to update all the texture layers since they cannot all be updated at once and it makes the most
     // sense for the Image class to not have to worry about layer subresource as well as mip subresources.
     GLsizei mLayerCounts[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
     ImageD3D **mImageArray[gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS];
 };
--- a/gfx/angle/src/libGLESv2/renderer/d3d/TextureStorage.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/TextureStorage.h
@@ -8,20 +8,23 @@
 
 #ifndef LIBGLESV2_RENDERER_TEXTURESTORAGE_H_
 #define LIBGLESV2_RENDERER_TEXTURESTORAGE_H_
 
 #include "common/debug.h"
 #include "libGLESv2/Error.h"
 
 #include <GLES2/gl2.h>
+#include <cstdint>
 
 namespace gl
 {
 struct ImageIndex;
+struct Box;
+struct PixelUnpackState;
 }
 
 namespace rx
 {
 class Renderer;
 class SwapChain;
 class RenderTarget;
 
@@ -35,16 +38,18 @@ class TextureStorage
     virtual bool isRenderTarget() const = 0;
     virtual bool isManaged() const = 0;
     virtual int getLevelCount() const = 0;
 
     virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0;
     virtual void generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0;
 
     virtual gl::Error copyToStorage(TextureStorage *destStorage) = 0;
+    virtual gl::Error setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type,
+                              const gl::PixelUnpackState &unpack, const uint8_t *pixelData) = 0;
 
     unsigned int getRenderTargetSerial(const gl::ImageIndex &index) const;
     unsigned int getTextureSerial() const;
 
   protected:
     void initializeSerials(unsigned int rtSerialsToReserve, unsigned int rtSerialsLayerStride);
 
   private:
--- a/gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp
@@ -9,16 +9,17 @@
 
 #include "libGLESv2/renderer/d3d/VertexDataManager.h"
 #include "libGLESv2/renderer/d3d/BufferD3D.h"
 #include "libGLESv2/renderer/d3d/VertexBuffer.h"
 #include "libGLESv2/renderer/Renderer.h"
 #include "libGLESv2/Buffer.h"
 #include "libGLESv2/ProgramBinary.h"
 #include "libGLESv2/VertexAttribute.h"
+#include "libGLESv2/State.h"
 
 namespace
 {
     enum { INITIAL_STREAM_BUFFER_SIZE = 1024*1024 };
     // This has to be at least 4k or else it fails on ATI cards.
     enum { CONSTANT_VERTEX_BUFFER_SIZE = 4096 };
 }
 
@@ -77,90 +78,95 @@ VertexDataManager::~VertexDataManager()
     delete mStreamingBuffer;
 
     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     {
         delete mCurrentValueBuffer[i];
     }
 }
 
-gl::Error VertexDataManager::prepareVertexData(const gl::VertexAttribute attribs[], const gl::VertexAttribCurrentValueData currentValues[],
-                                               gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *translated, GLsizei instances)
+gl::Error VertexDataManager::prepareVertexData(const gl::State &state, GLint start, GLsizei count,
+                                               TranslatedAttribute *translated, GLsizei instances)
 {
     if (!mStreamingBuffer)
     {
         return gl::Error(GL_OUT_OF_MEMORY, "Internal streaming vertex buffer is unexpectedly NULL.");
     }
 
     // Invalidate static buffers that don't contain matching attributes
     for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
     {
-        translated[attributeIndex].active = (programBinary->getSemanticIndex(attributeIndex) != -1);
+        translated[attributeIndex].active = (state.getCurrentProgramBinary()->getSemanticIndex(attributeIndex) != -1);
+        const gl::VertexAttribute &curAttrib = state.getVertexAttribState(attributeIndex);
 
-        if (translated[attributeIndex].active && attribs[attributeIndex].enabled)
+        if (translated[attributeIndex].active && curAttrib.enabled)
         {
-            invalidateMatchingStaticData(attribs[attributeIndex], currentValues[attributeIndex]);
+            invalidateMatchingStaticData(curAttrib, state.getVertexAttribCurrentValue(attributeIndex));
         }
     }
 
     // Reserve the required space in the buffers
     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     {
-        if (translated[i].active && attribs[i].enabled)
+        const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i);
+        if (translated[i].active && curAttrib.enabled)
         {
-            gl::Error error = reserveSpaceForAttrib(attribs[i], currentValues[i], count, instances);
+            gl::Error error = reserveSpaceForAttrib(curAttrib, state.getVertexAttribCurrentValue(i), count, instances);
             if (error.isError())
             {
                 return error;
             }
         }
     }
 
     // Perform the vertex data translations
     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     {
+        const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i);
         if (translated[i].active)
         {
-            if (attribs[i].enabled)
+            if (curAttrib.enabled)
             {
-                gl::Error error = storeAttribute(attribs[i], currentValues[i], &translated[i],
-                                                 start, count, instances);
+                gl::Error error = storeAttribute(curAttrib, state.getVertexAttribCurrentValue(i),
+                                                 &translated[i], start, count, instances);
+
                 if (error.isError())
                 {
                     return error;
                 }
             }
             else
             {
                 if (!mCurrentValueBuffer[i])
                 {
                     mCurrentValueBuffer[i] = new StreamingVertexBufferInterface(mRenderer, CONSTANT_VERTEX_BUFFER_SIZE);
                 }
 
-                gl::Error error = storeCurrentValue(attribs[i], currentValues[i], &translated[i],
+                gl::Error error = storeCurrentValue(curAttrib, state.getVertexAttribCurrentValue(i), &translated[i],
                                                     &mCurrentValue[i], &mCurrentValueOffsets[i],
                                                     mCurrentValueBuffer[i]);
                 if (error.isError())
                 {
                     return error;
                 }
             }
         }
     }
 
     for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++)
     {
-        if (translated[i].active && attribs[i].enabled)
+        const gl::VertexAttribute &curAttrib = state.getVertexAttribState(i);
+        if (translated[i].active && curAttrib.enabled)
         {
-            gl::Buffer *buffer = attribs[i].buffer.get();
+            gl::Buffer *buffer = curAttrib.buffer.get();
 
             if (buffer)
             {
                 BufferD3D *bufferImpl = BufferD3D::makeBufferD3D(buffer->getImplementation());
-                bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(attribs[i]));
+                bufferImpl->promoteStaticUsage(count * ComputeVertexAttributeTypeSize(curAttrib));
             }
         }
     }
 
     return gl::Error(GL_NO_ERROR);
 }
 
 void VertexDataManager::invalidateMatchingStaticData(const gl::VertexAttribute &attrib,
--- a/gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h
@@ -11,18 +11,19 @@
 #define LIBGLESV2_RENDERER_VERTEXDATAMANAGER_H_
 
 #include "libGLESv2/Constants.h"
 #include "libGLESv2/VertexAttribute.h"
 #include "common/angleutils.h"
 
 namespace gl
 {
+class ProgramBinary;
+class State;
 struct VertexAttribute;
-class ProgramBinary;
 struct VertexAttribCurrentValueData;
 }
 
 namespace rx
 {
 class BufferD3D;
 class StreamingVertexBufferInterface;
 class VertexBuffer;
@@ -47,18 +48,18 @@ struct TranslatedAttribute
 };
 
 class VertexDataManager
 {
   public:
     VertexDataManager(rx::Renderer *renderer);
     virtual ~VertexDataManager();
 
-    gl::Error prepareVertexData(const gl::VertexAttribute attribs[], const gl::VertexAttribCurrentValueData currentValues[],
-                                gl::ProgramBinary *programBinary, GLint start, GLsizei count, TranslatedAttribute *outAttribs, GLsizei instances);
+    gl::Error prepareVertexData(const gl::State &state, GLint start, GLsizei count,
+                                TranslatedAttribute *outAttribs, GLsizei instances);
 
   private:
     DISALLOW_COPY_AND_ASSIGN(VertexDataManager);
 
     gl::Error reserveSpaceForAttrib(const gl::VertexAttribute &attrib,
                                     const gl::VertexAttribCurrentValueData &currentValue,
                                     GLsizei count,
                                     GLsizei instances) const;
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
@@ -4,38 +4,40 @@
 // found in the LICENSE file.
 //
 
 // Image11.h: Implements the rx::Image11 class, which acts as the interface to
 // the actual underlying resources of a Texture
 
 #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
 #include "libGLESv2/renderer/d3d/d3d11/Image11.h"
+#include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h"
 #include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h"
 #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
 #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
 #include "libGLESv2/Framebuffer.h"
 #include "libGLESv2/FramebufferAttachment.h"
 #include "libGLESv2/main.h"
 
 #include "common/utilities.h"
 
 namespace rx
 {
 
 Image11::Image11()
+    : mRenderer(NULL),
+      mDXGIFormat(DXGI_FORMAT_UNKNOWN),
+      mStagingTexture(NULL),
+      mStagingSubresource(0),
+      mRecoverFromStorage(false),
+      mAssociatedStorage(NULL),
+      mAssociatedImageIndex(gl::ImageIndex::MakeInvalid()),
+      mRecoveredFromStorageCount(0)
+
 {
-    mStagingTexture = NULL;
-    mRenderer = NULL;
-    mDXGIFormat = DXGI_FORMAT_UNKNOWN;
-    mRecoverFromStorage = false;
-    mAssociatedStorage = NULL;
-    mAssociatedStorageLevel = 0;
-    mAssociatedStorageLayerTarget = 0;
-    mRecoveredFromStorageCount = 0;
 }
 
 Image11::~Image11()
 {
     disassociateStorage();
     releaseStagingTexture();
 }
 
@@ -94,96 +96,96 @@ bool Image11::isDirty() const
     if (mDirty && !mStagingTexture && !mRecoverFromStorage && !(d3d11::GetTextureFormatInfo(mInternalFormat).dataInitializerFunction != NULL))
     {
         return false;
     }
 
     return mDirty;
 }
 
-gl::Error Image11::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+gl::Error Image11::copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
 {
-    TextureStorage11_2D *storage11 = TextureStorage11_2D::makeTextureStorage11_2D(storage);
-    return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height);
+    TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage);
+    return copyToStorageImpl(storage11, index, region);
 }
 
-gl::Error Image11::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+gl::Error Image11::copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
 {
-    TextureStorage11_Cube *storage11 = TextureStorage11_Cube::makeTextureStorage11_Cube(storage);
-    return copyToStorageImpl(storage11, level, face, xoffset, yoffset, width, height);
+    TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage);
+    return copyToStorageImpl(storage11, index, region);
 }
 
-gl::Error Image11::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
+gl::Error Image11::copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
 {
-    TextureStorage11_3D *storage11 = TextureStorage11_3D::makeTextureStorage11_3D(storage);
-    return copyToStorageImpl(storage11, level, 0, xoffset, yoffset, width, height);
+    TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage);
+    return copyToStorageImpl(storage11, index, region);
 }
 
-gl::Error Image11::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height)
+gl::Error Image11::copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
 {
-    TextureStorage11_2DArray *storage11 = TextureStorage11_2DArray::makeTextureStorage11_2DArray(storage);
-    return copyToStorageImpl(storage11, level, arrayLayer, xoffset, yoffset, width, height);
+    TextureStorage11 *storage11 = TextureStorage11::makeTextureStorage11(storage);
+    return copyToStorageImpl(storage11, index, region);
 }
 
-gl::Error Image11::copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+gl::Error Image11::copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box &region)
 {
     // If an app's behavior results in an Image11 copying its data to/from to a TextureStorage multiple times,
     // then we should just keep the staging texture around to prevent the copying from impacting perf.
     // We allow the Image11 to copy its data to/from TextureStorage once.
     // This accounts for an app making a late call to glGenerateMipmap.
     bool attemptToReleaseStagingTexture = (mRecoveredFromStorageCount < 2);
 
     if (attemptToReleaseStagingTexture)
     {
         // If another image is relying on this Storage for its data, then we must let it recover its data before we overwrite it.
-        storage11->releaseAssociatedImage(level, layerTarget, this);
+        storage11->releaseAssociatedImage(index, this);
     }
 
-    gl::Error error = storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(), level, layerTarget,
-                                                        xoffset, yoffset, 0, width, height, 1);
+    gl::Error error = storage11->updateSubresourceLevel(getStagingTexture(), getStagingSubresource(),
+                                                        index, region);
     if (error.isError())
     {
         return error;
     }
 
     // Once the image data has been copied into the Storage, we can release it locally.
     if (attemptToReleaseStagingTexture)
     {
-        storage11->associateImage(this, level, layerTarget);
+        storage11->associateImage(this, index);
         releaseStagingTexture();
         mRecoverFromStorage = true;
         mAssociatedStorage = storage11;
-        mAssociatedStorageLevel = level;
-        mAssociatedStorageLayerTarget = layerTarget;
+        mAssociatedImageIndex = index;
     }
 
     return gl::Error(GL_NO_ERROR);
 }
 
 bool Image11::isAssociatedStorageValid(TextureStorage11* textureStorage) const
 {
     return (mAssociatedStorage == textureStorage);
 }
 
 bool Image11::recoverFromAssociatedStorage()
 {
     if (mRecoverFromStorage)
     {
         createStagingTexture();
 
-        bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this);
+        bool textureStorageCorrect = mAssociatedStorage->isAssociatedImageValid(mAssociatedImageIndex, this);
 
         // This means that the cached TextureStorage has been modified after this Image11 released its copy of its data. 
         // This should not have happened. The TextureStorage should have told this Image11 to recover its data before it was overwritten.
         ASSERT(textureStorageCorrect);
 
         if (textureStorageCorrect)
         {
             // CopySubResource from the Storage to the Staging texture
-            mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedStorageLevel, mAssociatedStorageLayerTarget, 0, 0, 0, mWidth, mHeight, mDepth);
+            gl::Box region(0, 0, 0, mWidth, mHeight, mDepth);
+            mAssociatedStorage->copySubresourceLevel(mStagingTexture, mStagingSubresource, mAssociatedImageIndex, region);
             mRecoveredFromStorageCount += 1;
         }
 
         // Reset all the recovery parameters, even if the texture storage association is broken.
         disassociateStorage();
 
         return textureStorageCorrect;
     }
@@ -191,22 +193,21 @@ bool Image11::recoverFromAssociatedStora
     return false;
 }
 
 void Image11::disassociateStorage()
 {
     if (mRecoverFromStorage)
     {
         // Make the texturestorage release the Image11 too
-        mAssociatedStorage->disassociateImage(mAssociatedStorageLevel, mAssociatedStorageLayerTarget, this);
+        mAssociatedStorage->disassociateImage(mAssociatedImageIndex, this);
 
         mRecoverFromStorage = false;
         mAssociatedStorage = NULL;
-        mAssociatedStorageLevel = 0;
-        mAssociatedStorageLayerTarget = 0;
+        mAssociatedImageIndex = gl::ImageIndex::MakeInvalid();
     }
 }
 
 bool Image11::redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease)
 {
     if (mWidth != width ||
         mHeight != height ||
         mInternalFormat != internalformat ||
@@ -315,78 +316,110 @@ gl::Error Image11::loadCompressedData(GL
                  reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch,
                  offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch);
 
     unmap();
 
     return gl::Error(GL_NO_ERROR);
 }
 
-void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
+{
+    RenderTarget11 *sourceRenderTarget = RenderTarget11::makeRenderTarget11(source);
+    ASSERT(sourceRenderTarget->getTexture());
+
+    UINT subresourceIndex = sourceRenderTarget->getSubresourceIndex();
+    ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(sourceRenderTarget->getTexture());
+
+    if (!sourceTexture2D)
+    {
+        // Error already generated
+        return;
+    }
+
+    copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex);
+
+    SafeRelease(sourceTexture2D);
+}
+
+void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, const gl::ImageIndex &sourceIndex, TextureStorage *source)
 {
-    gl::FramebufferAttachment *colorbuffer = source->getReadColorbuffer();
+    TextureStorage11 *sourceStorage11 = TextureStorage11::makeTextureStorage11(source);
+
+    UINT subresourceIndex = sourceStorage11->getSubresourceIndex(sourceIndex);
+    ID3D11Texture2D *sourceTexture2D = d3d11::DynamicCastComObject<ID3D11Texture2D>(sourceStorage11->getResource());
+
+    if (!sourceTexture2D)
+    {
+        // Error already generated
+        return;
+    }
 
-    if (colorbuffer && colorbuffer->getActualFormat() == mActualFormat)
+    copy(xoffset, yoffset, zoffset, sourceArea, sourceTexture2D, subresourceIndex);
+
+    SafeRelease(sourceTexture2D);
+}
+
+void Image11::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource)
+{
+    D3D11_TEXTURE2D_DESC textureDesc;
+    source->GetDesc(&textureDesc);
+
+    if (textureDesc.Format == mDXGIFormat)
     {
         // No conversion needed-- use copyback fastpath
-        ID3D11Texture2D *colorBufferTexture = NULL;
-        unsigned int subresourceIndex = 0;
+        ID3D11Device *device = mRenderer->getDevice();
+        ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
 
-        if (mRenderer->getRenderTargetResource(colorbuffer, &subresourceIndex, &colorBufferTexture))
+        UINT subresourceAfterResolve = sourceSubResource;
+
+        ID3D11Texture2D* srcTex = NULL;
+        if (textureDesc.SampleDesc.Count > 1)
         {
-            D3D11_TEXTURE2D_DESC textureDesc;
-            colorBufferTexture->GetDesc(&textureDesc);
+            D3D11_TEXTURE2D_DESC resolveDesc;
+            resolveDesc.Width = textureDesc.Width;
+            resolveDesc.Height = textureDesc.Height;
+            resolveDesc.MipLevels = 1;
+            resolveDesc.ArraySize = 1;
+            resolveDesc.Format = textureDesc.Format;
+            resolveDesc.SampleDesc.Count = 1;
+            resolveDesc.SampleDesc.Quality = 0;
+            resolveDesc.Usage = D3D11_USAGE_DEFAULT;
+            resolveDesc.BindFlags = 0;
+            resolveDesc.CPUAccessFlags = 0;
+            resolveDesc.MiscFlags = 0;
 
-            ID3D11Device *device = mRenderer->getDevice();
-            ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext();
-
-            ID3D11Texture2D* srcTex = NULL;
-            if (textureDesc.SampleDesc.Count > 1)
+            HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
+            if (FAILED(result))
             {
-                D3D11_TEXTURE2D_DESC resolveDesc;
-                resolveDesc.Width = textureDesc.Width;
-                resolveDesc.Height = textureDesc.Height;
-                resolveDesc.MipLevels = 1;
-                resolveDesc.ArraySize = 1;
-                resolveDesc.Format = textureDesc.Format;
-                resolveDesc.SampleDesc.Count = 1;
-                resolveDesc.SampleDesc.Quality = 0;
-                resolveDesc.Usage = D3D11_USAGE_DEFAULT;
-                resolveDesc.BindFlags = 0;
-                resolveDesc.CPUAccessFlags = 0;
-                resolveDesc.MiscFlags = 0;
-
-                HRESULT result = device->CreateTexture2D(&resolveDesc, NULL, &srcTex);
-                if (FAILED(result))
-                {
-                    ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
-                    return;
-                }
-
-                deviceContext->ResolveSubresource(srcTex, 0, colorBufferTexture, subresourceIndex, textureDesc.Format);
-                subresourceIndex = 0;
-            }
-            else
-            {
-                srcTex = colorBufferTexture;
-                srcTex->AddRef();
+                ERR("Failed to create resolve texture for Image11::copy, HRESULT: 0x%X.", result);
+                return;
             }
 
-            D3D11_BOX srcBox;
-            srcBox.left = x;
-            srcBox.right = x + width;
-            srcBox.top = y;
-            srcBox.bottom = y + height;
-            srcBox.front = 0;
-            srcBox.back = 1;
+            deviceContext->ResolveSubresource(srcTex, 0, source, sourceSubResource, textureDesc.Format);
+            subresourceAfterResolve = 0;
+        }
+        else
+        {
+            srcTex = source;
+        }
 
-            deviceContext->CopySubresourceRegion(mStagingTexture, 0, xoffset, yoffset, zoffset, srcTex, subresourceIndex, &srcBox);
+        D3D11_BOX srcBox;
+        srcBox.left = sourceArea.x;
+        srcBox.right = sourceArea.x + sourceArea.width;
+        srcBox.top = sourceArea.y;
+        srcBox.bottom = sourceArea.y + sourceArea.height;
+        srcBox.front = 0;
+        srcBox.back = 1;
 
+        deviceContext->CopySubresourceRegion(getStagingTexture(), 0, xoffset, yoffset, zoffset, srcTex, subresourceAfterResolve, &srcBox);
+
+        if (textureDesc.SampleDesc.Count > 1)
+        {
             SafeRelease(srcTex);
-            SafeRelease(colorBufferTexture);
         }
     }
     else
     {
         // This format requires conversion, so we must copy the texture to staging and manually convert via readPixels
         D3D11_MAPPED_SUBRESOURCE mappedImage;
         HRESULT result = map(D3D11_MAP_WRITE, &mappedImage);
         if (FAILED(result))
@@ -396,20 +429,22 @@ void Image11::copy(GLint xoffset, GLint 
         }
 
         // determine the offset coordinate into the destination buffer
         GLsizei rowOffset = gl::GetInternalFormatInfo(mActualFormat).pixelBytes * xoffset;
         uint8_t *dataOffset = static_cast<uint8_t*>(mappedImage.pData) + mappedImage.RowPitch * yoffset + rowOffset + zoffset * mappedImage.DepthPitch;
 
         const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat);
 
-        mRenderer->readPixels(source, x, y, width, height, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
+        mRenderer->readTextureData(source, sourceSubResource, sourceArea, formatInfo.format, formatInfo.type, mappedImage.RowPitch, gl::PixelPackState(), dataOffset);
 
         unmap();
     }
+
+    mDirty = true;
 }
 
 ID3D11Resource *Image11::getStagingTexture()
 {
     createStagingTexture();
 
     return mStagingTexture;
 }
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h
@@ -6,16 +6,17 @@
 
 // Image11.h: Defines the rx::Image11 class, which acts as the interface to
 // the actual underlying resources of a Texture
 
 #ifndef LIBGLESV2_RENDERER_IMAGE11_H_
 #define LIBGLESV2_RENDERER_IMAGE11_H_
 
 #include "libGLESv2/renderer/d3d/ImageD3D.h"
+#include "libGLESv2/ImageIndex.h"
 
 #include "common/debug.h"
 
 namespace gl
 {
 class Framebuffer;
 }
 
@@ -32,58 +33,60 @@ class Image11 : public ImageD3D
     virtual ~Image11();
 
     static Image11 *makeImage11(Image *img);
 
     static void generateMipmap(Image11 *dest, Image11 *src);
 
     virtual bool isDirty() const;
 
-    virtual gl::Error copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
-    virtual gl::Error copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
-    virtual gl::Error copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
-    virtual gl::Error copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint arrayLayer, GLsizei width, GLsizei height);
+    virtual gl::Error copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
+    virtual gl::Error copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
+    virtual gl::Error copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
+    virtual gl::Error copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
 
     virtual bool redefine(Renderer *renderer, GLenum target, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool forceRelease);
 
     DXGI_FORMAT getDXGIFormat() const;
 
     virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                GLint unpackAlignment, GLenum type, const void *input);
     virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                          const void *input);
 
-    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source);
+    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
+                      const gl::ImageIndex &sourceIndex, TextureStorage *source);
 
     bool recoverFromAssociatedStorage();
     bool isAssociatedStorageValid(TextureStorage11* textureStorage) const;
     void disassociateStorage();
 
   protected:
     HRESULT map(D3D11_MAP mapType, D3D11_MAPPED_SUBRESOURCE *map);
     void unmap();
 
   private:
     DISALLOW_COPY_AND_ASSIGN(Image11);
 
-    gl::Error copyToStorageImpl(TextureStorage11 *storage11, int level, int layerTarget, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
+    gl::Error copyToStorageImpl(TextureStorage11 *storage11, const gl::ImageIndex &index, const gl::Box &region);
+    void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, ID3D11Texture2D *source, UINT sourceSubResource);
 
     ID3D11Resource *getStagingTexture();
     unsigned int getStagingSubresource();
     void createStagingTexture();
     void releaseStagingTexture();
 
     Renderer11 *mRenderer;
 
     DXGI_FORMAT mDXGIFormat;
     ID3D11Resource *mStagingTexture;
     unsigned int mStagingSubresource;
 
     bool mRecoverFromStorage;
     TextureStorage11 *mAssociatedStorage;
-    int mAssociatedStorageLevel;
-    int mAssociatedStorageLayerTarget;
+    gl::ImageIndex mAssociatedImageIndex;
     unsigned int mRecoveredFromStorageCount;
 };
 
 }
 
 #endif // LIBGLESV2_RENDERER_IMAGE11_H_
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp
@@ -134,25 +134,33 @@ gl::Error InputLayoutCache::applyVertexB
         inputLayout = keyIter->second.inputLayout;
         keyIter->second.lastUsedTime = mCounter++;
     }
     else
     {
         gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
         GetInputLayout(attributes, shaderInputLayout);
         ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
-        ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programD3D->getVertexExecutableForInputLayout(shaderInputLayout));
+
+        ShaderExecutable *shader = NULL;
+        gl::Error error = programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader);
+        if (error.isError())
+        {
+            return error;
+        }
+
+        ShaderExecutable *shader11 = ShaderExecutable11::makeShaderExecutable11(shader);
 
         D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
         for (unsigned int j = 0; j < ilKey.elementCount; ++j)
         {
             descs[j] = ilKey.elements[j].desc;
         }
 
-        HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader->getFunction(), shader->getLength(), &inputLayout);
+        HRESULT result = mDevice->CreateInputLayout(descs, ilKey.elementCount, shader11->getFunction(), shader11->getLength(), &inputLayout);
         if (FAILED(result))
         {
             return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal input layout, HRESULT: 0x%08x", result);
         }
 
         if (mInputLayoutMap.size() >= kMaxInputLayouts)
         {
             TRACE("Overflowed the limit of %u input layouts, removing the least recently used "
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
@@ -6,16 +6,17 @@
 
 // Renderer11.cpp: Implements a back-end specific class for the D3D11 renderer.
 
 #include "libGLESv2/main.h"
 #include "libGLESv2/Buffer.h"
 #include "libGLESv2/FramebufferAttachment.h"
 #include "libGLESv2/ProgramBinary.h"
 #include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/State.h"
 #include "libGLESv2/renderer/d3d/ProgramD3D.h"
 #include "libGLESv2/renderer/d3d/ShaderD3D.h"
 #include "libGLESv2/renderer/d3d/TextureD3D.h"
 #include "libGLESv2/renderer/d3d/TransformFeedbackD3D.h"
 #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
 #include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h"
 #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
 #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
@@ -934,27 +935,26 @@ gl::Error Renderer11::applyRenderTarget(
         mDepthStencilInitialized = true;
     }
 
     invalidateFramebufferSwizzles(framebuffer);
 
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error Renderer11::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[],
-                                        GLint first, GLsizei count, GLsizei instances)
+gl::Error Renderer11::applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances)
 {
     TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS];
-    gl::Error error = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances);
+    gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances);
     if (error.isError())
     {
         return error;
     }
 
-    return mInputLayoutCache.applyVertexBuffers(attributes, programBinary);
+    return mInputLayoutCache.applyVertexBuffers(attributes, state.getCurrentProgramBinary());
 }
 
 gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
 {
     gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo);
     if (error.isError())
     {
         return error;
@@ -981,51 +981,65 @@ gl::Error Renderer11::applyIndexBuffer(c
         mAppliedIB = buffer;
         mAppliedIBFormat = bufferFormat;
         mAppliedIBOffset = indexInfo->startOffset;
     }
 
     return gl::Error(GL_NO_ERROR);
 }
 
-void Renderer11::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[])
+void Renderer11::applyTransformFeedbackBuffers(const gl::State& state)
 {
-    ID3D11Buffer* d3dBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
-    UINT d3dOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
+    size_t numXFBBindings = state.getTransformFeedbackBufferIndexRange();
+    ASSERT(numXFBBindings <= gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS);
+
     bool requiresUpdate = false;
-    for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+    for (size_t i = 0; i < numXFBBindings; i++)
     {
-        if (transformFeedbackBuffers[i])
+        gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i);
+        GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i);
+        ID3D11Buffer *d3dBuffer = NULL;
+        if (curXFBBuffer)
         {
-            Buffer11 *storage = Buffer11::makeBuffer11(transformFeedbackBuffers[i]->getImplementation());
-            ID3D11Buffer *buffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
-
-            d3dBuffers[i] = buffer;
-            d3dOffsets[i] = (mAppliedTFBuffers[i] != buffer) ? static_cast<UINT>(offsets[i]) : -1;
+            Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation());
+            d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
         }
-        else
-        {
-            d3dBuffers[i] = NULL;
-            d3dOffsets[i] = 0;
-        }
-
-        if (d3dBuffers[i] != mAppliedTFBuffers[i] || offsets[i] != mAppliedTFOffsets[i])
+
+        // TODO: mAppliedTFBuffers and friends should also be kept in a vector.
+        if (d3dBuffer != mAppliedTFBuffers[i] || curXFBOffset != mAppliedTFOffsets[i])
         {
             requiresUpdate = true;
         }
     }
 
     if (requiresUpdate)
     {
-        mDeviceContext->SOSetTargets(ArraySize(d3dBuffers), d3dBuffers, d3dOffsets);
-        for (size_t i = 0; i < gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS; i++)
+        for (size_t i = 0; i < numXFBBindings; ++i)
         {
-            mAppliedTFBuffers[i] = d3dBuffers[i];
-            mAppliedTFOffsets[i] = offsets[i];
+            gl::Buffer *curXFBBuffer = state.getIndexedTransformFeedbackBuffer(i);
+            GLintptr curXFBOffset = state.getIndexedTransformFeedbackBufferOffset(i);
+
+            if (curXFBBuffer)
+            {
+                Buffer11 *storage = Buffer11::makeBuffer11(curXFBBuffer->getImplementation());
+                ID3D11Buffer *d3dBuffer = storage->getBuffer(BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK);
+
+                mCurrentD3DOffsets[i] = (mAppliedTFBuffers[i] != d3dBuffer && mAppliedTFOffsets[i] != curXFBOffset) ?
+                                        static_cast<UINT>(curXFBOffset) : -1;
+                mAppliedTFBuffers[i] = d3dBuffer;
+            }
+            else
+            {
+                mAppliedTFBuffers[i] = NULL;
+                mCurrentD3DOffsets[i] = 0;
+            }
+            mAppliedTFOffsets[i] = curXFBOffset;
         }
+
+        mDeviceContext->SOSetTargets(numXFBBindings, mAppliedTFBuffers, mCurrentD3DOffsets);
     }
 }
 
 gl::Error Renderer11::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive)
 {
     if (mode == GL_POINTS && transformFeedbackActive)
     {
         // Since point sprites are generated with a geometry shader, too many vertices will
@@ -1325,18 +1339,31 @@ gl::Error Renderer11::drawTriangleFan(GL
 
     return gl::Error(GL_NO_ERROR);
 }
 
 gl::Error Renderer11::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive)
 {
     ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
-    ShaderExecutable *vertexExe = programD3D->getVertexExecutableForInputLayout(inputLayout);
-    ShaderExecutable *pixelExe = programD3D->getPixelExecutableForFramebuffer(framebuffer);
+
+    ShaderExecutable *vertexExe = NULL;
+    gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    ShaderExecutable *pixelExe = NULL;
+    error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe);
+    if (error.isError())
+    {
+        return error;
+    }
+
     ShaderExecutable *geometryExe = programD3D->getGeometryExecutable();
 
     ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL);
 
     ID3D11PixelShader *pixelShader = NULL;
     // Skip pixel shader if we're doing rasterizer discard.
     if (!rasterizerDiscard)
     {
@@ -2182,32 +2209,33 @@ ProgramImpl *Renderer11::createProgram()
     return new ProgramD3D(this);
 }
 
 void Renderer11::releaseShaderCompiler()
 {
     ShaderD3D::releaseCompiler();
 }
 
-ShaderExecutable *Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type,
-                                             const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                             bool separatedOutputBuffers)
+gl::Error Renderer11::loadExecutable(const void *function, size_t length, rx::ShaderType type,
+                                     const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                     bool separatedOutputBuffers, ShaderExecutable **outExecutable)
 {
-    ShaderExecutable11 *executable = NULL;
-    HRESULT result;
-
     switch (type)
     {
       case rx::SHADER_VERTEX:
         {
             ID3D11VertexShader *vertexShader = NULL;
             ID3D11GeometryShader *streamOutShader = NULL;
 
-            result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader);
+            HRESULT result = mDevice->CreateVertexShader(function, length, NULL, &vertexShader);
             ASSERT(SUCCEEDED(result));
+            if (FAILED(result))
+            {
+                return gl::Error(GL_OUT_OF_MEMORY, "Failed to create vertex shader, result: 0x%X.", result);
+            }
 
             if (transformFeedbackVaryings.size() > 0)
             {
                 std::vector<D3D11_SO_DECLARATION_ENTRY> soDeclaration;
                 for (size_t i = 0; i < transformFeedbackVaryings.size(); i++)
                 {
                     const gl::LinkedVarying &varying = transformFeedbackVaryings[i];
                     GLenum transposedType = gl::TransposeMatrixType(varying.type);
@@ -2223,77 +2251,81 @@ ShaderExecutable *Renderer11::loadExecut
                         entry.OutputSlot = (separatedOutputBuffers ? i : 0);
                         soDeclaration.push_back(entry);
                     }
                 }
 
                 result = mDevice->CreateGeometryShaderWithStreamOutput(function, length, soDeclaration.data(), soDeclaration.size(),
                                                                        NULL, 0, 0, NULL, &streamOutShader);
                 ASSERT(SUCCEEDED(result));
+                if (FAILED(result))
+                {
+                    return gl::Error(GL_OUT_OF_MEMORY, "Failed to create steam output shader, result: 0x%X.", result);
+                }
             }
 
-            if (vertexShader)
-            {
-                executable = new ShaderExecutable11(function, length, vertexShader, streamOutShader);
-            }
+            *outExecutable = new ShaderExecutable11(function, length, vertexShader, streamOutShader);
         }
         break;
       case rx::SHADER_PIXEL:
         {
             ID3D11PixelShader *pixelShader = NULL;
 
-            result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader);
+            HRESULT result = mDevice->CreatePixelShader(function, length, NULL, &pixelShader);
             ASSERT(SUCCEEDED(result));
-
-            if (pixelShader)
+            if (FAILED(result))
             {
-                executable = new ShaderExecutable11(function, length, pixelShader);
+                return gl::Error(GL_OUT_OF_MEMORY, "Failed to create pixel shader, result: 0x%X.", result);
             }
+
+            *outExecutable = new ShaderExecutable11(function, length, pixelShader);
         }
         break;
       case rx::SHADER_GEOMETRY:
         {
             ID3D11GeometryShader *geometryShader = NULL;
 
-            result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader);
+            HRESULT result = mDevice->CreateGeometryShader(function, length, NULL, &geometryShader);
             ASSERT(SUCCEEDED(result));
-
-            if (geometryShader)
+            if (FAILED(result))
             {
-                executable = new ShaderExecutable11(function, length, geometryShader);
+                return gl::Error(GL_OUT_OF_MEMORY, "Failed to create geometry shader, result: 0x%X.", result);
             }
+
+            *outExecutable = new ShaderExecutable11(function, length, geometryShader);
         }
         break;
       default:
         UNREACHABLE();
-        break;
+        return gl::Error(GL_INVALID_OPERATION);
     }
 
-    return executable;
+    return gl::Error(GL_NO_ERROR);
 }
 
-ShaderExecutable *Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
-                                                  const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                                  bool separatedOutputBuffers, D3DWorkaroundType workaround)
+gl::Error Renderer11::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
+                                          const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                          bool separatedOutputBuffers, D3DWorkaroundType workaround,
+                                          ShaderExecutable **outExectuable)
 {
     const char *profileType = NULL;
     switch (type)
     {
       case rx::SHADER_VERTEX:
         profileType = "vs";
         break;
       case rx::SHADER_PIXEL:
         profileType = "ps";
         break;
       case rx::SHADER_GEOMETRY:
         profileType = "gs";
         break;
       default:
         UNREACHABLE();
-        return NULL;
+        return gl::Error(GL_INVALID_OPERATION);
     }
 
     unsigned int profileMajorVersion = 0;
     unsigned int profileMinorVersion = 0;
     switch (mFeatureLevel)
     {
       case D3D_FEATURE_LEVEL_11_0:
         profileMajorVersion = 5;
@@ -2304,17 +2336,17 @@ ShaderExecutable *Renderer11::compileToE
         profileMinorVersion = 1;
         break;
       case D3D_FEATURE_LEVEL_10_0:
         profileMajorVersion = 4;
         profileMinorVersion = 0;
         break;
       default:
         UNREACHABLE();
-        return NULL;
+        return gl::Error(GL_INVALID_OPERATION);
     }
 
     std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion);
 
     UINT flags = D3DCOMPILE_OPTIMIZATION_LEVEL0;
 
     if (gl::perfActive())
     {
@@ -2327,27 +2359,40 @@ ShaderExecutable *Renderer11::compileToE
 
     // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options.
     // Try the default flags first and if compilation fails, try some alternatives.
     std::vector<CompileConfig> configs;
     configs.push_back(CompileConfig(flags,                                "default"          ));
     configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_VALIDATION,   "skip validation"  ));
     configs.push_back(CompileConfig(flags | D3DCOMPILE_SKIP_OPTIMIZATION, "skip optimization"));
 
-    ID3DBlob *binary = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs);
+    ID3DBlob *binary = NULL;
+    gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, &binary);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    // It's possible that binary is NULL if the compiler failed in all configurations.  Set the executable to NULL
+    // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK.
     if (!binary)
     {
-        return NULL;
+        *outExectuable = NULL;
+        return gl::Error(GL_NO_ERROR);
     }
 
-    ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
-                                                  transformFeedbackVaryings, separatedOutputBuffers);
+    error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
+                           transformFeedbackVaryings, separatedOutputBuffers, outExectuable);
     SafeRelease(binary);
-
-    return executable;
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 rx::UniformStorage *Renderer11::createUniformStorage(size_t storageSize)
 {
     return new UniformStorage11(this, storageSize);
 }
 
 VertexBuffer *Renderer11::createVertexBuffer()
@@ -2422,50 +2467,32 @@ bool Renderer11::supportsFastCopyBufferT
 
 gl::Error Renderer11::fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget,
                                               GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea)
 {
     ASSERT(supportsFastCopyBufferToTexture(destinationFormat));
     return mPixelTransfer->copyBufferToTexture(unpack, offset, destRenderTarget, destinationFormat, sourcePixelsType, destArea);
 }
 
-bool Renderer11::getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource)
+bool Renderer11::getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, ID3D11Texture2D **texture2DOut)
 {
     ASSERT(colorbuffer != NULL);
 
     RenderTarget11 *renderTarget = d3d11::GetAttachmentRenderTarget(colorbuffer);
-    if (renderTarget)
+    if (!renderTarget)
     {
-        *subresourceIndex = renderTarget->getSubresourceIndex();
-
-        ID3D11RenderTargetView *colorBufferRTV = renderTarget->getRenderTargetView();
-        if (colorBufferRTV)
-        {
-            ID3D11Resource *textureResource = NULL;
-            colorBufferRTV->GetResource(&textureResource);
-
-            if (textureResource)
-            {
-                HRESULT result = textureResource->QueryInterface(__uuidof(ID3D11Texture2D), (void**)resource);
-                SafeRelease(textureResource);
-
-                if (SUCCEEDED(result))
-                {
-                    return true;
-                }
-                else
-                {
-                    ERR("Failed to extract the ID3D11Texture2D from the render target resource, "
-                        "HRESULT: 0x%X.", result);
-                }
-            }
-        }
+        return false;
     }
 
-    return false;
+    ID3D11Resource *renderTargetResource = renderTarget->getTexture();
+
+    *subresourceIndexOut = renderTarget->getSubresourceIndex();
+    *texture2DOut = d3d11::DynamicCastComObject<ID3D11Texture2D>(renderTargetResource);
+
+    return (*texture2DOut != NULL);
 }
 
 gl::Error Renderer11::blitRect(gl::Framebuffer *readTarget, const gl::Rectangle &readRect, gl::Framebuffer *drawTarget, const gl::Rectangle &drawRect,
                                const gl::Rectangle *scissor, bool blitRenderTarget, bool blitDepth, bool blitStencil, GLenum filter)
 {
     if (blitRenderTarget)
     {
         gl::FramebufferAttachment *readBuffer = readTarget->getReadColorbuffer();
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
@@ -28,16 +28,17 @@ namespace rx
 {
 
 class VertexDataManager;
 class IndexDataManager;
 class StreamingIndexBufferInterface;
 class Blit11;
 class Clear11;
 class PixelTransfer11;
+class RenderTarget11;
 struct PackPixelsParams;
 
 enum
 {
     MAX_VERTEX_UNIFORM_VECTORS_D3D11 = 1024,
     MAX_FRAGMENT_UNIFORM_VECTORS_D3D11 = 1024
 };
 
@@ -74,21 +75,21 @@ class Renderer11 : public Renderer
     virtual void setScissorRectangle(const gl::Rectangle &scissor, bool enabled);
     virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
                              bool ignoreViewport);
 
     virtual bool applyPrimitiveType(GLenum mode, GLsizei count);
     virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer);
     virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive);
+
     virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
-    virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[],
-                                        GLint first, GLsizei count, GLsizei instances);
+    virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances);
     virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
-    virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]);
+    virtual void applyTransformFeedbackBuffers(const gl::State &state);
 
     virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive);
     virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
                                    gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
 
     virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer);
 
     virtual void markAllStateDirty();
@@ -135,22 +136,23 @@ class Renderer11 : public Renderer
     virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples);
 
     // Shader creation
     virtual ShaderImpl *createShader(GLenum type);
     virtual ProgramImpl *createProgram();
 
     // Shader operations
     virtual void releaseShaderCompiler();
-    virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type,
-                                             const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                             bool separatedOutputBuffers);
-    virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
-                                                  const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                                  bool separatedOutputBuffers, D3DWorkaroundType workaround);
+    virtual gl::Error loadExecutable(const void *function, size_t length, rx::ShaderType type,
+                                     const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                     bool separatedOutputBuffers, ShaderExecutable **outExecutable);
+    virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
+                                          const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                          bool separatedOutputBuffers, D3DWorkaroundType workaround,
+                                          ShaderExecutable **outExectuable);
     virtual UniformStorage *createUniformStorage(size_t storageSize);
 
     // Image operations
     virtual Image *createImage();
     virtual void generateMipmap(Image *dest, Image *source);
     virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain);
     virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels);
     virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels);
@@ -182,37 +184,37 @@ class Renderer11 : public Renderer
 
     Blit11 *getBlitter() { return mBlit; }
 
     // Buffer-to-texture and Texture-to-buffer copies
     virtual bool supportsFastCopyBufferToTexture(GLenum internalFormat) const;
     virtual gl::Error fastCopyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTarget *destRenderTarget,
                                               GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea);
 
-    bool getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndex, ID3D11Texture2D **resource);
+    bool getRenderTargetResource(gl::FramebufferAttachment *colorbuffer, unsigned int *subresourceIndexOut, ID3D11Texture2D **texture2DOut);
     void unapplyRenderTargets();
     void setOneTimeRenderTarget(ID3D11RenderTargetView *renderTargetView);
     void packPixels(ID3D11Texture2D *readTexture, const PackPixelsParams &params, uint8_t *pixelsOut);
 
     virtual bool getLUID(LUID *adapterLuid) const;
     virtual rx::VertexConversionType getVertexConversionType(const gl::VertexFormat &vertexFormat) const;
     virtual GLenum getVertexComponentType(const gl::VertexFormat &vertexFormat) const;
 
+    gl::Error readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format,
+                              GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels);
+
   private:
     DISALLOW_COPY_AND_ASSIGN(Renderer11);
 
     virtual void generateCaps(gl::Caps *outCaps, gl::TextureCapsMap *outTextureCaps, gl::Extensions *outExtensions) const;
     virtual Workarounds generateWorkarounds() const;
 
     gl::Error drawLineLoop(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer);
     gl::Error drawTriangleFan(GLsizei count, GLenum type, const GLvoid *indices, int minIndex, gl::Buffer *elementArrayBuffer, int instances);
 
-    gl::Error readTextureData(ID3D11Texture2D *texture, unsigned int subResource, const gl::Rectangle &area, GLenum format,
-                              GLenum type, GLuint outputPitch, const gl::PixelPackState &pack, uint8_t *pixels);
-
     gl::Error blitRenderbufferRect(const gl::Rectangle &readRect, const gl::Rectangle &drawRect, RenderTarget *readRenderTarget,
                                    RenderTarget *drawRenderTarget, GLenum filter, const gl::Rectangle *scissor,
                                    bool colorBlit, bool depthBlit, bool stencilBlit);
     ID3D11Texture2D *resolveMultisampledTexture(ID3D11Texture2D *source, unsigned int subresource);
 
     static void invalidateFBOAttachmentSwizzles(gl::FramebufferAttachment *attachment, int mipLevel);
     static void invalidateFramebufferSwizzles(gl::Framebuffer *framebuffer);
 
@@ -282,18 +284,24 @@ class Renderer11 : public Renderer
     D3D11_PRIMITIVE_TOPOLOGY mCurrentPrimitiveTopology;
 
     // Currently applied index buffer
     ID3D11Buffer *mAppliedIB;
     DXGI_FORMAT mAppliedIBFormat;
     unsigned int mAppliedIBOffset;
 
     // Currently applied transform feedback buffers
-    ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
-    GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];
+    ID3D11Buffer *mAppliedTFBuffers[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current D3D buffers
+                                                                                        // in use for streamout
+    GLintptr mAppliedTFOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS]; // Tracks the current GL-specified
+                                                                                   // buffer offsets to transform feedback
+                                                                                   // buffers
+    UINT mCurrentD3DOffsets[gl::IMPLEMENTATION_MAX_TRANSFORM_FEEDBACK_BUFFERS];  // Tracks the D3D buffer offsets,
+                                                                                 // which may differ from GLs, due
+                                                                                 // to different append behavior
 
     // Currently applied shaders
     ID3D11VertexShader *mAppliedVertexShader;
     ID3D11GeometryShader *mAppliedGeometryShader;
     ID3D11GeometryShader *mCurPointGeometryShader;
     ID3D11PixelShader *mAppliedPixelShader;
 
     dx_VertexConstants mVertexConstants;
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp
@@ -10,16 +10,17 @@
 #include "libGLESv2/renderer/d3d/d3d11/TextureStorage11.h"
 #include "libGLESv2/renderer/d3d/d3d11/Renderer11.h"
 #include "libGLESv2/renderer/d3d/d3d11/RenderTarget11.h"
 #include "libGLESv2/renderer/d3d/d3d11/SwapChain11.h"
 #include "libGLESv2/renderer/d3d/d3d11/renderer11_utils.h"
 #include "libGLESv2/renderer/d3d/d3d11/Blit11.h"
 #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
 #include "libGLESv2/renderer/d3d/d3d11/Image11.h"
+#include "libGLESv2/renderer/d3d/MemoryBuffer.h"
 #include "libGLESv2/renderer/d3d/TextureD3D.h"
 #include "libGLESv2/main.h"
 #include "libGLESv2/ImageIndex.h"
 
 #include "common/utilities.h"
 
 namespace rx
 {
@@ -178,24 +179,27 @@ int TextureStorage11::getLevelHeight(int
     return std::max(static_cast<int>(mTextureHeight) >> mipLevel, 1);
 }
 
 int TextureStorage11::getLevelDepth(int mipLevel) const
 {
     return std::max(static_cast<int>(mTextureDepth) >> mipLevel, 1);
 }
 
-UINT TextureStorage11::getSubresourceIndex(int mipLevel, int layerTarget) const
+UINT TextureStorage11::getSubresourceIndex(const gl::ImageIndex &index) const
 {
-    UINT index = 0;
+    UINT subresource = 0;
     if (getResource())
     {
-        index = D3D11CalcSubresource(mipLevel, layerTarget, mMipLevels);
+        UINT mipSlice = static_cast<UINT>(index.mipIndex + mTopLevel);
+        UINT arraySlice = static_cast<UINT>(index.hasLayer() ? index.layerIndex : 0);
+        subresource = D3D11CalcSubresource(mipSlice, arraySlice, mMipLevels);
+        ASSERT(subresource != std::numeric_limits<UINT>::max());
     }
-    return index;
+    return subresource;
 }
 
 ID3D11ShaderResourceView *TextureStorage11::getSRV(const gl::SamplerState &samplerState)
 {
     bool swizzleRequired = samplerState.swizzleRequired();
     bool mipmapping = gl::IsMipmapFiltered(samplerState);
     unsigned int mipLevels = mipmapping ? (samplerState.maxLevel - samplerState.baseLevel) : 1;
 
@@ -283,35 +287,35 @@ void TextureStorage11::invalidateSwizzle
 {
     for (unsigned int mipLevel = 0; mipLevel < ArraySize(mSwizzleCache); mipLevel++)
     {
         invalidateSwizzleCacheLevel(mipLevel);
     }
 }
 
 gl::Error TextureStorage11::updateSubresourceLevel(ID3D11Resource *srcTexture, unsigned int sourceSubresource,
-                                                   int level, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset,
-                                                   GLsizei width, GLsizei height, GLsizei depth)
+                                                   const gl::ImageIndex &index, const gl::Box &copyArea)
 {
     ASSERT(srcTexture);
 
+    GLint level = index.mipIndex;
+
     invalidateSwizzleCacheLevel(level);
 
     gl::Extents texSize(getLevelWidth(level), getLevelHeight(level), getLevelDepth(level));
-    gl::Box copyArea(xoffset, yoffset, zoffset, width, height, depth);
 
     bool fullCopy = copyArea.x == 0 &&
                     copyArea.y == 0 &&
                     copyArea.z == 0 &&
                     copyArea.width  == texSize.width &&
                     copyArea.height == texSize.height &&
                     copyArea.depth  == texSize.depth;
 
     ID3D11Resource *dstTexture = getResource();
-    unsigned int dstSubresource = getSubresourceIndex(level + mTopLevel, layerTarget);
+    unsigned int dstSubresource = getSubresourceIndex(index);
 
     ASSERT(dstTexture);
 
     const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat);
     if (!fullCopy && (dxgiFormatInfo.depthBits > 0 || dxgiFormatInfo.stencilBits > 0))
     {
         // CopySubresourceRegion cannot copy partial depth stencils, use the blitter instead
         Blit11 *blitter = mRenderer->getBlitter();
@@ -322,43 +326,42 @@ gl::Error TextureStorage11::updateSubres
     }
     else
     {
         const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(mTextureFormat);
 
         D3D11_BOX srcBox;
         srcBox.left = copyArea.x;
         srcBox.top = copyArea.y;
-        srcBox.right = copyArea.x + roundUp((unsigned int)width, dxgiFormatInfo.blockWidth);
-        srcBox.bottom = copyArea.y + roundUp((unsigned int)height, dxgiFormatInfo.blockHeight);
+        srcBox.right = copyArea.x + roundUp(static_cast<UINT>(copyArea.width), dxgiFormatInfo.blockWidth);
+        srcBox.bottom = copyArea.y + roundUp(static_cast<UINT>(copyArea.height), dxgiFormatInfo.blockHeight);
         srcBox.front = copyArea.z;
         srcBox.back = copyArea.z + copyArea.depth;
 
         ID3D11DeviceContext *context = mRenderer->getDeviceContext();
 
         context->CopySubresourceRegion(dstTexture, dstSubresource, copyArea.x, copyArea.y, copyArea.z,
                                        srcTexture, sourceSubresource, fullCopy ? NULL : &srcBox);
         return gl::Error(GL_NO_ERROR);
     }
 }
 
 bool TextureStorage11::copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource,
-                                            int level, int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset,
-                                            GLsizei width, GLsizei height, GLsizei depth)
+                                            const gl::ImageIndex &index, const gl::Box &region)
 {
     if (dstTexture)
     {
         ID3D11Resource *srcTexture = getResource();
-        unsigned int srcSubresource = getSubresourceIndex(level + mTopLevel, layerTarget);
+        unsigned int srcSubresource = getSubresourceIndex(index);
 
         ASSERT(srcTexture);
 
         ID3D11DeviceContext *context = mRenderer->getDeviceContext();
 
-        context->CopySubresourceRegion(dstTexture, dstSubresource, xoffset, yoffset, zoffset,
+        context->CopySubresourceRegion(dstTexture, dstSubresource, region.x, region.y, region.z,
                                        srcTexture, srcSubresource, NULL);
         return true;
     }
 
     return false;
 }
 
 void TextureStorage11::generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex)
@@ -409,16 +412,71 @@ gl::Error TextureStorage11::copyToStorag
     ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
     immediateContext->CopyResource(dest11->getResource(), getResource());
 
     dest11->invalidateSwizzleCache();
 
     return gl::Error(GL_NO_ERROR);
 }
 
+gl::Error TextureStorage11::setData(const gl::ImageIndex &index, const gl::Box &destBox, GLenum internalFormat, GLenum type,
+                                    const gl::PixelUnpackState &unpack, const uint8_t *pixelData)
+{
+    ID3D11Resource *resource = getResource();
+    ASSERT(resource);
+
+    UINT destSubresource = getSubresourceIndex(index);
+
+    const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat);
+
+    // TODO(jmadill): Handle compressed formats
+    // Compressed formats have different load syntax, so we'll have to handle them with slightly
+    // different logic. Will implemnent this in a follow-up patch, and ensure we do not use SetData
+    // with compressed formats in the calling logic.
+    ASSERT(!internalFormatInfo.compressed);
+
+    UINT srcRowPitch = internalFormatInfo.computeRowPitch(type, destBox.width, unpack.alignment);
+    UINT srcDepthPitch = internalFormatInfo.computeDepthPitch(type, destBox.width, destBox.height, unpack.alignment);
+
+    D3D11_BOX destD3DBox;
+    destD3DBox.left = destBox.x;
+    destD3DBox.right = destBox.x + destBox.width;
+    destD3DBox.top = destBox.y;
+    destD3DBox.bottom = destBox.y + destBox.height;
+    destD3DBox.front = 0;
+    destD3DBox.back = 1;
+
+    const d3d11::TextureFormat &d3d11Format = d3d11::GetTextureFormatInfo(internalFormat);
+    const d3d11::DXGIFormat &dxgiFormatInfo = d3d11::GetDXGIFormatInfo(d3d11Format.texFormat);
+
+    size_t outputPixelSize = dxgiFormatInfo.pixelBytes;
+
+    UINT bufferRowPitch = outputPixelSize * destBox.width;
+    UINT bufferDepthPitch = bufferRowPitch * destBox.height;
+
+    MemoryBuffer conversionBuffer;
+    if (!conversionBuffer.resize(bufferDepthPitch * destBox.depth))
+    {
+        return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer.");
+    }
+
+    // TODO: fast path
+    LoadImageFunction loadFunction = d3d11Format.loadFunctions.at(type);
+    loadFunction(destBox.width, destBox.height, destBox.depth,
+                 pixelData, srcRowPitch, srcDepthPitch,
+                 conversionBuffer.data(), bufferRowPitch, bufferDepthPitch);
+
+    ID3D11DeviceContext *immediateContext = mRenderer->getDeviceContext();
+    immediateContext->UpdateSubresource(resource, destSubresource,
+                                        &destD3DBox, conversionBuffer.data(),
+                                        bufferRowPitch, bufferDepthPitch);
+
+    return gl::Error(GL_NO_ERROR);
+}
+
 TextureStorage11_2D::TextureStorage11_2D(Renderer *renderer, SwapChain11 *swapchain)
     : TextureStorage11(renderer, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE),
       mTexture(swapchain->getOffscreenTexture()),
       mSwizzleTexture(NULL)
 {
     mTexture->AddRef();
 
     for (unsigned int i = 0; i < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS; i++)
@@ -555,58 +613,66 @@ TextureStorage11_2D::~TextureStorage11_2
 }
 
 TextureStorage11_2D *TextureStorage11_2D::makeTextureStorage11_2D(TextureStorage *storage)
 {
     ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2D*, storage));
     return static_cast<TextureStorage11_2D*>(storage);
 }
 
-void TextureStorage11_2D::associateImage(Image11* image, int level, int layerTarget)
+void TextureStorage11_2D::associateImage(Image11* image, const gl::ImageIndex &index)
 {
+    GLint level = index.mipIndex;
+
     ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
 
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         mAssociatedImages[level] = image;
     }
 }
 
-bool TextureStorage11_2D::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage)
+bool TextureStorage11_2D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage)
 {
+    GLint level = index.mipIndex;
+
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         // This validation check should never return false. It means the Image/TextureStorage association is broken.
         bool retValue = (mAssociatedImages[level] == expectedImage);
         ASSERT(retValue);
         return retValue;
     }
 
     return false;
 }
 
 // disassociateImage allows an Image to end its association with a Storage.
-void TextureStorage11_2D::disassociateImage(int level, int layerTarget, Image11* expectedImage)
+void TextureStorage11_2D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage)
 {
+    GLint level = index.mipIndex;
+
     ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
 
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         ASSERT(mAssociatedImages[level] == expectedImage);
 
         if (mAssociatedImages[level] == expectedImage)
         {
             mAssociatedImages[level] = NULL;
         }
     }
 }
 
 // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association.
-void TextureStorage11_2D::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage)
+void TextureStorage11_2D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage)
 {
+    GLint level = index.mipIndex;
+
     ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
 
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         // No need to let the old Image recover its data, if it is also the incoming Image.
         if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage)
         {
             // Ensure that the Image is still associated with this TextureStorage. This should be true.
@@ -898,49 +964,58 @@ TextureStorage11_Cube::~TextureStorage11
 }
 
 TextureStorage11_Cube *TextureStorage11_Cube::makeTextureStorage11_Cube(TextureStorage *storage)
 {
     ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_Cube*, storage));
     return static_cast<TextureStorage11_Cube*>(storage);
 }
 
-void TextureStorage11_Cube::associateImage(Image11* image, int level, int layerTarget)
+void TextureStorage11_Cube::associateImage(Image11* image, const gl::ImageIndex &index)
 {
+    GLint level = index.mipIndex;
+    GLint layerTarget = index.layerIndex;
+
     ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
     ASSERT(0 <= layerTarget && layerTarget < 6);
 
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         if (0 <= layerTarget && layerTarget < 6)
         {
             mAssociatedImages[layerTarget][level] = image;
         }
     }
 }
 
-bool TextureStorage11_Cube::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage)
+bool TextureStorage11_Cube::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage)
 {
+    GLint level = index.mipIndex;
+    GLint layerTarget = index.layerIndex;
+
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         if (0 <= layerTarget && layerTarget < 6)
         {
             // This validation check should never return false. It means the Image/TextureStorage association is broken.
             bool retValue = (mAssociatedImages[layerTarget][level] == expectedImage);
             ASSERT(retValue);
             return retValue;
         }
     }
 
     return false;
 }
 
 // disassociateImage allows an Image to end its association with a Storage.
-void TextureStorage11_Cube::disassociateImage(int level, int layerTarget, Image11* expectedImage)
+void TextureStorage11_Cube::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage)
 {
+    GLint level = index.mipIndex;
+    GLint layerTarget = index.layerIndex;
+
     ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
     ASSERT(0 <= layerTarget && layerTarget < 6);
 
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         if (0 <= layerTarget && layerTarget < 6)
         {
             ASSERT(mAssociatedImages[layerTarget][level] == expectedImage);
@@ -949,18 +1024,21 @@ void TextureStorage11_Cube::disassociate
             {
                 mAssociatedImages[layerTarget][level] = NULL;
             }
         }
     }
 }
 
 // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association.
-void TextureStorage11_Cube::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage)
+void TextureStorage11_Cube::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage)
 {
+    GLint level = index.mipIndex;
+    GLint layerTarget = index.layerIndex;
+
     ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
     ASSERT(0 <= layerTarget && layerTarget < 6);
 
     if ((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
     {
         if (0 <= layerTarget && layerTarget < 6)
         {
             // No need to let the old Image recover its data, if it is also the incoming Image.
@@ -1289,58 +1367,66 @@ TextureStorage11_3D::~TextureStorage11_3
 }
 
 TextureStorage11_3D *TextureStorage11_3D::makeTextureStorage11_3D(TextureStorage *storage)
 {
     ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_3D*, storage));
     return static_cast<TextureStorage11_3D*>(storage);
 }
 
-void TextureStorage11_3D::associateImage(Image11* image, int level, int layerTarget)
+void TextureStorage11_3D::associateImage(Image11* image, const gl::ImageIndex &index)
 {
+    GLint level = index.mipIndex;
+
     ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
 
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         mAssociatedImages[level] = image;
     }
 }
 
-bool TextureStorage11_3D::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage)
+bool TextureStorage11_3D::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage)
 {
+    GLint level = index.mipIndex;
+
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         // This validation check should never return false. It means the Image/TextureStorage association is broken.
         bool retValue = (mAssociatedImages[level] == expectedImage);
         ASSERT(retValue);
         return retValue;
     }
 
     return false;
 }
 
 // disassociateImage allows an Image to end its association with a Storage.
-void TextureStorage11_3D::disassociateImage(int level, int layerTarget, Image11* expectedImage)
+void TextureStorage11_3D::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage)
 {
+    GLint level = index.mipIndex;
+
     ASSERT(0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS);
 
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         ASSERT(mAssociatedImages[level] == expectedImage);
 
         if (mAssociatedImages[level] == expectedImage)
         {
             mAssociatedImages[level] = NULL;
         }
     }
 }
 
 // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association.
-void TextureStorage11_3D::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage)
+void TextureStorage11_3D::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage)
 {
+    GLint level = index.mipIndex;
+
     ASSERT((0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS));
 
     if (0 <= level && level < gl::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
     {
         // No need to let the old Image recover its data, if it is also the incoming Image.
         if (mAssociatedImages[level] != NULL && mAssociatedImages[level] != incomingImage)
         {
             // Ensure that the Image is still associated with this TextureStorage. This should be true.
@@ -1641,54 +1727,66 @@ TextureStorage11_2DArray::~TextureStorag
 }
 
 TextureStorage11_2DArray *TextureStorage11_2DArray::makeTextureStorage11_2DArray(TextureStorage *storage)
 {
     ASSERT(HAS_DYNAMIC_TYPE(TextureStorage11_2DArray*, storage));
     return static_cast<TextureStorage11_2DArray*>(storage);
 }
 
-void TextureStorage11_2DArray::associateImage(Image11* image, int level, int layerTarget)
+void TextureStorage11_2DArray::associateImage(Image11* image, const gl::ImageIndex &index)
 {
+    GLint level = index.mipIndex;
+    GLint layerTarget = index.layerIndex;
+
     ASSERT(0 <= level && level < getLevelCount());
 
     if (0 <= level && level < getLevelCount())
     {
         LevelLayerKey key(level, layerTarget);
         mAssociatedImages[key] = image;
     }
 }
 
-bool TextureStorage11_2DArray::isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage)
+bool TextureStorage11_2DArray::isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage)
 {
+    GLint level = index.mipIndex;
+    GLint layerTarget = index.layerIndex;
+
     LevelLayerKey key(level, layerTarget);
 
     // This validation check should never return false. It means the Image/TextureStorage association is broken.
     bool retValue = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage));
     ASSERT(retValue);
     return retValue;
 }
 
 // disassociateImage allows an Image to end its association with a Storage.
-void TextureStorage11_2DArray::disassociateImage(int level, int layerTarget, Image11* expectedImage)
+void TextureStorage11_2DArray::disassociateImage(const gl::ImageIndex &index, Image11* expectedImage)
 {
+    GLint level = index.mipIndex;
+    GLint layerTarget = index.layerIndex;
+
     LevelLayerKey key(level, layerTarget);
 
     bool imageAssociationCorrect = (mAssociatedImages.find(key) != mAssociatedImages.end() && (mAssociatedImages[key] == expectedImage));
     ASSERT(imageAssociationCorrect);
 
     if (imageAssociationCorrect)
     {
         mAssociatedImages[key] = NULL;
     }
 }
 
 // releaseAssociatedImage prepares the Storage for a new Image association. It lets the old Image recover its data before ending the association.
-void TextureStorage11_2DArray::releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage)
+void TextureStorage11_2DArray::releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage)
 {
+    GLint level = index.mipIndex;
+    GLint layerTarget = index.layerIndex;
+
     LevelLayerKey key(level, layerTarget);
 
     ASSERT(mAssociatedImages.find(key) != mAssociatedImages.end());
 
     if (mAssociatedImages.find(key) != mAssociatedImages.end())
     {
         if (mAssociatedImages[key] != NULL && mAssociatedImages[key] != incomingImage)
         {
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h
@@ -46,36 +46,36 @@ class TextureStorage11 : public TextureS
     virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0;
 
     virtual void generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex);
 
     virtual int getTopLevel() const;
     virtual bool isRenderTarget() const;
     virtual bool isManaged() const;
     virtual int getLevelCount() const;
-    UINT getSubresourceIndex(int mipLevel, int layerTarget) const;
+    UINT getSubresourceIndex(const gl::ImageIndex &index) const;
 
     gl::Error generateSwizzles(GLenum swizzleRed, GLenum swizzleGreen, GLenum swizzleBlue, GLenum swizzleAlpha);
     void invalidateSwizzleCacheLevel(int mipLevel);
     void invalidateSwizzleCache();
 
-    gl::Error updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource, int level,
-                                     int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset,
-                                     GLsizei width, GLsizei height, GLsizei depth);
+    gl::Error updateSubresourceLevel(ID3D11Resource *texture, unsigned int sourceSubresource,
+                                     const gl::ImageIndex &index, const gl::Box &copyArea);
 
-    bool copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource, int level,
-                              int layerTarget, GLint xoffset, GLint yoffset, GLint zoffset,
-                              GLsizei width, GLsizei height, GLsizei depth);
+    bool copySubresourceLevel(ID3D11Resource* dstTexture, unsigned int dstSubresource,
+                              const gl::ImageIndex &index, const gl::Box &region);
 
-    virtual void associateImage(Image11* image, int level, int layerTarget) = 0;
-    virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage) = 0;
-    virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage) = 0;
-    virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage) = 0;
+    virtual void associateImage(Image11* image, const gl::ImageIndex &index) = 0;
+    virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage) = 0;
+    virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage) = 0;
+    virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage) = 0;
 
     virtual gl::Error copyToStorage(TextureStorage *destStorage);
+    virtual gl::Error setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type,
+                              const gl::PixelUnpackState &unpack, const uint8_t *pixelData);
 
   protected:
     TextureStorage11(Renderer *renderer, UINT bindFlags);
     int getLevelWidth(int mipLevel) const;
     int getLevelHeight(int mipLevel) const;
     int getLevelDepth(int mipLevel) const;
 
     virtual ID3D11Resource *getSwizzleTexture() = 0;
@@ -159,20 +159,20 @@ class TextureStorage11_2D : public Textu
     TextureStorage11_2D(Renderer *renderer, GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels);
     virtual ~TextureStorage11_2D();
 
     static TextureStorage11_2D *makeTextureStorage11_2D(TextureStorage *storage);
 
     virtual ID3D11Resource *getResource() const;
     virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index);
 
-    virtual void associateImage(Image11* image, int level, int layerTarget);
-    virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage);
-    virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage);
-    virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage);
+    virtual void associateImage(Image11* image, const gl::ImageIndex &index);
+    virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage);
+    virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage);
+    virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage);
 
   protected:
     virtual ID3D11Resource *getSwizzleTexture();
     virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
 
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2D);
 
@@ -193,20 +193,20 @@ class TextureStorage11_Cube : public Tex
     TextureStorage11_Cube(Renderer *renderer, GLenum internalformat, bool renderTarget, int size, int levels);
     virtual ~TextureStorage11_Cube();
 
     static TextureStorage11_Cube *makeTextureStorage11_Cube(TextureStorage *storage);
 
     virtual ID3D11Resource *getResource() const;
     virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index);
 
-    virtual void associateImage(Image11* image, int level, int layerTarget);
-    virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage);
-    virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage);
-    virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage);
+    virtual void associateImage(Image11* image, const gl::ImageIndex &index);
+    virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage);
+    virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage);
+    virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage);
 
   protected:
     virtual ID3D11Resource *getSwizzleTexture();
     virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
 
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureStorage11_Cube);
 
@@ -230,20 +230,20 @@ class TextureStorage11_3D : public Textu
 
     static TextureStorage11_3D *makeTextureStorage11_3D(TextureStorage *storage);
 
     virtual ID3D11Resource *getResource() const;
 
     // Handles both layer and non-layer RTs
     virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index);
 
-    virtual void associateImage(Image11* image, int level, int layerTarget);
-    virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage);
-    virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage);
-    virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage);
+    virtual void associateImage(Image11* image, const gl::ImageIndex &index);
+    virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage);
+    virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage);
+    virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage);
 
   protected:
     virtual ID3D11Resource *getSwizzleTexture();
     virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
 
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureStorage11_3D);
 
@@ -269,20 +269,20 @@ class TextureStorage11_2DArray : public 
                              GLsizei width, GLsizei height, GLsizei depth, int levels);
     virtual ~TextureStorage11_2DArray();
 
     static TextureStorage11_2DArray *makeTextureStorage11_2DArray(TextureStorage *storage);
 
     virtual ID3D11Resource *getResource() const;
     virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index);
 
-    virtual void associateImage(Image11* image, int level, int layerTarget);
-    virtual void disassociateImage(int level, int layerTarget, Image11* expectedImage);
-    virtual bool isAssociatedImageValid(int level, int layerTarget, Image11* expectedImage);
-    virtual void releaseAssociatedImage(int level, int layerTarget, Image11* incomingImage);
+    virtual void associateImage(Image11* image, const gl::ImageIndex &index);
+    virtual void disassociateImage(const gl::ImageIndex &index, Image11* expectedImage);
+    virtual bool isAssociatedImageValid(const gl::ImageIndex &index, Image11* expectedImage);
+    virtual void releaseAssociatedImage(const gl::ImageIndex &index, Image11* incomingImage);
 
   protected:
     virtual ID3D11Resource *getSwizzleTexture();
     virtual ID3D11RenderTargetView *getSwizzleRenderTarget(int mipLevel);
 
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureStorage11_2DArray);
 
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
@@ -811,17 +811,17 @@ static size_t GetMaximumStreamOutputBuff
       case D3D_FEATURE_LEVEL_9_3:
       case D3D_FEATURE_LEVEL_9_2:
       case D3D_FEATURE_LEVEL_9_1:  return 0;
 
       default: UNREACHABLE();      return 0;
     }
 }
 
-static size_t GetMaximumStreamOutputInterleavedComponenets(D3D_FEATURE_LEVEL featureLevel)
+static size_t GetMaximumStreamOutputInterleavedComponents(D3D_FEATURE_LEVEL featureLevel)
 {
     switch (featureLevel)
     {
       case D3D_FEATURE_LEVEL_11_1:
       case D3D_FEATURE_LEVEL_11_0:
 
       case D3D_FEATURE_LEVEL_10_1:
       case D3D_FEATURE_LEVEL_10_0: return GetMaximumVertexOutputVectors(featureLevel) * 4;
@@ -829,22 +829,22 @@ static size_t GetMaximumStreamOutputInte
       case D3D_FEATURE_LEVEL_9_3:
       case D3D_FEATURE_LEVEL_9_2:
       case D3D_FEATURE_LEVEL_9_1:  return 0;
 
       default: UNREACHABLE();      return 0;
     }
 }
 
-static size_t GetMaximumStreamOutputSeparateCompeonents(D3D_FEATURE_LEVEL featureLevel)
+static size_t GetMaximumStreamOutputSeparateComponents(D3D_FEATURE_LEVEL featureLevel)
 {
     switch (featureLevel)
     {
       case D3D_FEATURE_LEVEL_11_1:
-      case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponenets(featureLevel) /
+      case D3D_FEATURE_LEVEL_11_0: return GetMaximumStreamOutputInterleavedComponents(featureLevel) /
                                           GetMaximumStreamOutputBuffers(featureLevel);
 
 
       // D3D 10 and 10.1 only allow one output per output slot if an output slot other than zero is used.
       case D3D_FEATURE_LEVEL_10_1:
       case D3D_FEATURE_LEVEL_10_0: return 4;
 
       case D3D_FEATURE_LEVEL_9_3:
@@ -943,19 +943,19 @@ void GenerateCaps(ID3D11Device *device, 
                                                static_cast<GLint64>(caps->maxVertexUniformComponents);
     caps->maxCombinedFragmentUniformComponents = (static_cast<GLint64>(caps->maxFragmentUniformBlocks) * static_cast<GLint64>(caps->maxUniformBlockSize / 4)) +
                                                  static_cast<GLint64>(caps->maxFragmentUniformComponents);
     caps->maxVaryingComponents = GetMaximumVertexOutputVectors(featureLevel) * 4;
     caps->maxVaryingVectors = GetMaximumVertexOutputVectors(featureLevel);
     caps->maxCombinedTextureImageUnits = caps->maxVertexTextureImageUnits + caps->maxTextureImageUnits;
 
     // Transform feedback limits
-    caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponenets(featureLevel);
+    caps->maxTransformFeedbackInterleavedComponents = GetMaximumStreamOutputInterleavedComponents(featureLevel);
     caps->maxTransformFeedbackSeparateAttributes = GetMaximumStreamOutputBuffers(featureLevel);
-    caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateCompeonents(featureLevel);
+    caps->maxTransformFeedbackSeparateComponents = GetMaximumStreamOutputSeparateComponents(featureLevel);
 
     // GL extension support
     extensions->setTextureExtensionSupport(*textureCapsMap);
     extensions->elementIndexUint = true;
     extensions->packedDepthStencil = true;
     extensions->getProgramBinary = true;
     extensions->rgb8rgba8 = true;
     extensions->readFormatBGRA = true;
@@ -1071,14 +1071,15 @@ RenderTarget11 *GetAttachmentRenderTarge
     RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment);
     return RenderTarget11::makeRenderTarget11(renderTarget);
 }
 
 Workarounds GenerateWorkarounds()
 {
     Workarounds workarounds;
     workarounds.mrtPerfWorkaround = true;
+    workarounds.setDataFasterThanImageUpload = true;
     return workarounds;
 }
 
 }
 
 }
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp
@@ -109,36 +109,36 @@ void Blit9::initGeometry()
     {
         ASSERT(result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY);
         return gl::error(GL_OUT_OF_MEMORY);
     }
 }
 
 template <class D3DShaderType>
 gl::Error Blit9::setShader(ShaderId source, const char *profile,
-                           D3DShaderType *(rx::Renderer9::*createShader)(const DWORD *, size_t length),
+                           gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader),
                            HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*))
 {
     IDirect3DDevice9 *device = mRenderer->getDevice();
 
     D3DShaderType *shader;
 
     if (mCompiledShaders[source] != NULL)
     {
         shader = static_cast<D3DShaderType*>(mCompiledShaders[source]);
     }
     else
     {
         const BYTE* shaderCode = g_shaderCode[source];
         size_t shaderSize = g_shaderSize[source];
 
-        shader = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize);
-        if (!shader)
+        gl::Error error = (mRenderer->*createShader)(reinterpret_cast<const DWORD*>(shaderCode), shaderSize, &shader);
+        if (error.isError())
         {
-            return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal shader for blit operation");
+            return error;
         }
 
         mCompiledShaders[source] = shader;
     }
 
     HRESULT hr = (device->*setShader)(shader);
     if (FAILED(hr))
     {
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h
@@ -71,17 +71,17 @@ class Blit9
         SHADER_COUNT
     };
 
     // This actually contains IDirect3DVertexShader9 or IDirect3DPixelShader9 casted to IUnknown.
     IUnknown *mCompiledShaders[SHADER_COUNT];
 
     template <class D3DShaderType>
     gl::Error setShader(ShaderId source, const char *profile,
-                        D3DShaderType *(Renderer9::*createShader)(const DWORD *, size_t length),
+                        gl::Error (Renderer9::*createShader)(const DWORD *, size_t length, D3DShaderType **outShader),
                         HRESULT (WINAPI IDirect3DDevice9::*setShader)(D3DShaderType*));
 
     gl::Error setVertexShader(ShaderId shader);
     gl::Error setPixelShader(ShaderId shader);
     void render();
 
     void saveState();
     void restoreState();
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp
@@ -296,46 +296,46 @@ void Image9::setManagedSurface(IDirect3D
             SafeRelease(mSurface);
         }
 
         mSurface = surface;
         mD3DPool = desc.Pool;
     }
 }
 
-gl::Error Image9::copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+gl::Error Image9::copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
 {
     ASSERT(getSurface() != NULL);
     TextureStorage9_2D *storage9 = TextureStorage9_2D::makeTextureStorage9_2D(storage);
-    IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(level, true);
+    IDirect3DSurface9 *destSurface = storage9->getSurfaceLevel(index.mipIndex, true);
 
-    gl::Error error = copyToSurface(destSurface, xoffset, yoffset, width, height);
+    gl::Error error = copyToSurface(destSurface, region.x, region.y, region.width, region.height);
     SafeRelease(destSurface);
     return error;
 }
 
-gl::Error Image9::copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
+gl::Error Image9::copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
 {
     ASSERT(getSurface() != NULL);
     TextureStorage9_Cube *storage9 = TextureStorage9_Cube::makeTextureStorage9_Cube(storage);
-    IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, level, true);
+    IDirect3DSurface9 *destSurface = storage9->getCubeMapSurface(index.type, index.mipIndex, true);
 
-    gl::Error error = copyToSurface(destSurface, xoffset, yoffset, width, height);
+    gl::Error error = copyToSurface(destSurface, region.x, region.y, region.width, region.height);
     SafeRelease(destSurface);
     return error;
 }
 
-gl::Error Image9::copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth)
+gl::Error Image9::copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
 {
     // 3D textures are not supported by the D3D9 backend.
     UNREACHABLE();
     return gl::Error(GL_INVALID_OPERATION);
 }
 
-gl::Error Image9::copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height)
+gl::Error Image9::copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region)
 {
     // 2D array textures are not supported by the D3D9 backend.
     UNREACHABLE();
     return gl::Error(GL_INVALID_OPERATION);
 }
 
 gl::Error Image9::copyToSurface(IDirect3DSurface9 *destSurface, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height)
 {
@@ -461,29 +461,25 @@ gl::Error Image9::loadCompressedData(GLi
                                 reinterpret_cast<uint8_t*>(locked.pBits), locked.Pitch, 0);
 
     unlock();
 
     return gl::Error(GL_NO_ERROR);
 }
 
 // This implements glCopyTex[Sub]Image2D for non-renderable internal texture formats and incomplete textures
-void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source)
+void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source)
 {
+    ASSERT(source);
+
     // ES3.0 only behaviour to copy into a 3d texture
     ASSERT(zoffset == 0);
 
-    RenderTarget9 *renderTarget = NULL;
+    RenderTarget9 *renderTarget = RenderTarget9::makeRenderTarget9(source);
     IDirect3DSurface9 *surface = NULL;
-    gl::FramebufferAttachment *colorbuffer = source->getColorbuffer(0);
-
-    if (colorbuffer)
-    {
-        renderTarget = d3d9::GetAttachmentRenderTarget(colorbuffer);
-    }
 
     if (renderTarget)
     {
         surface = renderTarget->getSurface();
     }
 
     if (!surface)
     {
@@ -511,18 +507,21 @@ void Image9::copy(GLint xoffset, GLint y
     if (FAILED(result))
     {
         ERR("GetRenderTargetData unexpectedly failed.");
         SafeRelease(renderTargetData);
         SafeRelease(surface);
         return gl::error(GL_OUT_OF_MEMORY);
     }
 
-    RECT sourceRect = {x, y, x + width, y + height};
-    RECT destRect = {xoffset, yoffset, xoffset + width, yoffset + height};
+    int width = sourceArea.width;
+    int height = sourceArea.height;
+
+    RECT sourceRect = { sourceArea.x, sourceArea.y, sourceArea.x + width, sourceArea.y + height };
+    RECT destRect = { xoffset, yoffset, xoffset + width, yoffset + height };
 
     D3DLOCKED_RECT sourceLock = {0};
     result = renderTargetData->LockRect(&sourceLock, &sourceRect, 0);
 
     if (FAILED(result))
     {
         ERR("Failed to lock the source surface (rectangle might be invalid).");
         SafeRelease(renderTargetData);
@@ -550,40 +549,40 @@ void Image9::copy(GLint xoffset, GLint y
         switch (description.Format)
         {
           case D3DFMT_X8R8G8B8:
           case D3DFMT_A8R8G8B8:
             switch(getD3DFormat())
             {
               case D3DFMT_X8R8G8B8:
               case D3DFMT_A8R8G8B8:
-                for(int y = 0; y < height; y++)
+                for (int y = 0; y < height; y++)
                 {
                     memcpy(dest, source, 4 * width);
 
                     source += sourceLock.Pitch;
                     dest += destLock.Pitch;
                 }
                 break;
               case D3DFMT_L8:
-                for(int y = 0; y < height; y++)
+                for (int y = 0; y < height; y++)
                 {
-                    for(int x = 0; x < width; x++)
+                    for (int x = 0; x < width; x++)
                     {
                         dest[x] = source[x * 4 + 2];
                     }
 
                     source += sourceLock.Pitch;
                     dest += destLock.Pitch;
                 }
                 break;
               case D3DFMT_A8L8:
-                for(int y = 0; y < height; y++)
+                for (int y = 0; y < height; y++)
                 {
-                    for(int x = 0; x < width; x++)
+                    for (int x = 0; x < width; x++)
                     {
                         dest[x * 2 + 0] = source[x * 4 + 2];
                         dest[x * 2 + 1] = source[x * 4 + 3];
                     }
 
                     source += sourceLock.Pitch;
                     dest += destLock.Pitch;
                 }
@@ -591,77 +590,77 @@ void Image9::copy(GLint xoffset, GLint y
               default:
                 UNREACHABLE();
             }
             break;
           case D3DFMT_R5G6B5:
             switch(getD3DFormat())
             {
               case D3DFMT_X8R8G8B8:
-                for(int y = 0; y < height; y++)
+                for (int y = 0; y < height; y++)
                 {
-                    for(int x = 0; x < width; x++)
+                    for (int x = 0; x < width; x++)
                     {
                         unsigned short rgb = ((unsigned short*)source)[x];
                         unsigned char red = (rgb & 0xF800) >> 8;
                         unsigned char green = (rgb & 0x07E0) >> 3;
                         unsigned char blue = (rgb & 0x001F) << 3;
                         dest[x + 0] = blue | (blue >> 5);
                         dest[x + 1] = green | (green >> 6);
                         dest[x + 2] = red | (red >> 5);
                         dest[x + 3] = 0xFF;
                     }
 
                     source += sourceLock.Pitch;
                     dest += destLock.Pitch;
                 }
                 break;
               case D3DFMT_L8:
-                for(int y = 0; y < height; y++)
+                for (int y = 0; y < height; y++)
                 {
-                    for(int x = 0; x < width; x++)
+                    for (int x = 0; x < width; x++)
                     {
                         unsigned char red = source[x * 2 + 1] & 0xF8;
                         dest[x] = red | (red >> 5);
                     }
 
                     source += sourceLock.Pitch;
                     dest += destLock.Pitch;
                 }
                 break;
               default:
                 UNREACHABLE();
             }
             break;
           case D3DFMT_A1R5G5B5:
-            switch(getD3DFormat())
+            switch (getD3DFormat())
             {
               case D3DFMT_X8R8G8B8:
-                for(int y = 0; y < height; y++)
+                for (int y = 0; y < height; y++)
                 {
-                    for(int x = 0; x < width; x++)
+                    for (int x = 0; x < width; x++)
                     {
                         unsigned short argb = ((unsigned short*)source)[x];
                         unsigned char red = (argb & 0x7C00) >> 7;
                         unsigned char green = (argb & 0x03E0) >> 2;
                         unsigned char blue = (argb & 0x001F) << 3;
                         dest[x + 0] = blue | (blue >> 5);
                         dest[x + 1] = green | (green >> 5);
                         dest[x + 2] = red | (red >> 5);
                         dest[x + 3] = 0xFF;
                     }
 
                     source += sourceLock.Pitch;
                     dest += destLock.Pitch;
                 }
                 break;
               case D3DFMT_A8R8G8B8:
-                for(int y = 0; y < height; y++)
+                for (int y = 0; y < height; y++)
                 {
-                    for(int x = 0; x < width; x++)
+                    for (int x = 0; x < width; x++)
                     {
                         unsigned short argb = ((unsigned short*)source)[x];
                         unsigned char red = (argb & 0x7C00) >> 7;
                         unsigned char green = (argb & 0x03E0) >> 2;
                         unsigned char blue = (argb & 0x001F) << 3;
                         unsigned char alpha = (signed short)argb >> 15;
                         dest[x + 0] = blue | (blue >> 5);
                         dest[x + 1] = green | (green >> 5);
@@ -669,32 +668,32 @@ void Image9::copy(GLint xoffset, GLint y
                         dest[x + 3] = alpha;
                     }
 
                     source += sourceLock.Pitch;
                     dest += destLock.Pitch;
                 }
                 break;
               case D3DFMT_L8:
-                for(int y = 0; y < height; y++)
+                for (int y = 0; y < height; y++)
                 {
-                    for(int x = 0; x < width; x++)
+                    for (int x = 0; x < width; x++)
                     {
                         unsigned char red = source[x * 2 + 1] & 0x7C;
                         dest[x] = (red << 1) | (red >> 4);
                     }
 
                     source += sourceLock.Pitch;
                     dest += destLock.Pitch;
                 }
                 break;
               case D3DFMT_A8L8:
-                for(int y = 0; y < height; y++)
+                for (int y = 0; y < height; y++)
                 {
-                    for(int x = 0; x < width; x++)
+                    for (int x = 0; x < width; x++)
                     {
                         unsigned char red = source[x * 2 + 1] & 0x7C;
                         dest[x * 2 + 0] = (red << 1) | (red >> 4);
                         dest[x * 2 + 1] = (signed char)source[x * 2 + 1] >> 7;
                     }
 
                     source += sourceLock.Pitch;
                     dest += destLock.Pitch;
@@ -713,9 +712,15 @@ void Image9::copy(GLint xoffset, GLint y
     renderTargetData->UnlockRect();
 
     SafeRelease(renderTargetData);
     SafeRelease(surface);
 
     mDirty = true;
 }
 
+void Image9::copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &area, const gl::ImageIndex &srcIndex, TextureStorage *srcStorage)
+{
+    // Currently unreachable, due to only being used in a D3D11-only workaround
+    UNIMPLEMENTED();
 }
+
+}
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h
@@ -39,27 +39,29 @@ class Image9 : public ImageD3D
 
     D3DFORMAT getD3DFormat() const;
 
     virtual bool isDirty() const;
     IDirect3DSurface9 *getSurface();
 
     virtual void setManagedSurface2D(TextureStorage *storage, int level);
     virtual void setManagedSurfaceCube(TextureStorage *storage, int face, int level);
-    virtual gl::Error copyToStorage2D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
-    virtual gl::Error copyToStorageCube(TextureStorage *storage, int face, int level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
-    virtual gl::Error copyToStorage3D(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth);
-    virtual gl::Error copyToStorage2DArray(TextureStorage *storage, int level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height);
+    virtual gl::Error copyToStorage2D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
+    virtual gl::Error copyToStorageCube(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
+    virtual gl::Error copyToStorage3D(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
+    virtual gl::Error copyToStorage2DArray(TextureStorage *storage, const gl::ImageIndex &index, const gl::Box &region);
 
     virtual gl::Error loadData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                GLint unpackAlignment, GLenum type, const void *input);
     virtual gl::Error loadCompressedData(GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth,
                                          const void *input);
 
-    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset,GLint x, GLint y, GLsizei width, GLsizei height, gl::Framebuffer *source);
+    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea, RenderTarget *source);
+    virtual void copy(GLint xoffset, GLint yoffset, GLint zoffset, const gl::Rectangle &sourceArea,
+                      const gl::ImageIndex &sourceIndex, TextureStorage *source);
 
   private:
     DISALLOW_COPY_AND_ASSIGN(Image9);
 
     void createSurface();
     void setManagedSurface(IDirect3DSurface9 *surface);
     gl::Error copyToSurface(IDirect3DSurface9 *dest, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height);
 
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
@@ -28,16 +28,17 @@
 #include "libGLESv2/renderer/d3d/TransformFeedbackD3D.h"
 #include "libGLESv2/main.h"
 #include "libGLESv2/Buffer.h"
 #include "libGLESv2/Texture.h"
 #include "libGLESv2/Framebuffer.h"
 #include "libGLESv2/FramebufferAttachment.h"
 #include "libGLESv2/Renderbuffer.h"
 #include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/State.h"
 #include "libGLESv2/angletypes.h"
 
 #include "libEGL/Display.h"
 
 #include "common/utilities.h"
 
 #include "third_party/trace_event/trace_event.h"
 
@@ -560,24 +561,24 @@ void Renderer9::freeEventQuery(IDirect3D
         SafeRelease(query);
     }
     else
     {
         mEventQueryPool.push_back(query);
     }
 }
 
-IDirect3DVertexShader9 *Renderer9::createVertexShader(const DWORD *function, size_t length)
+gl::Error Renderer9::createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader)
 {
-    return mVertexShaderCache.create(function, length);
+    return mVertexShaderCache.create(function, length, outShader);
 }
 
-IDirect3DPixelShader9 *Renderer9::createPixelShader(const DWORD *function, size_t length)
+gl::Error Renderer9::createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader)
 {
-    return mPixelShaderCache.create(function, length);
+    return mPixelShaderCache.create(function, length, outShader);
 }
 
 HRESULT Renderer9::createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer)
 {
     D3DPOOL Pool = getBufferPool(Usage);
     return mDevice->CreateVertexBuffer(Length, Usage, 0, Pool, ppVertexBuffer, NULL);
 }
 
@@ -1263,27 +1264,26 @@ gl::Error Renderer9::applyRenderTarget(g
         mRenderTargetDesc.height = attachment->getHeight();
         mRenderTargetDesc.format = attachment->getActualFormat();
         mRenderTargetDescInitialized = true;
     }
 
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error Renderer9::applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[],
-                                       GLint first, GLsizei count, GLsizei instances)
+gl::Error Renderer9::applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances)
 {
     TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS];
-    gl::Error error = mVertexDataManager->prepareVertexData(vertexAttributes, currentValues, programBinary, first, count, attributes, instances);
+    gl::Error error = mVertexDataManager->prepareVertexData(state, first, count, attributes, instances);
     if (error.isError())
     {
         return error;
     }
 
-    return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, programBinary, instances, &mRepeatDraw);
+    return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, state.getCurrentProgramBinary(), instances, &mRepeatDraw);
 }
 
 // Applies the indices and element array bindings to the Direct3D 9 device
 gl::Error Renderer9::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
 {
     gl::Error error = mIndexDataManager->prepareIndexData(type, count, elementArrayBuffer, indices, indexInfo);
     if (error.isError())
     {
@@ -1299,17 +1299,17 @@ gl::Error Renderer9::applyIndexBuffer(co
 
         mDevice->SetIndices(indexBuffer->getBuffer());
         mAppliedIBSerial = indexInfo->serial;
     }
 
     return gl::Error(GL_NO_ERROR);
 }
 
-void Renderer9::applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[])
+void Renderer9::applyTransformFeedbackBuffers(const gl::State& state)
 {
     UNREACHABLE();
 }
 
 gl::Error Renderer9::drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive)
 {
     ASSERT(!transformFeedbackActive);
 
@@ -1666,18 +1666,30 @@ gl::Error Renderer9::getCountingIB(size_
 
 gl::Error Renderer9::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                   bool rasterizerDiscard, bool transformFeedbackActive)
 {
     ASSERT(!transformFeedbackActive);
     ASSERT(!rasterizerDiscard);
 
     ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
-    ShaderExecutable *vertexExe = programD3D->getVertexExecutableForInputLayout(inputLayout);
-    ShaderExecutable *pixelExe = programD3D->getPixelExecutableForFramebuffer(framebuffer);
+
+    ShaderExecutable *vertexExe = NULL;
+    gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    ShaderExecutable *pixelExe = NULL;
+    error = programD3D->getPixelExecutableForFramebuffer(framebuffer, &pixelExe);
+    if (error.isError())
+    {
+        return error;
+    }
 
     IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL);
     IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL);
 
     if (vertexShader != mAppliedVertexShader)
     {
         mDevice->SetVertexShader(vertexShader);
         mAppliedVertexShader = vertexShader;
@@ -2786,72 +2798,75 @@ ProgramImpl *Renderer9::createProgram()
     return new ProgramD3D(this);
 }
 
 void Renderer9::releaseShaderCompiler()
 {
     ShaderD3D::releaseCompiler();
 }
 
-ShaderExecutable *Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type,
-                                            const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                            bool separatedOutputBuffers)
+gl::Error Renderer9::loadExecutable(const void *function, size_t length, rx::ShaderType type,
+                                    const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                    bool separatedOutputBuffers, ShaderExecutable **outExecutable)
 {
     // Transform feedback is not supported in ES2 or D3D9
     ASSERT(transformFeedbackVaryings.size() == 0);
 
-    ShaderExecutable9 *executable = NULL;
-
     switch (type)
     {
       case rx::SHADER_VERTEX:
         {
-            IDirect3DVertexShader9 *vshader = createVertexShader((DWORD*)function, length);
-            if (vshader)
+            IDirect3DVertexShader9 *vshader = NULL;
+            gl::Error error = createVertexShader((DWORD*)function, length, &vshader);
+            if (error.isError())
             {
-                executable = new ShaderExecutable9(function, length, vshader);
+                return error;
             }
+            *outExecutable = new ShaderExecutable9(function, length, vshader);
         }
         break;
       case rx::SHADER_PIXEL:
         {
-            IDirect3DPixelShader9 *pshader = createPixelShader((DWORD*)function, length);
-            if (pshader)
+            IDirect3DPixelShader9 *pshader = NULL;
+            gl::Error error = createPixelShader((DWORD*)function, length, &pshader);
+            if (error.isError())
             {
-                executable = new ShaderExecutable9(function, length, pshader);
+                return error;
             }
+            *outExecutable = new ShaderExecutable9(function, length, pshader);
         }
         break;
       default:
         UNREACHABLE();
-        break;
+        return gl::Error(GL_INVALID_OPERATION);
     }
 
-    return executable;
+    return gl::Error(GL_NO_ERROR);
 }
 
-ShaderExecutable *Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
-                                                 const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                                 bool separatedOutputBuffers, D3DWorkaroundType workaround)
+gl::Error Renderer9::compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
+                                         const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                         bool separatedOutputBuffers, D3DWorkaroundType workaround,
+                                         ShaderExecutable **outExectuable)
 {
     // Transform feedback is not supported in ES2 or D3D9
     ASSERT(transformFeedbackVaryings.size() == 0);
 
     const char *profileType = NULL;
     switch (type)
     {
       case rx::SHADER_VERTEX:
         profileType = "vs";
         break;
       case rx::SHADER_PIXEL:
         profileType = "ps";
         break;
       default:
         UNREACHABLE();
-        return NULL;
+        return gl::Error(GL_INVALID_OPERATION);
     }
     unsigned int profileMajorVersion = (getMajorShaderModel() >= 3) ? 3 : 2;
     unsigned int profileMinorVersion = 0;
     std::string profile = FormatString("%s_%u_%u", profileType, profileMajorVersion, profileMinorVersion);
 
     UINT flags = ANGLE_COMPILE_OPTIMIZATION_LEVEL;
 
     if (workaround == ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION)
@@ -2875,27 +2890,40 @@ ShaderExecutable *Renderer9::compileToEx
 
     // Sometimes D3DCompile will fail with the default compilation flags for complicated shaders when it would otherwise pass with alternative options.
     // Try the default flags first and if compilation fails, try some alternatives.
     std::vector<CompileConfig> configs;
     configs.push_back(CompileConfig(flags,                                  "default"            ));
     configs.push_back(CompileConfig(flags | D3DCOMPILE_AVOID_FLOW_CONTROL,  "avoid flow control" ));
     configs.push_back(CompileConfig(flags | D3DCOMPILE_PREFER_FLOW_CONTROL, "prefer flow control"));
 
-    ID3DBlob *binary = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs);
+    ID3DBlob *binary = NULL;
+    gl::Error error = mCompiler.compileToBinary(infoLog, shaderHLSL, profile, configs, &binary);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    // It's possible that binary is NULL if the compiler failed in all configurations.  Set the executable to NULL
+    // and return GL_NO_ERROR to signify that there was a link error but the internal state is still OK.
     if (!binary)
     {
-        return NULL;
+        *outExectuable = NULL;
+        return gl::Error(GL_NO_ERROR);
     }
 
-    ShaderExecutable *executable = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
-                                                  transformFeedbackVaryings, separatedOutputBuffers);
+    error = loadExecutable(binary->GetBufferPointer(), binary->GetBufferSize(), type,
+                           transformFeedbackVaryings, separatedOutputBuffers, outExectuable);
     SafeRelease(binary);
-
-    return executable;
+    if (error.isError())
+    {
+        return error;
+    }
+
+    return gl::Error(GL_NO_ERROR);
 }
 
 rx::UniformStorage *Renderer9::createUniformStorage(size_t storageSize)
 {
     return new UniformStorage(storageSize);
 }
 
 gl::Error Renderer9::boxFilter(IDirect3DSurface9 *source, IDirect3DSurface9 *dest)
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h
@@ -51,18 +51,18 @@ class Renderer9 : public Renderer
     virtual void sync(bool block);
 
     virtual SwapChain *createSwapChain(rx::NativeWindow nativeWindow, HANDLE shareHandle, GLenum backBufferFormat, GLenum depthBufferFormat);
 
     IDirect3DQuery9* allocateEventQuery();
     void freeEventQuery(IDirect3DQuery9* query);
 
     // resource creation
-    IDirect3DVertexShader9 *createVertexShader(const DWORD *function, size_t length);
-    IDirect3DPixelShader9 *createPixelShader(const DWORD *function, size_t length);
+    gl::Error createVertexShader(const DWORD *function, size_t length, IDirect3DVertexShader9 **outShader);
+    gl::Error createPixelShader(const DWORD *function, size_t length, IDirect3DPixelShader9 **outShader);
     HRESULT createVertexBuffer(UINT Length, DWORD Usage, IDirect3DVertexBuffer9 **ppVertexBuffer);
     HRESULT createIndexBuffer(UINT Length, DWORD Usage, D3DFORMAT Format, IDirect3DIndexBuffer9 **ppIndexBuffer);
     virtual gl::Error generateSwizzle(gl::Texture *texture);
     virtual gl::Error setSamplerState(gl::SamplerType type, int index, const gl::SamplerState &sampler);
     virtual gl::Error setTexture(gl::SamplerType type, int index, gl::Texture *texture);
 
     virtual gl::Error setUniformBuffers(const gl::Buffer *vertexUniformBuffers[], const gl::Buffer *fragmentUniformBuffers[]);
 
@@ -76,21 +76,20 @@ class Renderer9 : public Renderer
     virtual void setViewport(const gl::Rectangle &viewport, float zNear, float zFar, GLenum drawMode, GLenum frontFace,
                              bool ignoreViewport);
 
     virtual gl::Error applyRenderTarget(gl::Framebuffer *frameBuffer);
     virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive);
     virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
     virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount);
-    virtual gl::Error applyVertexBuffer(gl::ProgramBinary *programBinary, const gl::VertexAttribute vertexAttributes[], const gl::VertexAttribCurrentValueData currentValues[],
-                                        GLint first, GLsizei count, GLsizei instances);
+    virtual gl::Error applyVertexBuffer(const gl::State &state, GLint first, GLsizei count, GLsizei instances);
     virtual gl::Error applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo);
 
-    virtual void applyTransformFeedbackBuffers(gl::Buffer *transformFeedbackBuffers[], GLintptr offsets[]);
+    virtual void applyTransformFeedbackBuffers(const gl::State& state);
 
     virtual gl::Error drawArrays(GLenum mode, GLsizei count, GLsizei instances, bool transformFeedbackActive);
     virtual gl::Error drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices,
                                    gl::Buffer *elementArrayBuffer, const TranslatedIndexData &indexInfo, GLsizei instances);
 
     virtual gl::Error clear(const gl::ClearParameters &clearParams, gl::Framebuffer *frameBuffer);
 
     virtual void markAllStateDirty();
@@ -139,22 +138,23 @@ class Renderer9 : public Renderer
     virtual RenderTarget *createRenderTarget(int width, int height, GLenum format, GLsizei samples);
 
     // Shader creation
     virtual ShaderImpl *createShader(GLenum type);
     virtual ProgramImpl *createProgram();
 
     // Shader operations
     virtual void releaseShaderCompiler();
-    virtual ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type,
-                                             const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                             bool separatedOutputBuffers);
-    virtual ShaderExecutable *compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
-                                                  const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
-                                                  bool separatedOutputBuffers, D3DWorkaroundType workaround);
+    virtual gl::Error loadExecutable(const void *function, size_t length, rx::ShaderType type,
+                                     const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                     bool separatedOutputBuffers, ShaderExecutable **outExecutable);
+    virtual gl::Error compileToExecutable(gl::InfoLog &infoLog, const std::string &shaderHLSL, rx::ShaderType type,
+                                          const std::vector<gl::LinkedVarying> &transformFeedbackVaryings,
+                                          bool separatedOutputBuffers, D3DWorkaroundType workaround,
+                                          ShaderExecutable **outExectuable);
     virtual UniformStorage *createUniformStorage(size_t storageSize);
 
     // Image operations
     virtual Image *createImage();
     virtual void generateMipmap(Image *dest, Image *source);
     virtual TextureStorage *createTextureStorage2D(SwapChain *swapChain);
     virtual TextureStorage *createTextureStorage2D(GLenum internalformat, bool renderTarget, GLsizei width, GLsizei height, int levels);
     virtual TextureStorage *createTextureStorageCube(GLenum internalformat, bool renderTarget, int size, int levels);
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h
@@ -5,16 +5,18 @@
 //
 
 // ShaderCache: Defines rx::ShaderCache, a cache of Direct3D shader objects
 // keyed by their byte code.
 
 #ifndef LIBGLESV2_RENDERER_SHADER_CACHE_H_
 #define LIBGLESV2_RENDERER_SHADER_CACHE_H_
 
+#include "libGLESv2/Error.h"
+
 #include "common/debug.h"
 
 #include <cstddef>
 #include <unordered_map>
 #include <string>
 
 namespace rx
 {
@@ -32,44 +34,46 @@ class ShaderCache
         ASSERT(mMap.empty());
     }
 
     void initialize(IDirect3DDevice9* device)
     {
         mDevice = device;
     }
 
-    ShaderObject *create(const DWORD *function, size_t length)
+    gl::Error create(const DWORD *function, size_t length, ShaderObject **outShaderObject)
     {
         std::string key(reinterpret_cast<const char*>(function), length);
         typename Map::iterator it = mMap.find(key);
         if (it != mMap.end())
         {
             it->second->AddRef();
-            return it->second;
+            *outShaderObject = it->second;
+            return gl::Error(GL_NO_ERROR);
         }
 
         ShaderObject *shader;
         HRESULT result = createShader(function, &shader);
         if (FAILED(result))
         {
-            return NULL;
+            return gl::Error(GL_OUT_OF_MEMORY, "Failed to create shader, result: 0x%X.", result);
         }
 
         // Random eviction policy.
         if (mMap.size() >= kMaxMapSize)
         {
             SafeRelease(mMap.begin()->second);
             mMap.erase(mMap.begin());
         }
 
         shader->AddRef();
         mMap[key] = shader;
 
-        return shader;
+        *outShaderObject = shader;
+        return gl::Error(GL_NO_ERROR);
     }
 
     void clear()
     {
         for (typename Map::iterator it = mMap.begin(); it != mMap.end(); ++it)
         {
             SafeRelease(it->second);
         }
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp
@@ -82,16 +82,23 @@ int TextureStorage9::getTopLevel() const
     return mTopLevel;
 }
 
 int TextureStorage9::getLevelCount() const
 {
     return getBaseTexture() ? (getBaseTexture()->GetLevelCount() - getTopLevel()) : 0;
 }
 
+gl::Error TextureStorage9::setData(const gl::ImageIndex &index, const gl::Box &sourceBox, GLenum internalFormat, GLenum type,
+                                   const gl::PixelUnpackState &unpack, const uint8_t *pixelData)
+{
+    UNREACHABLE();
+    return gl::Error(GL_INVALID_OPERATION);
+}
+
 TextureStorage9_2D::TextureStorage9_2D(Renderer *renderer, SwapChain9 *swapchain)
     : TextureStorage9(renderer, D3DUSAGE_RENDERTARGET)
 {
     IDirect3DTexture9 *surfaceTexture = swapchain->getOffscreenTexture();
     mTexture = surfaceTexture;
     mRenderTarget = NULL;
 
     initializeRenderTarget();
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h
@@ -37,16 +37,19 @@ class TextureStorage9 : public TextureSt
     virtual RenderTarget *getRenderTarget(const gl::ImageIndex &index) = 0;
     virtual void generateMipmap(const gl::ImageIndex &sourceIndex, const gl::ImageIndex &destIndex) = 0;
 
     virtual int getTopLevel() const;
     virtual bool isRenderTarget() const;