Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / angle / src / libGLESv2 / ProgramBinary.cpp
index db993a5..40f1e8c 100644 (file)
@@ -1,6 +1,5 @@
-#include "precompiled.h"
 //
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Copyright (c) 2002-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 "libGLESv2/BinaryStream.h"
 #include "libGLESv2/ProgramBinary.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/FramebufferAttachment.h"
+#include "libGLESv2/Renderbuffer.h"
 #include "libGLESv2/renderer/ShaderExecutable.h"
 
 #include "common/debug.h"
 #include "common/version.h"
-#include "utilities.h"
+#include "common/utilities.h"
+#include "common/platform.h"
 
 #include "libGLESv2/main.h"
 #include "libGLESv2/Shader.h"
 #include "libGLESv2/Program.h"
-#include "libGLESv2/renderer/Renderer.h"
-#include "libGLESv2/renderer/VertexDataManager.h"
-
-#undef near
-#undef far
+#include "libGLESv2/renderer/ProgramImpl.h"
+#include "libGLESv2/renderer/d3d/ShaderD3D.h"
+#include "libGLESv2/Context.h"
+#include "libGLESv2/Buffer.h"
+#include "common/blocklayout.h"
+#include "common/features.h"
 
 namespace gl
 {
-std::string str(int i)
+
+namespace
 {
-    char buffer[20];
-    snprintf(buffer, sizeof(buffer), "%d", i);
-    return buffer;
-}
 
-static rx::D3DWorkaroundType DiscardWorkaround(bool usesDiscard, bool nestedBreak)
+unsigned int ParseAndStripArrayIndex(std::string* name)
 {
-    if (usesDiscard)
-    {
-        // ANGLE issue 486:
-        // Work-around a D3D9 compiler bug that presents itself when using conditional discard, by disabling optimization
-        return rx::ANGLE_D3D_WORKAROUND_SKIP_OPTIMIZATION;
-    }
+    unsigned int subscript = GL_INVALID_INDEX;
 
-    if (nestedBreak)
+    // Strip any trailing array operator and retrieve the subscript
+    size_t open = name->find_last_of('[');
+    size_t close = name->find_last_of(']');
+    if (open != std::string::npos && close == name->length() - 1)
     {
-        // ANGLE issue 603:
-        // Work-around a D3D9 compiler bug that presents itself when using break in a nested loop, by maximizing optimization
-        // We want to keep the use of ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION minimal to prevent hangs, so usesDiscard takes precedence
-        return rx::ANGLE_D3D_WORKAROUND_MAX_OPTIMIZATION;
+        subscript = atoi(name->substr(open + 1).c_str());
+        name->erase(open);
     }
 
-    return rx::ANGLE_D3D_WORKAROUND_NONE;
+    return subscript;
+}
+
 }
 
-UniformLocation::UniformLocation(const std::string &name, unsigned int element, unsigned int index)
+VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
     : name(name), element(element), index(index)
 {
 }
 
-unsigned int ProgramBinary::mCurrentSerial = 1;
+LinkedVarying::LinkedVarying()
+{
+}
 
-ProgramBinary::ProgramBinary(rx::Renderer *renderer) : mRenderer(renderer), RefCountObject(0), mSerial(issueSerial())
+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)
 {
-    mPixelExecutable = NULL;
-    mVertexExecutable = NULL;
-    mGeometryExecutable = NULL;
+}
 
-    mValidated = false;
+LinkResult::LinkResult(bool linkSuccess, const Error &error)
+    : linkSuccess(linkSuccess),
+      error(error)
+{
+}
 
-    for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
-    {
-        mSemanticIndex[index] = -1;
-    }
+unsigned int ProgramBinary::mCurrentSerial = 1;
 
-    for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++)
-    {
-        mSamplersPS[index].active = false;
-    }
+ProgramBinary::ProgramBinary(rx::ProgramImpl *impl)
+    : RefCountObject(0),
+      mProgram(impl),
+      mValidated(false),
+      mSerial(issueSerial())
+{
+    ASSERT(impl);
 
-    for (int index = 0; index < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; index++)
+    for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
     {
-        mSamplersVS[index].active = false;
+        mSemanticIndex[index] = -1;
     }
-
-    mUsedVertexSamplerRange = 0;
-    mUsedPixelSamplerRange = 0;
-    mUsesPointSize = false;
 }
 
 ProgramBinary::~ProgramBinary()
 {
-    delete mPixelExecutable;
-    mPixelExecutable = NULL;
-
-    delete mVertexExecutable;
-    mVertexExecutable = NULL;
-
-    delete mGeometryExecutable;
-    mGeometryExecutable = NULL;
-
-    while (!mUniforms.empty())
-    {
-        delete mUniforms.back();
-        mUniforms.pop_back();
-    }
+    reset();
+    SafeDelete(mProgram);
 }
 
 unsigned int ProgramBinary::getSerial() const
@@ -117,21 +106,6 @@ unsigned int ProgramBinary::issueSerial()
     return mCurrentSerial++;
 }
 
-rx::ShaderExecutable *ProgramBinary::getPixelExecutable()
-{
-    return mPixelExecutable;
-}
-
-rx::ShaderExecutable *ProgramBinary::getVertexExecutable()
-{
-    return mVertexExecutable;
-}
-
-rx::ShaderExecutable *ProgramBinary::getGeometryExecutable()
-{
-    return mGeometryExecutable;
-}
-
 GLuint ProgramBinary::getAttributeLocation(const char *name)
 {
     if (name)
@@ -151,1935 +125,625 @@ GLuint ProgramBinary::getAttributeLocation(const char *name)
 int ProgramBinary::getSemanticIndex(int attributeIndex)
 {
     ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
-    
+
     return mSemanticIndex[attributeIndex];
 }
 
 // Returns one more than the highest sampler index used.
 GLint ProgramBinary::getUsedSamplerRange(SamplerType type)
 {
-    switch (type)
-    {
-      case SAMPLER_PIXEL:
-        return mUsedPixelSamplerRange;
-      case SAMPLER_VERTEX:
-        return mUsedVertexSamplerRange;
-      default:
-        UNREACHABLE();
-        return 0;
-    }
+    return mProgram->getUsedSamplerRange(type);
 }
 
 bool ProgramBinary::usesPointSize() const
 {
-    return mUsesPointSize;
+    return mProgram->usesPointSize();
 }
 
-bool ProgramBinary::usesPointSpriteEmulation() const
+GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
 {
-    return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
+    return mProgram->getSamplerMapping(type, samplerIndex, caps);
 }
 
-bool ProgramBinary::usesGeometryShader() const
+GLenum ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
 {
-    return usesPointSpriteEmulation();
+    return mProgram->getSamplerTextureType(type, samplerIndex);
 }
 
-// Returns the index of the texture image unit (0-19) corresponding to a Direct3D 9 sampler
-// index (0-15 for the pixel shader and 0-3 for the vertex shader).
-GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex)
+GLint ProgramBinary::getUniformLocation(std::string name)
 {
-    GLint logicalTextureUnit = -1;
-
-    switch (type)
-    {
-      case SAMPLER_PIXEL:
-        ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
-
-        if (mSamplersPS[samplerIndex].active)
-        {
-            logicalTextureUnit = mSamplersPS[samplerIndex].logicalTextureUnit;
-        }
-        break;
-      case SAMPLER_VERTEX:
-        ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
-
-        if (mSamplersVS[samplerIndex].active)
-        {
-            logicalTextureUnit = mSamplersVS[samplerIndex].logicalTextureUnit;
-        }
-        break;
-      default: UNREACHABLE();
-    }
-
-    if (logicalTextureUnit >= 0 && logicalTextureUnit < (GLint)mRenderer->getMaxCombinedTextureImageUnits())
-    {
-        return logicalTextureUnit;
-    }
+    return mProgram->getUniformLocation(name);
+}
 
-    return -1;
+GLuint ProgramBinary::getUniformIndex(std::string name)
+{
+    return mProgram->getUniformIndex(name);
 }
 
-// Returns the texture type for a given Direct3D 9 sampler type and
-// index (0-15 for the pixel shader and 0-3 for the vertex shader).
-TextureType ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
+GLuint ProgramBinary::getUniformBlockIndex(std::string name)
 {
-    switch (type)
-    {
-      case SAMPLER_PIXEL:
-        ASSERT(samplerIndex < sizeof(mSamplersPS)/sizeof(mSamplersPS[0]));
-        ASSERT(mSamplersPS[samplerIndex].active);
-        return mSamplersPS[samplerIndex].textureType;
-      case SAMPLER_VERTEX:
-        ASSERT(samplerIndex < sizeof(mSamplersVS)/sizeof(mSamplersVS[0]));
-        ASSERT(mSamplersVS[samplerIndex].active);
-        return mSamplersVS[samplerIndex].textureType;
-      default: UNREACHABLE();
-    }
+    return mProgram->getUniformBlockIndex(name);
+}
 
-    return TEXTURE_2D;
+UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
+{
+    return mProgram->getUniformBlockByIndex(blockIndex);
 }
 
-GLint ProgramBinary::getUniformLocation(std::string name)
+GLint ProgramBinary::getFragDataLocation(const char *name) const
 {
-    unsigned int subscript = 0;
+    std::string baseName(name);
+    unsigned int arrayIndex;
+    arrayIndex = ParseAndStripArrayIndex(&baseName);
 
-    // Strip any trailing array operator and retrieve the subscript
-    size_t open = name.find_last_of('[');
-    size_t close = name.find_last_of(']');
-    if (open != std::string::npos && close == name.length() - 1)
+    for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
     {
-        subscript = atoi(name.substr(open + 1).c_str());
-        name.erase(open);
-    }
+        const VariableLocation &outputVariable = locationIt->second;
 
-    unsigned int numUniforms = mUniformIndex.size();
-    for (unsigned int location = 0; location < numUniforms; location++)
-    {
-        if (mUniformIndex[location].name == name &&
-            mUniformIndex[location].element == subscript)
+        if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
         {
-            return location;
+            return static_cast<GLint>(locationIt->first);
         }
     }
 
     return -1;
 }
 
-bool ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat* v)
+size_t ProgramBinary::getTransformFeedbackVaryingCount() const
 {
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
-    }
+    return mProgram->getTransformFeedbackLinkedVaryings().size();
+}
 
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
+const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const
+{
+    return mProgram->getTransformFeedbackLinkedVaryings()[idx];
+}
 
-    int elementCount = targetUniform->elementCount();
+GLenum ProgramBinary::getTransformFeedbackBufferMode() const
+{
+    return mProgram->getTransformFeedbackBufferMode();
+}
 
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) {
+    mProgram->setUniform1fv(location, count, v);
+}
 
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) {
+    mProgram->setUniform2fv(location, count, v);
+}
 
-    if (targetUniform->type == GL_FLOAT)
-    {
-        GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) {
+    mProgram->setUniform3fv(location, count, v);
+}
 
-        for (int i = 0; i < count; i++)
-        {
-            target[0] = v[0];
-            target[1] = 0;
-            target[2] = 0;
-            target[3] = 0;
-            target += 4;
-            v += 1;
-        }
-    }
-    else if (targetUniform->type == GL_BOOL)
-    {
-        GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) {
+    mProgram->setUniform4fv(location, count, v);
+}
 
