Moving Shader Executables into ProgramD3D

BUG=angle:731
Change-Id: I677fc9773914307184bcdd9ab7ac564956d77f6a
Reviewed-on: https://chromium-review.googlesource.com/219814
Tested-by: Brandon Jones <bajones@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
diff --git a/src/libGLESv2/BinaryStream.h b/src/libGLESv2/BinaryStream.h
index 4d7dde0..4f7f5f2 100644
--- a/src/libGLESv2/BinaryStream.h
+++ b/src/libGLESv2/BinaryStream.h
@@ -15,6 +15,7 @@
 #include <cstddef>
 #include <string>
 #include <vector>
+#include <stdint.h>
 
 namespace gl
 {
@@ -26,7 +27,7 @@
     {
         mError = false;
         mOffset = 0;
-        mData = static_cast<const char*>(data);
+        mData = static_cast<const uint8_t*>(data);
         mLength = length;
     }
 
@@ -85,7 +86,7 @@
             return;
         }
 
-        v->assign(mData + mOffset, length);
+        v->assign(reinterpret_cast<const char *>(mData) + mOffset, length);
         mOffset += length;
     }
 
@@ -115,11 +116,16 @@
         return mOffset == mLength;
     }
 
+    const uint8_t *data()
+    {
+        return mData;
+    }
+
   private:
     DISALLOW_COPY_AND_ASSIGN(BinaryInputStream);
     bool mError;
     size_t mOffset;
-    const char *mData;
+    const uint8_t *mData;
     size_t mLength;
 
     template <typename T>
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index d7d5d94..96f78ad 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -80,42 +80,6 @@
     return subscript;
 }
 
-void GetDefaultInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
-{
-    size_t layoutIndex = 0;
-    for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
-    {
-        ASSERT(layoutIndex < MAX_VERTEX_ATTRIBS);
-
-        const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex];
-
-        if (shaderAttr.type != GL_NONE)
-        {
-            GLenum transposedType = TransposeMatrixType(shaderAttr.type);
-
-            for (size_t rowIndex = 0; static_cast<int>(rowIndex) < VariableRowCount(transposedType); rowIndex++, layoutIndex++)
-            {
-                VertexFormat *defaultFormat = &inputLayout[layoutIndex];
-
-                defaultFormat->mType = VariableComponentType(transposedType);
-                defaultFormat->mNormalized = false;
-                defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool
-                defaultFormat->mComponents = VariableColumnCount(transposedType);
-            }
-        }
-    }
-}
-
-std::vector<GLenum> GetDefaultOutputLayoutFromShader(const std::vector<rx::PixelShaderOutputVariable> &shaderOutputVars)
-{
-    std::vector<GLenum> defaultPixelOutput(1);
-
-    ASSERT(!shaderOutputVars.empty());
-    defaultPixelOutput[0] = GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex;
-
-    return defaultPixelOutput;
-}
-
 bool IsRowMajorLayout(const sh::InterfaceBlockField &var)
 {
     return var.isRowMajorLayout;
@@ -133,47 +97,6 @@
 {
 }
 
-ProgramBinary::VertexExecutable::VertexExecutable(const VertexFormat inputLayout[],
-                                                  const GLenum signature[],
-                                                  rx::ShaderExecutable *shaderExecutable)
-    : mShaderExecutable(shaderExecutable)
-{
-    for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
-    {
-        mInputs[attributeIndex] = inputLayout[attributeIndex];
-        mSignature[attributeIndex] = signature[attributeIndex];
-    }
-}
-
-ProgramBinary::VertexExecutable::~VertexExecutable()
-{
-    SafeDelete(mShaderExecutable);
-}
-
-bool ProgramBinary::VertexExecutable::matchesSignature(const GLenum signature[]) const
-{
-    for (size_t attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++)
-    {
-        if (mSignature[attributeIndex] != signature[attributeIndex])
-        {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-ProgramBinary::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable)
-    : mOutputSignature(outputSignature),
-      mShaderExecutable(shaderExecutable)
-{
-}
-
-ProgramBinary::PixelExecutable::~PixelExecutable()
-{
-    SafeDelete(mShaderExecutable);
-}
-
 LinkedVarying::LinkedVarying()
 {
 }
@@ -189,7 +112,6 @@
 ProgramBinary::ProgramBinary(rx::ProgramImpl *impl)
     : RefCountObject(0),
       mProgram(impl),
-      mGeometryExecutable(NULL),
       mUsedVertexSamplerRange(0),
       mUsedPixelSamplerRange(0),
       mDirtySamplerMapping(true),
@@ -220,93 +142,6 @@
     return mCurrentSerial++;
 }
 
-rx::ShaderExecutable *ProgramBinary::getPixelExecutableForFramebuffer(const Framebuffer *fbo)
-{
-    std::vector<GLenum> outputs;
-
-    const gl::ColorbufferInfo &colorbuffers = fbo->getColorbuffersForRender();
-
-    for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
-    {
-        const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
-
-        if (colorbuffer)
-        {
-            outputs.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding());
-        }
-        else
-        {
-            outputs.push_back(GL_NONE);
-        }
-    }
-
-    return getPixelExecutableForOutputLayout(outputs);
-}
-
-rx::ShaderExecutable *ProgramBinary::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature)
-{
-    for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++)
-    {
-        if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
-        {
-            return mPixelExecutables[executableIndex]->shaderExecutable();
-        }
-    }
-
-    InfoLog tempInfoLog;
-    rx::ShaderExecutable *pixelExecutable = mProgram->getPixelExecutableForOutputLayout(tempInfoLog, outputSignature,
-            mTransformFeedbackLinkedVaryings, (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
-
-    if (!pixelExecutable)
-    {
-        std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
-        tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
-        ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]);
-    }
-    else
-    {
-        mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable));
-    }
-
-    return pixelExecutable;
-}
-
-rx::ShaderExecutable *ProgramBinary::getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS])
-{
-    GLenum signature[MAX_VERTEX_ATTRIBS];
-    mProgram->getInputLayoutSignature(inputLayout, signature);
-
-    for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
-    {
-        if (mVertexExecutables[executableIndex]->matchesSignature(signature))
-        {
-            return mVertexExecutables[executableIndex]->shaderExecutable();
-        }
-    }
-
-    InfoLog tempInfoLog;
-    rx::ShaderExecutable *vertexExecutable = mProgram->getVertexExecutableForInputLayout(tempInfoLog, inputLayout, mShaderAttributes,
-            mTransformFeedbackLinkedVaryings, (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
-
-    if (!vertexExecutable)
-    {
-        std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3);
-        tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
-        ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
-    }
-    else
-    {
-        mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable));
-    }
-
-    return vertexExecutable;
-}
-
-rx::ShaderExecutable *ProgramBinary::getGeometryExecutable() const
-{
-    return mGeometryExecutable;
-}
-
 GLuint ProgramBinary::getAttributeLocation(const char *name)
 {
     if (name)
@@ -497,17 +332,17 @@
 
 size_t ProgramBinary::getTransformFeedbackVaryingCount() const
 {
-    return mTransformFeedbackLinkedVaryings.size();
+    return mProgram->getTransformFeedbackLinkedVaryings().size();
 }
 
 const LinkedVarying &ProgramBinary::getTransformFeedbackVarying(size_t idx) const
 {
-    return mTransformFeedbackLinkedVaryings[idx];
+    return mProgram->getTransformFeedbackLinkedVaryings()[idx];
 }
 
 GLenum ProgramBinary::getTransformFeedbackBufferMode() const
 {
-    return mTransformFeedbackBufferMode;
+    return mProgram->getTransformFeedbackBufferMode();
 }
 
 template <typename T>
@@ -1064,8 +899,8 @@
     {
         stream.readInt(&mLinkedAttribute[i].type);
         stream.readString(&mLinkedAttribute[i].name);
-        stream.readInt(&mShaderAttributes[i].type);
-        stream.readString(&mShaderAttributes[i].name);
+        stream.readInt(&mProgram->getShaderAttributes()[i].type);
+        stream.readString(&mProgram->getShaderAttributes()[i].name);
         stream.readInt(&mSemanticIndex[i]);
     }
 
@@ -1170,102 +1005,6 @@
         stream.readInt(&mUniformIndex[uniformIndexIndex].index);
     }
 
