Merge the ProgramBinary class into Program.

BUG=angle:731

Change-Id: I2ee97155841dc62f04bb71c1f2035d210fd3883c
Reviewed-on: https://chromium-review.googlesource.com/232694
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index c02bbe6..fe85831 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -18,7 +18,6 @@
 #include "libANGLE/FramebufferAttachment.h"
 #include "libANGLE/Renderbuffer.h"
 #include "libANGLE/Program.h"
-#include "libANGLE/ProgramBinary.h"
 #include "libANGLE/Query.h"
 #include "libANGLE/ResourceManager.h"
 #include "libANGLE/Sampler.h"
@@ -123,17 +122,7 @@
 
 Context::~Context()
 {
-    GLuint currentProgram = mState.getCurrentProgramId();
-    if (currentProgram != 0)
-    {
-        Program *programObject = mResourceManager->getProgram(currentProgram);
-        if (programObject)
-        {
-            programObject->release();
-        }
-        currentProgram = 0;
-    }
-    mState.setCurrentProgram(0, NULL);
+    mState.reset();
 
     while (!mFramebufferMap.empty())
     {
@@ -623,58 +612,7 @@
 
 void Context::useProgram(GLuint program)
 {
-    GLuint priorProgramId = mState.getCurrentProgramId();
-    Program *priorProgram = mResourceManager->getProgram(priorProgramId);
-
-    if (priorProgramId != program)
-    {
-        mState.setCurrentProgram(program, mResourceManager->getProgram(program));
-
-        if (priorProgram)
-        {
-            priorProgram->release();
-        }
-    }
-}
-
-Error Context::linkProgram(GLuint program)
-{
-    Program *programObject = mResourceManager->getProgram(program);
-
-    Error error = programObject->link(getData());
-    if (error.isError())
-    {
-        return error;
-    }
-
-    // if the current program was relinked successfully we
-    // need to install the new executables
-    if (programObject->isLinked() && program == mState.getCurrentProgramId())
-    {
-        mState.setCurrentProgramBinary(programObject->getProgramBinary());
-    }
-
-    return Error(GL_NO_ERROR);
-}
-
-Error Context::setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length)
-{
-    Program *programObject = mResourceManager->getProgram(program);
-
-    Error error = programObject->setProgramBinary(binaryFormat, binary, length);
-    if (error.isError())
-    {
-        return error;
-    }
-
-    // if the current program was reloaded successfully we
-    // need to install the new executables
-    if (programObject->isLinked() && program == mState.getCurrentProgramId())
-    {
-        mState.setCurrentProgramBinary(programObject->getProgramBinary());
-    }
-
-    return Error(GL_NO_ERROR);
+    mState.setProgram(getProgram(program));
 }
 
 void Context::bindTransformFeedback(GLuint transformFeedback)
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
index 4836e40..8ceaa2b 100644
--- a/src/libANGLE/Context.h
+++ b/src/libANGLE/Context.h
@@ -43,7 +43,6 @@
 {
 class Shader;
 class Program;
-class ProgramBinary;
 class Texture;
 class Texture2D;
 class TextureCubeMap;
@@ -126,8 +125,6 @@
     void bindPixelPackBuffer(GLuint buffer);
     void bindPixelUnpackBuffer(GLuint buffer);
     void useProgram(GLuint program);
-    Error linkProgram(GLuint program);
-    Error setProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLint length);
     void bindTransformFeedback(GLuint transformFeedback);
 
     Error beginQuery(GLenum target, GLuint query);
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 6453454..0c086b4 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -8,14 +8,47 @@
 // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
 
 #include "libANGLE/Program.h"
-#include "libANGLE/ProgramBinary.h"
 #include "libANGLE/ResourceManager.h"
+#include "libANGLE/Data.h"
+#include "libANGLE/features.h"
 #include "libANGLE/renderer/Renderer.h"
+#include "libANGLE/renderer/ProgramImpl.h"
+#include "libANGLE/renderer/d3d/ShaderD3D.h"
+#include "libANGLE/renderer/d3d/VertexDataManager.h"
+
+#include "common/debug.h"
+#include "common/version.h"
+#include "common/utilities.h"
+#include "common/platform.h"
+#include "common/blocklayout.h"
+
+#include <algorithm>
 
 namespace gl
 {
 const char * const g_fakepath = "C:\\fakepath";
 
+namespace
+{
+
+unsigned int ParseAndStripArrayIndex(std::string* name)
+{
+    unsigned int subscript = GL_INVALID_INDEX;
+
+    // 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)
+    {
+        subscript = atoi(name->substr(open + 1).c_str());
+        name->erase(open);
+    }
+
+    return subscript;
+}
+
+}
+
 AttributeBindings::AttributeBindings()
 {
 }
@@ -136,17 +169,41 @@
     }
 }
 
-Program::Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle)
+VariableLocation::VariableLocation()
+    : name(), element(0), index(0)
 {
-    mFragmentShader = NULL;
-    mVertexShader = NULL;
-    mProgramBinary.set(NULL);
-    mDeleteStatus = false;
-    mLinked = false;
-    mRefCount = 0;
-    mRenderer = renderer;
+}
+
+VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
+    : name(name), element(element), index(index)
+{
+}
+
+LinkedVarying::LinkedVarying()
+{
+}
+
+LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
+                             unsigned int semanticIndex, unsigned int semanticIndexCount)
+    : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
+{
+}
+
+Program::Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle)
+    : mProgram(impl),
+      mValidated(false),
+      mFragmentShader(NULL),
+      mVertexShader(NULL),
+      mLinked(false),
+      mDeleteStatus(false),
+      mRefCount(0),
+      mResourceManager(manager),
+      mHandle(handle)
+{
+    ASSERT(mProgram);
 
     resetUniformBlockBindings();
+    unlink();
 }
 
 Program::~Program()
@@ -162,6 +219,8 @@
     {
         mFragmentShader->release();
     }
+
+    SafeDelete(mProgram);
 }
 
 bool Program::attachShader(Shader *shader)
@@ -251,15 +310,59 @@
     mInfoLog.reset();
     resetUniformBlockBindings();
 
-    mProgramBinary.set(new ProgramBinary(mRenderer->createProgram()));
-    LinkResult result = mProgramBinary->link(data, mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader,
-                                             mTransformFeedbackVaryings, mTransformFeedbackBufferMode);
-    if (result.error.isError())
+    if (!mFragmentShader || !mFragmentShader->isCompiled())
+    {
+        return Error(GL_NO_ERROR);
+    }
+    ASSERT(mFragmentShader->getType() == GL_FRAGMENT_SHADER);
+
+    if (!mVertexShader || !mVertexShader->isCompiled())
+    {
+        return Error(GL_NO_ERROR);
+    }
+    ASSERT(mVertexShader->getType() == GL_VERTEX_SHADER);
+
+    int registers;
+    std::vector<LinkedVarying> linkedVaryings;
+    rx::LinkResult result = mProgram->link(data, mInfoLog, mFragmentShader, mVertexShader, mTransformFeedbackVaryings, mTransformFeedbackBufferMode,
+                                           &registers, &linkedVaryings, &mOutputVariables);
+    if (result.error.isError() || !result.linkSuccess)
     {
         return result.error;
     }
 
-    mLinked = result.linkSuccess;
+    if (!linkAttributes(mInfoLog, mAttributeBindings, mVertexShader))
+    {
+        return Error(GL_NO_ERROR);
+    }
+
+    if (!mProgram->linkUniforms(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
+    {
+        return Error(GL_NO_ERROR);
+    }
+
+    if (!linkUniformBlocks(mInfoLog, *mVertexShader, *mFragmentShader, *data.caps))
+    {
+        return Error(GL_NO_ERROR);
+    }
+
+    if (!gatherTransformFeedbackLinkedVaryings(mInfoLog, linkedVaryings, mTransformFeedbackVaryings,
+                                               mTransformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps))
+    {
+        return Error(GL_NO_ERROR);
+    }
+
+    // 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(mInfoLog, mFragmentShader, mVertexShader, registers);
+    if (result.error.isError() || !result.linkSuccess)
+    {
+        mInfoLog.append("Failed to create D3D shaders.");
+        unlink(false);
+        return result.error;
+    }
+
+    mLinked = true;
     return gl::Error(GL_NO_ERROR);
 }
 
@@ -294,7 +397,15 @@
         }
     }
 
-    mProgramBinary.set(NULL);
+    std::fill(mLinkedAttribute, mLinkedAttribute + ArraySize(mLinkedAttribute), sh::Attribute());
+    std::fill(mSemanticIndex, mSemanticIndex + ArraySize(mSemanticIndex), -1);
+    std::fill(mAttributesByLayout, mAttributesByLayout + ArraySize(mAttributesByLayout), -1);
+    mOutputVariables.clear();
+
+    mProgram->reset();
+
+    mValidated = false;
+
     mLinked = false;
 }
 
@@ -303,27 +414,146 @@
     return mLinked;
 }
 
-ProgramBinary* Program::getProgramBinary() const
-{
-    return mProgramBinary.get();
-}
-
-Error Program::setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length)
+Error Program::loadBinary(GLenum binaryFormat, const void *binary, GLsizei length)
 {
     unlink(false);
 
-    mInfoLog.reset();
+#if ANGLE_PROGRAM_BINARY_LOAD != ANGLE_ENABLED
+    return Error(GL_NO_ERROR);
+#else
+    ASSERT(binaryFormat == mProgram->getBinaryFormat());
 
-    mProgramBinary.set(new ProgramBinary(mRenderer->createProgram()));
-    LinkResult result = mProgramBinary->load(mInfoLog, binaryFormat, binary, length);
-    if (result.error.isError())
+    BinaryInputStream stream(binary, length);
+
+    GLenum format = stream.readInt<GLenum>();
+    if (format != mProgram->getBinaryFormat())
     {
-        mProgramBinary.set(NULL);
+        mInfoLog.append("Invalid program binary format.");
+        return Error(GL_NO_ERROR);
+    }
+
+    int majorVersion = stream.readInt<int>();
+    int minorVersion = stream.readInt<int>();
+    if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
+    {
+        mInfoLog.append("Invalid program binary version.");
+        return Error(GL_NO_ERROR);
+    }
+
+    unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
+    stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
+    if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
+    {
+        mInfoLog.append("Invalid program binary version.");
+        return Error(GL_NO_ERROR);
+    }
+
+    // TODO: move to ProgramImpl
+    int compileFlags = stream.readInt<int>();
+    if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
+    {
+        mInfoLog.append("Mismatched compilation flags.");
+        return Error(GL_NO_ERROR);
+    }
+
+    for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
+    {
+        stream.readInt(&mLinkedAttribute[i].type);
+        stream.readString(&mLinkedAttribute[i].name);
+        stream.readInt(&mProgram->getShaderAttributes()[i].type);
+        stream.readString(&mProgram->getShaderAttributes()[i].name);
+        stream.readInt(&mSemanticIndex[i]);
+    }
+
+    initAttributesByLayout();
+
+    rx::LinkResult result = mProgram->load(mInfoLog, &stream);
+    if (result.error.isError() || !result.linkSuccess)
+    {
         return result.error;
     }
 
-    mLinked = result.linkSuccess;
+    mLinked = true;
     return Error(GL_NO_ERROR);
+#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
+}
+
+Error Program::saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const
+{
+    if (binaryFormat)
+    {
+        *binaryFormat = mProgram->getBinaryFormat();
+    }
+
+    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);
+
+    // TODO: move to ProgramImpl
+    stream.writeInt(ANGLE_COMPILE_OPTIMIZATION_LEVEL);
+
+    for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
+    {
+        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]);
+    }
+
+    gl::Error error = mProgram->save(&stream);
+    if (error.isError())
+    {
+        return error;
+    }
+
+    GLsizei streamLength = stream.length();
+    const void *streamData = stream.data();
+
+    if (streamLength > bufSize)
+    {
+        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);
+    }
+
+    if (binary)
+    {
+        char *ptr = reinterpret_cast<char*>(binary);
+
+        memcpy(ptr, streamData, streamLength);
+        ptr += streamLength;
+
+        ASSERT(ptr - streamLength == binary);
+    }
+
+    if (length)
+    {
+        *length = streamLength;
+    }
+
+    return Error(GL_NO_ERROR);
+}
+
+GLint Program::getBinaryLength() const
+{
+    GLint length;
+    Error error = saveBinary(NULL, NULL, std::numeric_limits<GLint>::max(), &length);
+    if (error.isError())
+    {
+        return 0;
+    }
+
+    return length;
 }
 
 void Program::release()
@@ -346,19 +576,6 @@
     return mRefCount;
 }
 
-GLint Program::getProgramBinaryLength() const
-{
-    ProgramBinary *programBinary = mProgramBinary.get();
-    if (programBinary)
-    {
-        return programBinary->getLength();
-    }
-    else
-    {
-        return 0;
-    }
-}
-
 int Program::getInfoLogLength() const
 {
     return mInfoLog.getLength();
@@ -399,12 +616,64 @@
     }
 }
 