-        for (int i = 0; i < count; i++)
-        {
-            boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams[1] = GL_FALSE;
-            boolParams[2] = GL_FALSE;
-            boolParams[3] = GL_FALSE;
-            boolParams += 4;
-            v += 1;
-        }
-    }
-    else
-    {
-        return false;
-    }
+void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) {
+    mProgram->setUniform1iv(location, count, v);
+}
 
-    return true;
+void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) {
+    mProgram->setUniform2iv(location, count, v);
 }
 
-bool ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
-{
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
-    }
+void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) {
+    mProgram->setUniform3iv(location, count, v);
+}
 
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
+void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) {
+    mProgram->setUniform4iv(location, count, v);
+}
 
-    int elementCount = targetUniform->elementCount();
+void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) {
+    mProgram->setUniform1uiv(location, count, v);
+}
 
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) {
+    mProgram->setUniform2uiv(location, count, v);
+}
 
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) {
+    mProgram->setUniform3uiv(location, count, v);
+}
 
-    if (targetUniform->type == GL_FLOAT_VEC2)
-    {
-        GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) {
+    mProgram->setUniform4uiv(location, count, v);
+}
 
-        for (int i = 0; i < count; i++)
-        {
-            target[0] = v[0];
-            target[1] = v[1];
-            target[2] = 0;
-            target[3] = 0;
-            target += 4;
-            v += 2;
-        }
-    }
-    else if (targetUniform->type == GL_BOOL_VEC2)
-    {
-        GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
+    mProgram->setUniformMatrix2fv(location, count, transpose, v);
+}
 
-        for (int i = 0; i < count; i++)
-        {
-            boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams[2] = GL_FALSE;
-            boolParams[3] = GL_FALSE;
-            boolParams += 4;
-            v += 2;
-        }
-    }
-    else 
-    {
-        return false;
-    }
+void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
+    mProgram->setUniformMatrix3fv(location, count, transpose, v);
+}
 
-    return true;
+void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
+    mProgram->setUniformMatrix4fv(location, count, transpose, v);
 }
 
-bool ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
-{
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
-    }
+void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
+    mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
+}
 
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
+void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
+    mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
+}
 
-    int elementCount = targetUniform->elementCount();
+void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
+    mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
+}
 
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
+    mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
+}
 
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
+    mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
+}
 
-    if (targetUniform->type == GL_FLOAT_VEC3)
-    {
-        GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
+    mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
+}
 
-        for (int i = 0; i < count; i++)
-        {
-            target[0] = v[0];
-            target[1] = v[1];
-            target[2] = v[2];
-            target[3] = 0;
-            target += 4;
-            v += 3;
-        }
-    }
-    else if (targetUniform->type == GL_BOOL_VEC3)
-    {
-        GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+void ProgramBinary::getUniformfv(GLint location, GLfloat *v) {
+    mProgram->getUniformfv(location, v);
+}
 
-        for (int i = 0; i < count; i++)
-        {
-            boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams[3] = GL_FALSE;
-            boolParams += 4;
-            v += 3;
-        }
-    }
-    else 
-    {
-        return false;
-    }
+void ProgramBinary::getUniformiv(GLint location, GLint *v) {
+    mProgram->getUniformiv(location, v);
+}
 
-    return true;
+void ProgramBinary::getUniformuiv(GLint location, GLuint *v) {
+    mProgram->getUniformuiv(location, v);
 }
 
-bool ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+void ProgramBinary::updateSamplerMapping()
 {
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
-    }
-
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
+    return mProgram->updateSamplerMapping();
+}
 