-    stream.readInt(&mTransformFeedbackBufferMode);
-    const unsigned int transformFeedbackVaryingCount = stream.readInt<unsigned int>();
-    mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount);
-    for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++)
-    {
-        LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex];
-
-        stream.readString(&varying.name);
-        stream.readInt(&varying.type);
-        stream.readInt(&varying.size);
-        stream.readString(&varying.semanticName);
-        stream.readInt(&varying.semanticIndex);
-        stream.readInt(&varying.semanticIndexCount);
-    }
-
-    const unsigned int vertexShaderCount = stream.readInt<unsigned int>();
-    for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
-    {
-        VertexFormat inputLayout[MAX_VERTEX_ATTRIBS];
-
-        for (size_t inputIndex = 0; inputIndex < MAX_VERTEX_ATTRIBS; inputIndex++)
-        {
-            VertexFormat *vertexInput = &inputLayout[inputIndex];
-            stream.readInt(&vertexInput->mType);
-            stream.readInt(&vertexInput->mNormalized);
-            stream.readInt(&vertexInput->mComponents);
-            stream.readBool(&vertexInput->mPureInteger);
-        }
-
-        unsigned int vertexShaderSize = stream.readInt<unsigned int>();
-        const unsigned char *vertexShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
-        rx::ShaderExecutable *shaderExecutable = mProgram->loadExecutable(reinterpret_cast<const DWORD*>(vertexShaderFunction),
-                                                                          vertexShaderSize, rx::SHADER_VERTEX,
-                                                                          mTransformFeedbackLinkedVaryings,
-                                                                          (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
-        if (!shaderExecutable)
-        {
-            infoLog.append("Could not create vertex shader.");
-            return false;
-        }
-
-        // generated converted input layout
-        GLenum signature[MAX_VERTEX_ATTRIBS];
-        mProgram->getInputLayoutSignature(inputLayout, signature);
-
-        // add new binary
-        mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable));
-
-        stream.skip(vertexShaderSize);
-    }
-
-    const size_t pixelShaderCount = stream.readInt<unsigned int>();
-    for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++)
-    {
-        const size_t outputCount = stream.readInt<unsigned int>();
-        std::vector<GLenum> outputs(outputCount);
-        for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++)
-        {
-            stream.readInt(&outputs[outputIndex]);
-        }
-
-        const size_t pixelShaderSize = stream.readInt<unsigned int>();
-        const unsigned char *pixelShaderFunction = reinterpret_cast<const unsigned char*>(binary) + stream.offset();
-        rx::ShaderExecutable *shaderExecutable = mProgram->loadExecutable(pixelShaderFunction, pixelShaderSize,
-                                                                          rx::SHADER_PIXEL, mTransformFeedbackLinkedVaryings,
-                                                                          (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
-
-        if (!shaderExecutable)
-        {
-            infoLog.append("Could not create pixel shader.");
-            return false;
-        }
-
-        // add new binary
-        mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable));
-
-        stream.skip(pixelShaderSize);
-    }
-
-    unsigned int geometryShaderSize = stream.readInt<unsigned int>();
-
-    if (geometryShaderSize > 0)
-    {
-        const char *geometryShaderFunction = (const char*) binary + stream.offset();
-        mGeometryExecutable = mProgram->loadExecutable(reinterpret_cast<const DWORD*>(geometryShaderFunction),
-                                                       geometryShaderSize, rx::SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
-                                                       (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
-
-        if (!mGeometryExecutable)
-        {
-            infoLog.append("Could not create geometry shader.");
-            return false;
-        }
-        stream.skip(geometryShaderSize);
-    }
-
     if (!mProgram->load(infoLog, &stream))
     {
         return false;
@@ -1296,8 +1035,8 @@
     {
         stream.writeInt(mLinkedAttribute[i].type);
         stream.writeString(mLinkedAttribute[i].name);
-        stream.writeInt(mShaderAttributes[i].type);
-        stream.writeString(mShaderAttributes[i].name);
+        stream.writeInt(mProgram->getShaderAttributes()[i].type);
+        stream.writeString(mProgram->getShaderAttributes()[i].name);
         stream.writeInt(mSemanticIndex[i]);
     }
 
@@ -1369,69 +1108,6 @@
         stream.writeInt(mUniformIndex[i].index);
     }
 
-    stream.writeInt(mTransformFeedbackBufferMode);
-    stream.writeInt(mTransformFeedbackLinkedVaryings.size());
-    for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
-    {
-        const LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
-
-        stream.writeString(varying.name);
-        stream.writeInt(varying.type);
-        stream.writeInt(varying.size);
-        stream.writeString(varying.semanticName);
-        stream.writeInt(varying.semanticIndex);
-        stream.writeInt(varying.semanticIndexCount);
-    }
-
-    stream.writeInt(mVertexExecutables.size());
-    for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++)
-    {
-        VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex];
-
-        for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
-        {
-            const VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex];
-            stream.writeInt(vertexInput.mType);
-            stream.writeInt(vertexInput.mNormalized);
-            stream.writeInt(vertexInput.mComponents);
-            stream.writeInt(vertexInput.mPureInteger);
-        }
-
-        size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength();
-        stream.writeInt(vertexShaderSize);
-
-        const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction();
-        stream.writeBytes(vertexBlob, vertexShaderSize);
-    }
-
-    stream.writeInt(mPixelExecutables.size());
-    for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++)
-    {
-        PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex];
-
-        const std::vector<GLenum> outputs = pixelExecutable->outputSignature();
-        stream.writeInt(outputs.size());
-        for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++)
-        {
-            stream.writeInt(outputs[outputIndex]);
-        }
-
-        size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength();
-        stream.writeInt(pixelShaderSize);
-
-        const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction();
-        stream.writeBytes(pixelBlob, pixelShaderSize);
-    }
-
-    size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
-    stream.writeInt(geometryShaderSize);
-
-    if (mGeometryExecutable != NULL && geometryShaderSize > 0)
-    {
-        const uint8_t *geometryBlob = mGeometryExecutable->getFunction();
-        stream.writeBytes(geometryBlob, geometryShaderSize);
-    }
-
     if (!mProgram->save(&stream))
     {
         if (length)
@@ -1506,14 +1182,13 @@
     mSamplersPS.resize(caps.maxTextureImageUnits);
     mSamplersVS.resize(caps.maxVertexTextureImageUnits);
 
-    mTransformFeedbackBufferMode = transformFeedbackBufferMode;
-
     rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
     rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
 
     int registers;
     std::vector<LinkedVarying> linkedVaryings;
-    if (!mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, &registers, &linkedVaryings, &mOutputVariables))
+    if (!mProgram->link(infoLog, fragmentShader, vertexShader, transformFeedbackVaryings, transformFeedbackBufferMode,
+                        &registers, &linkedVaryings, &mOutputVariables, caps))
     {
         return false;
     }