+GLuint Program::getAttributeLocation(const std::string &name)
+{
+    for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
+    {
+        if (mLinkedAttribute[index].name == name)
+        {
+            return index;
+        }
+    }
+
+    return -1;
+}
+
+int Program::getSemanticIndex(int attributeIndex)
+{
+    ASSERT(attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS);
+
+    return mSemanticIndex[attributeIndex];
+}
+
 void Program::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    if (mLinked)
     {
-        programBinary->getActiveAttribute(index, bufsize, length, size, type, name);
+        // Skip over inactive attributes
+        unsigned int activeAttribute = 0;
+        unsigned int attribute;
+        for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
+        {
+            if (mLinkedAttribute[attribute].name.empty())
+            {
+                continue;
+            }
+
+            if (activeAttribute == index)
+            {
+                break;
+            }
+
+            activeAttribute++;
+        }
+
+        if (bufsize > 0)
+        {
+            const char *string = mLinkedAttribute[attribute].name.c_str();
+
+            strncpy(name, string, bufsize);
+            name[bufsize - 1] = '\0';
+
+            if (length)
+            {
+                *length = strlen(name);
+            }
+        }
+
+        *size = 1;   // Always a single 'type' instance
+
+        *type = mLinkedAttribute[attribute].type;
     }
     else
     {
@@ -412,7 +681,7 @@
         {
             name[0] = '\0';
         }
-        
+
         if (length)
         {
             *length = 0;
@@ -425,36 +694,102 @@
 
 GLint Program::getActiveAttributeCount()
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    int count = 0;
+
+    if (mLinked)
     {
-        return programBinary->getActiveAttributeCount();
+        for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+        {
+            if (!mLinkedAttribute[attributeIndex].name.empty())
+            {
+                count++;
+            }
+        }
     }
-    else
-    {
-        return 0;
-    }
+
+    return count;
 }
 
 GLint Program::getActiveAttributeMaxLength()
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    int maxLength = 0;
+
+    if (mLinked)
     {
-        return programBinary->getActiveAttributeMaxLength();
+        for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
+        {
+            if (!mLinkedAttribute[attributeIndex].name.empty())
+            {
+                maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
+            }
+        }
     }
-    else
+
+    return maxLength;
+}
+
+// Returns one more than the highest sampler index used.
+GLint Program::getUsedSamplerRange(SamplerType type)
+{
+    return mProgram->getUsedSamplerRange(type);
+}
+
+bool Program::usesPointSize() const
+{
+    return mProgram->usesPointSize();
+}
+
+GLint Program::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
+{
+    return mProgram->getSamplerMapping(type, samplerIndex, caps);
+}
+
+GLenum Program::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
+{
+    return mProgram->getSamplerTextureType(type, samplerIndex);
+}
+
+GLint Program::getFragDataLocation(const std::string &name) const
+{
+    std::string baseName(name);
+    unsigned int arrayIndex = ParseAndStripArrayIndex(&baseName);
+    for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
     {
-        return 0;
+        const VariableLocation &outputVariable = locationIt->second;
+        if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
+        {
+            return static_cast<GLint>(locationIt->first);
+        }
     }
+    return -1;
 }
 
 void Program::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    if (mLinked)
     {
-        return programBinary->getActiveUniform(index, bufsize, length, size, type, name);
+        ASSERT(index < mProgram->getUniforms().size());   // index must be smaller than getActiveUniformCount()
+        LinkedUniform *uniform = mProgram->getUniforms()[index];
+
+        if (bufsize > 0)
+        {
+            std::string string = uniform->name;
+            if (uniform->isArray())
+            {
+                string += "[0]";
+            }
+
+            strncpy(name, string.c_str(), bufsize);
+            name[bufsize - 1] = '\0';
+
+            if (length)
+            {
+                *length = strlen(name);
+            }
+        }
+
+        *size = uniform->elementCount();
+        *type = uniform->type;
     }
     else
     {
@@ -475,10 +810,9 @@
 
 GLint Program::getActiveUniformCount()
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    if (mLinked)
     {
-        return programBinary->getActiveUniformCount();
+        return mProgram->getUniforms().size();
     }
     else
     {
@@ -488,15 +822,203 @@
 
 GLint Program::getActiveUniformMaxLength()
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    int maxLength = 0;
+
+    if (mLinked)
     {
-        return programBinary->getActiveUniformMaxLength();
+        unsigned int numUniforms = mProgram->getUniforms().size();
+        for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
+        {
+            if (!mProgram->getUniforms()[uniformIndex]->name.empty())
+            {
+                int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
+                if (mProgram->getUniforms()[uniformIndex]->isArray())
+                {
+                    length += 3;  // Counting in "[0]".
+                }
+                maxLength = std::max(length, maxLength);
+            }
+        }
     }
-    else
+
+    return maxLength;
+}
+
+GLint Program::getActiveUniformi(GLuint index, GLenum pname) const
+{
+    const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
+    switch (pname)
     {
-        return 0;
+      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 Program::isValidUniformLocation(GLint location) const
+{
+    ASSERT(rx::IsIntegerCastSafe<GLint>(mProgram->getUniformIndices().size()));
+    return (location >= 0 && location < static_cast<GLint>(mProgram->getUniformIndices().size()));
+}
+
+LinkedUniform *Program::getUniformByLocation(GLint location) const
+{
+    return mProgram->getUniformByLocation(location);
+}
+
+LinkedUniform *Program::getUniformByName(const std::string &name) const
+{
+    return mProgram->getUniformByName(name);
+}
+
+GLint Program::getUniformLocation(const std::string &name)
+{
+    return mProgram->getUniformLocation(name);
+}
+
+GLuint Program::getUniformIndex(const std::string &name)
+{
+    return mProgram->getUniformIndex(name);
+}
+
+void Program::setUniform1fv(GLint location, GLsizei count, const GLfloat *v)
+{
+    mProgram->setUniform1fv(location, count, v);
+}
+
+void Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v)
+{
+    mProgram->setUniform2fv(location, count, v);
+}
+
+void Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v)
+{
+    mProgram->setUniform3fv(location, count, v);
+}
+
+void Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v)
+{
+    mProgram->setUniform4fv(location, count, v);
+}
+
+void Program::setUniform1iv(GLint location, GLsizei count, const GLint *v)
+{
+    mProgram->setUniform1iv(location, count, v);
+}
+
+void Program::setUniform2iv(GLint location, GLsizei count, const GLint *v)
+{
+    mProgram->setUniform2iv(location, count, v);
+}
+
+void Program::setUniform3iv(GLint location, GLsizei count, const GLint *v)
+{
+    mProgram->setUniform3iv(location, count, v);
+}
+
+void Program::setUniform4iv(GLint location, GLsizei count, const GLint *v)
+{
+    mProgram->setUniform4iv(location, count, v);
+}
+
+void Program::setUniform1uiv(GLint location, GLsizei count, const GLuint *v)
+{
+    mProgram->setUniform1uiv(location, count, v);
+}
+
+void Program::setUniform2uiv(GLint location, GLsizei count, const GLuint *v)
+{
+    mProgram->setUniform2uiv(location, count, v);
+}
+
+void Program::setUniform3uiv(GLint location, GLsizei count, const GLuint *v)
+{
+    mProgram->setUniform3uiv(location, count, v);
+}
+
+void Program::setUniform4uiv(GLint location, GLsizei count, const GLuint *v)
+{
+    mProgram->setUniform4uiv(location, count, v);
+}
+
+void Program::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
+{
+    mProgram->setUniformMatrix2fv(location, count, transpose, v);
+}
+
+void Program::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
+{
+    mProgram->setUniformMatrix3fv(location, count, transpose, v);
+}
+
+void Program::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
+{
+    mProgram->setUniformMatrix4fv(location, count, transpose, v);
+}
+
+void Program::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
+{
+    mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
+}
+
+void Program::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
+{
+    mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
+}
+
+void Program::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
+{
+    mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
+}
+
+void Program::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
+{
+    mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
+}
+
+void Program::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
+{
+    mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
+}
+
+void Program::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v)
+{
+    mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
+}
+
+void Program::getUniformfv(GLint location, GLfloat *v)
+{
+    mProgram->getUniformfv(location, v);
+}
+
+void Program::getUniformiv(GLint location, GLint *v)
+{
+    mProgram->getUniformiv(location, v);
+}
+
+void Program::getUniformuiv(GLint location, GLuint *v)
+{
+    mProgram->getUniformuiv(location, v);
+}
+
+// Applies all the uniforms set for this program object to the renderer
+Error Program::applyUniforms()
+{
+    return mProgram->applyUniforms();
+}
+
+Error Program::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const Caps &caps)
+{
+    return mProgram->applyUniformBuffers(boundBuffers, caps);
 }
 
 void Program::flagForDeletion()
@@ -512,11 +1034,12 @@
 void Program::validate(const Caps &caps)
 {
     mInfoLog.reset();
+    mValidated = false;
 
-    ProgramBinary *programBinary = getProgramBinary();
-    if (isLinked() && programBinary)
+    if (mLinked)
     {
-        programBinary->validate(mInfoLog, caps);
+        applyUniforms();
+        mValidated = mProgram->validateSamplers(&mInfoLog, caps);
     }
     else
     {
@@ -524,43 +1047,114 @@
     }
 }
 
+bool Program::validateSamplers(InfoLog *infoLog, const Caps &caps)
+{
+    return mProgram->validateSamplers(infoLog, caps);
+}
+
 bool Program::isValidated() const
 {
-    ProgramBinary *programBinary = mProgramBinary.get();
-    if (programBinary)
+    return mValidated;
+}
+
+void Program::updateSamplerMapping()
+{
+    return mProgram->updateSamplerMapping();
+}
+
+GLuint Program::getActiveUniformBlockCount()
+{
+    return mProgram->getUniformBlocks().size();
+}
+
+void Program::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
+{
+    ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size());   // index must be smaller than getActiveUniformBlockCount()
+
+    const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+
+    if (bufSize > 0)
     {
-        return programBinary->isValidated();
-    }
-    else
-    {
-        return false;
+        std::string string = uniformBlock.name;
+
+        if (uniformBlock.isArrayElement())
+        {
+            string += ArrayString(uniformBlock.elementIndex);
+        }
+
+        strncpy(uniformBlockName, string.c_str(), bufSize);
+        uniformBlockName[bufSize - 1] = '\0';
+
+        if (length)
+        {
+            *length = strlen(uniformBlockName);
+        }
     }
 }
 
-GLint Program::getActiveUniformBlockCount()
+void Program::getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size());   // index must be smaller than getActiveUniformBlockCount()
+
+    const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+
+    switch (pname)
     {
-        return static_cast<GLint>(programBinary->getActiveUniformBlockCount());
-    }
-    else
-    {
-        return 0;
+      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++)
+            {
+                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();
     }
 }
 
 GLint Program::getActiveUniformBlockMaxLength()
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    int maxLength = 0;
+
+    if (mLinked)
     {
-        return static_cast<GLint>(programBinary->getActiveUniformBlockMaxLength());
+        unsigned int numUniformBlocks = mProgram->getUniformBlocks().size();
+        for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
+        {
+            const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
+            if (!uniformBlock.name.empty())
+            {
+                const int length = uniformBlock.name.length() + 1;
+
+                // Counting in "[0]".
+                const int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
+
+                maxLength = std::max(length + arrayLength, maxLength);
+            }
+        }
     }
-    else
-    {
-        return 0;
-    }
+
+    return maxLength;
+}
+
+GLuint Program::getUniformBlockIndex(const std::string &name)
+{
+    return mProgram->getUniformBlockIndex(name);
 }
 
 void Program::bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding)
@@ -594,10 +1188,10 @@
 
 void Program::getTransformFeedbackVarying(GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name) const
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary && index < programBinary->getTransformFeedbackVaryingCount())
+    if (mLinked)
     {
-        const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(index);
+        ASSERT(index < mProgram->getTransformFeedbackLinkedVaryings().size());
+        const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[index];
         GLsizei lastNameIdx = std::min(bufSize - 1, static_cast<GLsizei>(varying.name.length()));
         if (length)
         {
@@ -621,10 +1215,9 @@
 
 GLsizei Program::getTransformFeedbackVaryingCount() const
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    if (mLinked)
     {
-        return static_cast<GLsizei>(programBinary->getTransformFeedbackVaryingCount());
+        return static_cast<GLsizei>(mProgram->getTransformFeedbackLinkedVaryings().size());
     }
     else
     {
@@ -634,13 +1227,12 @@
 
 GLsizei Program::getTransformFeedbackVaryingMaxLength() const
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    if (mLinked)
     {
         GLsizei maxSize = 0;
-        for (size_t i = 0; i < programBinary->getTransformFeedbackVaryingCount(); i++)
+        for (size_t i = 0; i < mProgram->getTransformFeedbackLinkedVaryings().size(); i++)
         {
-            const LinkedVarying &varying = programBinary->getTransformFeedbackVarying(i);
+            const LinkedVarying &varying = mProgram->getTransformFeedbackLinkedVaryings()[i];
             maxSize = std::max(maxSize, static_cast<GLsizei>(varying.name.length() + 1));
         }
 
@@ -654,15 +1246,430 @@
 
 GLenum Program::getTransformFeedbackBufferMode() const
 {
-    ProgramBinary *programBinary = getProgramBinary();
-    if (programBinary)
+    return mTransformFeedbackBufferMode;
+}
+
+struct AttributeSorter
+{
+    AttributeSorter(const int(&semanticIndices)[MAX_VERTEX_ATTRIBS])
+        : originalIndices(semanticIndices)
     {
-        return programBinary->getTransformFeedbackBufferMode();
     }
-    else
+
+    bool operator()(int a, int b)
     {
-        return mTransformFeedbackBufferMode;
+        if (originalIndices[a] == -1) return false;
+        if (originalIndices[b] == -1) return true;
+        return (originalIndices[a] < originalIndices[b]);
     }
+
+    const int(&originalIndices)[MAX_VERTEX_ATTRIBS];
+};
+
+void Program::initAttributesByLayout()
+{
+    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+    {
+        mAttributesByLayout[i] = i;
+    }
+
+    std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
+}
+
+void Program::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
+{
+    rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
+
+    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+    {
+        oldTranslatedAttributes[i] = attributes[i];
+    }
+
+    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
+    {
+        int oldIndex = mAttributesByLayout[i];
+        sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
+        attributes[i] = oldTranslatedAttributes[oldIndex];
+    }
+}
+
+bool Program::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
+{
+    std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
+    std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
+
+    for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
+    {
+        PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
+        bool matched = false;
+
+        // Built-in varyings obey special rules
+        if (input->isBuiltIn())
+        {
+            continue;
+        }
+
+        for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
+        {
+            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;
+            }
+        }
+
+        // We permit unmatched, unreferenced varyings
+        if (!matched && input->staticUse)
+        {
+            infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Program::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
+{
+    if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
+    {
+        return false;
+    }
+
+    if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
+    {
+        infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
+bool Program::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 (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
+    {
+        const sh::Attribute &attribute = shaderAttributes[attributeIndex];
+
+        ASSERT(attribute.staticUse);
+
+        const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
+
+        mProgram->getShaderAttributes()[attributeIndex] = attribute;
+
+        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);
+
+                return false;
+            }
+
+            for (int row = 0; row < rows; row++)
+            {
+                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 (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
+    {
+        const sh::Attribute &attribute = shaderAttributes[attributeIndex];
+
+        ASSERT(attribute.staticUse);
+
+        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 = 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());
+
+                return false;   // Fail to link
+            }
+
+            mLinkedAttribute[availableIndex] = attribute;
+        }
+    }
+
+    for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
+    {
+        int index = vertexShaderD3D->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
+        int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
+
+        for (int r = 0; r < rows; r++)
+        {
+            mSemanticIndex[attributeIndex++] = index++;
+        }
+    }
+
+    initAttributesByLayout();
+
+    return true;
+}
+
+bool Program::linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps)
+{
+    const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
+    const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
+    // Check that interface blocks defined in the vertex and fragment shaders are identical
+    typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
+    UniformBlockMap linkedUniformBlocks;
+    for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
+    {
+        const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
+        linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
+    }
+    for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
+    {
+        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;
+            }
+        }
+    }
+    for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
+    {
+        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;
+            }
+        }
+    }
+    for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
+    {
+        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;
+            }
+        }
+    }
+    return true;
+}
+
+bool Program::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
+                                         const sh::InterfaceBlock &fragmentInterfaceBlock)
+{
+    const char* blockName = vertexInterfaceBlock.name.c_str();
+    // validate blocks for the same member types
+    if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
+    {
+        infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
+        return false;
+    }
+    if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
+    {
+        infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
+        return false;
+    }
+    if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
+    {
+        infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
+        return false;
+    }
+    const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
+    for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
+    {
+        const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
+        const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
+        if (vertexMember.name != fragmentMember.name)
+        {
+            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;
+        }
+        std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
+        if (!linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
+        {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool Program::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
+                                              const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
+{
+    if (vertexVariable.type != fragmentVariable.type)
+    {
+        infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
+        return false;
+    }
+    if (vertexVariable.arraySize != fragmentVariable.arraySize)
+    {
+        infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
+        return false;
+    }
+    if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
+    {
+        infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
+        return false;
+    }
+
+    if (vertexVariable.fields.size() != fragmentVariable.fields.size())
+    {
+        infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
+        return false;
+    }
+    const unsigned int numMembers = vertexVariable.fields.size();
+    for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
+    {
+        const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
+        const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
+
+        if (vertexMember.name != fragmentMember.name)
+        {
+            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;
+        }
+
+        const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
+                                       vertexMember.name + "'";
+
+        if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Program::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
+{
+    if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool Program::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
+{
+    if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
+    {
+        return false;
+    }
+
+    if (vertexVarying.interpolation != fragmentVarying.interpolation)
+    {
+        infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
+        return false;
+    }
+
+    return true;
+}
+
+bool Program::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;
+
+    // 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++)
+    {
+        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;
+                    }
+                }
+
+                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;
+                }
+
+                totalComponents += componentCount;
+
+                outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
+                found = true;
+                break;
+            }
+        }
+
+        // All transform feedback varyings are expected to exist since packVaryings checks for them.
+        ASSERT(found);
+    }
+
+    if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents)
+    {
+        infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
+                       totalComponents, caps.maxTransformFeedbackInterleavedComponents);
+        return false;
+    }
+
+    return true;
 }
 
 }
diff --git a/src/libANGLE/Program.h b/src/libANGLE/Program.h
index 0253c2d..f60471d 100644
--- a/src/libANGLE/Program.h
+++ b/src/libANGLE/Program.h
@@ -10,13 +10,16 @@
 #ifndef LIBANGLE_PROGRAM_H_
 #define LIBANGLE_PROGRAM_H_
 
-#include "common/angleutils.h"
-#include "libANGLE/RefCountObject.h"
+#include "libANGLE/angletypes.h"
 #include "libANGLE/Constants.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Error.h"
 #include "libANGLE/export.h"
+#include "libANGLE/RefCountObject.h"
+
+#include "common/angleutils.h"
 
 #include <GLES2/gl2.h>
+#include <GLSLANG/ShaderLang.h>
 
 #include <vector>
 #include <string>
@@ -25,6 +28,10 @@
 namespace rx
 {
 class Renderer;
+class Renderer;
+struct TranslatedAttribute;
+class UniformStorage;
+class ProgramImpl;
 }
 
 namespace gl