-    int elementCount = targetUniform->elementCount();
+// Applies all the uniforms set for this program object to the renderer
+Error ProgramBinary::applyUniforms()
+{
+    return mProgram->applyUniforms();
+}
 
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+Error ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const Caps &caps)
+{
+    return mProgram->applyUniformBuffers(boundBuffers, caps);
+}
 
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+bool ProgramBinary::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
+{
+    std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
+    std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
 
-    if (targetUniform->type == GL_FLOAT_VEC4)
+    for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
     {
-        GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
+        PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
+        bool matched = false;
+
+        // Built-in varyings obey special rules
+        if (input->isBuiltIn())
+        {
+            continue;
+        }
 
-        for (int i = 0; i < count; i++)
+        for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
         {
-            target[0] = v[0];
-            target[1] = v[1];
-            target[2] = v[2];
-            target[3] = v[3];
-            target += 4;
-            v += 4;
+            PackedVarying *output = &vertexVaryings[vertVaryingIndex];
+            if (output->name == input->name)
+            {
+                if (!linkValidateVaryings(infoLog, output->name, *input, *output))
+                {
+                    return false;
+                }
+
+                output->registerIndex = input->registerIndex;
+                output->columnIndex = input->columnIndex;
+
+                matched = true;
+                break;
+            }
         }
-    }
-    else if (targetUniform->type == GL_BOOL_VEC4)
-    {
-        GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
 
-        for (int i = 0; i < count; i++)
+        // We permit unmatched, unreferenced varyings
+        if (!matched && input->staticUse)
         {
-            boolParams[0] = (v[0] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams[1] = (v[1] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams[2] = (v[2] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams[3] = (v[3] == 0.0f) ? GL_FALSE : GL_TRUE;
-            boolParams += 4;
-            v += 4;
+            infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
+            return false;
         }
     }
-    else 
-    {
-        return false;
-    }
 
     return true;
 }
 
-template<typename T, int targetWidth, int targetHeight, int srcWidth, int srcHeight>
-void transposeMatrix(T *target, const GLfloat *value)
+LinkResult ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length)
 {
-    int copyWidth = std::min(targetWidth, srcWidth);
-    int copyHeight = std::min(targetHeight, srcHeight);
+#if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
+    return LinkResult(false, Error(GL_NO_ERROR));
+#else
+    ASSERT(binaryFormat == mProgram->getBinaryFormat());
 
-    for (int x = 0; x < copyWidth; x++)
+    reset();
+
+    BinaryInputStream stream(binary, length);
+
+    GLenum format = stream.readInt<GLenum>();
+    if (format != mProgram->getBinaryFormat())
     {
-        for (int y = 0; y < copyHeight; y++)
-        {
-            target[x * targetWidth + y] = (T)value[y * srcWidth + x];
-        }
+        infoLog.append("Invalid program binary format.");
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
-    // clear unfilled right side
-    for (int y = 0; y < copyHeight; y++)
+
+    int majorVersion = stream.readInt<int>();
+    int minorVersion = stream.readInt<int>();
+    if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
     {
-        for (int x = srcWidth; x < targetWidth; x++)
-        {
-            target[y * targetWidth + x] = (T)0;
-        }
+        infoLog.append("Invalid program binary version.");
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
-    // clear unfilled bottom.
-    for (int y = srcHeight; y < targetHeight; y++)
+
+    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)
     {
-        for (int x = 0; x < targetWidth; x++)
-        {
-            target[y * targetWidth + x] = (T)0;
-        }
+        infoLog.append("Invalid program binary version.");
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
-}
 
-bool ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value)
-{
-    if (location < 0 || location >= (int)mUniformIndex.size())
+    int compileFlags = stream.readInt<int>();
+    if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
     {
-        return false;
+        infoLog.append("Mismatched compilation flags.");
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
-
-    if (targetUniform->type != GL_FLOAT_MAT2)
+    for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
     {
-        return false;
+        stream.readInt(&mLinkedAttribute[i].type);
+        stream.readString(&mLinkedAttribute[i].name);
+        stream.readInt(&mProgram->getShaderAttributes()[i].type);
+        stream.readString(&mProgram->getShaderAttributes()[i].name);
+        stream.readInt(&mSemanticIndex[i]);
     }
 
-    int elementCount = targetUniform->elementCount();
-
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-    GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8;
+    initAttributesByLayout();
 
-    for (int i = 0; i < count; i++)
+    LinkResult result = mProgram->load(infoLog, &stream);
+    if (result.error.isError() || !result.linkSuccess)
     {
-        transposeMatrix<GLfloat,4,2,2,2>(target, value);
-        target += 8;
-        value += 4;
+        return result;
     }
 
-    return true;
+    return LinkResult(true, Error(GL_NO_ERROR));
+#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
 }
 
-bool ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value)
+Error ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length)
 {
-    if (location < 0 || location >= (int)mUniformIndex.size())
+    if (binaryFormat)
     {
-        return false;
+        *binaryFormat = mProgram->getBinaryFormat();
     }
 
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
+    BinaryOutputStream stream;
+
+    stream.writeInt(mProgram->getBinaryFormat());
+    stream.writeInt(ANGLE_MAJOR_VERSION);
+    stream.writeInt(ANGLE_MINOR_VERSION);
+    stream.writeBytes(reinterpret_cast<const unsigned char*>(ANGLE_COMMIT_HASH), ANGLE_COMMIT_HASH_SIZE);
+    stream.writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
 
-    if (targetUniform->type != GL_FLOAT_MAT3)
+    for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
     {
-        return false;
+        stream.writeInt(mLinkedAttribute[i].type);
+        stream.writeString(mLinkedAttribute[i].name);
+        stream.writeInt(mProgram->getShaderAttributes()[i].type);
+        stream.writeString(mProgram->getShaderAttributes()[i].name);
+        stream.writeInt(mSemanticIndex[i]);
     }
 
-    int elementCount = targetUniform->elementCount();
+    mProgram->save(&stream);
 
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-    GLfloat *target = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12;
+    GLsizei streamLength = stream.length();
+    const void *streamData = stream.data();
 
-    for (int i = 0; i < count; i++)
+    if (streamLength > bufSize)
     {
-        transposeMatrix<GLfloat,4,3,3,3>(target, value);
-        target += 12;
-        value += 9;
+        if (length)
+        {
+            *length = 0;
+        }
+
+        // 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);
     }
 
-    return true;
-}
+    if (binary)
+    {
+        char *ptr = (char*) binary;
 
+        memcpy(ptr, streamData, streamLength);
+        ptr += streamLength;
 
-bool ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value)
-{
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
+        ASSERT(ptr - streamLength == binary);
     }
 
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
-
-    if (targetUniform->type != GL_FLOAT_MAT4)
+    if (length)
     {
-        return false;
+        *length = streamLength;
     }
 
-    int elementCount = targetUniform->elementCount();
-
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-    GLfloat *target = (GLfloat*)(targetUniform->data + mUniformIndex[location].element * sizeof(GLfloat) * 16);
+    return Error(GL_NO_ERROR);
+}
 
-    for (int i = 0; i < count; i++)
+GLint ProgramBinary::getLength()
+{
+    GLint length;
+    Error error = save(NULL, NULL, INT_MAX, &length);
+    if (error.isError())
     {
-        transposeMatrix<GLfloat,4,4,4,4>(target, value);
-        target += 16;
-        value += 16;
+        return 0;
     }
 
-    return true;
+    return length;
 }
 
-bool ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v)
+LinkResult ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, Shader *fragmentShader, Shader *vertexShader,
+                               const std::vector<std::string>& transformFeedbackVaryings, GLenum transformFeedbackBufferMode, const Caps &caps)
 {
-    if (location < 0 || location >= (int)mUniformIndex.size())
+    if (!fragmentShader || !fragmentShader->isCompiled())
     {
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
+    ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
 
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
-
-    int elementCount = targetUniform->elementCount();
-
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
+    if (!vertexShader || !vertexShader->isCompiled())
+    {
+        return LinkResult(false, Error(GL_NO_ERROR));
+    }
+    ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
 
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
+    reset();
 
-    if (targetUniform->type == GL_INT ||
-        targetUniform->type == GL_SAMPLER_2D ||
-        targetUniform->type == GL_SAMPLER_CUBE)
+    int registers;
+    std::vector<LinkedVarying> linkedVaryings;
+    LinkResult result = mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode,
+                                       &registers, &linkedVaryings, &mOutputVariables, caps);
+    if (result.error.isError() || !result.linkSuccess)
     {
-        GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+        return result;
+    }
 
-        for (int i = 0; i < count; i++)
-        {
-            target[0] = v[0];
-            target[1] = 0;
-            target[2] = 0;
-            target[3] = 0;
-            target += 4;
-            v += 1;
-        }
+    if (!linkAttributes(infoLog, attributeBindings, vertexShader))
+    {
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
-    else if (targetUniform->type == GL_BOOL)
+
+    if (!mProgram->linkUniforms(infoLog, *vertexShader, *fragmentShader, caps))
     {
-        GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
+        return LinkResult(false, Error(GL_NO_ERROR));
+    }
 
-        for (int i = 0; i < count; i++)
-        {
-            boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams[1] = GL_FALSE;
-            boolParams[2] = GL_FALSE;
-            boolParams[3] = GL_FALSE;
-            boolParams += 4;
-            v += 1;
-        }
-    }
-    else
-    {
-        return false;
-    }
-
-    return true;
-}
-
-bool ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v)
-{
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
-    }
-
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
-
-    int elementCount = targetUniform->elementCount();
-
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-
-    if (targetUniform->type == GL_INT_VEC2)
-    {
-        GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-        for (int i = 0; i < count; i++)
-        {
-            target[0] = v[0];
-            target[1] = v[1];
-            target[2] = 0;
-            target[3] = 0;
-            target += 4;
-            v += 2;
-        }
-    }
-    else if (targetUniform->type == GL_BOOL_VEC2)
-    {
-        GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-        for (int i = 0; i < count; i++)
-        {
-            boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams[2] = GL_FALSE;
-            boolParams[3] = GL_FALSE;
-            boolParams += 4;
-            v += 2;
-        }
-    }
-    else
-    {
-        return false;
-    }
-
-    return true;
-}
-
-bool ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v)
-{
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
-    }
-
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
-
-    int elementCount = targetUniform->elementCount();
-
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-
-    if (targetUniform->type == GL_INT_VEC3)
-    {
-        GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-        for (int i = 0; i < count; i++)
-        {
-            target[0] = v[0];
-            target[1] = v[1];
-            target[2] = v[2];
-            target[3] = 0;
-            target += 4;
-            v += 3;
-        }
-    }
-    else if (targetUniform->type == GL_BOOL_VEC3)
-    {
-        GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-        for (int i = 0; i < count; i++)
-        {
-            boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams[3] = GL_FALSE;
-            boolParams += 4;
-            v += 3;
-        }
-    }
-    else
-    {
-        return false;
-    }
-
-    return true;
-}
-
-bool ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v)
-{
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
-    }
-
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-    targetUniform->dirty = true;
-
-    int elementCount = targetUniform->elementCount();
-
-    if (elementCount == 1 && count > 1)
-        return false; // attempting to write an array to a non-array uniform is an INVALID_OPERATION
-
-    count = std::min(elementCount - (int)mUniformIndex[location].element, count);
-
-    if (targetUniform->type == GL_INT_VEC4)
-    {
-        GLint *target = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-        for (int i = 0; i < count; i++)
-        {
-            target[0] = v[0];
-            target[1] = v[1];
-            target[2] = v[2];
-            target[3] = v[3];
-            target += 4;
-            v += 4;
-        }
-    }
-    else if (targetUniform->type == GL_BOOL_VEC4)
-    {
-        GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-        for (int i = 0; i < count; i++)
-        {
-            boolParams[0] = (v[0] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams[1] = (v[1] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams[2] = (v[2] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams[3] = (v[3] == 0) ? GL_FALSE : GL_TRUE;
-            boolParams += 4;
-            v += 4;
-        }
-    }
-    else
-    {
-        return false;
-    }
-
-    return true;
-}
-
-bool ProgramBinary::getUniformfv(GLint location, GLsizei *bufSize, GLfloat *params)
-{
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
-    }
-
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-
-    // sized queries -- ensure the provided buffer is large enough
-    if (bufSize)
-    {
-        int requiredBytes = UniformExternalSize(targetUniform->type);
-        if (*bufSize < requiredBytes)
-        {
-            return false;
-        }
-    }
-
-    switch (targetUniform->type)
-    {
-      case GL_FLOAT_MAT2:
-        transposeMatrix<GLfloat,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
-        break;
-      case GL_FLOAT_MAT3:
-        transposeMatrix<GLfloat,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
-        break;
-      case GL_FLOAT_MAT4:
-        transposeMatrix<GLfloat,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
-        break;
-      default:
-        {
-            unsigned int size = UniformComponentCount(targetUniform->type);
-
-            switch (UniformComponentType(targetUniform->type))
-            {
-              case GL_BOOL:
-                {
-                    GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-                    for (unsigned int i = 0; i < size; i++)
-                    {
-                        params[i] = (boolParams[i] == GL_FALSE) ? 0.0f : 1.0f;
-                    }
-                }
-                break;
-              case GL_FLOAT:
-                memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLfloat),
-                       size * sizeof(GLfloat));
-                break;
-              case GL_INT:
-                {
-                    GLint *intParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-                    for (unsigned int i = 0; i < size; i++)
-                    {
-                        params[i] = (float)intParams[i];
-                    }
-                }
-                break;
-              default: UNREACHABLE();
-            }
-        }
-    }
-
-    return true;
-}
-
-bool ProgramBinary::getUniformiv(GLint location, GLsizei *bufSize, GLint *params)
-{
-    if (location < 0 || location >= (int)mUniformIndex.size())
-    {
-        return false;
-    }
-
-    Uniform *targetUniform = mUniforms[mUniformIndex[location].index];
-
-    // sized queries -- ensure the provided buffer is large enough
-    if (bufSize)
-    {
-        int requiredBytes = UniformExternalSize(targetUniform->type);
-        if (*bufSize < requiredBytes)
-        {
-            return false;
-        }
-    }
-
-    switch (targetUniform->type)
-    {
-      case GL_FLOAT_MAT2:
-        transposeMatrix<GLint,2,2,4,2>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 8);
-        break;
-      case GL_FLOAT_MAT3:
-        transposeMatrix<GLint,3,3,4,3>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 12);
-        break;
-      case GL_FLOAT_MAT4:
-        transposeMatrix<GLint,4,4,4,4>(params, (GLfloat*)targetUniform->data + mUniformIndex[location].element * 16);
-        break;
-      default:
-        {
-            unsigned int size = VariableColumnCount(targetUniform->type);
-
-            switch (UniformComponentType(targetUniform->type))
-            {
-              case GL_BOOL:
-                {
-                    GLint *boolParams = (GLint*)targetUniform->data + mUniformIndex[location].element * 4;
-
-                    for (unsigned int i = 0; i < size; i++)
-                    {
-                        params[i] = boolParams[i];
-                    }
-                }
-                break;
-              case GL_FLOAT:
-                {
-                    GLfloat *floatParams = (GLfloat*)targetUniform->data + mUniformIndex[location].element * 4;
-
-                    for (unsigned int i = 0; i < size; i++)
-                    {
-                        params[i] = (GLint)floatParams[i];
-                    }
-                }
-                break;
-              case GL_INT:
-                memcpy(params, targetUniform->data + mUniformIndex[location].element * 4 * sizeof(GLint),
-                    size * sizeof(GLint));
-                break;
-              default: UNREACHABLE();
-            }
-        }
-    }
-
-    return true;
-}
-
-void ProgramBinary::dirtyAllUniforms()
-{
-    unsigned int numUniforms = mUniforms.size();
-    for (unsigned int index = 0; index < numUniforms; index++)
-    {
-        mUniforms[index]->dirty = true;
-    }
-}
-
-// Applies all the uniforms set for this program object to the renderer
-void ProgramBinary::applyUniforms()
-{
-    // Retrieve sampler uniform values
-    for (std::vector<Uniform*>::iterator ub = mUniforms.begin(), ue = mUniforms.end(); ub != ue; ++ub)
-    {
-        Uniform *targetUniform = *ub;
-
-        if (targetUniform->dirty)
-        {
-            if (targetUniform->type == GL_SAMPLER_2D || 
-                targetUniform->type == GL_SAMPLER_CUBE)
-            {
-                int count = targetUniform->elementCount();
-                GLint (*v)[4] = (GLint(*)[4])targetUniform->data;
-
-                if (targetUniform->psRegisterIndex >= 0)
-                {
-                    unsigned int firstIndex = targetUniform->psRegisterIndex;
-
-                    for (int i = 0; i < count; i++)
-                    {
-                        unsigned int samplerIndex = firstIndex + i;
-
-                        if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
-                        {
-                            ASSERT(mSamplersPS[samplerIndex].active);
-                            mSamplersPS[samplerIndex].logicalTextureUnit = v[i][0];
-                        }
-                    }
-                }
-
-                if (targetUniform->vsRegisterIndex >= 0)
-                {
-                    unsigned int firstIndex = targetUniform->vsRegisterIndex;
-
-                    for (int i = 0; i < count; i++)
-                    {
-                        unsigned int samplerIndex = firstIndex + i;
-
-                        if (samplerIndex < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS)
-                        {
-                            ASSERT(mSamplersVS[samplerIndex].active);
-                            mSamplersVS[samplerIndex].logicalTextureUnit = v[i][0];
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    mRenderer->applyUniforms(this, &mUniforms);
-}
-
-// Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
-// Returns the number of used varying registers, or -1 if unsuccesful
-int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
-{
-    const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
-
-    fragmentShader->resetVaryingsRegisterAssignment();
-
-    for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
-    {
-        int n = VariableRowCount(varying->type) * varying->size;
-        int m = VariableColumnCount(varying->type);
-        bool success = false;
-
-        if (m == 2 || m == 3 || m == 4)
-        {
-            for (int r = 0; r <= maxVaryingVectors - n && !success; r++)
-            {
-                bool available = true;
-
-                for (int y = 0; y < n && available; y++)
-                {
-                    for (int x = 0; x < m && available; x++)
-                    {
-                        if (packing[r + y][x])
-                        {
-                            available = false;
-                        }
-                    }
-                }
-
-                if (available)
-                {
-                    varying->reg = r;
-                    varying->col = 0;
-
-                    for (int y = 0; y < n; y++)
-                    {
-                        for (int x = 0; x < m; x++)
-                        {
-                            packing[r + y][x] = &*varying;
-                        }
-                    }
-
-                    success = true;
-                }
-            }
-
-            if (!success && m == 2)
-            {
-                for (int r = maxVaryingVectors - n; r >= 0 && !success; r--)
-                {
-                    bool available = true;
-
-                    for (int y = 0; y < n && available; y++)
-                    {
-                        for (int x = 2; x < 4 && available; x++)
-                        {
-                            if (packing[r + y][x])
-                            {
-                                available = false;
-                            }
-                        }
-                    }
-
-                    if (available)
-                    {
-                        varying->reg = r;
-                        varying->col = 2;
-
-                        for (int y = 0; y < n; y++)
-                        {
-                            for (int x = 2; x < 4; x++)
-                            {
-                                packing[r + y][x] = &*varying;
-                            }
-                        }
-
-                        success = true;
-                    }
-                }
-            }
-        }
-        else if (m == 1)
-        {
-            int space[4] = {0};
-
-            for (int y = 0; y < maxVaryingVectors; y++)
-            {
-                for (int x = 0; x < 4; x++)
-                {
-                    space[x] += packing[y][x] ? 0 : 1;
-                }
-            }
-
-            int column = 0;
-
-            for (int x = 0; x < 4; x++)
-            {
-                if (space[x] >= n && space[x] < space[column])
-                {
-                    column = x;
-                }
-            }
-
-            if (space[column] >= n)
-            {
-                for (int r = 0; r < maxVaryingVectors; r++)
-                {
-                    if (!packing[r][column])
-                    {
-                        varying->reg = r;
-
-                        for (int y = r; y < r + n; y++)
-                        {
-                            packing[y][column] = &*varying;
-                        }
-
-                        break;
-                    }
-                }
-
-                varying->col = column;
-
-                success = true;
-            }
-        }
-        else UNREACHABLE();
-
-        if (!success)
-        {
-            infoLog.append("Could not pack varying %s", varying->name.c_str());
-
-            return -1;
-        }
-    }
-
-    // Return the number of used registers
-    int registers = 0;
-
-    for (int r = 0; r < maxVaryingVectors; r++)
-    {
-        if (packing[r][0] || packing[r][1] || packing[r][2] || packing[r][3])
-        {
-            registers++;
-        }
-    }
-
-    return registers;
-}
-
-bool ProgramBinary::linkVaryings(InfoLog &infoLog, int registers, const Varying *packing[][4],
-                                 std::string& pixelHLSL, std::string& vertexHLSL,
-                                 FragmentShader *fragmentShader, VertexShader *vertexShader)
-{
-    if (pixelHLSL.empty() || vertexHLSL.empty())
-    {
-        return false;
-    }
-
-    bool usesMRT = fragmentShader->mUsesMultipleRenderTargets;
-    bool usesFragColor = fragmentShader->mUsesFragColor;
-    bool usesFragData = fragmentShader->mUsesFragData;
-    if (usesFragColor && usesFragData)
-    {
-        infoLog.append("Cannot use both gl_FragColor and gl_FragData in the same fragment shader.");
-        return false;
-    }
-
-    // Write the HLSL input/output declarations
-    const int shaderModel = mRenderer->getMajorShaderModel();
-    const int maxVaryingVectors = mRenderer->getMaxVaryingVectors();
-
-    const int registersNeeded = registers + (fragmentShader->mUsesFragCoord ? 1 : 0) + (fragmentShader->mUsesPointCoord ? 1 : 0);
-
-    // The output color is broadcast to all enabled draw buffers when writing to gl_FragColor 
-    const bool broadcast = fragmentShader->mUsesFragColor;
-    const unsigned int numRenderTargets = (broadcast || usesMRT ? mRenderer->getMaxRenderTargets() : 1);
-
-    if (registersNeeded > maxVaryingVectors)
-    {
-        infoLog.append("No varying registers left to support gl_FragCoord/gl_PointCoord");
-
-        return false;
-    }
-
-    vertexShader->resetVaryingsRegisterAssignment();
-
-    for (VaryingList::iterator input = fragmentShader->mVaryings.begin(); input != fragmentShader->mVaryings.end(); input++)
-    {
-        bool matched = false;
-
-        for (VaryingList::iterator output = vertexShader->mVaryings.begin(); output != vertexShader->mVaryings.end(); output++)
-        {
-            if (output->name == input->name)
-            {
-                if (output->type != input->type || output->size != input->size)
-                {
-                    infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
-
-                    return false;
-                }
-
-                output->reg = input->reg;
-                output->col = input->col;
-
-                matched = true;
-                break;
-            }
-        }
-
-        if (!matched)
-        {
-            infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
-
-            return false;
-        }
-    }
-
-    mUsesPointSize = vertexShader->mUsesPointSize;
-    std::string varyingSemantic = (mUsesPointSize && shaderModel == 3) ? "COLOR" : "TEXCOORD";
-    std::string targetSemantic = (shaderModel >= 4) ? "SV_Target" : "COLOR";
-    std::string positionSemantic = (shaderModel >= 4) ? "SV_Position" : "POSITION";
-    std::string depthSemantic = (shaderModel >= 4) ? "SV_Depth" : "DEPTH";
-
-    // special varyings that use reserved registers
-    int reservedRegisterIndex = registers;
-    std::string fragCoordSemantic;
-    std::string pointCoordSemantic;
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
-    }
-
-    if (fragmentShader->mUsesPointCoord)
-    {
-        // Shader model 3 uses a special TEXCOORD semantic for point sprite texcoords.
-        // In DX11 we compute this in the GS.
-        if (shaderModel == 3)
-        {
-            pointCoordSemantic = "TEXCOORD0";
-        }
-        else if (shaderModel >= 4)
-        {
-            pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++); 
-        }
-    }
-
-    vertexHLSL += "struct VS_INPUT\n"
-                  "{\n";
-
-    int semanticIndex = 0;
-    for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
-    {
-        switch (attribute->type)
-        {
-          case GL_FLOAT:      vertexHLSL += "    float ";    break;
-          case GL_FLOAT_VEC2: vertexHLSL += "    float2 ";   break;
-          case GL_FLOAT_VEC3: vertexHLSL += "    float3 ";   break;
-          case GL_FLOAT_VEC4: vertexHLSL += "    float4 ";   break;
-          case GL_FLOAT_MAT2: vertexHLSL += "    float2x2 "; break;
-          case GL_FLOAT_MAT3: vertexHLSL += "    float3x3 "; break;
-          case GL_FLOAT_MAT4: vertexHLSL += "    float4x4 "; break;
-          default:  UNREACHABLE();
-        }
-
-        vertexHLSL += decorateAttribute(attribute->name) + " : TEXCOORD" + str(semanticIndex) + ";\n";
-
-        semanticIndex += VariableRowCount(attribute->type);
-    }
-
-    vertexHLSL += "};\n"
-                  "\n"
-                  "struct VS_OUTPUT\n"
-                  "{\n";
-
-    if (shaderModel < 4)
-    {
-        vertexHLSL += "    float4 gl_Position : " + positionSemantic + ";\n";
-    }
-
-    for (int r = 0; r < registers; r++)
-    {
-        int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
-
-        vertexHLSL += "    float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
-    }
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        vertexHLSL += "    float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
-    }
-
-    if (vertexShader->mUsesPointSize && shaderModel >= 3)
-    {
-        vertexHLSL += "    float gl_PointSize : PSIZE;\n";
-    }
-
-    if (shaderModel >= 4)
-    {
-        vertexHLSL += "    float4 gl_Position : " + positionSemantic + ";\n";
-    }
-
-    vertexHLSL += "};\n"
-                  "\n"
-                  "VS_OUTPUT main(VS_INPUT input)\n"
-                  "{\n";
-
-    for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
-    {
-        vertexHLSL += "    " + decorateAttribute(attribute->name) + " = ";
-
-        if (VariableRowCount(attribute->type) > 1)   // Matrix
-        {
-            vertexHLSL += "transpose";
-        }
-
-        vertexHLSL += "(input." + decorateAttribute(attribute->name) + ");\n";
-    }
-
-    if (shaderModel >= 4)
-    {
-        vertexHLSL += "\n"
-                      "    gl_main();\n"
-                      "\n"
-                      "    VS_OUTPUT output;\n"
-                      "    output.gl_Position.x = gl_Position.x;\n"
-                      "    output.gl_Position.y = -gl_Position.y;\n"
-                      "    output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
-                      "    output.gl_Position.w = gl_Position.w;\n";
-    }
-    else
-    {
-        vertexHLSL += "\n"
-                      "    gl_main();\n"
-                      "\n"
-                      "    VS_OUTPUT output;\n"
-                      "    output.gl_Position.x = gl_Position.x * dx_ViewAdjust.z + dx_ViewAdjust.x * gl_Position.w;\n"
-                      "    output.gl_Position.y = -(gl_Position.y * dx_ViewAdjust.w + dx_ViewAdjust.y * gl_Position.w);\n"
-                      "    output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n"
-                      "    output.gl_Position.w = gl_Position.w;\n";
-    }
-
-    if (vertexShader->mUsesPointSize && shaderModel >= 3)
-    {
-        vertexHLSL += "    output.gl_PointSize = gl_PointSize;\n";
-    }
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        vertexHLSL += "    output.gl_FragCoord = gl_Position;\n";
-    }
-
-    for (VaryingList::iterator varying = vertexShader->mVaryings.begin(); varying != vertexShader->mVaryings.end(); varying++)
-    {
-        if (varying->reg >= 0)
-        {
-            for (int i = 0; i < varying->size; i++)
-            {
-                int rows = VariableRowCount(varying->type);
-
-                for (int j = 0; j < rows; j++)
-                {
-                    int r = varying->reg + i * rows + j;
-                    vertexHLSL += "    output.v" + str(r);
-
-                    bool sharedRegister = false;   // Register used by multiple varyings
-                    
-                    for (int x = 0; x < 4; x++)
-                    {
-                        if (packing[r][x] && packing[r][x] != packing[r][0])
-                        {
-                            sharedRegister = true;
-                            break;
-                        }
-                    }
-
-                    if(sharedRegister)
-                    {
-                        vertexHLSL += ".";
-
-                        for (int x = 0; x < 4; x++)
-                        {
-                            if (packing[r][x] == &*varying)
-                            {
-                                switch(x)
-                                {
-                                  case 0: vertexHLSL += "x"; break;
-                                  case 1: vertexHLSL += "y"; break;
-                                  case 2: vertexHLSL += "z"; break;
-                                  case 3: vertexHLSL += "w"; break;
-                                }
-                            }
-                        }
-                    }
-
-                    vertexHLSL += " = " + varying->name;
-                    
-                    if (varying->array)
-                    {
-                        vertexHLSL += "[" + str(i) + "]";
-                    }
-
-                    if (rows > 1)
-                    {
-                        vertexHLSL += "[" + str(j) + "]";
-                    }
-                    
-                    vertexHLSL += ";\n";
-                }
-            }
-        }
-    }
-
-    vertexHLSL += "\n"
-                  "    return output;\n"
-                  "}\n";
-
-    pixelHLSL += "struct PS_INPUT\n"
-                 "{\n";
-    
-    for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
-    {
-        if (varying->reg >= 0)
-        {
-            for (int i = 0; i < varying->size; i++)
-            {
-                int rows = VariableRowCount(varying->type);
-                for (int j = 0; j < rows; j++)
-                {
-                    std::string n = str(varying->reg + i * rows + j);
-                    pixelHLSL += "    float" + str(VariableColumnCount(varying->type)) + " v" + n + " : " + varyingSemantic + n + ";\n";
-                }
-            }
-        }
-        else UNREACHABLE();
-    }
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        pixelHLSL += "    float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
-    }
-        
-    if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
-    {
-        pixelHLSL += "    float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
-    }
-
-    // Must consume the PSIZE element if the geometry shader is not active
-    // We won't know if we use a GS until we draw
-    if (vertexShader->mUsesPointSize && shaderModel >= 4)
-    {
-        pixelHLSL += "    float gl_PointSize : PSIZE;\n";
-    }
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        if (shaderModel >= 4)
-        {
-            pixelHLSL += "    float4 dx_VPos : SV_Position;\n";
-        }
-        else if (shaderModel >= 3)
-        {
-            pixelHLSL += "    float2 dx_VPos : VPOS;\n";
-        }
-    }
-
-    pixelHLSL += "};\n"
-                 "\n"
-                 "struct PS_OUTPUT\n"
-                 "{\n";
-
-    for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
-    {
-        pixelHLSL += "    float4 gl_Color" + str(renderTargetIndex) + " : " + targetSemantic + str(renderTargetIndex) + ";\n";
-    }
-
-    if (fragmentShader->mUsesFragDepth)
-    {
-        pixelHLSL += "    float gl_Depth : " + depthSemantic + ";\n";
-    }
-
-    pixelHLSL += "};\n"
-                 "\n";
-
-    if (fragmentShader->mUsesFrontFacing)
-    {
-        if (shaderModel >= 4)
-        {
-            pixelHLSL += "PS_OUTPUT main(PS_INPUT input, bool isFrontFace : SV_IsFrontFace)\n"
-                         "{\n";
-        }
-        else
-        {
-            pixelHLSL += "PS_OUTPUT main(PS_INPUT input, float vFace : VFACE)\n"
-                         "{\n";
-        }
-    }
-    else
-    {
-        pixelHLSL += "PS_OUTPUT main(PS_INPUT input)\n"
-                     "{\n";
-    }
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        pixelHLSL += "    float rhw = 1.0 / input.gl_FragCoord.w;\n";
-        
-        if (shaderModel >= 4)
-        {
-            pixelHLSL += "    gl_FragCoord.x = input.dx_VPos.x;\n"
-                         "    gl_FragCoord.y = input.dx_VPos.y;\n";
-        }
-        else if (shaderModel >= 3)
-        {
-            pixelHLSL += "    gl_FragCoord.x = input.dx_VPos.x + 0.5;\n"
-                         "    gl_FragCoord.y = input.dx_VPos.y + 0.5;\n";
-        }
-        else
-        {
-            // dx_ViewCoords contains the viewport width/2, height/2, center.x and center.y. See Renderer::setViewport()
-            pixelHLSL += "    gl_FragCoord.x = (input.gl_FragCoord.x * rhw) * dx_ViewCoords.x + dx_ViewCoords.z;\n"
-                         "    gl_FragCoord.y = (input.gl_FragCoord.y * rhw) * dx_ViewCoords.y + dx_ViewCoords.w;\n";
-        }
-        
-        pixelHLSL += "    gl_FragCoord.z = (input.gl_FragCoord.z * rhw) * dx_DepthFront.x + dx_DepthFront.y;\n"
-                     "    gl_FragCoord.w = rhw;\n";
-    }
-
-    if (fragmentShader->mUsesPointCoord && shaderModel >= 3)
-    {
-        pixelHLSL += "    gl_PointCoord.x = input.gl_PointCoord.x;\n";
-        pixelHLSL += "    gl_PointCoord.y = 1.0 - input.gl_PointCoord.y;\n";
-    }
-
-    if (fragmentShader->mUsesFrontFacing)
-    {
-        if (shaderModel <= 3)
-        {
-            pixelHLSL += "    gl_FrontFacing = (vFace * dx_DepthFront.z >= 0.0);\n";
-        }
-        else
-        {
-            pixelHLSL += "    gl_FrontFacing = isFrontFace;\n";
-        }
-    }
-
-    for (VaryingList::iterator varying = fragmentShader->mVaryings.begin(); varying != fragmentShader->mVaryings.end(); varying++)
-    {
-        if (varying->reg >= 0)
-        {
-            for (int i = 0; i < varying->size; i++)
-            {
-                int rows = VariableRowCount(varying->type);
-                for (int j = 0; j < rows; j++)
-                {
-                    std::string n = str(varying->reg + i * rows + j);
-                    pixelHLSL += "    " + varying->name;
-
-                    if (varying->array)
-                    {
-                        pixelHLSL += "[" + str(i) + "]";
-                    }
-
-                    if (rows > 1)
-                    {
-                        pixelHLSL += "[" + str(j) + "]";
-                    }
-
-                    switch (VariableColumnCount(varying->type))
-                    {
-                      case 1: pixelHLSL += " = input.v" + n + ".x;\n";   break;
-                      case 2: pixelHLSL += " = input.v" + n + ".xy;\n";  break;
-                      case 3: pixelHLSL += " = input.v" + n + ".xyz;\n"; break;
-                      case 4: pixelHLSL += " = input.v" + n + ";\n";     break;
-                      default: UNREACHABLE();
-                    }
-                }
-            }
-        }
-        else UNREACHABLE();
-    }
-
-    pixelHLSL += "\n"
-                 "    gl_main();\n"
-                 "\n"
-                 "    PS_OUTPUT output;\n";
-
-    for (unsigned int renderTargetIndex = 0; renderTargetIndex < numRenderTargets; renderTargetIndex++)
-    {
-        unsigned int sourceColorIndex = broadcast ? 0 : renderTargetIndex;
-
-        pixelHLSL += "    output.gl_Color" + str(renderTargetIndex) + " = gl_Color[" + str(sourceColorIndex) + "];\n";
-    }
-
-    if (fragmentShader->mUsesFragDepth)
-    {
-        pixelHLSL += "    output.gl_Depth = gl_Depth;\n";
-    }
-
-    pixelHLSL += "\n"
-                 "    return output;\n"
-                 "}\n";
-
-    return true;
-}
-
-bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
-{
-    BinaryInputStream stream(binary, length);
-
-    int format = 0;
-    stream.read(&format);
-    if (format != GL_PROGRAM_BINARY_ANGLE)
-    {
-        infoLog.append("Invalid program binary format.");
-        return false;
-    }
-
-    int majorVersion = 0;
-    int minorVersion = 0;
-    stream.read(&majorVersion);
-    stream.read(&minorVersion);
-    if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
-    {
-        infoLog.append("Invalid program binary version.");
-        return false;
-    }
-
-    unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
-    stream.read(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;
-    }
-
-    int compileFlags = 0;
-    stream.read(&compileFlags);
-    if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
-    {
-        infoLog.append("Mismatched compilation flags.");
-        return false;
-    }
-
-    for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
-    {
-        stream.read(&mLinkedAttribute[i].type);
-        std::string name;
-        stream.read(&name);
-        mLinkedAttribute[i].name = name;
-        stream.read(&mSemanticIndex[i]);
-    }
-
-    initAttributesByLayout();
-
-    for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
-    {
-        stream.read(&mSamplersPS[i].active);
-        stream.read(&mSamplersPS[i].logicalTextureUnit);
-        
-        int textureType;
-        stream.read(&textureType);
-        mSamplersPS[i].textureType = (TextureType) textureType;
-    }
-
-    for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
-    {
-        stream.read(&mSamplersVS[i].active);
-        stream.read(&mSamplersVS[i].logicalTextureUnit);
-        
-        int textureType;
-        stream.read(&textureType);
-        mSamplersVS[i].textureType = (TextureType) textureType;
-    }
-
-    stream.read(&mUsedVertexSamplerRange);
-    stream.read(&mUsedPixelSamplerRange);
-    stream.read(&mUsesPointSize);
-
-    size_t size;
-    stream.read(&size);
-    if (stream.error())
-    {
-        infoLog.append("Invalid program binary.");
-        return false;
-    }
-
-    mUniforms.resize(size);
-    for (unsigned int i = 0; i < size; ++i)
-    {
-        GLenum type;
-        GLenum precision;
-        std::string name;
-        unsigned int arraySize;
-
-        stream.read(&type);
-        stream.read(&precision);
-        stream.read(&name);
-        stream.read(&arraySize);
-
-        mUniforms[i] = new Uniform(type, precision, name, arraySize);
-        
-        stream.read(&mUniforms[i]->psRegisterIndex);
-        stream.read(&mUniforms[i]->vsRegisterIndex);
-        stream.read(&mUniforms[i]->registerCount);
-    }
-
-    stream.read(&size);
-    if (stream.error())
-    {
-        infoLog.append("Invalid program binary.");
-        return false;
-    }
-
-    mUniformIndex.resize(size);
-    for (unsigned int i = 0; i < size; ++i)
-    {
-        stream.read(&mUniformIndex[i].name);
-        stream.read(&mUniformIndex[i].element);
-        stream.read(&mUniformIndex[i].index);
-    }
-
-    unsigned int pixelShaderSize;
-    stream.read(&pixelShaderSize);
-
-    unsigned int vertexShaderSize;
-    stream.read(&vertexShaderSize);
-
-    unsigned int geometryShaderSize;
-    stream.read(&geometryShaderSize);
-
-    const char *ptr = (const char*) binary + stream.offset();
-
-    const GUID *binaryIdentifier = (const GUID *) ptr;
-    ptr += sizeof(GUID);
-
-    GUID identifier = mRenderer->getAdapterIdentifier();
-    if (memcmp(&identifier, binaryIdentifier, sizeof(GUID)) != 0)
-    {
-        infoLog.append("Invalid program binary.");
-        return false;
-    }
-
-    const char *pixelShaderFunction = ptr;
-    ptr += pixelShaderSize;
-
-    const char *vertexShaderFunction = ptr;
-    ptr += vertexShaderSize;
-
-    const char *geometryShaderFunction = geometryShaderSize > 0 ? ptr : NULL;
-    ptr += geometryShaderSize;
-
-    mPixelExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(pixelShaderFunction),
-                                                 pixelShaderSize, rx::SHADER_PIXEL);
-    if (!mPixelExecutable)
+    if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, caps))
     {
-        infoLog.append("Could not create pixel shader.");
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
-    mVertexExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
-                                                  vertexShaderSize, rx::SHADER_VERTEX);
-    if (!mVertexExecutable)
+    if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
+                                               transformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), caps))
     {
-        infoLog.append("Could not create vertex shader.");
-        delete mPixelExecutable;
-        mPixelExecutable = NULL;
-        return false;
+        return LinkResult(false, Error(GL_NO_ERROR));
     }
 