@@ -1546,29 +1221,16 @@
     }
 
     if (!gatherTransformFeedbackLinkedVaryings(infoLog, linkedVaryings, transformFeedbackVaryings,
-                                               transformFeedbackBufferMode, &mTransformFeedbackLinkedVaryings, caps))
+                                               transformFeedbackBufferMode, &mProgram->getTransformFeedbackLinkedVaryings(), caps))
     {
         success = false;
     }
 
     if (success)
     {
-        VertexFormat defaultInputLayout[MAX_VERTEX_ATTRIBS];
-        GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout);
-        rx::ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
-
-        std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(mProgram->getPixelShaderKey());
-        rx::ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput);
-
-        if (mProgram->usesGeometryShader())
-        {
-            mGeometryExecutable = mProgram->getGeometryExecutable(infoLog, fragmentShader, vertexShader,
-                                                                  mTransformFeedbackLinkedVaryings,
-                                                                  (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
-                                                                  registers);
-        }
-
-        if (!defaultVertexExecutable || !defaultPixelExecutable || (mProgram->usesGeometryShader() && !mGeometryExecutable))
+        // TODO: The concept of "executables" is D3D only, and as such this belongs in ProgramD3D. It must be called,
+        // however, last in this function, so it can't simply be moved to ProgramD3D::link without further shuffling.
+        if (!mProgram->compileProgramExecutables(infoLog, fragmentShader, vertexShader, registers))
         {
             infoLog.append("Failed to create D3D shaders.");
             success = false;
@@ -1596,7 +1258,7 @@
 
         const int location = attribute.location == -1 ? attributeBindings.getAttributeBinding(attribute.name) : attribute.location;
 
-        mShaderAttributes[attributeIndex] = attribute;
+        mProgram->getShaderAttributes()[attributeIndex] = attribute;
 
         if (location != -1)   // Set by glBindAttribLocation or by location layout qualifier
         {
@@ -2678,13 +2340,6 @@
 
 void ProgramBinary::reset()
 {
-    SafeDeleteContainer(mVertexExecutables);
-    SafeDeleteContainer(mPixelExecutables);
-    SafeDelete(mGeometryExecutable);
-
-    mTransformFeedbackBufferMode = GL_NONE;
-    mTransformFeedbackLinkedVaryings.clear();
-
     mSamplersPS.clear();
     mSamplersVS.clear();
 
diff --git a/src/libGLESv2/ProgramBinary.h b/src/libGLESv2/ProgramBinary.h
index 1c9c8c0..b3bd246 100644
--- a/src/libGLESv2/ProgramBinary.h
+++ b/src/libGLESv2/ProgramBinary.h
@@ -101,11 +101,6 @@
     rx::ProgramImpl *getImplementation() { return mProgram; }
     const rx::ProgramImpl *getImplementation() const { return mProgram; }
 
-    rx::ShaderExecutable *getPixelExecutableForFramebuffer(const Framebuffer *fbo);
-    rx::ShaderExecutable *getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout);
-    rx::ShaderExecutable *getVertexExecutableForInputLayout(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS]);
-    rx::ShaderExecutable *getGeometryExecutable() const;
-
     GLuint getAttributeLocation(const char *name);
     int getSemanticIndex(int attributeIndex);
 
@@ -250,56 +245,12 @@
     template <typename T>
     void getUniformv(GLint location, T *params, GLenum uniformType);
 
-    class VertexExecutable
-    {
-      public:
-        VertexExecutable(const VertexFormat inputLayout[MAX_VERTEX_ATTRIBS],
-                         const GLenum signature[MAX_VERTEX_ATTRIBS],
-                         rx::ShaderExecutable *shaderExecutable);
-        ~VertexExecutable();
-
-        bool matchesSignature(const GLenum convertedLayout[MAX_VERTEX_ATTRIBS]) const;
-
-        const VertexFormat *inputs() const { return mInputs; }
-        const GLenum *signature() const { return mSignature; }
-        rx::ShaderExecutable *shaderExecutable() const { return mShaderExecutable; }
-
-      private:
-        VertexFormat mInputs[MAX_VERTEX_ATTRIBS];
-        GLenum mSignature[MAX_VERTEX_ATTRIBS];
-        rx::ShaderExecutable *mShaderExecutable;
-    };
-
-    class PixelExecutable
-    {
-      public:
-        PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable);
-        ~PixelExecutable();
-
-        bool matchesSignature(const std::vector<GLenum> &signature) const { return mOutputSignature == signature; }
-
-        const std::vector<GLenum> &outputSignature() const { return mOutputSignature; }
-        rx::ShaderExecutable *shaderExecutable() const { return mShaderExecutable; }
-
-      private:
-        std::vector<GLenum> mOutputSignature;
-        rx::ShaderExecutable *mShaderExecutable;
-    };
-
     rx::ProgramImpl *mProgram;
 
-    std::vector<VertexExecutable *> mVertexExecutables;
-    std::vector<PixelExecutable *> mPixelExecutables;
-    rx::ShaderExecutable *mGeometryExecutable;
-
     sh::Attribute mLinkedAttribute[MAX_VERTEX_ATTRIBS];
-    sh::Attribute mShaderAttributes[MAX_VERTEX_ATTRIBS];
     int mSemanticIndex[MAX_VERTEX_ATTRIBS];
     int mAttributesByLayout[MAX_VERTEX_ATTRIBS];
 
-    GLenum mTransformFeedbackBufferMode;
-    std::vector<LinkedVarying> mTransformFeedbackLinkedVaryings;
-
     std::vector<Sampler> mSamplersPS;
     std::vector<Sampler> mSamplersVS;
     GLuint mUsedVertexSamplerRange;
diff --git a/src/libGLESv2/renderer/ProgramImpl.h b/src/libGLESv2/renderer/ProgramImpl.h
index 4d765d6..ede5c57 100644
--- a/src/libGLESv2/renderer/ProgramImpl.h
+++ b/src/libGLESv2/renderer/ProgramImpl.h
@@ -25,37 +25,23 @@
 public:
     virtual ~ProgramImpl() { }
 
-    virtual const std::vector<rx::PixelShaderOutputVariable> &getPixelShaderKey() = 0;
-
     virtual bool usesPointSize() const = 0;
-    virtual bool usesGeometryShader() const = 0;
     virtual int getShaderVersion() const = 0;
+    virtual GLenum getTransformFeedbackBufferMode() const = 0;
+    virtual std::vector<gl::LinkedVarying> &getTransformFeedbackLinkedVaryings() = 0;
+    virtual sh::Attribute *getShaderAttributes() = 0;
 
     virtual GLenum getBinaryFormat() = 0;
     virtual bool load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream) = 0;
     virtual bool save(gl::BinaryOutputStream *stream) = 0;
 
