Bug 1085046. Update ANGLE to get Intel D3D11 texture upload performance work around.
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Tue, 28 Oct 2014 23:04:32 -0400
changeset 212813 d398f259ef257d4bec6550b59f002073ed5a617e
parent 212812 4b6381e5f9051f2e2d2c70676816c3e720c056d7
child 212814 408e9201cebb5a13756b9fd0958b8933918760fc
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)
bugs1085046
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
Bug 1085046. Update ANGLE to get Intel D3D11 texture upload performance work around.
gfx/angle/AUTHORS
gfx/angle/CONTRIBUTORS
gfx/angle/include/GLSLANG/ShaderLang.h
gfx/angle/include/GLSLANG/ShaderVars.h
gfx/angle/src/commit.h
gfx/angle/src/common/angleutils.cpp
gfx/angle/src/compiler/translator/Compiler.cpp
gfx/angle/src/compiler/translator/ShaderLang.cpp
gfx/angle/src/compiler/translator/ShaderVars.cpp
gfx/angle/src/compiler/translator/TranslatorESSL.cpp
gfx/angle/src/libGLESv2/Context.cpp
gfx/angle/src/libGLESv2/Context.h
gfx/angle/src/libGLESv2/ImageIndex.cpp
gfx/angle/src/libGLESv2/ImageIndex.h
gfx/angle/src/libGLESv2/Program.cpp
gfx/angle/src/libGLESv2/Program.h
gfx/angle/src/libGLESv2/ProgramBinary.cpp
gfx/angle/src/libGLESv2/ProgramBinary.h
gfx/angle/src/libGLESv2/State.cpp
gfx/angle/src/libGLESv2/State.h
gfx/angle/src/libGLESv2/angletypes.cpp
gfx/angle/src/libGLESv2/angletypes.h
gfx/angle/src/libGLESv2/libGLESv2.cpp
gfx/angle/src/libGLESv2/renderer/Image.cpp
gfx/angle/src/libGLESv2/renderer/Image.h
gfx/angle/src/libGLESv2/renderer/ProgramImpl.h
gfx/angle/src/libGLESv2/renderer/Renderer.h
gfx/angle/src/libGLESv2/renderer/Workarounds.h
gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.cpp
gfx/angle/src/libGLESv2/renderer/d3d/HLSLCompiler.h
gfx/angle/src/libGLESv2/renderer/d3d/ImageD3D.h
gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.cpp
gfx/angle/src/libGLESv2/renderer/d3d/ProgramD3D.h
gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.cpp
gfx/angle/src/libGLESv2/renderer/d3d/TextureD3D.h
gfx/angle/src/libGLESv2/renderer/d3d/TextureStorage.h
gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.cpp
gfx/angle/src/libGLESv2/renderer/d3d/VertexDataManager.h
gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.cpp
gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Image11.h
gfx/angle/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp
gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
gfx/angle/src/libGLESv2/renderer/d3d/d3d11/Renderer11.h
gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.cpp
gfx/angle/src/libGLESv2/renderer/d3d/d3d11/TextureStorage11.h
gfx/angle/src/libGLESv2/renderer/d3d/d3d11/renderer11_utils.cpp
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.cpp
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Blit9.h
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.cpp
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Image9.h
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/Renderer9.h
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/ShaderCache.h
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.cpp
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/TextureStorage9.h
gfx/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp
gfx/angle/src/libGLESv2/validationES.cpp
gfx/angle/src/libGLESv2/validationES2.cpp
--- 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;
     virtual bool isManaged() const;
     virtual int getLevelCount() const;
 
+    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:
     int mTopLevel;
     Renderer9 *mRenderer;
 
     TextureStorage9(Renderer *renderer, DWORD usage);
 
   private:
     DISALLOW_COPY_AND_ASSIGN(TextureStorage9);
--- a/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp
+++ b/gfx/angle/src/libGLESv2/renderer/d3d/d3d9/renderer9_utils.cpp
@@ -386,18 +386,19 @@ void GenerateCaps(IDirect3D9 *d3d9, IDir
 
     const size_t reservedVertexUniformVectors = 2; // dx_ViewAdjust and dx_DepthRange.
     const size_t MAX_VERTEX_CONSTANT_VECTORS_D3D9 = 256;
     caps->maxVertexUniformVectors = MAX_VERTEX_CONSTANT_VECTORS_D3D9 - reservedVertexUniformVectors;
     caps->maxVertexUniformComponents = caps->maxVertexUniformVectors * 4;
 
     caps->maxVertexUniformBlocks = 0;
 
-    const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 10;
-    const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 8;
+    // SM3 only supports 11 output variables, with a special 12th register for PSIZE.
+    const size_t MAX_VERTEX_OUTPUT_VECTORS_SM3 = 9;
+    const size_t MAX_VERTEX_OUTPUT_VECTORS_SM2 = 7;
     caps->maxVertexOutputComponents = ((deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0)) ? MAX_VERTEX_OUTPUT_VECTORS_SM3
                                                                                                : MAX_VERTEX_OUTPUT_VECTORS_SM2) * 4;
 
     // Only Direct3D 10 ready devices support all the necessary vertex texture formats.
     // We test this using D3D9 by checking support for the R16F format.
     if (deviceCaps.VertexShaderVersion >= D3DVS_VERSION(3, 0) &&
         SUCCEEDED(d3d9->CheckDeviceFormat(adapter, deviceType, currentDisplayMode.Format,
                                           D3DUSAGE_QUERY_VERTEXTEXTURE, D3DRTYPE_TEXTURE, D3DFMT_R16F)))