@@ -33,6 +40,12 @@
 struct Data;
 class ResourceManager;
 class Shader;
+class InfoLog;
+class AttributeBindings;
+class Buffer;
+class Framebuffer;
+struct UniformBlock;
+struct LinkedUniform;
 
 extern const char * const g_fakepath;
 
@@ -66,13 +79,46 @@
     char *mInfoLog;
 };
 
+// Struct used for correlating uniforms/elements of uniform arrays to handles
+struct VariableLocation
+{
+    VariableLocation();
+    VariableLocation(const std::string &name, unsigned int element, unsigned int index);
+
+    std::string name;
+    unsigned int element;
+    unsigned int index;
+};
+
+struct LinkedVarying
+{
+    LinkedVarying();
+    LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
+        unsigned int semanticIndex, unsigned int semanticIndexCount);
+
+    // Original GL name
+    std::string name;
+
+    GLenum type;
+    GLsizei size;
+
+    // DirectX semantic information
+    std::string semanticName;
+    unsigned int semanticIndex;
+    unsigned int semanticIndexCount;
+};
+
 class ANGLE_EXPORT Program
 {
   public:
-    Program(rx::Renderer *renderer, ResourceManager *manager, GLuint handle);
-
+    Program(rx::ProgramImpl *impl, ResourceManager *manager, GLuint handle);
     ~Program();
 
+    GLuint id() const { return mHandle; }
+
+    rx::ProgramImpl *getImplementation() { return mProgram; }
+    const rx::ProgramImpl *getImplementation() const { return mProgram; }
+
     bool attachShader(Shader *shader);
     bool detachShader(Shader *shader);
     int getAttachedShadersCount() const;
@@ -81,24 +127,75 @@
 
     Error link(const Data &data);
     bool isLinked();
-    Error setProgramBinary(GLenum binaryFormat, const void *binary, GLsizei length);
-    ProgramBinary *getProgramBinary() const;
+
+    Error loadBinary(GLenum binaryFormat, const void *binary, GLsizei length);
+    Error saveBinary(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length) const;
+    GLint getBinaryLength() const;
 
     int getInfoLogLength() const;
     void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
     void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
 
+    GLuint getAttributeLocation(const std::string &name);
+    int getSemanticIndex(int attributeIndex);
+
     void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
     GLint getActiveAttributeCount();
     GLint getActiveAttributeMaxLength();
 
+    GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps);
+    GLenum getSamplerTextureType(SamplerType type, unsigned int samplerIndex);
+    GLint getUsedSamplerRange(SamplerType type);
+    bool usesPointSize() const;
+
+    GLint getFragDataLocation(const std::string &name) const;
+
     void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
     GLint getActiveUniformCount();
     GLint getActiveUniformMaxLength();
+    GLint getActiveUniformi(GLuint index, GLenum pname) const;
+    bool isValidUniformLocation(GLint location) const;
+    LinkedUniform *getUniformByLocation(GLint location) const;
+    LinkedUniform *getUniformByName(const std::string &name) const;
 
-    GLint getActiveUniformBlockCount();
+    GLint getUniformLocation(const std::string &name);
+    GLuint getUniformIndex(const std::string &name);
+    void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
+    void setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
+    void setUniform3fv(GLint location, GLsizei count, const GLfloat *v);
+    void setUniform4fv(GLint location, GLsizei count, const GLfloat *v);
+    void setUniform1iv(GLint location, GLsizei count, const GLint *v);
+    void setUniform2iv(GLint location, GLsizei count, const GLint *v);
+    void setUniform3iv(GLint location, GLsizei count, const GLint *v);
+    void setUniform4iv(GLint location, GLsizei count, const GLint *v);
+    void setUniform1uiv(GLint location, GLsizei count, const GLuint *v);
+    void setUniform2uiv(GLint location, GLsizei count, const GLuint *v);
+    void setUniform3uiv(GLint location, GLsizei count, const GLuint *v);
+    void setUniform4uiv(GLint location, GLsizei count, const GLuint *v);
+    void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+
+    void getUniformfv(GLint location, GLfloat *params);
+    void getUniformiv(GLint location, GLint *params);
+    void getUniformuiv(GLint location, GLuint *params);
+
+    Error applyUniforms();
+    Error applyUniformBuffers(const std::vector<Buffer*> boundBuffers, const Caps &caps);
+
+    void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const;
+    void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const;
+    GLuint getActiveUniformBlockCount();
     GLint getActiveUniformBlockMaxLength();
 
+    GLuint getUniformBlockIndex(const std::string &name);
+
     void bindUniformBlock(GLuint uniformBlockIndex, GLuint uniformBlockBinding);
     GLuint getUniformBlockBinding(GLuint uniformBlockIndex) const;
 
@@ -108,6 +205,13 @@
     GLsizei getTransformFeedbackVaryingMaxLength() const;
     GLenum getTransformFeedbackBufferMode() const;
 
+    void initAttributesByLayout();
+    void sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const;
+
+    static bool linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader);
+    static bool linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform);
+    static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform);
+
     void addRef();
     void release();
     unsigned int getRefCount() const;
@@ -115,9 +219,9 @@
     bool isFlaggedForDeletion() const;
 
     void validate(const Caps &caps);
+    bool validateSamplers(InfoLog *infoLog, const Caps &caps);
     bool isValidated() const;
-
-    GLint getProgramBinaryLength() const;
+    void updateSamplerMapping();
 
   private:
     DISALLOW_COPY_AND_ASSIGN(Program);
@@ -125,6 +229,36 @@
     void unlink(bool destroy = false);
     void resetUniformBlockBindings();
 
+    bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader);
+    bool linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps);
+    bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
+                                    const sh::InterfaceBlock &fragmentInterfaceBlock);
+
+    static bool linkValidateVariablesBase(InfoLog &infoLog,
+                                          const std::string &variableName,
+                                          const sh::ShaderVariable &vertexVariable,
+                                          const sh::ShaderVariable &fragmentVariable,
+                                          bool validatePrecision);
+
+    static bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying);
+    bool gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
+                                               const std::vector<std::string> &transformFeedbackVaryingNames,
+                                               GLenum transformFeedbackBufferMode,
+                                               std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
+                                               const Caps &caps) const;
+    bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps);
+    void defineOutputVariables(Shader *fragmentShader);
+
+    rx::ProgramImpl *mProgram;
+
+    sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS];
+    int mSemanticIndex[MAX_VERTEX_ATTRIBS];
+    int mAttributesByLayout[MAX_VERTEX_ATTRIBS];
+
+    std::map<int, VariableLocation> mOutputVariables;
+
+    bool mValidated;
+
     Shader *mFragmentShader;
     Shader *mVertexShader;
 
@@ -133,9 +267,8 @@
     GLuint mUniformBlockBindings[IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS];
 
     std::vector<std::string> mTransformFeedbackVaryings;
-    GLuint mTransformFeedbackBufferMode;
+    GLenum mTransformFeedbackBufferMode;
 
-    BindingPointer<ProgramBinary> mProgramBinary;
     bool mLinked;
     bool mDeleteStatus;   // Flag to indicate that the program can be deleted when no longer in use
 