-    virtual rx::ShaderExecutable *getPixelExecutableForOutputLayout(gl::InfoLog &infoLog, const std::vector<GLenum> &outputSignature,
-                                                                    const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                                                    bool separatedOutputBuffers) = 0;
-    virtual rx::ShaderExecutable *getVertexExecutableForInputLayout(gl::InfoLog &infoLog,
-                                                                    const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS],
-                                                                    const sh::Attribute shaderAttributes[],
-                                                                    const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                                                    bool separatedOutputBuffers) = 0;
-    virtual rx::ShaderExecutable *getGeometryExecutable(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                                        const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                                        bool separatedOutputBuffers, int registers) = 0;
-    virtual rx::ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type,
-                                                 const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                                 bool separatedOutputBuffers) = 0;
+    virtual bool compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                           int registers) = 0;
 
     virtual bool link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                      const std::vector<std::string> &transformFeedbackVaryings, int *registers,
-                      std::vector<gl::LinkedVarying> *linkedVaryings, std::map<int,
-                      gl::VariableLocation> *outputVariables) = 0;
-
-    virtual void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const = 0;
+                      const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
+                      int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
+                      std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps) = 0;
 
     virtual void initializeUniformStorage(const std::vector<gl::LinkedUniform*> &uniforms) = 0;
 
diff --git a/src/libGLESv2/renderer/d3d/ProgramD3D.cpp b/src/libGLESv2/renderer/d3d/ProgramD3D.cpp
index f65a3aa..d377924 100644
--- a/src/libGLESv2/renderer/d3d/ProgramD3D.cpp
+++ b/src/libGLESv2/renderer/d3d/ProgramD3D.cpp
@@ -9,6 +9,8 @@
 #include "libGLESv2/renderer/d3d/ProgramD3D.h"
 
 #include "common/utilities.h"
+#include "libGLESv2/Framebuffer.h"
+#include "libGLESv2/FramebufferAttachment.h"
 #include "libGLESv2/Program.h"
 #include "libGLESv2/ProgramBinary.h"
 #include "libGLESv2/renderer/Renderer.h"