-    if (geometryShaderFunction != NULL && geometryShaderSize > 0)
-    {
-        mGeometryExecutable = mRenderer->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
-                                                        geometryShaderSize, rx::SHADER_GEOMETRY);
-        if (!mGeometryExecutable)
-        {
-            infoLog.append("Could not create geometry shader.");
-            delete mPixelExecutable;
-            mPixelExecutable = NULL;
-            delete mVertexExecutable;
-            mVertexExecutable = NULL;
-            return false;
-        }
-    }
-    else
+    // 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)
     {
-        mGeometryExecutable = NULL;
+        infoLog.append("Failed to create D3D shaders.");
+        reset();
+        return result;
     }
 
-    return true;
+    return LinkResult(true, Error(GL_NO_ERROR));
 }
 
-bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
+bool ProgramBinary::linkUniformBlocks(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader,
+                                   const gl::Caps &caps)
 {
-    BinaryOutputStream stream;
-
-    stream.write(GL_PROGRAM_BINARY_ANGLE);
-    stream.write(ANGLE_MAJOR_VERSION);
-    stream.write(ANGLE_MINOR_VERSION);
-    stream.write(ANGLE_COMMIT_HASH, ANGLE_COMMIT_HASH_SIZE);
-    stream.write(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
-
-    for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
-    {
-        stream.write(mLinkedAttribute[i].type);
-        stream.write(mLinkedAttribute[i].name);
-        stream.write(mSemanticIndex[i]);
-    }
-
-    for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
-    {
-        stream.write(mSamplersPS[i].active);
-        stream.write(mSamplersPS[i].logicalTextureUnit);
-        stream.write((int) mSamplersPS[i].textureType);
-    }
-
-    for (unsigned int i = 0; i < IMPLEMENTATION_MAX_VERTEX_TEXTURE_IMAGE_UNITS; ++i)
-    {
-        stream.write(mSamplersVS[i].active);
-        stream.write(mSamplersVS[i].logicalTextureUnit);
-        stream.write((int) mSamplersVS[i].textureType);
-    }
-
-    stream.write(mUsedVertexSamplerRange);
-    stream.write(mUsedPixelSamplerRange);
-    stream.write(mUsesPointSize);
-
-    stream.write(mUniforms.size());
-    for (unsigned int i = 0; i < mUniforms.size(); ++i)
-    {
-        stream.write(mUniforms[i]->type);
-        stream.write(mUniforms[i]->precision);
-        stream.write(mUniforms[i]->name);
-        stream.write(mUniforms[i]->arraySize);
-
-        stream.write(mUniforms[i]->psRegisterIndex);
-        stream.write(mUniforms[i]->vsRegisterIndex);
-        stream.write(mUniforms[i]->registerCount);
-    }
-
-    stream.write(mUniformIndex.size());
-    for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
-    {
-        stream.write(mUniformIndex[i].name);
-        stream.write(mUniformIndex[i].element);
-        stream.write(mUniformIndex[i].index);
-    }
-
-    UINT pixelShaderSize = mPixelExecutable->getLength();
-    stream.write(pixelShaderSize);
-
-    UINT vertexShaderSize = mVertexExecutable->getLength();
-    stream.write(vertexShaderSize);
-
-    UINT geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
-    stream.write(geometryShaderSize);
-
-    GUID identifier = mRenderer->getAdapterIdentifier();
-
-    GLsizei streamLength = stream.length();
-    const void *streamData = stream.data();
-
-    GLsizei totalLength = streamLength + sizeof(GUID) + pixelShaderSize + vertexShaderSize + geometryShaderSize;
-    if (totalLength > bufSize)
-    {
-        if (length)
-        {
-            *length = 0;
-        }
-
-        return false;
-    }
-
-    if (binary)
-    {
-        char *ptr = (char*) binary;
-
-        memcpy(ptr, streamData, streamLength);
-        ptr += streamLength;
-
-        memcpy(ptr, &identifier, sizeof(GUID));
-        ptr += sizeof(GUID);
-
-        memcpy(ptr, mPixelExecutable->getFunction(), pixelShaderSize);
-        ptr += pixelShaderSize;
-
-        memcpy(ptr, mVertexExecutable->getFunction(), vertexShaderSize);
-        ptr += vertexShaderSize;
-
-        if (mGeometryExecutable != NULL && geometryShaderSize > 0)
-        {
-            memcpy(ptr, mGeometryExecutable->getFunction(), geometryShaderSize);
-            ptr += geometryShaderSize;
-        }
-
-        ASSERT(ptr - totalLength == binary);
-    }
-
-    if (length)
-    {
-        *length = totalLength;
-    }
+    const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
+    const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
 
-    return true;
-}
-
-GLint ProgramBinary::getLength()
-{
-    GLint length;
-    if (save(NULL, INT_MAX, &length))
-    {
-        return length;
-    }
-    else
-    {
-        return 0;
-    }
-}
+    // Check that interface blocks defined in the vertex and fragment shaders are identical
+    typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
+    UniformBlockMap linkedUniformBlocks;
 
-bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
-{
-    if (!fragmentShader || !fragmentShader->isCompiled())
+    for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
     {
-        return false;
+        const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
+        linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
     }
 
-    if (!vertexShader || !vertexShader->isCompiled())
+    for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
     {
-        return false;
+        const sh::InterfaceBlock &fragmentInterfaceBlock = fragmentInterfaceBlocks[blockIndex];
+        UniformBlockMap::const_iterator entry = linkedUniformBlocks.find(fragmentInterfaceBlock.name);
+        if (entry != linkedUniformBlocks.end())
+        {
+            const sh::InterfaceBlock &vertexInterfaceBlock = *entry->second;
+            if (!areMatchingInterfaceBlocks(infoLog, vertexInterfaceBlock, fragmentInterfaceBlock))
+            {
+                return false;
+            }
+        }
     }
 
-    std::string pixelHLSL = fragmentShader->getHLSL();
-    std::string vertexHLSL = vertexShader->getHLSL();
-
-    // Map the varyings to the register file
-    const Varying *packing[IMPLEMENTATION_MAX_VARYING_VECTORS][4] = {NULL};
-    int registers = packVaryings(infoLog, packing, fragmentShader);
-
-    if (registers < 0)
+    for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
     {
-        return false;
+        const sh::InterfaceBlock &interfaceBlock = vertexInterfaceBlocks[blockIndex];
+
+        // Note: shared and std140 layouts are always considered active
+        if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
+        {
+            if (!mProgram->defineUniformBlock(infoLog, vertexShader, interfaceBlock, caps))
+            {
+                return false;
+            }
+        }
     }
 
-    if (!linkVaryings(infoLog, registers, packing, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
+    for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
     {
-        return false;
+        const sh::InterfaceBlock &interfaceBlock = fragmentInterfaceBlocks[blockIndex];
+
+        // Note: shared and std140 layouts are always considered active
+        if (interfaceBlock.staticUse || interfaceBlock.layout != sh::BLOCKLAYOUT_PACKED)
+        {
+            if (!mProgram->defineUniformBlock(infoLog, fragmentShader, interfaceBlock, caps))
+            {
+                return false;
+            }
+        }
     }
 
-    bool success = true;
+    return true;
+}
+
+bool ProgramBinary::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
+                                            const sh::InterfaceBlock &fragmentInterfaceBlock)
+{
+    const char* blockName = vertexInterfaceBlock.name.c_str();
 
-    if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
+    // validate blocks for the same member types
+    if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
     {
-        success = false;
+        infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
+        return false;
     }
 
-    if (!linkUniforms(infoLog, vertexShader->getUniforms(), fragmentShader->getUniforms()))
+    if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
     {
-        success = false;
+        infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
+        return false;
     }
 
-    // special case for gl_DepthRange, the only built-in uniform (also a struct)
-    if (vertexShader->mUsesDepthRange || fragmentShader->mUsesDepthRange)
+    if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
     {
-        mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.near", 0));
-        mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.far", 0));
-        mUniforms.push_back(new Uniform(GL_FLOAT, GL_HIGH_FLOAT, "gl_DepthRange.diff", 0));
+        infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
+        return false;
     }
 
-    if (success)
+    const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
+    for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
     {
-        mVertexExecutable = mRenderer->compileToExecutable(infoLog, vertexHLSL.c_str(), rx::SHADER_VERTEX, DiscardWorkaround(vertexShader->mUsesDiscardRewriting, vertexShader->mUsesNestedBreak));
-        mPixelExecutable = mRenderer->compileToExecutable(infoLog, pixelHLSL.c_str(), rx::SHADER_PIXEL, DiscardWorkaround(fragmentShader->mUsesDiscardRewriting, fragmentShader->mUsesNestedBreak));
+        const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
+        const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
 
-        if (usesGeometryShader())
+        if (vertexMember.name != fragmentMember.name)
         {
-            std::string geometryHLSL = generateGeometryShaderHLSL(registers, packing, fragmentShader, vertexShader);
-            mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL.c_str(), rx::SHADER_GEOMETRY, rx::ANGLE_D3D_WORKAROUND_NONE);
+            infoLog.append("Name mismatch for field %d of interface block '%s': (in vertex: '%s', in fragment: '%s')",
+                           blockMemberIndex, blockName, vertexMember.name.c_str(), fragmentMember.name.c_str());
+            return false;
         }
 
-        if (!mVertexExecutable || !mPixelExecutable || (usesGeometryShader() && !mGeometryExecutable))
+        std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
+        if (!gl::ProgramBinary::linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
         {
-            infoLog.append("Failed to create D3D shaders.");
-            success = false;
-
-            delete mVertexExecutable;
-            mVertexExecutable = NULL;
-            delete mPixelExecutable;
-            mPixelExecutable = NULL;
-            delete mGeometryExecutable;
-            mGeometryExecutable = NULL;
+            return false;
         }
     }
 
-    return success;
+    return true;
 }
 
 // Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
-bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
+bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader)
 {
+    const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
+
     unsigned int usedLocations = 0;
+    const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
 
     // Link attributes that have a binding location
-    for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+    for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
     {
-        int location = attributeBindings.getAttributeBinding(attribute->name);
+        const sh::Attribute &attribute = shaderAttributes[attributeIndex];
 
-        if (location != -1)   // Set by glBindAttribLocation
-        {
-            if (!mLinkedAttribute[location].name.empty())
-            {
-                // Multiple active attributes bound to the same location; not an error
-            }
+        ASSERT(attribute.staticUse);
+
+        const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
 
-            mLinkedAttribute[location] = *attribute;
+        mProgram->getShaderAttributes()[attributeIndex] = attribute;
 
-            int rows = VariableRowCount(attribute->type);
+        if (location != -1)   // Set by glBindAttribLocation or by location layout qualifier
+        {
+            const int rows = VariableRegisterCount(attribute.type);
 
             if (rows + location > MAX_VERTEX_ATTRIBS)
             {
-                infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
+                infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute.name.c_str(), location);
 
                 return false;
             }
 
-            for (int i = 0; i < rows; i++)
+            for (int row = 0; row < rows; row++)
             {
-                usedLocations |= 1 << (location + i);
+                const int rowLocation = location + row;
+                sh::ShaderVariable &linkedAttribute = mLinkedAttribute[rowLocation];
+
+                // In GLSL 3.00, attribute aliasing produces a link error
+                // In GLSL 1.00, attribute aliasing is allowed
+                if (mProgram->getShaderVersion() >= 300)
+                {
+                    if (!linkedAttribute.name.empty())
+                    {
+                        infoLog.append("Attribute '%s' aliases attribute '%s' at location %d", attribute.name.c_str(), linkedAttribute.name.c_str(), rowLocation);
+                        return false;
+                    }
+                }
+
+                linkedAttribute = attribute;
+                usedLocations |= 1 << rowLocation;
             }
         }
     }
 
     // Link attributes that don't have a binding location
-    for (AttributeArray::iterator attribute = vertexShader->mAttributes.begin(); attribute != vertexShader->mAttributes.end(); attribute++)
+    for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
     {
-        int location = attributeBindings.getAttributeBinding(attribute->name);
+        const sh::Attribute &attribute = shaderAttributes[attributeIndex];
+
+        ASSERT(attribute.staticUse);
 
-        if (location == -1)   // Not set by glBindAttribLocation
+        const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
+
+        if (location == -1)   // Not set by glBindAttribLocation or by location layout qualifier
         {
-            int rows = VariableRowCount(attribute->type);
+            int rows = VariableRegisterCount(attribute.type);
             int availableIndex = AllocateFirstFreeBits(&usedLocations, rows, MAX_VERTEX_ATTRIBS);
 
             if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
             {
-                infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
+                infoLog.append("Too many active attributes (%s)", attribute.name.c_str());
 
                 return false;   // Fail to link
             }
 
-            mLinkedAttribute[availableIndex] = *attribute;
+            mLinkedAttribute[availableIndex] = attribute;
         }
     }
 
     for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
     {
-        int index = vertexShader->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
-        int rows = std::max(VariableRowCount(mLinkedAttribute[attributeIndex].type), 1);
+        int index = vertexShaderD3D->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
+        int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
 
         for (int r = 0; r < rows; r++)
         {
@@ -2092,295 +756,156 @@ bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &at
     return true;
 }
 
-bool ProgramBinary::linkUniforms(InfoLog &infoLog, const sh::ActiveUniforms &vertexUniforms, const sh::ActiveUniforms &fragmentUniforms)
-{
-    for (sh::ActiveUniforms::const_iterator uniform = vertexUniforms.begin(); uniform != vertexUniforms.end(); uniform++)
-    {
-        if (!defineUniform(GL_VERTEX_SHADER, *uniform, infoLog))
-        {
-            return false;
-        }
-    }
-
-    for (sh::ActiveUniforms::const_iterator uniform = fragmentUniforms.begin(); uniform != fragmentUniforms.end(); uniform++)
-    {
-        if (!defineUniform(GL_FRAGMENT_SHADER, *uniform, infoLog))
-        {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-bool ProgramBinary::defineUniform(GLenum shader, const sh::Uniform &constant, InfoLog &infoLog)
+bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
+                                              const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
 {
-    if (constant.type == GL_SAMPLER_2D ||
-        constant.type == GL_SAMPLER_CUBE)
-    {
-        unsigned int samplerIndex = constant.registerIndex;
-            
-        do
-        {
-            if (shader == GL_VERTEX_SHADER)
-            {
-                if (samplerIndex < mRenderer->getMaxVertexTextureImageUnits())
-                {
-                    mSamplersVS[samplerIndex].active = true;
-                    mSamplersVS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
-                    mSamplersVS[samplerIndex].logicalTextureUnit = 0;
-                    mUsedVertexSamplerRange = std::max(samplerIndex + 1, mUsedVertexSamplerRange);
-                }
-                else
-                {
-                    infoLog.append("Vertex shader sampler count exceeds the maximum vertex texture units (%d).", mRenderer->getMaxVertexTextureImageUnits());
-                    return false;
-                }
-            }
-            else if (shader == GL_FRAGMENT_SHADER)
-            {
-                if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS)
-                {
-                    mSamplersPS[samplerIndex].active = true;
-                    mSamplersPS[samplerIndex].textureType = (constant.type == GL_SAMPLER_CUBE) ? TEXTURE_CUBE : TEXTURE_2D;
-                    mSamplersPS[samplerIndex].logicalTextureUnit = 0;
-                    mUsedPixelSamplerRange = std::max(samplerIndex + 1, mUsedPixelSamplerRange);
-                }
-                else
-                {
-                    infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
-                    return false;
-                }
-            }
-            else UNREACHABLE();
-
-            samplerIndex++;
-        }
-        while (samplerIndex < constant.registerIndex + constant.arraySize);
-    }
-
-    Uniform *uniform = NULL;
-    GLint location = getUniformLocation(constant.name);
-
-    if (location >= 0)   // Previously defined, type and precision must match
-    {
-        uniform = mUniforms[mUniformIndex[location].index];
-
-        if (uniform->type != constant.type)
-        {
-            infoLog.append("Types for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
-            return false;
-        }
-
-        if (uniform->precision != constant.precision)
-        {
-            infoLog.append("Precisions for uniform %s do not match between the vertex and fragment shader", uniform->name.c_str());
-            return false;
-        }
-    }
-    else
-    {
-        uniform = new Uniform(constant.type, constant.precision, constant.name, constant.arraySize);
-    }
-
-    if (!uniform)
+    if (vertexVariable.type != fragmentVariable.type)
     {
+        infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
         return false;
     }
-
-    if (shader == GL_FRAGMENT_SHADER)
+    if (vertexVariable.arraySize != fragmentVariable.arraySize)
     {
-        uniform->psRegisterIndex = constant.registerIndex;
+        infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
+        return false;
     }
-    else if (shader == GL_VERTEX_SHADER)
+    if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
     {
-        uniform->vsRegisterIndex = constant.registerIndex;
+        infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
+        return false;
     }
-    else UNREACHABLE();
 
-    if (location >= 0)
+    if (vertexVariable.fields.size() != fragmentVariable.fields.size())
     {
-        return uniform->type == constant.type;
+        infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
+        return false;
     }
-
-    mUniforms.push_back(uniform);
-    unsigned int uniformIndex = mUniforms.size() - 1;
-
-    for (unsigned int i = 0; i < uniform->elementCount(); i++)
+    const unsigned int numMembers = vertexVariable.fields.size();
+    for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
     {
-        mUniformIndex.push_back(UniformLocation(constant.name, i, uniformIndex));
-    }
+        const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
+        const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
 
-    if (shader == GL_VERTEX_SHADER)
-    {
-        if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedVertexUniformVectors() + mRenderer->getMaxVertexUniformVectors())
+        if (vertexMember.name != fragmentMember.name)
         {
-            infoLog.append("Vertex shader active uniforms exceed GL_MAX_VERTEX_UNIFORM_VECTORS (%u)", mRenderer->getMaxVertexUniformVectors());
+            infoLog.append("Name mismatch for field '%d' of %s: (in vertex: '%s', in fragment: '%s')",
+                           memberIndex, variableName.c_str(),
+                           vertexMember.name.c_str(), fragmentMember.name.c_str());
             return false;
         }
-    }
-    else if (shader == GL_FRAGMENT_SHADER)
-    {
-        if (constant.registerIndex + uniform->registerCount > mRenderer->getReservedFragmentUniformVectors() + mRenderer->getMaxFragmentUniformVectors())
+
+        const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
+                                       vertexMember.name + "'";
+
+        if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
         {
-            infoLog.append("Fragment shader active uniforms exceed GL_MAX_FRAGMENT_UNIFORM_VECTORS (%u)", mRenderer->getMaxFragmentUniformVectors());
             return false;
         }
     }
-    else UNREACHABLE();
 
     return true;
 }
 
-std::string ProgramBinary::generateGeometryShaderHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
-{
-    // for now we only handle point sprite emulation
-    ASSERT(usesPointSpriteEmulation());
-    return generatePointSpriteHLSL(registers, packing, fragmentShader, vertexShader);
-}
-
-std::string ProgramBinary::generatePointSpriteHLSL(int registers, const Varying *packing[][4], FragmentShader *fragmentShader, VertexShader *vertexShader) const
+bool ProgramBinary::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
 {
-    ASSERT(registers >= 0);
-    ASSERT(vertexShader->mUsesPointSize);
-    ASSERT(mRenderer->getMajorShaderModel() >= 4);
-
-    std::string geomHLSL;
-
-    std::string varyingSemantic = "TEXCOORD";
-
-    std::string fragCoordSemantic;
-    std::string pointCoordSemantic;
-
-    int reservedRegisterIndex = registers;
-
-    if (fragmentShader->mUsesFragCoord)
-    {
-        fragCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
-    }
-
-    if (fragmentShader->mUsesPointCoord)
+    if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
     {
-        pointCoordSemantic = varyingSemantic + str(reservedRegisterIndex++);
+        return false;
     }
 
-    geomHLSL += "uniform float4 dx_ViewCoords : register(c1);\n"
-                "\n"
-                "struct GS_INPUT\n"
-                "{\n";
+    return true;
+}
 
-    for (int r = 0; r < registers; r++)
+bool ProgramBinary::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
+{
+    if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
     {
-        int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
-
-        geomHLSL += "    float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
+        return false;
     }
 
-    if (fragmentShader->mUsesFragCoord)
+    if (vertexVarying.interpolation != fragmentVarying.interpolation)
     {
-        geomHLSL += "    float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+        infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
+        return false;
     }
 
-    geomHLSL += "    float gl_PointSize : PSIZE;\n"
-                "    float4 gl_Position : SV_Position;\n"
-                "};\n"
-                "\n"
-                "struct GS_OUTPUT\n"
-                "{\n";
-
-    for (int r = 0; r < registers; r++)
-    {
-        int registerSize = packing[r][3] ? 4 : (packing[r][2] ? 3 : (packing[r][1] ? 2 : 1));
-
-        geomHLSL += "    float" + str(registerSize) + " v" + str(r) + " : " + varyingSemantic + str(r) + ";\n";
-    }
+    return true;
+}
 
-    if (fragmentShader->mUsesFragCoord)
+bool ProgramBinary::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
+{
+    if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
     {
-        geomHLSL += "    float4 gl_FragCoord : " + fragCoordSemantic + ";\n";
+        return false;
     }
 
-    if (fragmentShader->mUsesPointCoord)
+    if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
     {
-        geomHLSL += "    float2 gl_PointCoord : " + pointCoordSemantic + ";\n";
+        infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
+        return false;
     }
 
-    geomHLSL +=   "    float gl_PointSize : PSIZE;\n"
-                  "    float4 gl_Position : SV_Position;\n"
-                  "};\n"
-                  "\n"
-                  "static float2 pointSpriteCorners[] = \n"
-                  "{\n"
-                  "    float2( 0.5f, -0.5f),\n"
-                  "    float2( 0.5f,  0.5f),\n"
-                  "    float2(-0.5f, -0.5f),\n"
-                  "    float2(-0.5f,  0.5f)\n"
-                  "};\n"
-                  "\n"
-                  "static float2 pointSpriteTexcoords[] = \n"
-                  "{\n"
-                  "    float2(1.0f, 1.0f),\n"
-                  "    float2(1.0f, 0.0f),\n"
-                  "    float2(0.0f, 1.0f),\n"
-                  "    float2(0.0f, 0.0f)\n"
-                  "};\n"
-                  "\n"
-                  "static float minPointSize = " + str(ALIASED_POINT_SIZE_RANGE_MIN) + ".0f;\n"
-                  "static float maxPointSize = " + str(mRenderer->getMaxPointSize()) + ".0f;\n"
-                  "\n"
-                  "[maxvertexcount(4)]\n"
-                  "void main(point GS_INPUT input[1], inout TriangleStream<GS_OUTPUT> outStream)\n"
-                  "{\n"
-                  "    GS_OUTPUT output = (GS_OUTPUT)0;\n"
-                  "    output.gl_PointSize = input[0].gl_PointSize;\n";
+    return true;
+}
 
-    for (int r = 0; r < registers; r++)
-    {
-        geomHLSL += "    output.v" + str(r) + " = input[0].v" + str(r) + ";\n";
-    }
+bool ProgramBinary::gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
+                                                          const std::vector<std::string> &transformFeedbackVaryingNames,
+                                                          GLenum transformFeedbackBufferMode,
+                                                          std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
+                                                          const Caps &caps) const
+{
+    size_t totalComponents = 0;
 
-    if (fragmentShader->mUsesFragCoord)
+    // Gather the linked varyings that are used for transform feedback, they should all exist.
+    outTransformFeedbackLinkedVaryings->clear();
+    for (size_t i = 0; i < transformFeedbackVaryingNames.size(); i++)
     {
-        geomHLSL += "    output.gl_FragCoord = input[0].gl_FragCoord;\n";
-    }
+        bool found = false;
+        for (size_t j = 0; j < linkedVaryings.size(); j++)
+        {
+            if (transformFeedbackVaryingNames[i] == linkedVaryings[j].name)
+            {
+                for (size_t k = 0; k < outTransformFeedbackLinkedVaryings->size(); k++)
+                {
+                    if (outTransformFeedbackLinkedVaryings->at(k).name == linkedVaryings[j].name)
+                    {
+                        infoLog.append("Two transform feedback varyings specify the same output variable (%s).", linkedVaryings[j].name.c_str());
+                        return false;
+                    }
+                }
 
-    geomHLSL += "    \n"
-                "    float gl_PointSize = clamp(input[0].gl_PointSize, minPointSize, maxPointSize);\n"
-                "    float4 gl_Position = input[0].gl_Position;\n"
-                "    float2 viewportScale = float2(1.0f / dx_ViewCoords.x, 1.0f / dx_ViewCoords.y) * gl_Position.w;\n";
+                size_t componentCount = linkedVaryings[j].semanticIndexCount * 4;
+                if (transformFeedbackBufferMode == GL_SEPARATE_ATTRIBS &&
+                    componentCount > caps.maxTransformFeedbackSeparateComponents)
+                {
+                    infoLog.append("Transform feedback varying's %s components (%u) exceed the maximum separate components (%u).",
+                                   linkedVaryings[j].name.c_str(), componentCount, caps.maxTransformFeedbackSeparateComponents);
+                    return false;
+                }
 
-    for (int corner = 0; corner < 4; corner++)
-    {
-        geomHLSL += "    \n"
-                    "    output.gl_Position = gl_Position + float4(pointSpriteCorners[" + str(corner) + "] * viewportScale * gl_PointSize, 0.0f, 0.0f);\n";
+                totalComponents += componentCount;
 
-        if (fragmentShader->mUsesPointCoord)
-        {
-            geomHLSL += "    output.gl_PointCoord = pointSpriteTexcoords[" + str(corner) + "];\n";
+                outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
+                found = true;
+                break;
+            }
         }
 
-        geomHLSL += "    outStream.Append(output);\n";
+        // All transform feedback varyings are expected to exist since packVaryings checks for them.
+        ASSERT(found);
     }
 
-    geomHLSL += "    \n"
-                "    outStream.RestartStrip();\n"
-                "}\n";
-
-    return geomHLSL;
-}
-
-// This method needs to match OutputHLSL::decorate
-std::string ProgramBinary::decorateAttribute(const std::string &name)
-{
-    if (name.compare(0, 3, "gl_") != 0 && name.compare(0, 3, "dx_") != 0)
+    if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents)
     {
-        return "_" + name;
+        infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
+                       totalComponents, caps.maxTransformFeedbackInterleavedComponents);
+        return false;
     }
-    
-    return name;
+
+    return true;
 }
 
-bool ProgramBinary::isValidated() const 
+bool ProgramBinary::isValidated() const
 {
     return mValidated;
 }
@@ -2455,13 +980,13 @@ GLint ProgramBinary::getActiveAttributeMaxLength() const
 
 void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
 {
-    ASSERT(index < mUniforms.size());   // index must be smaller than getActiveUniformCount()
+    ASSERT(index < mProgram->getUniforms().size());   // index must be smaller than getActiveUniformCount()
 
     if (bufsize > 0)
     {
-        std::string string = mUniforms[index]->name;
+        std::string string = mProgram->getUniforms()[index]->name;
 
-        if (mUniforms[index]->isArray())
+        if (mProgram->getUniforms()[index]->isArray())
         {
             string += "[0]";
         }
@@ -2475,27 +1000,27 @@ void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *len
         }
     }
 
-    *size = mUniforms[index]->elementCount();
+    *size = mProgram->getUniforms()[index]->elementCount();
 
-    *type = mUniforms[index]->type;
+    *type = mProgram->getUniforms()[index]->type;
 }
 
 GLint ProgramBinary::getActiveUniformCount() const
 {
-    return mUniforms.size();
+    return mProgram->getUniforms().size();
 }
 
 GLint ProgramBinary::getActiveUniformMaxLength() const
 {
     int maxLength = 0;
 
-    unsigned int numUniforms = mUniforms.size();
+    unsigned int numUniforms = mProgram->getUniforms().size();
     for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
     {
-        if (!mUniforms[uniformIndex]->name.empty())
+        if (!mProgram->getUniforms()[uniformIndex]->name.empty())
         {
-            int length = (int)(mUniforms[uniformIndex]->name.length() + 1);
-            if (mUniforms[uniformIndex]->isArray())
+            int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
+            if (mProgram->getUniforms()[uniformIndex]->isArray())
             {
                 length += 3;  // Counting in "[0]".
             }
@@ -2506,108 +1031,148 @@ GLint ProgramBinary::getActiveUniformMaxLength() const
     return maxLength;
 }
 
-void ProgramBinary::validate(InfoLog &infoLog)
+GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
 {
-    applyUniforms();
-    if (!validateSamplers(&infoLog))
-    {
-        mValidated = false;
-    }
-    else
+    const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
+
+    switch (pname)
     {
-        mValidated = true;
+      case GL_UNIFORM_TYPE:         return static_cast<GLint>(uniform.type);
+      case GL_UNIFORM_SIZE:         return static_cast<GLint>(uniform.elementCount());
+      case GL_UNIFORM_NAME_LENGTH:  return static_cast<GLint>(uniform.name.size() + 1 + (uniform.isArray() ? 3 : 0));
+      case GL_UNIFORM_BLOCK_INDEX:  return uniform.blockIndex;
+
+      case GL_UNIFORM_OFFSET:       return uniform.blockInfo.offset;
+      case GL_UNIFORM_ARRAY_STRIDE: return uniform.blockInfo.arrayStride;
+      case GL_UNIFORM_MATRIX_STRIDE: return uniform.blockInfo.matrixStride;
+      case GL_UNIFORM_IS_ROW_MAJOR: return static_cast<GLint>(uniform.blockInfo.isRowMajorMatrix);
+
+      default:
+        UNREACHABLE();
+        break;
     }
+    return 0;
+}
+
+bool ProgramBinary::isValidUniformLocation(GLint location) const
+{
+    ASSERT(rx::IsIntegerCastSafe<GLint>(mProgram->getUniformIndices().size()));
+    return (location >= 0 && location < static_cast<GLint>(mProgram->getUniformIndices().size()));
 }
 
-bool ProgramBinary::validateSamplers(InfoLog *infoLog)
+LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const
 {
-    // if any two active samplers in a program are of different types, but refer to the same
-    // texture image unit, and this is the current program, then ValidateProgram will fail, and
-    // DrawArrays and DrawElements will issue the INVALID_OPERATION error.
+    return mProgram->getUniformByLocation(location);
+}
 
-    const unsigned int maxCombinedTextureImageUnits = mRenderer->getMaxCombinedTextureImageUnits();
-    TextureType textureUnitType[IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS];
+LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const
+{
+    return mProgram->getUniformByName(name);
+}
 
-    for (unsigned int i = 0; i < IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS; ++i)
-    {
-        textureUnitType[i] = TEXTURE_UNKNOWN;
-    }
+void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
+{
+    ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size());   // index must be smaller than getActiveUniformBlockCount()
 
-    for (unsigned int i = 0; i < mUsedPixelSamplerRange; ++i)
+    const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+
+    if (bufSize > 0)
     {
-        if (mSamplersPS[i].active)
+        std::string string = uniformBlock.name;
+
+        if (uniformBlock.isArrayElement())
         {
-            unsigned int unit = mSamplersPS[i].logicalTextureUnit;
-            
-            if (unit >= maxCombinedTextureImageUnits)
-            {
-                if (infoLog)
-                {
-                    infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
-                }
+            string += ArrayString(uniformBlock.elementIndex);
+        }
 
-                return false;
-            }
+        strncpy(uniformBlockName, string.c_str(), bufSize);
+        uniformBlockName[bufSize - 1] = '\0';
 
-            if (textureUnitType[unit] != TEXTURE_UNKNOWN)
-            {
-                if (mSamplersPS[i].textureType != textureUnitType[unit])
-                {
-                    if (infoLog)
-                    {
-                        infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
-                    }
+        if (length)
+        {
+            *length = strlen(uniformBlockName);
+        }
+    }
+}
 
-                    return false;
-                }
-            }
-            else
+void ProgramBinary::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
+{
+    ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size());   // index must be smaller than getActiveUniformBlockCount()
+
+    const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+
+    switch (pname)
+    {
+      case GL_UNIFORM_BLOCK_DATA_SIZE:
+        *params = static_cast<GLint>(uniformBlock.dataSize);
+        break;
+      case GL_UNIFORM_BLOCK_NAME_LENGTH:
+        *params = static_cast<GLint>(uniformBlock.name.size() + 1 + (uniformBlock.isArrayElement() ? 3 : 0));
+        break;
+      case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+        *params = static_cast<GLint>(uniformBlock.memberUniformIndexes.size());
+        break;
+      case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
+        {
+            for (unsigned int blockMemberIndex = 0; blockMemberIndex < uniformBlock.memberUniformIndexes.size(); blockMemberIndex++)
             {
-                textureUnitType[unit] = mSamplersPS[i].textureType;
+                params[blockMemberIndex] = static_cast<GLint>(uniformBlock.memberUniformIndexes[blockMemberIndex]);
             }
         }
+        break;
+      case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+        *params = static_cast<GLint>(uniformBlock.isReferencedByVertexShader());
+        break;
+      case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+        *params = static_cast<GLint>(uniformBlock.isReferencedByFragmentShader());
+        break;
+      default: UNREACHABLE();
     }
+}
+
+GLuint ProgramBinary::getActiveUniformBlockCount() const
+{
+    return mProgram->getUniformBlocks().size();
+}
 
-    for (unsigned int i = 0; i < mUsedVertexSamplerRange; ++i)
+GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
+{
+    unsigned int maxLength = 0;
+
+    unsigned int numUniformBlocks = mProgram->getUniformBlocks().size();
+    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
     {
-        if (mSamplersVS[i].active)
+        const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+        if (!uniformBlock.name.empty())
         {
-            unsigned int unit = mSamplersVS[i].logicalTextureUnit;
-            
-            if (unit >= maxCombinedTextureImageUnits)
-            {
-                if (infoLog)
-                {
-                    infoLog->append("Sampler uniform (%d) exceeds IMPLEMENTATION_MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
-                }
-
-                return false;
-            }
+            const unsigned int length = uniformBlock.name.length() + 1;
 
-            if (textureUnitType[unit] != TEXTURE_UNKNOWN)
-            {
-                if (mSamplersVS[i].textureType != textureUnitType[unit])
-                {
-                    if (infoLog)
-                    {
-                        infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
-                    }
+            // Counting in "[0]".
+            const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
 
-                    return false;
-                }
-            }
-            else
-            {
-                textureUnitType[unit] = mSamplersVS[i].textureType;
-            }
+            maxLength = std::max(length + arrayLength, maxLength);
         }
     }
 
-    return true;
+    return maxLength;
+}
+
+void ProgramBinary::validate(InfoLog &infoLog, const Caps &caps)
+{
+    applyUniforms();
+    if (!validateSamplers(&infoLog, caps))
+    {
+        mValidated = false;
+    }
+    else
+    {
+        mValidated = true;
+    }
 }
 
-ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
+bool ProgramBinary::validateSamplers(InfoLog *infoLog, const Caps &caps)
 {
+    return mProgram->validateSamplers(infoLog, caps);
 }
 
 struct AttributeSorter
@@ -2654,4 +1219,13 @@ void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MA
     }
 }
 
+void ProgramBinary::reset()
+{
+    mOutputVariables.clear();
+
+    mProgram->reset();
+
+    mValidated = false;
+}
+
 }