diff --git a/src/libANGLE/ProgramBinary.cpp b/src/libANGLE/ProgramBinary.cpp
deleted file mode 100644
index 9ecb58b..0000000
--- a/src/libANGLE/ProgramBinary.cpp
+++ /dev/null
@@ -1,1232 +0,0 @@
-//
-// 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.
-//
-
-// Program.cpp: Implements the gl::Program class. Implements GL program objects
-// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
-
-#include "libANGLE/BinaryStream.h"
-#include "libANGLE/ProgramBinary.h"
-#include "libANGLE/Framebuffer.h"
-#include "libANGLE/FramebufferAttachment.h"
-#include "libANGLE/Renderbuffer.h"
-#include "libANGLE/renderer/ShaderExecutable.h"
-
-#include "libANGLE/Shader.h"
-#include "libANGLE/Program.h"
-#include "libANGLE/renderer/ProgramImpl.h"
-#include "libANGLE/renderer/d3d/ShaderD3D.h"
-#include "libANGLE/Context.h"
-#include "libANGLE/Buffer.h"
-#include "libANGLE/features.h"
-
-#include "common/blocklayout.h"
-#include "common/debug.h"
-#include "common/utilities.h"
-#include "common/platform.h"
-#include "common/version.h"
-
-namespace gl
-{
-
-namespace
-{
-
-unsigned int ParseAndStripArrayIndex(std::string* name)
-{
-    unsigned int subscript = GL_INVALID_INDEX;
-
-    // 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)
-    {
-        subscript = atoi(name->substr(open + 1).c_str());
-        name->erase(open);
-    }
-
-    return subscript;
-}
-
-}
-
-VariableLocation::VariableLocation(const std::string &name, unsigned int element, unsigned int index)
-    : name(name), element(element), index(index)
-{
-}
-
-LinkedVarying::LinkedVarying()
-{
-}
-
-LinkedVarying::LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
-                             unsigned int semanticIndex, unsigned int semanticIndexCount)
-    : name(name), type(type), size(size), semanticName(semanticName), semanticIndex(semanticIndex), semanticIndexCount(semanticIndexCount)
-{
-}
-
-LinkResult::LinkResult(bool linkSuccess, const Error &error)
-    : linkSuccess(linkSuccess),
-      error(error)
-{
-}
-
-unsigned int ProgramBinary::mCurrentSerial = 1;
-
-ProgramBinary::ProgramBinary(rx::ProgramImpl *impl)
-    : RefCountObject(0),
-      mProgram(impl),
-      mValidated(false),
-      mSerial(issueSerial())
-{
-    ASSERT(impl);
-
-    for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
-    {
-        mSemanticIndex[index] = -1;
-    }
-}
-
-ProgramBinary::~ProgramBinary()
-{
-    reset();
-    SafeDelete(mProgram);
-}
-
-unsigned int ProgramBinary::getSerial() const
-{
-    return mSerial;
-}
-
-unsigned int ProgramBinary::issueSerial()
-{
-    return mCurrentSerial++;
-}
-
-GLuint ProgramBinary::getAttributeLocation(const char *name)
-{
-    if (name)
-    {
-        for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
-        {
-            if (mLinkedAttribute[index].name == std::string(name))
-            {
-                return index;
-            }
-        }
-    }
-
-    return -1;
-}
-
-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)
-{
-    return mProgram->getUsedSamplerRange(type);
-}
-
-bool ProgramBinary::usesPointSize() const
-{
-    return mProgram->usesPointSize();
-}
-
-GLint ProgramBinary::getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps)
-{
-    return mProgram->getSamplerMapping(type, samplerIndex, caps);
-}
-
-GLenum ProgramBinary::getSamplerTextureType(SamplerType type, unsigned int samplerIndex)
-{
-    return mProgram->getSamplerTextureType(type, samplerIndex);
-}
-
-GLint ProgramBinary::getUniformLocation(std::string name)
-{
-    return mProgram->getUniformLocation(name);
-}
-
-GLuint ProgramBinary::getUniformIndex(std::string name)
-{
-    return mProgram->getUniformIndex(name);
-}
-
-GLuint ProgramBinary::getUniformBlockIndex(std::string name)
-{
-    return mProgram->getUniformBlockIndex(name);
-}
-
-UniformBlock *ProgramBinary::getUniformBlockByIndex(GLuint blockIndex)
-{
-    return mProgram->getUniformBlockByIndex(blockIndex);
-}
-
-GLint ProgramBinary::getFragDataLocation(const char *name) const
-{
-    std::string baseName(name);
-    unsigned int arrayIndex;
-    arrayIndex = ParseAndStripArrayIndex(&baseName);
-
-    for (auto locationIt = mOutputVariables.begin(); locationIt != mOutputVariables.end(); locationIt++)
-    {
-        const VariableLocation &outputVariable = locationIt->second;
-
-        if (outputVariable.name == baseName && (arrayIndex == GL_INVALID_INDEX || arrayIndex == outputVariable.element))
-        {
-            return static_cast<GLint>(locationIt->first);
-        }
-    }
-
-    return -1;
-}
-
-size_t ProgramBinary::getTransformFeedbackVaryingCount() const
-{
-    return mProgram->getTransformFeedbackLinkedVaryings().size();
-}
-
-const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const
-{
-    return mProgram->getTransformFeedbackLinkedVaryings()[idx];
-}
-
-GLenum ProgramBinary::getTransformFeedbackBufferMode() const
-{
-    return mProgram->getTransformFeedbackBufferMode();
-}
-
-void ProgramBinary::setUniform1fv(GLint location, GLsizei count, const GLfloat *v) {
-    mProgram->setUniform1fv(location, count, v);
-}
-
-void ProgramBinary::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) {
-    mProgram->setUniform2fv(location, count, v);
-}
-
-void ProgramBinary::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) {
-    mProgram->setUniform3fv(location, count, v);
-}
-
-void ProgramBinary::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) {
-    mProgram->setUniform4fv(location, count, v);
-}
-
-void ProgramBinary::setUniform1iv(GLint location, GLsizei count, const GLint *v) {
-    mProgram->setUniform1iv(location, count, v);
-}
-
-void ProgramBinary::setUniform2iv(GLint location, GLsizei count, const GLint *v) {
-    mProgram->setUniform2iv(location, count, v);
-}
-
-void ProgramBinary::setUniform3iv(GLint location, GLsizei count, const GLint *v) {
-    mProgram->setUniform3iv(location, count, v);
-}
-
-void ProgramBinary::setUniform4iv(GLint location, GLsizei count, const GLint *v) {
-    mProgram->setUniform4iv(location, count, v);
-}
-
-void ProgramBinary::setUniform1uiv(GLint location, GLsizei count, const GLuint *v) {
-    mProgram->setUniform1uiv(location, count, v);
-}
-
-void ProgramBinary::setUniform2uiv(GLint location, GLsizei count, const GLuint *v) {
-    mProgram->setUniform2uiv(location, count, v);
-}
-
-void ProgramBinary::setUniform3uiv(GLint location, GLsizei count, const GLuint *v) {
-    mProgram->setUniform3uiv(location, count, v);
-}
-
-void ProgramBinary::setUniform4uiv(GLint location, GLsizei count, const GLuint *v) {
-    mProgram->setUniform4uiv(location, count, v);
-}
-
-void ProgramBinary::setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
-    mProgram->setUniformMatrix2fv(location, count, transpose, v);
-}
-
-void ProgramBinary::setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
-    mProgram->setUniformMatrix3fv(location, count, transpose, v);
-}
-
-void ProgramBinary::setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
-    mProgram->setUniformMatrix4fv(location, count, transpose, v);
-}
-
-void ProgramBinary::setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
-    mProgram->setUniformMatrix2x3fv(location, count, transpose, v);
-}
-
-void ProgramBinary::setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
-    mProgram->setUniformMatrix2x4fv(location, count, transpose, v);
-}
-
-void ProgramBinary::setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
-    mProgram->setUniformMatrix3x2fv(location, count, transpose, v);
-}
-
-void ProgramBinary::setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
-    mProgram->setUniformMatrix3x4fv(location, count, transpose, v);
-}
-
-void ProgramBinary::setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
-    mProgram->setUniformMatrix4x2fv(location, count, transpose, v);
-}
-
-void ProgramBinary::setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *v) {
-    mProgram->setUniformMatrix4x3fv(location, count, transpose, v);
-}
-
-void ProgramBinary::getUniformfv(GLint location, GLfloat *v) {
-    mProgram->getUniformfv(location, v);
-}
-
-void ProgramBinary::getUniformiv(GLint location, GLint *v) {
-    mProgram->getUniformiv(location, v);
-}
-
-void ProgramBinary::getUniformuiv(GLint location, GLuint *v) {
-    mProgram->getUniformuiv(location, v);
-}
-
-void ProgramBinary::updateSamplerMapping()
-{
-    return mProgram->updateSamplerMapping();
-}
-
-// Applies all the uniforms set for this program object to the renderer
-Error ProgramBinary::applyUniforms()
-{
-    return mProgram->applyUniforms();
-}
-
-Error ProgramBinary::applyUniformBuffers(const std::vector<gl::Buffer*> boundBuffers, const Caps &caps)
-{
-    return mProgram->applyUniformBuffers(boundBuffers, caps);
-}
-
-bool ProgramBinary::linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader)
-{
-    std::vector<PackedVarying> &fragmentVaryings = fragmentShader->getVaryings();
-    std::vector<PackedVarying> &vertexVaryings = vertexShader->getVaryings();
-
-    for (size_t fragVaryingIndex = 0; fragVaryingIndex < fragmentVaryings.size(); fragVaryingIndex++)
-    {
-        PackedVarying *input = &fragmentVaryings[fragVaryingIndex];
-        bool matched = false;
-
-        // Built-in varyings obey special rules
-        if (input->isBuiltIn())
-        {
-            continue;
-        }
-
-        for (size_t vertVaryingIndex = 0; vertVaryingIndex < vertexVaryings.size(); vertVaryingIndex++)
-        {
-            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;
-            }
-        }
-
-        // We permit unmatched, unreferenced varyings
-        if (!matched && input->staticUse)
-        {
-            infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
-            return false;
-        }
-    }
-
-    return true;
-}
-
-LinkResult ProgramBinary::load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length)
-{
-#if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_DISABLED
-    return LinkResult(false, Error(GL_NO_ERROR));
-#else
-    ASSERT(binaryFormat == mProgram->getBinaryFormat());
-
-    reset();
-
-    BinaryInputStream stream(binary, length);
-
-    GLenum format = stream.readInt<GLenum>();
-    if (format != mProgram->getBinaryFormat())
-    {
-        infoLog.append("Invalid program binary format.");
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-
-    int majorVersion = stream.readInt<int>();
-    int minorVersion = stream.readInt<int>();
-    if (majorVersion != ANGLE_MAJOR_VERSION || minorVersion != ANGLE_MINOR_VERSION)
-    {
-        infoLog.append("Invalid program binary version.");
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-
-    unsigned char commitString[ANGLE_COMMIT_HASH_SIZE];
-    stream.readBytes(commitString, ANGLE_COMMIT_HASH_SIZE);
-    if (memcmp(commitString, ANGLE_COMMIT_HASH, sizeof(unsigned char) * ANGLE_COMMIT_HASH_SIZE) != 0)
-    {
-        infoLog.append("Invalid program binary version.");
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-
-    int compileFlags = stream.readInt<int>();
-    if (compileFlags != ANGLE_COMPILE_OPTIMIZATION_LEVEL)
-    {
-        infoLog.append("Mismatched compilation flags.");
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-
-    for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
-    {
-        stream.readInt(&mLinkedAttribute[i].type);
-        stream.readString(&mLinkedAttribute[i].name);
-        stream.readInt(&mProgram->getShaderAttributes()[i].type);
-        stream.readString(&mProgram->getShaderAttributes()[i].name);
-        stream.readInt(&mSemanticIndex[i]);
-    }
-
-    initAttributesByLayout();
-
-    LinkResult result = mProgram->load(infoLog, &stream);
-    if (result.error.isError() || !result.linkSuccess)
-    {
-        return result;
-    }
-
-    return LinkResult(true, Error(GL_NO_ERROR));
-#endif // #if ANGLE_PROGRAM_BINARY_LOAD == ANGLE_ENABLED
-}
-
-Error ProgramBinary::save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length)
-{
-    if (binaryFormat)
-    {
-        *binaryFormat = mProgram->getBinaryFormat();
-    }
-
-    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);
-
-    for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
-    {
-        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]);
-    }
-
-    mProgram->save(&stream);
-
-    GLsizei streamLength = stream.length();
-    const void *streamData = stream.data();
-
-    if (streamLength > bufSize)
-    {
-        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);
-    }
-
-    if (binary)
-    {
-        char *ptr = (char*) binary;
-
-        memcpy(ptr, streamData, streamLength);
-        ptr += streamLength;
-
-        ASSERT(ptr - streamLength == binary);
-    }
-
-    if (length)
-    {
-        *length = streamLength;
-    }
-
-    return Error(GL_NO_ERROR);
-}
-
-GLint ProgramBinary::getLength()
-{
-    GLint length;
-    Error error = save(NULL, NULL, INT_MAX, &length);
-    if (error.isError())
-    {
-        return 0;
-    }
-
-    return length;
-}
-
-LinkResult ProgramBinary::link(const Data &data, InfoLog &infoLog, const AttributeBindings &attributeBindings,
-                               Shader *fragmentShader, Shader *vertexShader,
-                               const std::vector<std::string> &transformFeedbackVaryings,
-                               GLenum transformFeedbackBufferMode)
-{
-    if (!fragmentShader || !fragmentShader->isCompiled())
-    {
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-    ASSERT(fragmentShader->getType() == GL_FRAGMENT_SHADER);
-
-    if (!vertexShader || !vertexShader->isCompiled())
-    {
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-    ASSERT(vertexShader->getType() == GL_VERTEX_SHADER);
-
-    reset();
-
-    int registers;
-    std::vector<LinkedVarying> linkedVaryings;
-    LinkResult result = mProgram->link(data, infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode,
-                                       &registers, &linkedVaryings, &mOutputVariables);
-    if (result.error.isError() || !result.linkSuccess)
-    {
-        return result;
-    }
-
-    if (!linkAttributes(infoLog, attributeBindings, vertexShader))
-    {
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-
-    if (!mProgram->linkUniforms(infoLog, *vertexShader, *fragmentShader, *data.caps))
-    {
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-
-    if (!linkUniformBlocks(infoLog, *vertexShader, *fragmentShader, *data.caps))
-    {
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-
-    if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
-                                               transformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), *data.caps))
-    {
-        return LinkResult(false, Error(GL_NO_ERROR));
-    }
-
-    // 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)
-    {
-        infoLog.append("Failed to create D3D shaders.");
-        reset();
-        return result;
-    }
-
-    return LinkResult(true, Error(GL_NO_ERROR));
-}
-
-bool ProgramBinary::linkUniformBlocks(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader,
-                                   const gl::Caps &caps)
-{
-    const std::vector<sh::InterfaceBlock> &vertexInterfaceBlocks = vertexShader.getInterfaceBlocks();
-    const std::vector<sh::InterfaceBlock> &fragmentInterfaceBlocks = fragmentShader.getInterfaceBlocks();
-
-    // Check that interface blocks defined in the vertex and fragment shaders are identical
-    typedef std::map<std::string, const sh::InterfaceBlock*> UniformBlockMap;
-    UniformBlockMap linkedUniformBlocks;
-
-    for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
-    {
-        const sh::InterfaceBlock &vertexInterfaceBlock = vertexInterfaceBlocks[blockIndex];
-        linkedUniformBlocks[vertexInterfaceBlock.name] = &vertexInterfaceBlock;
-    }
-
-    for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
-    {
-        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;
-            }
-        }
-    }
-
-    for (unsigned int blockIndex = 0; blockIndex < vertexInterfaceBlocks.size(); blockIndex++)
-    {
-        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;
-            }
-        }
-    }
-
-    for (unsigned int blockIndex = 0; blockIndex < fragmentInterfaceBlocks.size(); blockIndex++)
-    {
-        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;
-            }
-        }
-    }
-
-    return true;
-}
-
-bool ProgramBinary::areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
-                                            const sh::InterfaceBlock &fragmentInterfaceBlock)
-{
-    const char* blockName = vertexInterfaceBlock.name.c_str();
-
-    // validate blocks for the same member types
-    if (vertexInterfaceBlock.fields.size() != fragmentInterfaceBlock.fields.size())
-    {
-        infoLog.append("Types for interface block '%s' differ between vertex and fragment shaders", blockName);
-        return false;
-    }
-
-    if (vertexInterfaceBlock.arraySize != fragmentInterfaceBlock.arraySize)
-    {
-        infoLog.append("Array sizes differ for interface block '%s' between vertex and fragment shaders", blockName);
-        return false;
-    }
-
-    if (vertexInterfaceBlock.layout != fragmentInterfaceBlock.layout || vertexInterfaceBlock.isRowMajorLayout != fragmentInterfaceBlock.isRowMajorLayout)
-    {
-        infoLog.append("Layout qualifiers differ for interface block '%s' between vertex and fragment shaders", blockName);
-        return false;
-    }
-
-    const unsigned int numBlockMembers = vertexInterfaceBlock.fields.size();
-    for (unsigned int blockMemberIndex = 0; blockMemberIndex < numBlockMembers; blockMemberIndex++)
-    {
-        const sh::InterfaceBlockField &vertexMember = vertexInterfaceBlock.fields[blockMemberIndex];
-        const sh::InterfaceBlockField &fragmentMember = fragmentInterfaceBlock.fields[blockMemberIndex];
-
-        if (vertexMember.name != fragmentMember.name)
-        {
-            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;
-        }
-
-        std::string memberName = "interface block '" + vertexInterfaceBlock.name + "' member '" + vertexMember.name + "'";
-        if (!gl::ProgramBinary::linkValidateInterfaceBlockFields(infoLog, memberName, vertexMember, fragmentMember))
-        {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
-bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader)
-{
-    const rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
-
-    unsigned int usedLocations = 0;
-    const std::vector<sh::Attribute> &shaderAttributes = vertexShader->getActiveAttributes();
-
-    // Link attributes that have a binding location
-    for (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
-    {
-        const sh::Attribute &attribute = shaderAttributes[attributeIndex];
-
-        ASSERT(attribute.staticUse);
-
-        const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
-
-        mProgram->getShaderAttributes()[attributeIndex] = attribute;
-
-        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);
-
-                return false;
-            }
-
-            for (int row = 0; row < rows; row++)
-            {
-                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 (unsigned int attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
-    {
-        const sh::Attribute &attribute = shaderAttributes[attributeIndex];
-
-        ASSERT(attribute.staticUse);
-
-        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 = 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());
-
-                return false;   // Fail to link
-            }
-
-            mLinkedAttribute[availableIndex] = attribute;
-        }
-    }
-
-    for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; )
-    {
-        int index = vertexShaderD3D->getSemanticIndex(mLinkedAttribute[attributeIndex].name);
-        int rows = VariableRegisterCount(mLinkedAttribute[attributeIndex].type);
-
-        for (int r = 0; r < rows; r++)
-        {
-            mSemanticIndex[attributeIndex++] = index++;
-        }
-    }
-
-    initAttributesByLayout();
-
-    return true;
-}
-
-bool ProgramBinary::linkValidateVariablesBase(InfoLog &infoLog, const std::string &variableName, const sh::ShaderVariable &vertexVariable,
-                                              const sh::ShaderVariable &fragmentVariable, bool validatePrecision)
-{
-    if (vertexVariable.type != fragmentVariable.type)
-    {
-        infoLog.append("Types for %s differ between vertex and fragment shaders", variableName.c_str());
-        return false;
-    }
-    if (vertexVariable.arraySize != fragmentVariable.arraySize)
-    {
-        infoLog.append("Array sizes for %s differ between vertex and fragment shaders", variableName.c_str());
-        return false;
-    }
-    if (validatePrecision && vertexVariable.precision != fragmentVariable.precision)
-    {
-        infoLog.append("Precisions for %s differ between vertex and fragment shaders", variableName.c_str());
-        return false;
-    }
-
-    if (vertexVariable.fields.size() != fragmentVariable.fields.size())
-    {
-        infoLog.append("Structure lengths for %s differ between vertex and fragment shaders", variableName.c_str());
-        return false;
-    }
-    const unsigned int numMembers = vertexVariable.fields.size();
-    for (unsigned int memberIndex = 0; memberIndex < numMembers; memberIndex++)
-    {
-        const sh::ShaderVariable &vertexMember = vertexVariable.fields[memberIndex];
-        const sh::ShaderVariable &fragmentMember = fragmentVariable.fields[memberIndex];
-
-        if (vertexMember.name != fragmentMember.name)
-        {
-            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;
-        }
-
-        const std::string memberName = variableName.substr(0, variableName.length() - 1) + "." +
-                                       vertexMember.name + "'";
-
-        if (!linkValidateVariablesBase(infoLog, vertexMember.name, vertexMember, fragmentMember, validatePrecision))
-        {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-bool ProgramBinary::linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform)
-{
-    if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
-    {
-        return false;
-    }
-
-    return true;
-}
-
-bool ProgramBinary::linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying)
-{
-    if (!linkValidateVariablesBase(infoLog, varyingName, vertexVarying, fragmentVarying, false))
-    {
-        return false;
-    }
-
-    if (vertexVarying.interpolation != fragmentVarying.interpolation)
-    {
-        infoLog.append("Interpolation types for %s differ between vertex and fragment shaders", varyingName.c_str());
-        return false;
-    }
-
-    return true;
-}
-
-bool ProgramBinary::linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform)
-{
-    if (!linkValidateVariablesBase(infoLog, uniformName, vertexUniform, fragmentUniform, true))
-    {
-        return false;
-    }
-
-    if (vertexUniform.isRowMajorLayout != fragmentUniform.isRowMajorLayout)
-    {
-        infoLog.append("Matrix packings for %s differ between vertex and fragment shaders", uniformName.c_str());
-        return false;
-    }
-
-    return true;
-}
-
-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;
-
-    // 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++)
-    {
-        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;
-                    }
-                }
-
-                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;
-                }
-
-                totalComponents += componentCount;
-
-                outTransformFeedbackLinkedVaryings->push_back(linkedVaryings[j]);
-                found = true;
-                break;
-            }
-        }
-
-        // All transform feedback varyings are expected to exist since packVaryings checks for them.
-        ASSERT(found);
-    }
-
-    if (transformFeedbackBufferMode == GL_INTERLEAVED_ATTRIBS && totalComponents > caps.maxTransformFeedbackInterleavedComponents)
-    {
-        infoLog.append("Transform feedback varying total components (%u) exceed the maximum interleaved components (%u).",
-                       totalComponents, caps.maxTransformFeedbackInterleavedComponents);
-        return false;
-    }
-
-    return true;
-}
-
-bool ProgramBinary::isValidated() const
-{
-    return mValidated;
-}
-
-void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
-{
-    // Skip over inactive attributes
-    unsigned int activeAttribute = 0;
-    unsigned int attribute;
-    for (attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++)
-    {
-        if (mLinkedAttribute[attribute].name.empty())
-        {
-            continue;
-        }
-
-        if (activeAttribute == index)
-        {
-            break;
-        }
-
-        activeAttribute++;
-    }
-
-    if (bufsize > 0)
-    {
-        const char *string = mLinkedAttribute[attribute].name.c_str();
-
-        strncpy(name, string, bufsize);
-        name[bufsize - 1] = '\0';
-
-        if (length)
-        {
-            *length = strlen(name);
-        }
-    }
-
-    *size = 1;   // Always a single 'type' instance
-
-    *type = mLinkedAttribute[attribute].type;
-}
-
-GLint ProgramBinary::getActiveAttributeCount() const
-{
-    int count = 0;
-
-    for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
-    {
-        if (!mLinkedAttribute[attributeIndex].name.empty())
-        {
-            count++;
-        }
-    }
-
-    return count;
-}
-
-GLint ProgramBinary::getActiveAttributeMaxLength() const
-{
-    int maxLength = 0;
-
-    for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
-    {
-        if (!mLinkedAttribute[attributeIndex].name.empty())
-        {
-            maxLength = std::max((int)(mLinkedAttribute[attributeIndex].name.length() + 1), maxLength);
-        }
-    }
-
-    return maxLength;
-}
-
-void ProgramBinary::getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const
-{
-    ASSERT(index < mProgram->getUniforms().size());   // index must be smaller than getActiveUniformCount()
-
-    if (bufsize > 0)
-    {
-        std::string string = mProgram->getUniforms()[index]->name;
-
-        if (mProgram->getUniforms()[index]->isArray())
-        {
-            string += "[0]";
-        }
-
-        strncpy(name, string.c_str(), bufsize);
-        name[bufsize - 1] = '\0';
-
-        if (length)
-        {
-            *length = strlen(name);
-        }
-    }
-
-    *size = mProgram->getUniforms()[index]->elementCount();
-
-    *type = mProgram->getUniforms()[index]->type;
-}
-
-GLint ProgramBinary::getActiveUniformCount() const
-{
-    return mProgram->getUniforms().size();
-}
-
-GLint ProgramBinary::getActiveUniformMaxLength() const
-{
-    int maxLength = 0;
-
-    unsigned int numUniforms = mProgram->getUniforms().size();
-    for (unsigned int uniformIndex = 0; uniformIndex < numUniforms; uniformIndex++)
-    {
-        if (!mProgram->getUniforms()[uniformIndex]->name.empty())
-        {
-            int length = (int)(mProgram->getUniforms()[uniformIndex]->name.length() + 1);
-            if (mProgram->getUniforms()[uniformIndex]->isArray())
-            {
-                length += 3;  // Counting in "[0]".
-            }
-            maxLength = std::max(length, maxLength);
-        }
-    }
-
-    return maxLength;
-}
-
-GLint ProgramBinary::getActiveUniformi(GLuint index, GLenum pname) const
-{
-    const gl::LinkedUniform& uniform = *mProgram->getUniforms()[index];
-
-    switch (pname)
-    {
-      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()));
-}
-
-LinkedUniform *ProgramBinary::getUniformByLocation(GLint location) const
-{
-    return mProgram->getUniformByLocation(location);
-}
-
-LinkedUniform *ProgramBinary::getUniformByName(const std::string &name) const
-{
-    return mProgram->getUniformByName(name);
-}
-
-void ProgramBinary::getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const
-{
-    ASSERT(uniformBlockIndex < mProgram->getUniformBlocks().size());   // index must be smaller than getActiveUniformBlockCount()
-
-    const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
-
-    if (bufSize > 0)
-    {
-        std::string string = uniformBlock.name;
-
-        if (uniformBlock.isArrayElement())
-        {
-            string += ArrayString(uniformBlock.elementIndex);
-        }
-
-        strncpy(uniformBlockName, string.c_str(), bufSize);
-        uniformBlockName[bufSize - 1] = '\0';
-
-        if (length)
-        {
-            *length = strlen(uniformBlockName);
-        }
-    }
-}
-
-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++)
-            {
-                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();
-}
-
-GLuint ProgramBinary::getActiveUniformBlockMaxLength() const
-{
-    unsigned int maxLength = 0;
-
-    unsigned int numUniformBlocks = mProgram->getUniformBlocks().size();
-    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < numUniformBlocks; uniformBlockIndex++)
-    {
-        const UniformBlock &uniformBlock = *mProgram->getUniformBlocks()[uniformBlockIndex];
-        if (!uniformBlock.name.empty())
-        {
-            const unsigned int length = uniformBlock.name.length() + 1;
-
-            // Counting in "[0]".
-            const unsigned int arrayLength = (uniformBlock.isArrayElement() ? 3 : 0);
-
-            maxLength = std::max(length + arrayLength, maxLength);
-        }
-    }
-
-    return maxLength;
-}
-
-void ProgramBinary::validate(InfoLog &infoLog, const Caps &caps)
-{
-    applyUniforms();
-    if (!validateSamplers(&infoLog, caps))
-    {
-        mValidated = false;
-    }
-    else
-    {
-        mValidated = true;
-    }
-}
-
-bool ProgramBinary::validateSamplers(InfoLog *infoLog, const Caps &caps)
-{
-    return mProgram->validateSamplers(infoLog, caps);
-}
-
-struct AttributeSorter
-{
-    AttributeSorter(const int (&semanticIndices)[MAX_VERTEX_ATTRIBS])
-        : originalIndices(semanticIndices)
-    {
-    }
-
-    bool operator()(int a, int b)
-    {
-        if (originalIndices[a] == -1) return false;
-        if (originalIndices[b] == -1) return true;
-        return (originalIndices[a] < originalIndices[b]);
-    }
-
-    const int (&originalIndices)[MAX_VERTEX_ATTRIBS];
-};
-
-void ProgramBinary::initAttributesByLayout()
-{
-    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
-    {
-        mAttributesByLayout[i] = i;
-    }
-
-    std::sort(&mAttributesByLayout[0], &mAttributesByLayout[MAX_VERTEX_ATTRIBS], AttributeSorter(mSemanticIndex));
-}
-
-void ProgramBinary::sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const
-{
-    rx::TranslatedAttribute oldTranslatedAttributes[MAX_VERTEX_ATTRIBS];
-
-    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
-    {
-        oldTranslatedAttributes[i] = attributes[i];
-    }
-
-    for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
-    {
-        int oldIndex = mAttributesByLayout[i];
-        sortedSemanticIndices[i] = mSemanticIndex[oldIndex];
-        attributes[i] = oldTranslatedAttributes[oldIndex];
-    }
-}
-
-void ProgramBinary::reset()
-{
-    mOutputVariables.clear();
-
-    mProgram->reset();
-
-    mValidated = false;
-}
-
-}
diff --git a/src/libANGLE/ProgramBinary.h b/src/libANGLE/ProgramBinary.h
deleted file mode 100644
index 6365034..0000000
--- a/src/libANGLE/ProgramBinary.h
+++ /dev/null
@@ -1,238 +0,0 @@
-//
-// 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.
-//
-
-// Program.h: Defines the gl::Program class. Implements GL program objects
-// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
-
-#ifndef LIBANGLE_PROGRAM_BINARY_H_
-#define LIBANGLE_PROGRAM_BINARY_H_
-
-#include "common/mathutil.h"
-#include "libANGLE/angletypes.h"
-#include "libANGLE/RefCountObject.h"
-#include "libANGLE/Uniform.h"
-#include "libANGLE/Shader.h"
-#include "libANGLE/Constants.h"
-#include "libANGLE/renderer/d3d/VertexDataManager.h"
-#include "libANGLE/renderer/d3d/DynamicHLSL.h"
-#include "libANGLE/export.h"
-
-#include "angle_gl.h"
-
-#include <string>
-#include <vector>
-
-namespace sh
-{
-class HLSLBlockEncoder;
-}
-
-#include <GLES3/gl3.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <string>
-#include <vector>
-
-namespace rx
-{
-class ShaderExecutable;
-struct TranslatedAttribute;
-class UniformStorage;
-class ProgramImpl;
-}
-
-namespace gl
-{
-struct Caps;
-class Shader;
-class InfoLog;
-class AttributeBindings;
-class Buffer;
-class Framebuffer;
-struct Data;
-
-// Struct used for correlating uniforms/elements of uniform arrays to handles
-struct VariableLocation
-{
-    VariableLocation()
-    {
-    }
-
-    VariableLocation(const std::string &name, unsigned int element, unsigned int index);
-
-    std::string name;
-    unsigned int element;
-    unsigned int index;
-};
-
-struct LinkedVarying
-{
-    LinkedVarying();
-    LinkedVarying(const std::string &name, GLenum type, GLsizei size, const std::string &semanticName,
-                  unsigned int semanticIndex, unsigned int semanticIndexCount);
-
-    // Original GL name
-    std::string name;
-
-    GLenum type;
-    GLsizei size;
-
-    // DirectX semantic information
-    std::string semanticName;
-    unsigned int semanticIndex;
-    unsigned int semanticIndexCount;
-};
-
-struct LinkResult
-{
-    bool linkSuccess;
-    Error error;
-
-    LinkResult(bool linkSuccess, const Error &error);
-};
-
-// This is the result of linking a program. It is the state that would be passed to ProgramBinary.
-class ANGLE_EXPORT ProgramBinary : public RefCountObject
-{
-  public:
-    explicit ProgramBinary(rx::ProgramImpl *impl);
-    ~ProgramBinary();
-
-    rx::ProgramImpl *getImplementation() { return mProgram; }
-    const rx::ProgramImpl *getImplementation() const { return mProgram; }
-
-    GLuint getAttributeLocation(const char *name);
-    int getSemanticIndex(int attributeIndex);
-
-    GLint getSamplerMapping(SamplerType type, unsigned int samplerIndex, const Caps &caps);
-    GLenum getSamplerTextureType(SamplerType type, unsigned int samplerIndex);
-    GLint getUsedSamplerRange(SamplerType type);
-    bool usesPointSize() const;
-
-    GLint getUniformLocation(std::string name);
-    GLuint getUniformIndex(std::string name);
-    GLuint getUniformBlockIndex(std::string name);
-    void setUniform1fv(GLint location, GLsizei count, const GLfloat *v);
-    void setUniform2fv(GLint location, GLsizei count, const GLfloat *v);
-    void setUniform3fv(GLint location, GLsizei count, const GLfloat *v);
-    void setUniform4fv(GLint location, GLsizei count, const GLfloat *v);
-    void setUniform1iv(GLint location, GLsizei count, const GLint *v);
-    void setUniform2iv(GLint location, GLsizei count, const GLint *v);
-    void setUniform3iv(GLint location, GLsizei count, const GLint *v);
-    void setUniform4iv(GLint location, GLsizei count, const GLint *v);
-    void setUniform1uiv(GLint location, GLsizei count, const GLuint *v);
-    void setUniform2uiv(GLint location, GLsizei count, const GLuint *v);
-    void setUniform3uiv(GLint location, GLsizei count, const GLuint *v);
-    void setUniform4uiv(GLint location, GLsizei count, const GLuint *v);
-    void setUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-    void setUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-    void setUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-    void setUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-    void setUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-    void setUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-    void setUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-    void setUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-    void setUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-
-    void getUniformfv(GLint location, GLfloat *params);
-    void getUniformiv(GLint location, GLint *params);
-    void getUniformuiv(GLint location, GLuint *params);
-
-    Error applyUniforms();
-    Error applyUniformBuffers(const std::vector<Buffer*> boundBuffers, const Caps &caps);
-
-    LinkResult load(InfoLog &infoLog, GLenum binaryFormat, const void *binary, GLsizei length);
-    Error save(GLenum *binaryFormat, void *binary, GLsizei bufSize, GLsizei *length);
-    GLint getLength();
-
-    LinkResult link(const Data &data, InfoLog &infoLog, const AttributeBindings &attributeBindings,
-                    Shader *fragmentShader, Shader *vertexShader,
-                    const std::vector<std::string> &transformFeedbackVaryings,
-                    GLenum transformFeedbackBufferMode);
-
-    void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const;
-    GLint getActiveAttributeCount() const;
-    GLint getActiveAttributeMaxLength() const;
-
-    void getActiveUniform(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name) const;
-    GLint getActiveUniformCount() const;
-    GLint getActiveUniformMaxLength() const;
-    GLint getActiveUniformi(GLuint index, GLenum pname) const;
-    bool isValidUniformLocation(GLint location) const;
-    LinkedUniform *getUniformByLocation(GLint location) const;
-    LinkedUniform *getUniformByName(const std::string &name) const;
-
-    void getActiveUniformBlockName(GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName) const;
-    void getActiveUniformBlockiv(GLuint uniformBlockIndex, GLenum pname, GLint *params) const;
-    GLuint getActiveUniformBlockCount() const;
-    GLuint getActiveUniformBlockMaxLength() const;
-    UniformBlock *getUniformBlockByIndex(GLuint blockIndex);
-
-    GLint getFragDataLocation(const char *name) const;
-
-    size_t getTransformFeedbackVaryingCount() const;
-    const LinkedVarying &getTransformFeedbackVarying(size_t idx) const;
-    GLenum getTransformFeedbackBufferMode() const;
-
-    void validate(InfoLog &infoLog, const Caps &caps);
-    bool validateSamplers(InfoLog *infoLog, const Caps &caps);
-    bool isValidated() const;
-    void updateSamplerMapping();
-
-    unsigned int getSerial() const;
-
-    void initAttributesByLayout();
-    void sortAttributesByLayout(rx::TranslatedAttribute attributes[MAX_VERTEX_ATTRIBS], int sortedSemanticIndices[MAX_VERTEX_ATTRIBS]) const;
-
-    static bool linkVaryings(InfoLog &infoLog, Shader *fragmentShader, Shader *vertexShader);
-    static bool linkValidateUniforms(InfoLog &infoLog, const std::string &uniformName, const sh::Uniform &vertexUniform, const sh::Uniform &fragmentUniform);
-    static bool linkValidateInterfaceBlockFields(InfoLog &infoLog, const std::string &uniformName, const sh::InterfaceBlockField &vertexUniform, const sh::InterfaceBlockField &fragmentUniform);
-
-  private:
-    DISALLOW_COPY_AND_ASSIGN(ProgramBinary);
-
-    void reset();
-
-    bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, const Shader *vertexShader);
-    bool linkUniformBlocks(InfoLog &infoLog, const Shader &vertexShader, const Shader &fragmentShader, const Caps &caps);
-    bool areMatchingInterfaceBlocks(gl::InfoLog &infoLog, const sh::InterfaceBlock &vertexInterfaceBlock,
-                                    const sh::InterfaceBlock &fragmentInterfaceBlock);
-
-    static bool linkValidateVariablesBase(InfoLog &infoLog,
-                                          const std::string &variableName,
-                                          const sh::ShaderVariable &vertexVariable,
-                                          const sh::ShaderVariable &fragmentVariable,
-                                          bool validatePrecision);
-
-    static bool linkValidateVaryings(InfoLog &infoLog, const std::string &varyingName, const sh::Varying &vertexVarying, const sh::Varying &fragmentVarying);
-    bool gatherTransformFeedbackLinkedVaryings(InfoLog &infoLog, const std::vector<LinkedVarying> &linkedVaryings,
-                                               const std::vector<std::string> &transformFeedbackVaryingNames,
-                                               GLenum transformFeedbackBufferMode,
-                                               std::vector<LinkedVarying> *outTransformFeedbackLinkedVaryings,
-                                               const Caps &caps) const;
-    bool assignUniformBlockRegister(InfoLog &infoLog, UniformBlock *uniformBlock, GLenum shader, unsigned int registerIndex, const Caps &caps);
-    void defineOutputVariables(Shader *fragmentShader);
-
-    rx::ProgramImpl *mProgram;
-
-    sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS];
-    int mSemanticIndex[MAX_VERTEX_ATTRIBS];
-    int mAttributesByLayout[MAX_VERTEX_ATTRIBS];
-
-    std::map<int, VariableLocation> mOutputVariables;
-
-    bool mValidated;
-
-    const unsigned int mSerial;
-
-    static unsigned int issueSerial();
-    static unsigned int mCurrentSerial;
-};
-
-}
-
-#endif   // LIBANGLE_PROGRAM_BINARY_H_
diff --git a/src/libANGLE/ResourceManager.cpp b/src/libANGLE/ResourceManager.cpp
index 7cebe30..3ed77f1 100644
--- a/src/libANGLE/ResourceManager.cpp
+++ b/src/libANGLE/ResourceManager.cpp
@@ -106,7 +106,7 @@
 {
     GLuint handle = mProgramShaderHandleAllocator.allocate();
 
-    mProgramMap[handle] = new Program(mRenderer, this, handle);
+    mProgramMap[handle] = new Program(mRenderer->createProgram(), this, handle);
 
     return handle;
 }
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index dae55b4..0b1cab5 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -138,8 +138,7 @@
     mActiveQueries[GL_ANY_SAMPLES_PASSED_CONSERVATIVE].set(NULL);
     mActiveQueries[GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN].set(NULL);
 