@@ -20,18 +22,101 @@
 namespace rx
 {
 
-ProgramD3D::ProgramD3D(rx::Renderer *renderer)
+namespace
+{
+
+void GetDefaultInputLayoutFromShader(const std::vector<sh::Attribute> &shaderAttributes, gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
+{
+    size_t layoutIndex = 0;
+    for (size_t attributeIndex = 0; attributeIndex < shaderAttributes.size(); attributeIndex++)
+    {
+        ASSERT(layoutIndex < gl::MAX_VERTEX_ATTRIBS);
+
+        const sh::Attribute &shaderAttr = shaderAttributes[attributeIndex];
+
+        if (shaderAttr.type != GL_NONE)
+        {
+            GLenum transposedType = gl::TransposeMatrixType(shaderAttr.type);
+
+            for (size_t rowIndex = 0; static_cast<int>(rowIndex) < gl::VariableRowCount(transposedType); rowIndex++, layoutIndex++)
+            {
+                gl::VertexFormat *defaultFormat = &inputLayout[layoutIndex];
+
+                defaultFormat->mType = gl::VariableComponentType(transposedType);
+                defaultFormat->mNormalized = false;
+                defaultFormat->mPureInteger = (defaultFormat->mType != GL_FLOAT); // note: inputs can not be bool
+                defaultFormat->mComponents = gl::VariableColumnCount(transposedType);
+            }
+        }
+    }
+}
+
+std::vector<GLenum> GetDefaultOutputLayoutFromShader(const std::vector<PixelShaderOutputVariable> &shaderOutputVars)
+{
+    std::vector<GLenum> defaultPixelOutput(1);
+
+    ASSERT(!shaderOutputVars.empty());
+    defaultPixelOutput[0] = GL_COLOR_ATTACHMENT0 + shaderOutputVars[0].outputIndex;
+
+    return defaultPixelOutput;
+}
+
+}
+
+ProgramD3D::VertexExecutable::VertexExecutable(const gl::VertexFormat inputLayout[],
+                                               const GLenum signature[],
+                                               ShaderExecutable *shaderExecutable)
+    : mShaderExecutable(shaderExecutable)
+{
+    for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
+    {
+        mInputs[attributeIndex] = inputLayout[attributeIndex];
+        mSignature[attributeIndex] = signature[attributeIndex];
+    }
+}
+
+ProgramD3D::VertexExecutable::~VertexExecutable()
+{
+    SafeDelete(mShaderExecutable);
+}
+
+bool ProgramD3D::VertexExecutable::matchesSignature(const GLenum signature[]) const
+{
+    for (size_t attributeIndex = 0; attributeIndex < gl::MAX_VERTEX_ATTRIBS; attributeIndex++)
+    {
+        if (mSignature[attributeIndex] != signature[attributeIndex])
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+ProgramD3D::PixelExecutable::PixelExecutable(const std::vector<GLenum> &outputSignature, ShaderExecutable *shaderExecutable)
+    : mOutputSignature(outputSignature),
+      mShaderExecutable(shaderExecutable)
+{
+}
+
+ProgramD3D::PixelExecutable::~PixelExecutable()
+{
+    SafeDelete(mShaderExecutable);
+}
+
+ProgramD3D::ProgramD3D(Renderer *renderer)
     : ProgramImpl(),
       mRenderer(renderer),
       mDynamicHLSL(NULL),
-      mVertexWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
-      mPixelWorkarounds(rx::ANGLE_D3D_WORKAROUND_NONE),
+      mGeometryExecutable(NULL),
+      mVertexWorkarounds(ANGLE_D3D_WORKAROUND_NONE),
+      mPixelWorkarounds(ANGLE_D3D_WORKAROUND_NONE),
       mUsesPointSize(false),
       mVertexUniformStorage(NULL),
       mFragmentUniformStorage(NULL),
       mShaderVersion(100)
 {
-    mDynamicHLSL = new rx::DynamicHLSL(renderer);
+    mDynamicHLSL = new DynamicHLSL(renderer);
 }
 
 ProgramD3D::~ProgramD3D()
@@ -52,11 +137,6 @@
     return static_cast<const ProgramD3D*>(impl);
 }
 
-bool ProgramD3D::usesPointSize() const
-{
-    return mUsesPointSize;
-}
-
 bool ProgramD3D::usesPointSpriteEmulation() const
 {
     return mUsesPointSize && mRenderer->getMajorShaderModel() >= 4;
@@ -71,6 +151,21 @@
 {
     stream->readInt(&mShaderVersion);
 
+    stream->readInt(&mTransformFeedbackBufferMode);
+    const unsigned int transformFeedbackVaryingCount = stream->readInt<unsigned int>();
+    mTransformFeedbackLinkedVaryings.resize(transformFeedbackVaryingCount);
+    for (unsigned int varyingIndex = 0; varyingIndex < transformFeedbackVaryingCount; varyingIndex++)
+    {
+        gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[varyingIndex];
+
+        stream->readString(&varying.name);
+        stream->readInt(&varying.type);
+        stream->readInt(&varying.size);
+        stream->readString(&varying.semanticName);
+        stream->readInt(&varying.semanticIndex);
+        stream->readInt(&varying.semanticIndexCount);
+    }
+
     stream->readString(&mVertexHLSL);
     stream->readInt(&mVertexWorkarounds);
     stream->readString(&mPixelHLSL);
@@ -88,6 +183,91 @@
         stream->readInt(&mPixelShaderKey[pixelShaderKeyIndex].outputIndex);
     }
 
+    const unsigned char* binary = reinterpret_cast<const unsigned char*>(stream->data());
+
+    const unsigned int vertexShaderCount = stream->readInt<unsigned int>();
+    for (unsigned int vertexShaderIndex = 0; vertexShaderIndex < vertexShaderCount; vertexShaderIndex++)
+    {
+        gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS];
+
+        for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
+        {
+            gl::VertexFormat *vertexInput = &inputLayout[inputIndex];
+            stream->readInt(&vertexInput->mType);
+            stream->readInt(&vertexInput->mNormalized);
+            stream->readInt(&vertexInput->mComponents);
+            stream->readBool(&vertexInput->mPureInteger);
+        }
+
+        unsigned int vertexShaderSize = stream->readInt<unsigned int>();
+        const unsigned char *vertexShaderFunction = binary + stream->offset();
+        ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(vertexShaderFunction, vertexShaderSize,
+                                                                       SHADER_VERTEX,
+                                                                       mTransformFeedbackLinkedVaryings,
+                                                                       (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+        if (!shaderExecutable)
+        {
+            infoLog.append("Could not create vertex shader.");
+            return false;
+        }
+
+        // generated converted input layout
+        GLenum signature[gl::MAX_VERTEX_ATTRIBS];
+        getInputLayoutSignature(inputLayout, signature);
+
+        // add new binary
+        mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, shaderExecutable));
+
+        stream->skip(vertexShaderSize);
+    }
+
+    const size_t pixelShaderCount = stream->readInt<unsigned int>();
+    for (size_t pixelShaderIndex = 0; pixelShaderIndex < pixelShaderCount; pixelShaderIndex++)
+    {
+        const size_t outputCount = stream->readInt<unsigned int>();
+        std::vector<GLenum> outputs(outputCount);
+        for (size_t outputIndex = 0; outputIndex < outputCount; outputIndex++)
+        {
+            stream->readInt(&outputs[outputIndex]);
+        }
+
+        const size_t pixelShaderSize = stream->readInt<unsigned int>();
+        const unsigned char *pixelShaderFunction = binary + stream->offset();
+        ShaderExecutable *shaderExecutable = mRenderer->loadExecutable(pixelShaderFunction, pixelShaderSize,
+                                                                       SHADER_PIXEL,
+                                                                       mTransformFeedbackLinkedVaryings,
+                                                                       (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+
+        if (!shaderExecutable)
+        {
+            infoLog.append("Could not create pixel shader.");
+            return false;
+        }
+
+        // add new binary
+        mPixelExecutables.push_back(new PixelExecutable(outputs, shaderExecutable));
+
+        stream->skip(pixelShaderSize);
+    }
+
+    unsigned int geometryShaderSize = stream->readInt<unsigned int>();
+
+    if (geometryShaderSize > 0)
+    {
+        const unsigned char *geometryShaderFunction = binary + stream->offset();
+        mGeometryExecutable = mRenderer->loadExecutable(geometryShaderFunction, geometryShaderSize,
+                                                        SHADER_GEOMETRY,
+                                                        mTransformFeedbackLinkedVaryings,
+                                                        (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS));
+
+        if (!mGeometryExecutable)
+        {
+            infoLog.append("Could not create geometry shader.");
+            return false;
+        }
+        stream->skip(geometryShaderSize);
+    }
+
     GUID binaryIdentifier = {0};
     stream->readBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier), sizeof(GUID));
 
@@ -105,6 +285,20 @@
 {
     stream->writeInt(mShaderVersion);
 
+    stream->writeInt(mTransformFeedbackBufferMode);
+    stream->writeInt(mTransformFeedbackLinkedVaryings.size());
+    for (size_t i = 0; i < mTransformFeedbackLinkedVaryings.size(); i++)
+    {
+        const gl::LinkedVarying &varying = mTransformFeedbackLinkedVaryings[i];
+
+        stream->writeString(varying.name);
+        stream->writeInt(varying.type);
+        stream->writeInt(varying.size);
+        stream->writeString(varying.semanticName);
+        stream->writeInt(varying.semanticIndex);
+        stream->writeInt(varying.semanticIndexCount);
+    }
+
     stream->writeString(mVertexHLSL);
     stream->writeInt(mVertexWorkarounds);
     stream->writeString(mPixelHLSL);
@@ -112,85 +306,201 @@
     stream->writeInt(mUsesFragDepth);
     stream->writeInt(mUsesPointSize);
 
-    const std::vector<rx::PixelShaderOutputVariable> &pixelShaderKey = mPixelShaderKey;
+    const std::vector<PixelShaderOutputVariable> &pixelShaderKey = mPixelShaderKey;
     stream->writeInt(pixelShaderKey.size());
     for (size_t pixelShaderKeyIndex = 0; pixelShaderKeyIndex < pixelShaderKey.size(); pixelShaderKeyIndex++)
     {
-        const rx::PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex];
+        const PixelShaderOutputVariable &variable = pixelShaderKey[pixelShaderKeyIndex];
         stream->writeInt(variable.type);
         stream->writeString(variable.name);
         stream->writeString(variable.source);
         stream->writeInt(variable.outputIndex);
     }
 
+    stream->writeInt(mVertexExecutables.size());
+    for (size_t vertexExecutableIndex = 0; vertexExecutableIndex < mVertexExecutables.size(); vertexExecutableIndex++)
+    {
+        VertexExecutable *vertexExecutable = mVertexExecutables[vertexExecutableIndex];
+
+        for (size_t inputIndex = 0; inputIndex < gl::MAX_VERTEX_ATTRIBS; inputIndex++)
+        {
+            const gl::VertexFormat &vertexInput = vertexExecutable->inputs()[inputIndex];
+            stream->writeInt(vertexInput.mType);
+            stream->writeInt(vertexInput.mNormalized);
+            stream->writeInt(vertexInput.mComponents);
+            stream->writeInt(vertexInput.mPureInteger);
+        }
+
+        size_t vertexShaderSize = vertexExecutable->shaderExecutable()->getLength();
+        stream->writeInt(vertexShaderSize);
+
+        const uint8_t *vertexBlob = vertexExecutable->shaderExecutable()->getFunction();
+        stream->writeBytes(vertexBlob, vertexShaderSize);
+    }
+
+    stream->writeInt(mPixelExecutables.size());
+    for (size_t pixelExecutableIndex = 0; pixelExecutableIndex < mPixelExecutables.size(); pixelExecutableIndex++)
+    {
+        PixelExecutable *pixelExecutable = mPixelExecutables[pixelExecutableIndex];
+
+        const std::vector<GLenum> outputs = pixelExecutable->outputSignature();
+        stream->writeInt(outputs.size());
+        for (size_t outputIndex = 0; outputIndex < outputs.size(); outputIndex++)
+        {
+            stream->writeInt(outputs[outputIndex]);
+        }
+
+        size_t pixelShaderSize = pixelExecutable->shaderExecutable()->getLength();
+        stream->writeInt(pixelShaderSize);
+
+        const uint8_t *pixelBlob = pixelExecutable->shaderExecutable()->getFunction();
+        stream->writeBytes(pixelBlob, pixelShaderSize);
+    }
+
+    size_t geometryShaderSize = (mGeometryExecutable != NULL) ? mGeometryExecutable->getLength() : 0;
+    stream->writeInt(geometryShaderSize);
+
+    if (mGeometryExecutable != NULL && geometryShaderSize > 0)
+    {
+        const uint8_t *geometryBlob = mGeometryExecutable->getFunction();
+        stream->writeBytes(geometryBlob, geometryShaderSize);
+    }
+
     GUID binaryIdentifier = mRenderer->getAdapterIdentifier();
     stream->writeBytes(reinterpret_cast<unsigned char*>(&binaryIdentifier),  sizeof(GUID));
 
     return true;
 }
 
-ShaderExecutable *ProgramD3D::getPixelExecutableForOutputLayout(gl::InfoLog &infoLog, const std::vector<GLenum> &outputSignature,
-                                                                const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                                                bool separatedOutputBuffers)
+ShaderExecutable *ProgramD3D::getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo)
 {
+    std::vector<GLenum> outputs;
+
+    const gl::ColorbufferInfo &colorbuffers = fbo->getColorbuffersForRender();
+
+    for (size_t colorAttachment = 0; colorAttachment < colorbuffers.size(); ++colorAttachment)
+    {
+        const gl::FramebufferAttachment *colorbuffer = colorbuffers[colorAttachment];
+
+        if (colorbuffer)
+        {
+            outputs.push_back(colorbuffer->getBinding() == GL_BACK ? GL_COLOR_ATTACHMENT0 : colorbuffer->getBinding());
+        }
+        else
+        {
+            outputs.push_back(GL_NONE);
+        }
+    }
+
+    return getPixelExecutableForOutputLayout(outputs);
+}
+
+ShaderExecutable *ProgramD3D::getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputSignature)
+{
+    for (size_t executableIndex = 0; executableIndex < mPixelExecutables.size(); executableIndex++)
+    {
+        if (mPixelExecutables[executableIndex]->matchesSignature(outputSignature))
+        {
+            return mPixelExecutables[executableIndex]->shaderExecutable();
+        }
+    }
+
     std::string finalPixelHLSL = mDynamicHLSL->generatePixelShaderForOutputSignature(mPixelHLSL, mPixelShaderKey, mUsesFragDepth,
                                                                                      outputSignature);
 
     // Generate new pixel executable
-    ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(infoLog, finalPixelHLSL, rx::SHADER_PIXEL,
-                                                                        transformFeedbackLinkedVaryings, separatedOutputBuffers,
-                                                                        mPixelWorkarounds);
+    gl::InfoLog tempInfoLog;
+    ShaderExecutable *pixelExecutable = mRenderer->compileToExecutable(tempInfoLog, finalPixelHLSL, SHADER_PIXEL,
+                                                                       mTransformFeedbackLinkedVaryings,
+                                                                       (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+                                                                       mPixelWorkarounds);
+
+    if (!pixelExecutable)
+    {
+        std::vector<char> tempCharBuffer(tempInfoLog.getLength() + 3);
+        tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
+        ERR("Error compiling dynamic pixel executable:\n%s\n", &tempCharBuffer[0]);
+    }
+    else
+    {
+        mPixelExecutables.push_back(new PixelExecutable(outputSignature, pixelExecutable));
+    }
 
     return pixelExecutable;
 }
 
-ShaderExecutable *ProgramD3D::getVertexExecutableForInputLayout(gl::InfoLog &infoLog,
-                                                                const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS],
-                                                                const sh::Attribute shaderAttributes[],
-                                                                const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                                                bool separatedOutputBuffers)
+ShaderExecutable *ProgramD3D::getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS])
 {
+    GLenum signature[gl::MAX_VERTEX_ATTRIBS];
+    getInputLayoutSignature(inputLayout, signature);
+
+    for (size_t executableIndex = 0; executableIndex < mVertexExecutables.size(); executableIndex++)
+    {
+        if (mVertexExecutables[executableIndex]->matchesSignature(signature))
+        {
+            return mVertexExecutables[executableIndex]->shaderExecutable();
+        }
+    }
+
     // Generate new dynamic layout with attribute conversions
-    std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, shaderAttributes);
+    std::string finalVertexHLSL = mDynamicHLSL->generateVertexShaderForInputLayout(mVertexHLSL, inputLayout, mShaderAttributes);
 
     // Generate new vertex executable