@@ -537,14 +538,15 @@ RenderTarget9 *GetAttachmentRenderTarget
     RenderTarget *renderTarget = rx::GetAttachmentRenderTarget(attachment);
     return RenderTarget9::makeRenderTarget9(renderTarget);
 }
 
 Workarounds GenerateWorkarounds()
 {
     Workarounds workarounds;
     workarounds.mrtPerfWorkaround = true;
+    workarounds.setDataFasterThanImageUpload = false;
     return workarounds;
 }
 
 }
 
 }
--- a/gfx/angle/src/libGLESv2/validationES.cpp
+++ b/gfx/angle/src/libGLESv2/validationES.cpp
@@ -583,17 +583,18 @@ bool ValidateBlitFramebufferParameters(g
                         ASSERT(attachment);
 
                         if (attachment->type() != GL_TEXTURE_2D && attachment->type() != GL_RENDERBUFFER)
                         {
                             context->recordError(Error(GL_INVALID_OPERATION));
                             return false;
                         }
 
-                        if (attachment->getActualFormat() != readColorBuffer->getActualFormat())
+                        // Return an error if the destination formats do not match
+                        if (attachment->getInternalFormat() != readColorBuffer->getInternalFormat())
                         {
                             context->recordError(Error(GL_INVALID_OPERATION));
                             return false;
                         }
                     }
                 }
                 if (readFramebuffer->getSamples() != 0 && IsPartialBlit(context, readColorBuffer, drawColorBuffer,
                                                                         srcX0, srcY0, srcX1, srcY1,
--- a/gfx/angle/src/libGLESv2/validationES2.cpp
+++ b/gfx/angle/src/libGLESv2/validationES2.cpp
@@ -527,66 +527,71 @@ bool ValidateES2CopyTexImageParameters(C
     if (isSubImage)
     {
         switch (textureFormat)
         {
           case GL_ALPHA:
             if (colorbufferFormat != GL_ALPHA8_EXT &&
                 colorbufferFormat != GL_RGBA4 &&
                 colorbufferFormat != GL_RGB5_A1 &&
-                colorbufferFormat != GL_RGBA8_OES)
+                colorbufferFormat != GL_RGBA8_OES &&
+                colorbufferFormat != GL_BGRA8_EXT)
             {
                 context->recordError(Error(GL_INVALID_OPERATION));
                 return false;
             }
             break;
           case GL_LUMINANCE:
               if (colorbufferFormat != GL_R8_EXT &&
                   colorbufferFormat != GL_RG8_EXT &&
                   colorbufferFormat != GL_RGB565 &&
                   colorbufferFormat != GL_RGB8_OES &&
                   colorbufferFormat != GL_RGBA4 &&
                   colorbufferFormat != GL_RGB5_A1 &&
-                  colorbufferFormat != GL_RGBA8_OES)
+                  colorbufferFormat != GL_RGBA8_OES &&
+                  colorbufferFormat != GL_BGRA8_EXT)
               {
                   context->recordError(Error(GL_INVALID_OPERATION));
                   return false;
               }
               break;
           case GL_RED_EXT:
               if (colorbufferFormat != GL_R8_EXT &&
                   colorbufferFormat != GL_RG8_EXT &&
                   colorbufferFormat != GL_RGB565 &&
                   colorbufferFormat != GL_RGB8_OES &&
                   colorbufferFormat != GL_RGBA4 &&
                   colorbufferFormat != GL_RGB5_A1 &&
-                  colorbufferFormat != GL_RGBA8_OES)
+                  colorbufferFormat != GL_RGBA8_OES &&
+                  colorbufferFormat != GL_BGRA8_EXT)
               {
                   context->recordError(Error(GL_INVALID_OPERATION));
                   return false;
               }
               break;
           case GL_RG_EXT:
               if (colorbufferFormat != GL_RG8_EXT &&
                   colorbufferFormat != GL_RGB565 &&
                   colorbufferFormat != GL_RGB8_OES &&
                   colorbufferFormat != GL_RGBA4 &&
                   colorbufferFormat != GL_RGB5_A1 &&
-                  colorbufferFormat != GL_RGBA8_OES)
+                  colorbufferFormat != GL_RGBA8_OES &&
+                  colorbufferFormat != GL_BGRA8_EXT)
               {
                   context->recordError(Error(GL_INVALID_OPERATION));
                   return false;
               }
               break;
           case GL_RGB:
             if (colorbufferFormat != GL_RGB565 &&
                 colorbufferFormat != GL_RGB8_OES &&
                 colorbufferFormat != GL_RGBA4 &&
                 colorbufferFormat != GL_RGB5_A1 &&
-                colorbufferFormat != GL_RGBA8_OES)
+                colorbufferFormat != GL_RGBA8_OES &&
+                colorbufferFormat != GL_BGRA8_EXT)
             {
                 context->recordError(Error(GL_INVALID_OPERATION));
                 return false;
             }
             break;
           case GL_LUMINANCE_ALPHA:
           case GL_RGBA:
             if (colorbufferFormat != GL_RGBA4 &&