-    mCurrentProgramId = 0;
-    mCurrentProgramBinary.set(NULL);
+    mProgram = NULL;
 
     mReadFramebuffer = NULL;
     mDrawFramebuffer = NULL;
@@ -163,6 +162,12 @@
     mArrayBuffer.set(NULL);
     mRenderbuffer.set(NULL);
 
+    if (mProgram)
+    {
+        mProgram->release();
+    }
+    mProgram = NULL;
+
     mTransformFeedback.set(NULL);
 
     for (State::ActiveQueryMap::iterator i = mActiveQueries.begin(); i != mActiveQueries.end(); i++)
@@ -187,6 +192,8 @@
 
     mPack.pixelBuffer.set(NULL);
     mUnpack.pixelBuffer.set(NULL);
+
+    mProgram = NULL;
 }
 
 const RasterizerState &State::getRasterizerState() const
@@ -845,31 +852,27 @@
     return false;
 }
 
-void State::setCurrentProgram(GLuint programId, Program *newProgram)
+void State::setProgram(Program *newProgram)
 {
-    mCurrentProgramId = programId; // set new ID before trying to delete program binary; otherwise it will only be flagged for deletion
-    mCurrentProgramBinary.set(NULL);
-
-    if (newProgram)
+    if (mProgram != newProgram)
     {
-        newProgram->addRef();
-        mCurrentProgramBinary.set(newProgram->getProgramBinary());
+        if (mProgram)
+        {
+            mProgram->release();
+        }
+
+        mProgram = newProgram;
+
+        if (mProgram)
+        {
+            newProgram->addRef();
+        }
     }
 }
 