-    ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(infoLog, finalVertexHLSL,
-                                                                        rx::SHADER_VERTEX,
-                                                                        transformFeedbackLinkedVaryings, separatedOutputBuffers,
+    gl::InfoLog tempInfoLog;
+    ShaderExecutable *vertexExecutable = mRenderer->compileToExecutable(tempInfoLog, finalVertexHLSL,
+                                                                        SHADER_VERTEX,
+                                                                        mTransformFeedbackLinkedVaryings,
+                                                                        (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
                                                                         mVertexWorkarounds);
+    if (!vertexExecutable)
+    {
+        std::vector<char> tempCharBuffer(tempInfoLog.getLength()+3);
+        tempInfoLog.getLog(tempInfoLog.getLength(), NULL, &tempCharBuffer[0]);
+        ERR("Error compiling dynamic vertex executable:\n%s\n", &tempCharBuffer[0]);
+    }
+    else
+    {
+        mVertexExecutables.push_back(new VertexExecutable(inputLayout, signature, vertexExecutable));
+    }
 
     return vertexExecutable;
 }
 
-ShaderExecutable *ProgramD3D::getGeometryExecutable(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                                    const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                                    bool separatedOutputBuffers, int registers)
+bool 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());
 
-    std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D);
+    gl::VertexFormat defaultInputLayout[gl::MAX_VERTEX_ATTRIBS];
+    GetDefaultInputLayoutFromShader(vertexShader->getActiveAttributes(), defaultInputLayout);
+    ShaderExecutable *defaultVertexExecutable = getVertexExecutableForInputLayout(defaultInputLayout);
 