-void State::setCurrentProgramBinary(ProgramBinary *binary)
+Program *State::getProgram() const
 {
-    mCurrentProgramBinary.set(binary);
-}
-
-GLuint State::getCurrentProgramId() const
-{
-    return mCurrentProgramId;
-}
-
-ProgramBinary *State::getCurrentProgramBinary() const
-{
-    return mCurrentProgramBinary.get();
+    return mProgram;
 }
 
 void State::setTransformFeedbackBinding(TransformFeedback *transformFeedback)
@@ -1214,7 +1217,7 @@
       case GL_READ_FRAMEBUFFER_BINDING_ANGLE:           *params = mReadFramebuffer->id();                         break;
       case GL_RENDERBUFFER_BINDING:                     *params = mRenderbuffer.id();                             break;
       case GL_VERTEX_ARRAY_BINDING:                     *params = mVertexArray->id();                             break;
-      case GL_CURRENT_PROGRAM:                          *params = mCurrentProgramId;                              break;
+      case GL_CURRENT_PROGRAM:                          *params = mProgram ? mProgram->id() : 0;                  break;
       case GL_PACK_ALIGNMENT:                           *params = mPack.alignment;                                break;
       case GL_PACK_REVERSE_ROW_ORDER_ANGLE:             *params = mPack.reverseRowOrder;                          break;
       case GL_UNPACK_ALIGNMENT:                         *params = mUnpack.alignment;                              break;
diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h
index 4b78804..abd12b4 100644
--- a/src/libANGLE/State.h
+++ b/src/libANGLE/State.h
@@ -168,10 +168,8 @@
     bool removeVertexArrayBinding(GLuint vertexArray);
 
     // Program binding manipulation
-    void setCurrentProgram(GLuint programId, Program *newProgram);
-    void setCurrentProgramBinary(ProgramBinary *binary);
-    GLuint getCurrentProgramId() const;
-    ProgramBinary *getCurrentProgramBinary() const;
+    void setProgram(Program *newProgram);
+    Program *getProgram() const;
 
     // Transform feedback object (not buffer) binding manipulation
     void setTransformFeedbackBinding(TransformFeedback *transformFeedback);
@@ -285,8 +283,7 @@
     Framebuffer *mReadFramebuffer;
     Framebuffer *mDrawFramebuffer;
     BindingPointer<Renderbuffer> mRenderbuffer;
-    GLuint mCurrentProgramId;
-    BindingPointer<ProgramBinary> mCurrentProgramBinary;
+    Program *mProgram;
 
     typedef std::vector<VertexAttribCurrentValueData> VertexAttribVector;
     VertexAttribVector mVertexAttribCurrentValues; // From glVertexAttrib
diff --git a/src/libANGLE/angletypes.cpp b/src/libANGLE/angletypes.cpp
index 6f5d56b..16be27d 100644
--- a/src/libANGLE/angletypes.cpp
+++ b/src/libANGLE/angletypes.cpp
@@ -7,7 +7,7 @@
 // angletypes.h : Defines a variety of structures and enum types that are used throughout libGLESv2
 
 #include "libANGLE/angletypes.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Program.h"
 #include "libANGLE/VertexAttribute.h"
 #include "libANGLE/State.h"
 #include "libANGLE/VertexArray.h"
@@ -149,13 +149,13 @@
 }
 
 void VertexFormat::GetInputLayout(VertexFormat *inputLayout,
-                                  ProgramBinary *programBinary,
+                                  Program *program,
                                   const State &state)
 {
     const VertexAttribute *vertexAttributes = state.getVertexArray()->getVertexAttributes();
     for (unsigned int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
     {
-        int semanticIndex = programBinary->getSemanticIndex(attributeIndex);
+        int semanticIndex = program->getSemanticIndex(attributeIndex);
 
         if (semanticIndex != -1)
         {
diff --git a/src/libANGLE/angletypes.h b/src/libANGLE/angletypes.h
index 4af82d5..21ede00 100644
--- a/src/libANGLE/angletypes.h
+++ b/src/libANGLE/angletypes.h
@@ -18,7 +18,7 @@
 {
 class Buffer;
 class State;
-class ProgramBinary;
+class Program;
 struct VertexAttribute;
 struct VertexAttribCurrentValueData;
 
@@ -233,7 +233,7 @@
     VertexFormat(const VertexAttribute &attribute, GLenum currentValueType);
 
     static void GetInputLayout(VertexFormat *inputLayout,
-                               ProgramBinary *programBinary,
+                               Program *program,
                                const State& currentValues);
 
     bool operator==(const VertexFormat &other) const;
diff --git a/src/libANGLE/renderer/ProgramImpl.cpp b/src/libANGLE/renderer/ProgramImpl.cpp
index 047691f..b4dfc45 100644
--- a/src/libANGLE/renderer/ProgramImpl.cpp
+++ b/src/libANGLE/renderer/ProgramImpl.cpp
@@ -34,6 +34,12 @@
 
 }
 
+LinkResult::LinkResult(bool linkSuccess, const gl::Error &error)
+    : linkSuccess(linkSuccess),
+      error(error)
+{
+}
+
 ProgramImpl::~ProgramImpl()
 {
     // Ensure that reset was called by the inherited class during destruction
diff --git a/src/libANGLE/renderer/ProgramImpl.h b/src/libANGLE/renderer/ProgramImpl.h
index bdb4044..c4b329b 100644
--- a/src/libANGLE/renderer/ProgramImpl.h
+++ b/src/libANGLE/renderer/ProgramImpl.h
@@ -12,7 +12,7 @@
 #include "common/angleutils.h"
 #include "libANGLE/BinaryStream.h"
 #include "libANGLE/Constants.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Program.h"
 #include "libANGLE/Shader.h"
 #include "libANGLE/renderer/Renderer.h"
 
@@ -21,6 +21,13 @@
 namespace rx
 {
 
+struct LinkResult
+{
+    bool linkSuccess;
+    gl::Error error;
+    LinkResult(bool linkSuccess, const gl::Error &error);
+};
+
 class ProgramImpl
 {
   public:
@@ -52,15 +59,15 @@
     virtual GLenum getTransformFeedbackBufferMode() const = 0;
 
     virtual GLenum getBinaryFormat() = 0;
-    virtual gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0;
+    virtual LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0;
     virtual gl::Error save(gl::BinaryOutputStream *stream) = 0;
 
-    virtual gl::LinkResult link(const gl::Data &data, gl::InfoLog &infoLog,
-                                gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                const std::vector<std::string> &transformFeedbackVaryings,
-                                GLenum transformFeedbackBufferMode,
-                                int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
-                                std::map<int, gl::VariableLocation> *outputVariables) = 0;
+    virtual LinkResult link(const gl::Data &data, gl::InfoLog &infoLog,
+                            gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                            const std::vector<std::string> &transformFeedbackVaryings,
+                            GLenum transformFeedbackBufferMode,
+                            int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
+                            std::map<int, gl::VariableLocation> *outputVariables) = 0;
 
     virtual void setUniform1fv(GLint location, GLsizei count, const GLfloat *v) = 0;
     virtual void setUniform2fv(GLint location, GLsizei count, const GLfloat *v) = 0;
@@ -98,8 +105,8 @@
     virtual void updateSamplerMapping() = 0;
     virtual bool validateSamplers(gl::InfoLog *infoLog, const gl::Caps &caps) = 0;
 
-    virtual gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                                     int registers) = 0;
+    virtual LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                                 int registers) = 0;
 
     virtual bool linkUniforms(gl::InfoLog &infoLog, const gl::Shader &vertexShader, const gl::Shader &fragmentShader,
                               const gl::Caps &caps) = 0;
diff --git a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
index 3ad1ed5..8e0c2bd 100644
--- a/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
+++ b/src/libANGLE/renderer/d3d/DynamicHLSL.cpp
@@ -10,7 +10,6 @@
 #include "libANGLE/renderer/d3d/ShaderD3D.h"
 #include "libANGLE/renderer/d3d/RendererD3D.h"
 #include "libANGLE/Program.h"
-#include "libANGLE/ProgramBinary.h"
 #include "libANGLE/Shader.h"
 #include "libANGLE/formatutils.h"
 
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.cpp b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
index 05707a8..e7317e6 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.cpp
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.cpp
@@ -11,7 +11,6 @@
 #include "libANGLE/Framebuffer.h"
 #include "libANGLE/FramebufferAttachment.h"
 #include "libANGLE/Program.h"
-#include "libANGLE/ProgramBinary.h"
 #include "libANGLE/renderer/ShaderExecutable.h"
 #include "libANGLE/renderer/d3d/DynamicHLSL.h"
 #include "libANGLE/renderer/d3d/RendererD3D.h"
@@ -148,6 +147,8 @@
 {
 }
 
+unsigned int ProgramD3D::mCurrentSerial = 1;
+
 ProgramD3D::ProgramD3D(RendererD3D *renderer)
     : ProgramImpl(),
       mRenderer(renderer),
@@ -161,7 +162,8 @@
       mUsedVertexSamplerRange(0),
       mUsedPixelSamplerRange(0),
       mDirtySamplerMapping(true),
-      mShaderVersion(100)
+      mShaderVersion(100),
+      mSerial(issueSerial())
 {
     mDynamicHLSL = new DynamicHLSL(renderer);
 }
@@ -398,7 +400,7 @@
     return true;
 }
 
-gl::LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
+LinkResult ProgramD3D::load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream)
 {
     stream->readInt(&mShaderVersion);
 
@@ -428,7 +430,7 @@
     if (stream->error())
     {
         infoLog.append("Invalid program binary.");
-        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+        return LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
     mUniforms.resize(uniformCount);
@@ -461,7 +463,7 @@
     if (stream->error())
     {
         infoLog.append("Invalid program binary.");
-        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+        return LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
     mUniformIndex.resize(uniformIndexCount);
@@ -476,7 +478,7 @@
     if (stream->error())
     {
         infoLog.append("Invalid program binary.");
-        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+        return LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
     mUniformBlocks.resize(uniformBlockCount);
@@ -560,13 +562,13 @@
                                                     &shaderExecutable);
         if (error.isError())
         {
-            return gl::LinkResult(false, error);
+            return LinkResult(false, error);
         }
 
         if (!shaderExecutable)
         {
             infoLog.append("Could not create vertex shader.");
-            return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+            return LinkResult(false, gl::Error(GL_NO_ERROR));
         }
 
         // generated converted input layout
@@ -598,13 +600,13 @@
                                                     &shaderExecutable);
         if (error.isError())
         {
-            return gl::LinkResult(false, error);
+            return LinkResult(false, error);
         }
 
         if (!shaderExecutable)
         {
             infoLog.append("Could not create pixel shader.");
-            return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+            return LinkResult(false, gl::Error(GL_NO_ERROR));
         }
 
         // add new binary
@@ -624,13 +626,13 @@
                                                     &mGeometryExecutable);
         if (error.isError())
         {
-            return gl::LinkResult(false, error);
+            return LinkResult(false, error);
         }
 
         if (!mGeometryExecutable)
         {
             infoLog.append("Could not create geometry shader.");
-            return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+            return LinkResult(false, gl::Error(GL_NO_ERROR));
         }
         stream->skip(geometryShaderSize);
     }
@@ -642,12 +644,12 @@
     if (memcmp(&identifier, &binaryIdentifier, sizeof(GUID)) != 0)
     {
         infoLog.append("Invalid program binary.");
-        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+        return LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
     initializeUniformStorage();
 
-    return gl::LinkResult(true, gl::Error(GL_NO_ERROR));
+    return LinkResult(true, gl::Error(GL_NO_ERROR));
 }
 
 gl::Error ProgramD3D::save(gl::BinaryOutputStream *stream)
@@ -917,8 +919,8 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                                     int registers)
+LinkResult ProgramD3D::compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                                 int registers)
 {
     ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
     ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
@@ -929,7 +931,7 @@
     gl::Error error = getVertexExecutableForInputLayout(defaultInputLayout, &defaultVertexExecutable);
     if (error.isError())
     {
-        return gl::LinkResult(false, error);
+        return LinkResult(false, error);
     }
 
     std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey());
@@ -937,7 +939,7 @@
     error = getPixelExecutableForOutputLayout(defaultPixelOutput, &defaultPixelExecutable);
     if (error.isError())
     {
-        return gl::LinkResult(false, error);
+        return LinkResult(false, error);
     }
 
     if (usesGeometryShader())
@@ -950,7 +952,7 @@
                                                ANGLE_D3D_WORKAROUND_NONE, &mGeometryExecutable);
         if (error.isError())
         {
-            return gl::LinkResult(false, error);
+            return LinkResult(false, error);
         }
     }
 
@@ -976,15 +978,15 @@
 #endif
 
     bool linkSuccess = (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable));
-    return gl::LinkResult(linkSuccess, gl::Error(GL_NO_ERROR));
+    return LinkResult(linkSuccess, gl::Error(GL_NO_ERROR));
 }
 
-gl::LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog,
-                                gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                const std::vector<std::string> &transformFeedbackVaryings,
-                                GLenum transformFeedbackBufferMode,
-                                int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
-                                std::map<int, gl::VariableLocation> *outputVariables)
+LinkResult ProgramD3D::link(const gl::Data &data, gl::InfoLog &infoLog,
+                            gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                            const std::vector<std::string> &transformFeedbackVaryings,
+                            GLenum transformFeedbackBufferMode,
+                            int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
+                            std::map<int, gl::VariableLocation> *outputVariables)
 {
     ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
     ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
@@ -1007,24 +1009,24 @@
 
     if (*registers < 0)
     {
-        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+        return LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
-    if (!gl::ProgramBinary::linkVaryings(infoLog, fragmentShader, vertexShader))
+    if (!gl::Program::linkVaryings(infoLog, fragmentShader, vertexShader))
     {
-        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+        return LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
     if (!mDynamicHLSL->generateShaderLinkHLSL(data, infoLog, *registers, packing, mPixelHLSL, mVertexHLSL,
                                               fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings,
                                               linkedVaryings, outputVariables, &mPixelShaderKey, &mUsesFragDepth))
     {
-        return gl::LinkResult(false, gl::Error(GL_NO_ERROR));
+        return LinkResult(false, gl::Error(GL_NO_ERROR));
     }
 
     mUsesPointSize = vertexShaderD3D->usesPointSize();
 
-    return gl::LinkResult(true, gl::Error(GL_NO_ERROR));
+    return LinkResult(true, gl::Error(GL_NO_ERROR));
 }
 
 void ProgramD3D::getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const
@@ -1307,7 +1309,7 @@
         {
             const sh::Uniform &vertexUniform = *entry->second;
             const std::string &uniformName = "uniform '" + vertexUniform.name + "'";
-            if (!gl::ProgramBinary::linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
+            if (!gl::Program::linkValidateUniforms(infoLog, uniformName, vertexUniform, fragmentUniform))
             {
                 return false;
             }
@@ -1921,4 +1923,14 @@
     mDirtySamplerMapping = true;
 }
 
+unsigned int ProgramD3D::getSerial() const
+{
+    return mSerial;
+}
+
+unsigned int ProgramD3D::issueSerial()
+{
+    return mCurrentSerial++;
+}
+
 }
diff --git a/src/libANGLE/renderer/d3d/ProgramD3D.h b/src/libANGLE/renderer/d3d/ProgramD3D.h
index cf5f9d2..7b6219a 100644
--- a/src/libANGLE/renderer/d3d/ProgramD3D.h
+++ b/src/libANGLE/renderer/d3d/ProgramD3D.h
@@ -11,6 +11,7 @@
 
 #include "libANGLE/renderer/ProgramImpl.h"
 #include "libANGLE/renderer/Workarounds.h"
+#include "libANGLE/renderer/d3d/DynamicHLSL.h"
 
 #include <string>
 #include <vector>
@@ -26,6 +27,7 @@
 {
 class RendererD3D;
 class UniformStorage;
+class ShaderExecutable;
 
 class ProgramD3D : public ProgramImpl
 {
@@ -51,7 +53,7 @@
     bool usesGeometryShader() const;
 
     GLenum getBinaryFormat() { return GL_PROGRAM_BINARY_ANGLE; }
-    gl::LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream);
+    LinkResult load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream);
     gl::Error save(gl::BinaryOutputStream *stream);
 
     gl::Error getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo, ShaderExecutable **outExectuable);
@@ -59,15 +61,15 @@
     gl::Error getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS], ShaderExecutable **outExectuable);
     ShaderExecutable *getGeometryExecutable() const { return mGeometryExecutable; }
 