-    ShaderExecutable *geometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL,
-                                                                          rx::SHADER_GEOMETRY, transformFeedbackLinkedVaryings,
-                                                                          separatedOutputBuffers, rx::ANGLE_D3D_WORKAROUND_NONE);
+    std::vector<GLenum> defaultPixelOutput = GetDefaultOutputLayoutFromShader(getPixelShaderKey());
+    ShaderExecutable *defaultPixelExecutable = getPixelExecutableForOutputLayout(defaultPixelOutput);
 
-    return geometryExecutable;
-}
+    if (usesGeometryShader())
+    {
+        std::string geometryHLSL = mDynamicHLSL->generateGeometryShaderHLSL(registers, fragmentShaderD3D, vertexShaderD3D);
 
-ShaderExecutable *ProgramD3D::loadExecutable(const void *function, size_t length, rx::ShaderType type,
-                                             const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                             bool separatedOutputBuffers)
-{
-    return mRenderer->loadExecutable(function, length, type, transformFeedbackLinkedVaryings, separatedOutputBuffers);
+        mGeometryExecutable = mRenderer->compileToExecutable(infoLog, geometryHLSL,
+                                                             SHADER_GEOMETRY, mTransformFeedbackLinkedVaryings,
+                                                             (mTransformFeedbackBufferMode == GL_SEPARATE_ATTRIBS),
+                                                             ANGLE_D3D_WORKAROUND_NONE);
+    }
+
+    return (defaultVertexExecutable && defaultPixelExecutable && (!usesGeometryShader() || mGeometryExecutable));
 }
 
 bool ProgramD3D::link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                      const std::vector<std::string> &transformFeedbackVaryings, int *registers,
-                      std::vector<gl::LinkedVarying> *linkedVaryings, std::map<int, gl::VariableLocation> *outputVariables)
+                      const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
+                      int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
+                      std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps)
 {
-    rx::ShaderD3D *vertexShaderD3D = rx::ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
-    rx::ShaderD3D *fragmentShaderD3D = rx::ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
+    ShaderD3D *vertexShaderD3D = ShaderD3D::makeShaderD3D(vertexShader->getImplementation());
+    ShaderD3D *fragmentShaderD3D = ShaderD3D::makeShaderD3D(fragmentShader->getImplementation());
+
+    mTransformFeedbackBufferMode = transformFeedbackBufferMode;
 
     mPixelHLSL = fragmentShaderD3D->getTranslatedSource();
     mPixelWorkarounds = fragmentShaderD3D->getD3DWorkarounds();
@@ -200,7 +510,7 @@
     mShaderVersion = vertexShaderD3D->getShaderVersion();
 
     // Map the varyings to the register file
-    rx::VaryingPacking packing = { NULL };
+    VaryingPacking packing = { NULL };
     *registers = mDynamicHLSL->packVaryings(infoLog, packing, fragmentShaderD3D, vertexShaderD3D, transformFeedbackVaryings);
 
     if (*registers < 0)
@@ -262,7 +572,7 @@
 }
 
 gl::Error ProgramD3D::applyUniformBuffers(const std::vector<gl::UniformBlock*> uniformBlocks, const std::vector<gl::Buffer*> boundBuffers,
-                                     const gl::Caps &caps)
+                                          const gl::Caps &caps)
 {
     const gl::Buffer *vertexUniformBuffers[gl::IMPLEMENTATION_MAX_VERTEX_SHADER_UNIFORM_BUFFERS] = {NULL};
     const gl::Buffer *fragmentUniformBuffers[gl::IMPLEMENTATION_MAX_FRAGMENT_SHADER_UNIFORM_BUFFERS] = {NULL};
@@ -352,12 +662,19 @@
 
 void ProgramD3D::reset()
 {
+    SafeDeleteContainer(mVertexExecutables);
+    SafeDeleteContainer(mPixelExecutables);
+    SafeDelete(mGeometryExecutable);
+
+    mTransformFeedbackBufferMode = GL_NONE;
+    mTransformFeedbackLinkedVaryings.clear();
+
     mVertexHLSL.clear();
-    mVertexWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE;
+    mVertexWorkarounds = ANGLE_D3D_WORKAROUND_NONE;
     mShaderVersion = 100;
 
     mPixelHLSL.clear();
-    mPixelWorkarounds = rx::ANGLE_D3D_WORKAROUND_NONE;
+    mPixelWorkarounds = ANGLE_D3D_WORKAROUND_NONE;
     mUsesFragDepth = false;
     mPixelShaderKey.clear();
     mUsesPointSize = false;
diff --git a/src/libGLESv2/renderer/d3d/ProgramD3D.h b/src/libGLESv2/renderer/d3d/ProgramD3D.h
index 0ca4643..50bdc58 100644
--- a/src/libGLESv2/renderer/d3d/ProgramD3D.h
+++ b/src/libGLESv2/renderer/d3d/ProgramD3D.h
@@ -37,8 +37,11 @@
 
     const std::vector<rx::PixelShaderOutputVariable> &getPixelShaderKey() { return mPixelShaderKey; }
     int getShaderVersion() const { return mShaderVersion; }
+    GLenum getTransformFeedbackBufferMode() const { return mTransformFeedbackBufferMode; }
+    std::vector<gl::LinkedVarying> &getTransformFeedbackLinkedVaryings() { return mTransformFeedbackLinkedVaryings; }
+    sh::Attribute *getShaderAttributes() { return mShaderAttributes; }
 
-    bool usesPointSize() const;
+    bool usesPointSize() const { return mUsesPointSize; }
     bool usesPointSpriteEmulation() const;
     bool usesGeometryShader() const;
 
@@ -46,24 +49,18 @@
     bool load(gl::InfoLog &infoLog, gl::BinaryInputStream *stream);
     bool save(gl::BinaryOutputStream *stream);
 
-    ShaderExecutable *getPixelExecutableForOutputLayout(gl::InfoLog &infoLog, const std::vector<GLenum> &outputSignature,
-                                                        const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                                        bool separatedOutputBuffers);
-    ShaderExecutable *getVertexExecutableForInputLayout(gl::InfoLog &infoLog,
-                                                        const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS],
-                                                        const sh::Attribute shaderAttributes[],
-                                                        const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                                        bool separatedOutputBuffers);
-    ShaderExecutable *getGeometryExecutable(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-                                            const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                            bool separatedOutputBuffers, int registers);
-    ShaderExecutable *loadExecutable(const void *function, size_t length, rx::ShaderType type,
-                                     const std::vector<gl::LinkedVarying> &transformFeedbackLinkedVaryings,
-                                     bool separatedOutputBuffers);
+    ShaderExecutable *getPixelExecutableForFramebuffer(const gl::Framebuffer *fbo);
+    ShaderExecutable *getPixelExecutableForOutputLayout(const std::vector<GLenum> &outputLayout);
+    ShaderExecutable *getVertexExecutableForInputLayout(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS]);
+    ShaderExecutable *getGeometryExecutable() const { return mGeometryExecutable; }
+
+    bool compileProgramExecutables(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
+                                   int registers);
 
     bool link(gl::InfoLog &infoLog, gl::Shader *fragmentShader, gl::Shader *vertexShader,
-              const std::vector<std::string> &transformFeedbackVaryings, int *registers,
-              std::vector<gl::LinkedVarying> *linkedVaryings, std::map<int, gl::VariableLocation> *outputVariables);
+              const std::vector<std::string> &transformFeedbackVaryings, GLenum transformFeedbackBufferMode,
+              int *registers, std::vector<gl::LinkedVarying> *linkedVaryings,
+              std::map<int, gl::VariableLocation> *outputVariables, const gl::Caps &caps);
 
     void getInputLayoutSignature(const gl::VertexFormat inputLayout[], GLenum signature[]) const;
 