-    gl::LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                             int registers);
+    LinkResult compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                         int registers);
 
-    gl::LinkResult link(const gl::Data &data, gl::InfoLog &infoLog,
-                        gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                        const std::vector<std::string> &transformFeedbackVaryings,
-                        GLenum transformFeedbackBufferMode,
-                        int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
-                        std::map<int, gl::VariableLocation> *outputVariables);
+    LinkResult link(const gl::Data &data, gl::InfoLog &infoLog,
+                    gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                    const std::vector<std::string> &transformFeedbackVaryings,
+                    GLenum transformFeedbackBufferMode,
+                    int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
+                    std::map<int, gl::VariableLocation> *outputVariables);
 
     void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const;
 
@@ -113,6 +115,8 @@
 
     void reset();
 
+    unsigned int getSerial() const;
+
   private:
     DISALLOW_COPY_AND_ASSIGN(ProgramD3D);
 
@@ -212,6 +216,11 @@
     bool mDirtySamplerMapping;
 
     int mShaderVersion;
+
+    unsigned int mSerial;
+
+    static unsigned int issueSerial();
+    static unsigned int mCurrentSerial;
 };
 
 }
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.cpp b/src/libANGLE/renderer/d3d/RendererD3D.cpp
index e31d61d..8312b8a 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.cpp
+++ b/src/libANGLE/renderer/d3d/RendererD3D.cpp
@@ -53,10 +53,10 @@
                                     const GLvoid *indices, GLsizei instances,
                                     const RangeUI &indexRange)
 {
-    ASSERT(data.state->getCurrentProgramId() != 0);
+    gl::Program *program = data.state->getProgram();
+    ASSERT(program != NULL);
 
-    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
-    programBinary->updateSamplerMapping();
+    program->updateSamplerMapping();
 
     gl::Error error = generateSwizzles(data);
     if (error.isError())
@@ -136,10 +136,10 @@
                                   GLenum mode, GLint first,
                                   GLsizei count, GLsizei instances)
 {
-    ASSERT(data.state->getCurrentProgramId() != 0);
+    gl::Program *program = data.state->getProgram();
+    ASSERT(program != NULL);
 
-    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
-    programBinary->updateSamplerMapping();
+    program->updateSamplerMapping();
 
     gl::Error error = generateSwizzles(data);
     if (error.isError())
@@ -209,14 +209,14 @@
 
 gl::Error RendererD3D::generateSwizzles(const gl::Data &data, gl::SamplerType type)
 {
-    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
+    gl::Program *program = data.state->getProgram();
 
-    size_t samplerRange = programBinary->getUsedSamplerRange(type);
+    size_t samplerRange = program->getUsedSamplerRange(type);
 
     for (size_t i = 0; i < samplerRange; i++)
     {
-        GLenum textureType = programBinary->getSamplerTextureType(type, i);
-        GLint textureUnit = programBinary->getSamplerMapping(type, i, *data.caps);
+        GLenum textureType = program->getSamplerTextureType(type, i);
+        GLint textureUnit = program->getSamplerMapping(type, i, *data.caps);
         if (textureUnit != -1)
         {
             gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType);
@@ -355,20 +355,20 @@
 // Applies the shaders and shader constants to the Direct3D device
 gl::Error RendererD3D::applyShaders(const gl::Data &data, bool transformFeedbackActive)
 {
-    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
+    gl::Program *program = data.state->getProgram();
 
     gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS];
-    gl::VertexFormat::GetInputLayout(inputLayout, programBinary, *data.state);
+    gl::VertexFormat::GetInputLayout(inputLayout, program, *data.state);
 
     const gl::Framebuffer *fbo = data.state->getDrawFramebuffer();
 
-    gl::Error error = applyShaders(programBinary, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, transformFeedbackActive);
+    gl::Error error = applyShaders(program, inputLayout, fbo, data.state->getRasterizerState().rasterizerDiscard, transformFeedbackActive);
     if (error.isError())
     {
         return error;
     }
 
-    return programBinary->applyUniforms();
+    return program->applyUniforms();
 }
 
 // For each Direct3D sampler of either the pixel or vertex stage,
@@ -377,13 +377,13 @@
 gl::Error RendererD3D::applyTextures(const gl::Data &data, gl::SamplerType shaderType,
                                      const FramebufferTextureSerialArray &framebufferSerials, size_t framebufferSerialCount)
 {
-    gl::ProgramBinary *programBinary = data.state->getCurrentProgramBinary();
+    gl::Program *program = data.state->getProgram();
 
-    size_t samplerRange = programBinary->getUsedSamplerRange(shaderType);
+    size_t samplerRange = program->getUsedSamplerRange(shaderType);
     for (size_t samplerIndex = 0; samplerIndex < samplerRange; samplerIndex++)
     {
-        GLenum textureType = programBinary->getSamplerTextureType(shaderType, samplerIndex);
-        GLint textureUnit = programBinary->getSamplerMapping(shaderType, samplerIndex, *data.caps);
+        GLenum textureType = program->getSamplerTextureType(shaderType, samplerIndex);
+        GLint textureUnit = program->getSamplerMapping(shaderType, samplerIndex, *data.caps);
         if (textureUnit != -1)
         {
             gl::Texture *texture = data.state->getSamplerTexture(textureUnit, textureType);
@@ -471,14 +471,13 @@
 
 gl::Error RendererD3D::applyUniformBuffers(const gl::Data &data)
 {
-    gl::Program *programObject = data.resourceManager->getProgram(data.state->getCurrentProgramId());
-    gl::ProgramBinary *programBinary = programObject->getProgramBinary();
+    gl::Program *program = data.state->getProgram();
 
     std::vector<gl::Buffer*> boundBuffers;
 
-    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < programBinary->getActiveUniformBlockCount(); uniformBlockIndex++)
+    for (unsigned int uniformBlockIndex = 0; uniformBlockIndex < program->getActiveUniformBlockCount(); uniformBlockIndex++)
     {
-        GLuint blockBinding = programObject->getUniformBlockBinding(uniformBlockIndex);
+        GLuint blockBinding = program->getUniformBlockBinding(uniformBlockIndex);
 
         if (data.state->getIndexedUniformBuffer(blockBinding)->id() == 0)
         {
@@ -493,7 +492,7 @@
         }
     }
 
-    return programBinary->applyUniformBuffers(boundBuffers, *data.caps);
+    return program->applyUniformBuffers(boundBuffers, *data.caps);
 }
 
 bool RendererD3D::skipDraw(const gl::Data &data, GLenum drawMode)
@@ -503,7 +502,7 @@
         // ProgramBinary assumes non-point rendering if gl_PointSize isn't written,
         // which affects varying interpolation. Since the value of gl_PointSize is
         // undefined when not written, just skip drawing to avoid unexpected results.
-        if (!data.state->getCurrentProgramBinary()->usesPointSize())
+        if (!data.state->getProgram()->usesPointSize())
         {
             // This is stictly speaking not an error, but developers should be
             // notified of risking undefined behavior.
diff --git a/src/libANGLE/renderer/d3d/RendererD3D.h b/src/libANGLE/renderer/d3d/RendererD3D.h
index 323c7e9..6df0487 100644
--- a/src/libANGLE/renderer/d3d/RendererD3D.h
+++ b/src/libANGLE/renderer/d3d/RendererD3D.h
@@ -91,7 +91,7 @@
                              bool ignoreViewport) = 0;
 
     virtual gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) = 0;
-    virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
+    virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive) = 0;
     virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray) = 0;
     virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount) = 0;
diff --git a/src/libANGLE/renderer/d3d/VertexDataManager.cpp b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
index 64e58c3..37a3633 100644
--- a/src/libANGLE/renderer/d3d/VertexDataManager.cpp
+++ b/src/libANGLE/renderer/d3d/VertexDataManager.cpp
@@ -12,7 +12,7 @@
 #include "libANGLE/renderer/d3d/VertexBuffer.h"
 #include "libANGLE/renderer/Renderer.h"
 #include "libANGLE/Buffer.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Program.h"
 #include "libANGLE/VertexAttribute.h"
 #include "libANGLE/State.h"
 
@@ -94,7 +94,7 @@
     // Invalidate static buffers that don't contain matching attributes
     for (int attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
     {
-        translated[attributeIndex].active = (state.getCurrentProgramBinary()->getSemanticIndex(attributeIndex) != -1);
+        translated[attributeIndex].active = (state.getProgram()->getSemanticIndex(attributeIndex) != -1);
         const gl::VertexAttribute &curAttrib = state.getVertexAttribState(attributeIndex);
 
         if (translated[attributeIndex].active && curAttrib.enabled)
diff --git a/src/libANGLE/renderer/d3d/VertexDataManager.h b/src/libANGLE/renderer/d3d/VertexDataManager.h
index fe0c68b..a82749a 100644
--- a/src/libANGLE/renderer/d3d/VertexDataManager.h
+++ b/src/libANGLE/renderer/d3d/VertexDataManager.h
@@ -16,7 +16,6 @@
 
 namespace gl
 {
-class ProgramBinary;
 class State;
 struct VertexAttribute;
 struct VertexAttribCurrentValueData;
diff --git a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
index ac9d99f..e2b4d7b 100644
--- a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.cpp
@@ -14,7 +14,7 @@
 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
 #include "libANGLE/renderer/d3d/ProgramD3D.h"
 #include "libANGLE/renderer/d3d/VertexDataManager.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Program.h"
 #include "libANGLE/VertexAttribute.h"
 
 #include "third_party/murmurhash/MurmurHash3.h"
@@ -87,10 +87,10 @@
 }
 
 gl::Error InputLayoutCache::applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
-                                               gl::ProgramBinary *programBinary)
+                                               gl::Program *program)
 {
     int sortedSemanticIndices[gl::MAX_VERTEX_ATTRIBS];
-    programBinary->sortAttributesByLayout(attributes, sortedSemanticIndices);
+    program->sortAttributesByLayout(attributes, sortedSemanticIndices);
 
     if (!mDevice || !mDeviceContext)
     {
@@ -113,7 +113,7 @@
             // Record the type of the associated vertex shader vector in our key
             // This will prevent mismatched vertex shaders from using the same input layout
             GLint attributeSize;
-            programBinary->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);
+            program->getActiveAttribute(ilKey.elementCount, 0, NULL, &attributeSize, &ilKey.elements[ilKey.elementCount].glslElementType, NULL);
 
             ilKey.elements[ilKey.elementCount].desc.SemanticName = semanticName;
             ilKey.elements[ilKey.elementCount].desc.SemanticIndex = sortedSemanticIndices[i];
@@ -138,7 +138,7 @@
     {
         gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
         GetInputLayout(attributes, shaderInputLayout);
-        ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
+        ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(program->getImplementation());
 
         ShaderExecutable *shader = NULL;
         gl::Error error = programD3D->getVertexExecutableForInputLayout(shaderInputLayout, &shader);
diff --git a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h
index 2e48304..9cebee2 100644
--- a/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h
+++ b/src/libANGLE/renderer/d3d/d3d11/InputLayoutCache.h
@@ -21,7 +21,7 @@
 
 namespace gl
 {
-class ProgramBinary;
+class Program;
 }
 
 namespace rx
@@ -39,7 +39,7 @@
     void markDirty();
 
     gl::Error applyVertexBuffers(TranslatedAttribute attributes[gl::MAX_VERTEX_ATTRIBS],
-                                 gl::ProgramBinary *programBinary);
+                                 gl::Program *program);
 
   private:
     DISALLOW_COPY_AND_ASSIGN(InputLayoutCache);
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index 999d2ea..8cee038 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -14,7 +14,7 @@
 #include "libANGLE/Display.h"
 #include "libANGLE/Framebuffer.h"
 #include "libANGLE/FramebufferAttachment.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Program.h"
 #include "libANGLE/State.h"
 #include "libANGLE/Surface.h"
 #include "libANGLE/renderer/d3d/FramebufferD3D.h"
@@ -1073,7 +1073,7 @@
         return error;
     }
 
-    return mInputLayoutCache.applyVertexBuffers(attributes, state.getCurrentProgramBinary());
+    return mInputLayoutCache.applyVertexBuffers(attributes, state.getProgram());
 }
 
 gl::Error Renderer11::applyIndexBuffer(const GLvoid *indices, gl::Buffer *elementArrayBuffer, GLsizei count, GLenum mode, GLenum type, TranslatedIndexData *indexInfo)
@@ -1478,10 +1478,10 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error Renderer11::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
+gl::Error Renderer11::applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive)
 {
-    ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
+    ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(program->getImplementation());
 
     ShaderExecutable *vertexExe = NULL;
     gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe);
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index fd83885..2562404 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -82,7 +82,7 @@
 
     virtual bool applyPrimitiveType(GLenum mode, GLsizei count);
     gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override;
-    virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
+    virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive);
 
     virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
diff --git a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
index 47f6c31..fac523a 100644
--- a/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/renderer11_utils.cpp
@@ -11,7 +11,7 @@
 #include "libANGLE/renderer/d3d/d3d11/formatutils11.h"
 #include "libANGLE/renderer/d3d/d3d11/RenderTarget11.h"
 #include "libANGLE/renderer/Workarounds.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Program.h"
 #include "libANGLE/Framebuffer.h"
 
 #include "common/debug.h"
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
index 02eaa9a..c4594d3 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.cpp
@@ -13,7 +13,7 @@
 #include "libANGLE/Display.h"
 #include "libANGLE/Framebuffer.h"
 #include "libANGLE/FramebufferAttachment.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Program.h"
 #include "libANGLE/Renderbuffer.h"
 #include "libANGLE/State.h"
 #include "libANGLE/Surface.h"
@@ -1320,7 +1320,7 @@
         return error;
     }
 
-    return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, state.getCurrentProgramBinary(), instances, &mRepeatDraw);
+    return mVertexDeclarationCache.applyDeclaration(mDevice, attributes, state.getProgram(), instances, &mRepeatDraw);
 }
 
 // Applies the indices and element array bindings to the Direct3D 9 device
@@ -1719,13 +1719,13 @@
     return gl::Error(GL_NO_ERROR);
 }
 
-gl::Error Renderer9::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
+gl::Error Renderer9::applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                   bool rasterizerDiscard, bool transformFeedbackActive)
 {
     ASSERT(!transformFeedbackActive);
     ASSERT(!rasterizerDiscard);
 
-    ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
+    ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(program->getImplementation());
 
     ShaderExecutable *vertexExe = NULL;
     gl::Error error = programD3D->getVertexExecutableForInputLayout(inputLayout, &vertexExe);
@@ -1761,7 +1761,7 @@
     // per-program, checking the program serial guarantees we upload fresh
     // uniform data even if our shader pointers are the same.
     // https://code.google.com/p/angleproject/issues/detail?id=661
-    unsigned int programSerial = programBinary->getSerial();
+    unsigned int programSerial = programD3D->getSerial();
     if (programSerial != mAppliedProgramSerial)
     {
         programD3D->dirtyAllUniforms();
diff --git a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
index f47bbb8..72ef5c2 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/Renderer9.h
@@ -82,7 +82,7 @@
                              bool ignoreViewport);
 
     gl::Error applyRenderTarget(const gl::Framebuffer *frameBuffer) override;
-    virtual gl::Error applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
+    virtual gl::Error applyShaders(gl::Program *program, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive);
     virtual gl::Error applyUniforms(const ProgramImpl &program, const std::vector<gl::LinkedUniform*> &uniformArray);
     virtual bool applyPrimitiveType(GLenum primitiveType, GLsizei elementCount);
diff --git a/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp b/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp
index 568273e..f9eded9 100644
--- a/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp
+++ b/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.cpp
@@ -9,7 +9,7 @@
 #include "libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h"
 #include "libANGLE/renderer/d3d/d3d9/VertexBuffer9.h"
 #include "libANGLE/renderer/d3d/d3d9/formatutils9.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Program.h"
 #include "libANGLE/VertexAttribute.h"
 
 namespace rx
@@ -40,7 +40,7 @@
     }
 }
 
-gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw)
+gl::Error VertexDeclarationCache::applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::Program *program, GLsizei instances, GLsizei *repeatDraw)
 {
     *repeatDraw = 1;
 
@@ -155,7 +155,7 @@
             element->Type = d3d9VertexInfo.nativeFormat;
             element->Method = D3DDECLMETHOD_DEFAULT;
             element->Usage = D3DDECLUSAGE_TEXCOORD;
-            element->UsageIndex = programBinary->getSemanticIndex(i);
+            element->UsageIndex = program->getSemanticIndex(i);
             element++;
         }
     }
diff --git a/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h b/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h
index 3272e50..fbd6730 100644
--- a/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h
+++ b/src/libANGLE/renderer/d3d/d3d9/VertexDeclarationCache.h
@@ -15,6 +15,7 @@
 namespace gl
 {
 class VertexDataManager;
+class Program;
 }
 
 namespace rx
@@ -26,7 +27,7 @@
     VertexDeclarationCache();
     ~VertexDeclarationCache();
 
-    gl::Error applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::ProgramBinary *programBinary, GLsizei instances, GLsizei *repeatDraw);
+    gl::Error applyDeclaration(IDirect3DDevice9 *device, TranslatedAttribute attributes[], gl::Program *program, GLsizei instances, GLsizei *repeatDraw);
 
     void markStateDirty();
 
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 695f94f..08ded1d 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -15,7 +15,8 @@
 #include "libANGLE/FramebufferAttachment.h"
 #include "libANGLE/formatutils.h"
 #include "libANGLE/Query.h"
-#include "libANGLE/ProgramBinary.h"
+#include "libANGLE/Program.h"
+#include "libANGLE/Uniform.h"
 #include "libANGLE/TransformFeedback.h"
 #include "libANGLE/VertexArray.h"
 #include "libANGLE/renderer/BufferImpl.h"
@@ -1058,8 +1059,8 @@
         return false;
     }
 
-    gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-    if (!programBinary)
+    gl::Program *program = context->getState().getProgram();
+    if (!program)
     {
         context->recordError(Error(GL_INVALID_OPERATION));
         return false;
@@ -1071,13 +1072,13 @@
         return false;
     }
 
-    if (!programBinary->isValidUniformLocation(location))
+    if (!program->isValidUniformLocation(location))
     {
         context->recordError(Error(GL_INVALID_OPERATION));
         return false;
     }
 
-    LinkedUniform *uniform = programBinary->getUniformByLocation(location);
+    LinkedUniform *uniform = program->getUniformByLocation(location);
 
     // attempting to write an array to a non-array uniform is an INVALID_OPERATION
     if (uniform->elementCount() == 1 && count > 1)
@@ -1461,14 +1462,14 @@
         return false;
     }
 
-    if (state.getCurrentProgramId() == 0)
+    gl::Program *program = state.getProgram();
+    if (!program)
     {
         context->recordError(Error(GL_INVALID_OPERATION));
         return false;
     }
 
-    gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
-    if (!programBinary->validateSamplers(NULL, context->getCaps()))
+    if (!program->validateSamplers(NULL, context->getCaps()))
     {
         context->recordError(Error(GL_INVALID_OPERATION));
         return false;
@@ -1479,7 +1480,7 @@
     for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
     {
         const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
-        bool attribActive = (programBinary->getSemanticIndex(attributeIndex) != -1);
+        bool attribActive = (program->getSemanticIndex(attributeIndex) != -1);
         if (attribActive && attrib.enabled)
         {
             gl::Buffer *buffer = attrib.buffer.get();
@@ -1573,13 +1574,13 @@
     // Verify there is at least one active attribute with a divisor of zero
     const gl::State& state = context->getState();
 
-    gl::ProgramBinary *programBinary = state.getCurrentProgramBinary();
+    gl::Program *program = state.getProgram();
 
     const VertexArray *vao = state.getVertexArray();
     for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
     {
         const VertexAttribute &attrib = vao->getVertexAttribute(attributeIndex);
-        bool active = (programBinary->getSemanticIndex(attributeIndex) != -1);
+        bool active = (program->getSemanticIndex(attributeIndex) != -1);
         if (active && attrib.divisor == 0)
         {
             return true;
@@ -1886,14 +1887,7 @@
         return false;
     }
 
-    gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-    if (!programBinary)
-    {
-        context->recordError(Error(GL_INVALID_OPERATION));
-        return false;
-    }
-
-    if (!programBinary->isValidUniformLocation(location))
+    if (!programObject->isValidUniformLocation(location))
     {
         context->recordError(Error(GL_INVALID_OPERATION));
         return false;
@@ -1921,10 +1915,9 @@
 
     gl::Program *programObject = context->getProgram(program);
     ASSERT(programObject);
-    gl::ProgramBinary *programBinary = programObject->getProgramBinary();
 
     // sized queries -- ensure the provided buffer is large enough
-    LinkedUniform *uniform = programBinary->getUniformByLocation(location);
+    LinkedUniform *uniform = programObject->getUniformByLocation(location);
     size_t requiredBytes = VariableExternalSize(uniform->type);
     if (static_cast<size_t>(bufSize) < requiredBytes)
     {
diff --git a/src/libGLESv2.gypi b/src/libGLESv2.gypi
index b32965b..32f602c 100644
--- a/src/libGLESv2.gypi
+++ b/src/libGLESv2.gypi
@@ -74,8 +74,6 @@
             'libANGLE/ImageIndex.cpp',
             'libANGLE/Program.cpp',
             'libANGLE/Program.h',
-            'libANGLE/ProgramBinary.cpp',
-            'libANGLE/ProgramBinary.h',
             'libANGLE/Query.cpp',
             'libANGLE/Query.h',
             'libANGLE/RefCountObject.cpp',
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 71e4f30..a197e67 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -13,8 +13,8 @@
 #include "libANGLE/Fence.h"
 #include "libANGLE/Framebuffer.h"
 #include "libANGLE/Renderbuffer.h"
+#include "libANGLE/Shader.h"
 #include "libANGLE/Program.h"
-#include "libANGLE/ProgramBinary.h"
 #include "libANGLE/Texture.h"
 #include "libANGLE/Query.h"
 #include "libANGLE/Context.h"
@@ -1996,14 +1996,13 @@
             }
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        if (!programObject->isLinked() || !programBinary)
+        if (!programObject->isLinked())
         {
             context->recordError(gl::Error(GL_INVALID_OPERATION));
             return -1;
         }
 
-        return programBinary->getAttributeLocation(name);
+        return programObject->getAttributeLocation(name);
     }
 
     return -1;
@@ -2546,7 +2545,7 @@
             *params = programObject->getActiveUniformMaxLength();
             return;
           case GL_PROGRAM_BINARY_LENGTH_OES:
-            *params = programObject->getProgramBinaryLength();
+            *params = programObject->getBinaryLength();
             return;
           case GL_ACTIVE_UNIFORM_BLOCKS:
             *params = programObject->getActiveUniformBlockCount();
@@ -3218,10 +3217,8 @@
 
         gl::Program *programObject = context->getProgram(program);
         ASSERT(programObject);
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        ASSERT(programBinary);
 
-        programBinary->getUniformfv(location, params);
+        programObject->getUniformfv(location, params);
     }
 }
 
@@ -3239,10 +3236,8 @@
 
         gl::Program *programObject = context->getProgram(program);
         ASSERT(programObject);
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        ASSERT(programBinary);
 
-        programBinary->getUniformfv(location, params);
+        programObject->getUniformfv(location, params);
     }
 }
 
@@ -3261,10 +3256,8 @@
 
         gl::Program *programObject = context->getProgram(program);
         ASSERT(programObject);
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        ASSERT(programBinary);
 
-        programBinary->getUniformiv(location, params);
+        programObject->getUniformiv(location, params);
     }
 }
 
@@ -3282,10 +3275,8 @@
 
         gl::Program *programObject = context->getProgram(program);
         ASSERT(programObject);
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        ASSERT(programBinary);
 
-        programBinary->getUniformiv(location, params);
+        programObject->getUniformiv(location, params);
     }
 }
 
@@ -3317,14 +3308,13 @@
             }
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        if (!programObject->isLinked() || !programBinary)
+        if (!programObject->isLinked())
         {
             context->recordError(gl::Error(GL_INVALID_OPERATION));
             return -1;
         }
 
-        return programBinary->getUniformLocation(name);
+        return programObject->getUniformLocation(name);
     }
 
     return -1;
@@ -3659,7 +3649,7 @@
             }
         }
 
-        gl::Error error = context->linkProgram(program);
+        gl::Error error = programObject->link(context->getData());
         if (error.isError())
         {
             context->recordError(error);
@@ -4467,8 +4457,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform1fv(location, count, v);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform1fv(location, count, v);
     }
 }
 
@@ -4489,8 +4479,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform1iv(location, count, v);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform1iv(location, count, v);
     }
 }
 
@@ -4513,8 +4503,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform2fv(location, count, v);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform2fv(location, count, v);
     }
 }
 
@@ -4537,8 +4527,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform2iv(location, count, v);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform2iv(location, count, v);
     }
 }
 
@@ -4561,8 +4551,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform3fv(location, count, v);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform3fv(location, count, v);
     }
 }
 
@@ -4585,8 +4575,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform3iv(location, count, v);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform3iv(location, count, v);
     }
 }
 
@@ -4609,8 +4599,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform4fv(location, count, v);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform4fv(location, count, v);
     }
 }
 
@@ -4633,8 +4623,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform4iv(location, count, v);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform4iv(location, count, v);
     }
 }
 
@@ -4651,8 +4641,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniformMatrix2fv(location, count, transpose, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniformMatrix2fv(location, count, transpose, value);
     }
 }
 
@@ -4669,8 +4659,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniformMatrix3fv(location, count, transpose, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniformMatrix3fv(location, count, transpose, value);
     }
 }
 
@@ -4687,8 +4677,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniformMatrix4fv(location, count, transpose, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniformMatrix4fv(location, count, transpose, value);
     }
 }
 
@@ -5628,8 +5618,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniformMatrix2x3fv(location, count, transpose, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniformMatrix2x3fv(location, count, transpose, value);
     }
 }
 
@@ -5646,8 +5636,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniformMatrix3x2fv(location, count, transpose, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniformMatrix3x2fv(location, count, transpose, value);
     }
 }
 
@@ -5664,8 +5654,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniformMatrix2x4fv(location, count, transpose, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniformMatrix2x4fv(location, count, transpose, value);
     }
 }
 
@@ -5682,8 +5672,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniformMatrix4x2fv(location, count, transpose, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniformMatrix4x2fv(location, count, transpose, value);
     }
 }
 
@@ -5700,8 +5690,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniformMatrix3x4fv(location, count, transpose, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniformMatrix3x4fv(location, count, transpose, value);
     }
 }
 
@@ -5718,8 +5708,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniformMatrix4x3fv(location, count, transpose, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniformMatrix4x3fv(location, count, transpose, value);
     }
 }
 
@@ -6593,10 +6583,8 @@
 
         gl::Program *programObject = context->getProgram(program);
         ASSERT(programObject);
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        ASSERT(programBinary);
 
-        programBinary->getUniformuiv(location, params);
+        programObject->getUniformuiv(location, params);
     }
 }
 
@@ -6628,14 +6616,7 @@
             return -1;
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        if (!programBinary)
-        {
-            context->recordError(gl::Error(GL_INVALID_OPERATION));
-            return -1;
-        }
-
-        return programBinary->getFragDataLocation(name);
+        return programObject->getFragDataLocation(name);
     }
 
     return 0;
@@ -6677,8 +6658,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform1uiv(location, count, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform1uiv(location, count, value);
     }
 }
 
@@ -6695,8 +6676,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform2uiv(location, count, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform2uiv(location, count, value);
     }
 }
 
@@ -6713,8 +6694,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform3uiv(location, count, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform3uiv(location, count, value);
     }
 }
 
@@ -6731,8 +6712,8 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = context->getState().getCurrentProgramBinary();
-        programBinary->setUniform4uiv(location, count, value);
+        gl::Program *program = context->getState().getProgram();
+        program->setUniform4uiv(location, count, value);
     }
 }
 
@@ -7030,8 +7011,7 @@
             }
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        if (!programObject->isLinked() || !programBinary)
+        if (!programObject->isLinked())
         {
             for (int uniformId = 0; uniformId < uniformCount; uniformId++)
             {
@@ -7042,7 +7022,7 @@
         {
             for (int uniformId = 0; uniformId < uniformCount; uniformId++)
             {
-                uniformIndices[uniformId] = programBinary->getUniformIndex(uniformNames[uniformId]);
+                uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);
             }
         }
     }
@@ -7101,9 +7081,7 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-
-        if (!programBinary && uniformCount > 0)
+        if (uniformCount > 0)
         {
             context->recordError(gl::Error(GL_INVALID_VALUE));
             return;
@@ -7113,7 +7091,7 @@
         {
             const GLuint index = uniformIndices[uniformId];
 
-            if (index >= (GLuint)programBinary->getActiveUniformCount())
+            if (index >= static_cast<GLuint>(programObject->getActiveUniformCount()))
             {
                 context->recordError(gl::Error(GL_INVALID_VALUE));
                 return;
@@ -7123,7 +7101,7 @@
         for (int uniformId = 0; uniformId < uniformCount; uniformId++)
         {
             const GLuint index = uniformIndices[uniformId];
-            params[uniformId] = programBinary->getActiveUniformi(index, pname);
+            params[uniformId] = programObject->getActiveUniformi(index, pname);
         }
     }
 }
@@ -7157,13 +7135,7 @@
             }
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-        if (!programBinary)
-        {
-            return GL_INVALID_INDEX;
-        }
-
-        return programBinary->getUniformBlockIndex(uniformBlockName);
+        return programObject->getUniformBlockIndex(uniformBlockName);
     }
 
     return 0;
@@ -7198,9 +7170,7 @@
             }
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-
-        if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount())
+        if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
         {
             context->recordError(gl::Error(GL_INVALID_VALUE));
             return;
@@ -7218,7 +7188,7 @@
           case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
           case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
           case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
-            programBinary->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
+            programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
             break;
 
           default:
@@ -7258,15 +7228,13 @@
             }
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-
-        if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount())
+        if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
         {
             context->recordError(gl::Error(GL_INVALID_VALUE));
             return;
         }
 
-        programBinary->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
+        programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
     }
 }
 
@@ -7306,10 +7274,8 @@
             }
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-
         // if never linked, there won't be any uniform blocks
-        if (!programBinary || uniformBlockIndex >= programBinary->getActiveUniformBlockCount())
+        if (uniformBlockIndex >= programObject->getActiveUniformBlockCount())
         {
             context->recordError(gl::Error(GL_INVALID_VALUE));
             return;
@@ -8498,15 +8464,7 @@
             return;
         }
 
-        gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-
-        if (!programBinary)
-        {
-            context->recordError(gl::Error(GL_INVALID_OPERATION));
-            return;
-        }
-
-        gl::Error error = programBinary->save(binaryFormat, binary, bufSize, length);
+        gl::Error error = programObject->saveBinary(binaryFormat, binary, bufSize, length);
         if (error.isError())
         {
             context->recordError(error);
@@ -8538,7 +8496,7 @@
             return;
         }
 
-        gl::Error error = context->setProgramBinary(program, binaryFormat, binary, length);
+        gl::Error error = programObject->loadBinary(binaryFormat, binary, length);
         if (error.isError())
         {
             context->recordError(error);