@@ -83,9 +80,49 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(ProgramD3D);
 
+    class VertexExecutable
+    {
+      public:
+        VertexExecutable(const gl::VertexFormat inputLayout[gl::MAX_VERTEX_ATTRIBS],
+                         const GLenum signature[gl::MAX_VERTEX_ATTRIBS],
+                         rx::ShaderExecutable *shaderExecutable);
+        ~VertexExecutable();
+
+        bool matchesSignature(const GLenum convertedLayout[gl::MAX_VERTEX_ATTRIBS]) const;
+
+        const gl::VertexFormat *inputs() const { return mInputs; }
+        const GLenum *signature() const { return mSignature; }
+        rx::ShaderExecutable *shaderExecutable() const { return mShaderExecutable; }
+
+      private:
+        gl::VertexFormat mInputs[gl::MAX_VERTEX_ATTRIBS];
+        GLenum mSignature[gl::MAX_VERTEX_ATTRIBS];
+        rx::ShaderExecutable *mShaderExecutable;
+    };
+
+    class PixelExecutable
+    {
+      public:
+        PixelExecutable(const std::vector<GLenum> &outputSignature, rx::ShaderExecutable *shaderExecutable);
+        ~PixelExecutable();
+
+        bool matchesSignature(const std::vector<GLenum> &signature) const { return mOutputSignature == signature; }
+
+        const std::vector<GLenum> &outputSignature() const { return mOutputSignature; }
+        rx::ShaderExecutable *shaderExecutable() const { return mShaderExecutable; }
+
+      private:
+        std::vector<GLenum> mOutputSignature;
+        rx::ShaderExecutable *mShaderExecutable;
+    };
+
     Renderer *mRenderer;
     DynamicHLSL *mDynamicHLSL;
 
+    std::vector<VertexExecutable *> mVertexExecutables;
+    std::vector<PixelExecutable *> mPixelExecutables;
+    rx::ShaderExecutable *mGeometryExecutable;
+
     std::string mVertexHLSL;
     rx::D3DWorkaroundType mVertexWorkarounds;
 
@@ -99,6 +136,11 @@
     UniformStorage *mVertexUniformStorage;
     UniformStorage *mFragmentUniformStorage;
 
+    GLenum mTransformFeedbackBufferMode;
+    std::vector<gl::LinkedVarying> mTransformFeedbackLinkedVaryings;
+
+    sh::Attribute mShaderAttributes[gl::MAX_VERTEX_ATTRIBS];
+
     int mShaderVersion;
 };
 
diff --git a/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp b/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp
index b006c04..2cd7988 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/InputLayoutCache.cpp
@@ -12,6 +12,7 @@
 #include "libGLESv2/renderer/d3d/d3d11/Buffer11.h"
 #include "libGLESv2/renderer/d3d/d3d11/ShaderExecutable11.h"
 #include "libGLESv2/renderer/d3d/d3d11/formatutils11.h"
+#include "libGLESv2/renderer/d3d/ProgramD3D.h"
 #include "libGLESv2/renderer/d3d/VertexDataManager.h"
 #include "libGLESv2/ProgramBinary.h"
 #include "libGLESv2/VertexAttribute.h"
@@ -137,7 +138,8 @@
     {
         gl::VertexFormat shaderInputLayout[gl::MAX_VERTEX_ATTRIBS];
         GetInputLayout(attributes, shaderInputLayout);
-        ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programBinary->getVertexExecutableForInputLayout(shaderInputLayout));
+        ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
+        ShaderExecutable11 *shader = ShaderExecutable11::makeShaderExecutable11(programD3D->getVertexExecutableForInputLayout(shaderInputLayout));
 
         D3D11_INPUT_ELEMENT_DESC descs[gl::MAX_VERTEX_ATTRIBS];
         for (unsigned int j = 0; j < ilKey.elementCount; ++j)
diff --git a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
index 990972d..fe8998f 100644
--- a/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d11/Renderer11.cpp
@@ -1329,9 +1329,10 @@
 gl::Error Renderer11::applyShaders(gl::ProgramBinary *programBinary, const gl::VertexFormat inputLayout[], const gl::Framebuffer *framebuffer,
                                    bool rasterizerDiscard, bool transformFeedbackActive)
 {
-    ShaderExecutable *vertexExe = programBinary->getVertexExecutableForInputLayout(inputLayout);
-    ShaderExecutable *pixelExe = programBinary->getPixelExecutableForFramebuffer(framebuffer);
-    ShaderExecutable *geometryExe = programBinary->getGeometryExecutable();
+    ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
+    ShaderExecutable *vertexExe = programD3D->getVertexExecutableForInputLayout(inputLayout);
+    ShaderExecutable *pixelExe = programD3D->getPixelExecutableForFramebuffer(framebuffer);
+    ShaderExecutable *geometryExe = programD3D->getGeometryExecutable();
 
     ID3D11VertexShader *vertexShader = (vertexExe ? ShaderExecutable11::makeShaderExecutable11(vertexExe)->getVertexShader() : NULL);
 
diff --git a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
index 17cb86c..9729f51 100644
--- a/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
+++ b/src/libGLESv2/renderer/d3d/d3d9/Renderer9.cpp
@@ -1670,8 +1670,9 @@
     ASSERT(!transformFeedbackActive);
     ASSERT(!rasterizerDiscard);
 
-    ShaderExecutable *vertexExe = programBinary->getVertexExecutableForInputLayout(inputLayout);
-    ShaderExecutable *pixelExe = programBinary->getPixelExecutableForFramebuffer(framebuffer);
+    ProgramD3D *programD3D = ProgramD3D::makeProgramD3D(programBinary->getImplementation());
+    ShaderExecutable *vertexExe = programD3D->getVertexExecutableForInputLayout(inputLayout);
+    ShaderExecutable *pixelExe = programD3D->getPixelExecutableForFramebuffer(framebuffer);
 
     IDirect3DVertexShader9 *vertexShader = (vertexExe ? ShaderExecutable9::makeShaderExecutable9(vertexExe)->getVertexShader() : NULL);
     IDirect3DPixelShader9 *pixelShader = (pixelExe ? ShaderExecutable9::makeShaderExecutable9(pixelExe)->getPixelShader() : NULL);