Refactor program info log out of ProgramBinary and in to Program.

Tested by setting breakpoint in esLoadProgram with the broken program.
Review URL: https://codereview.appspot.com/6305114

git-svn-id: https://angleproject.googlecode.com/svn/trunk@1164 736b8ea6-26fd-11df-bfd4-992fa37f6226
diff --git a/src/common/version.h b/src/common/version.h
index 4d6752c..83c1541 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -1,7 +1,7 @@
 #define MAJOR_VERSION 1
 #define MINOR_VERSION 0
 #define BUILD_VERSION 0
-#define BUILD_REVISION 1162
+#define BUILD_REVISION 1164
 
 #define STRINGIFY(x) #x
 #define MACRO_STRINGIFY(x) STRINGIFY(x)
diff --git a/src/libGLESv2/Context.cpp b/src/libGLESv2/Context.cpp
index 2004f51..1b4664c 100644
--- a/src/libGLESv2/Context.cpp
+++ b/src/libGLESv2/Context.cpp
@@ -2996,7 +2996,7 @@
     applyShaders();

     applyTextures();

 

-    if (!getCurrentProgram()->getProgramBinary()->validateSamplers(false))

+    if (!getCurrentProgram()->getProgramBinary()->validateSamplers(NULL))

     {

         return error(GL_INVALID_OPERATION);

     }

diff --git a/src/libGLESv2/Program.cpp b/src/libGLESv2/Program.cpp
index 184a02c..f28a9d8 100644
--- a/src/libGLESv2/Program.cpp
+++ b/src/libGLESv2/Program.cpp
@@ -20,6 +20,8 @@
 
 namespace gl
 {
+const char * const g_fakepath = "C:\\fakepath";
+
 unsigned int Program::mCurrentSerial = 1;
 
 AttributeBindings::AttributeBindings()
@@ -30,6 +32,112 @@
 {
 }
 
+InfoLog::InfoLog() : mInfoLog(NULL)
+{
+}
+
+InfoLog::~InfoLog()
+{
+    delete[] mInfoLog;
+}
+
+
+int InfoLog::getLength() const
+{
+    if (!mInfoLog)
+    {
+        return 0;
+    }
+    else
+    {
+       return strlen(mInfoLog) + 1;
+    }
+}
+
+void InfoLog::getLog(GLsizei bufSize, GLsizei *length, char *infoLog)
+{
+    int index = 0;
+
+    if (bufSize > 0)
+    {
+        if (mInfoLog)
+        {
+            index = std::min(bufSize - 1, (int)strlen(mInfoLog));
+            memcpy(infoLog, mInfoLog, index);
+        }
+
+        infoLog[index] = '\0';
+    }
+
+    if (length)
+    {
+        *length = index;
+    }
+}
+
+// append a santized message to the program info log.
+// The D3D compiler includes a fake file path in some of the warning or error 
+// messages, so lets remove all occurrences of this fake file path from the log.
+void InfoLog::appendSanitized(const char *message)
+{
+    std::string msg(message);
+
+    size_t found;
+    do
+    {
+        found = msg.find(g_fakepath);
+        if (found != std::string::npos)
+        {
+            msg.erase(found, strlen(g_fakepath));
+        }
+    }
+    while (found != std::string::npos);
+
+    append("%s\n", msg.c_str());
+}
+
+void InfoLog::append(const char *format, ...)
+{
+    if (!format)
+    {
+        return;
+    }
+
+    char info[1024];
+
+    va_list vararg;
+    va_start(vararg, format);
+    vsnprintf(info, sizeof(info), format, vararg);
+    va_end(vararg);
+
+    size_t infoLength = strlen(info);
+
+    if (!mInfoLog)
+    {
+        mInfoLog = new char[infoLength + 1];
+        strcpy(mInfoLog, info);
+    }
+    else
+    {
+        size_t logLength = strlen(mInfoLog);
+        char *newLog = new char[logLength + infoLength + 1];
+        strcpy(newLog, mInfoLog);
+        strcpy(newLog + logLength, info);
+
+        delete[] mInfoLog;
+        mInfoLog = newLog;
+    }
+}
+
+void InfoLog::reset()
+{
+    if (mInfoLog)
+    {
+        delete [] mInfoLog;
+        mInfoLog = NULL;
+    }
+}
+
 Program::Program(ResourceManager *manager, GLuint handle) : mResourceManager(manager), mHandle(handle), mSerial(issueSerial())
 {
     mFragmentShader = NULL;
@@ -138,8 +246,10 @@
 {
     unlink(false);
 
+    mInfoLog.reset();
+
     mProgramBinary = new ProgramBinary;
-    if (!mProgramBinary->link(mAttributeBindings, mFragmentShader, mVertexShader))
+    if (!mProgramBinary->link(mInfoLog, mAttributeBindings, mFragmentShader, mVertexShader))
     {
         unlink(false);
     }
@@ -226,34 +336,12 @@
 
 int Program::getInfoLogLength() const
 {
-    if (mProgramBinary)
-    {
-        return mProgramBinary->getInfoLogLength();
-    }
-    else
-    {
-       return 0;
-    }
+    return mInfoLog.getLength();
 }
 
 void Program::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
 {
-    if (mProgramBinary)
-    {
-        return mProgramBinary->getInfoLog(bufSize, length, infoLog);
-    }
-    else
-    {
-        if (bufSize > 0)
-        {
-            infoLog[0] = '\0';
-        }
-
-        if (length)
-        {
-            *length = 0;
-        }
-    }
+    return mInfoLog.getLog(bufSize, length, infoLog);
 }
 
 void Program::getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders)
@@ -390,6 +478,20 @@
     return mDeleteStatus;
 }
 
+void Program::validate()
+{
+    mInfoLog.reset();
+
+    if (mProgramBinary)
+    {
+        mProgramBinary->validate(mInfoLog);
+    }
+    else
+    {
+        mInfoLog.append("Program has not been successfully linked.");
+    }
+}
+
 bool Program::isValidated() const
 {
     if (mProgramBinary)
diff --git a/src/libGLESv2/Program.h b/src/libGLESv2/Program.h
index 1b4239a..244731d 100644
--- a/src/libGLESv2/Program.h
+++ b/src/libGLESv2/Program.h
@@ -23,6 +23,8 @@
 class FragmentShader;
 class VertexShader;
 
+extern const char * const g_fakepath;
+
 class AttributeBindings
 {
   public:
@@ -36,6 +38,23 @@
     std::set<std::string> mAttributeBinding[MAX_VERTEX_ATTRIBS];
 };
 
+class InfoLog
+{
+  public:
+    InfoLog();
+    ~InfoLog();
+
+    int getLength() const;
+    void getLog(GLsizei bufSize, GLsizei *length, char *infoLog);
+
+    void appendSanitized(const char *message);
+    void append(const char *info, ...);
+    void reset();
+  private:
+    DISALLOW_COPY_AND_ASSIGN(InfoLog);
+    char *mInfoLog;
+};
+
 class Program
 {
   public:
@@ -71,6 +90,7 @@
     void flagForDeletion();
     bool isFlaggedForDeletion() const;
 
+    void validate();
     bool isValidated() const;
 
     unsigned int getSerial() const;
@@ -98,6 +118,8 @@
 
     ResourceManager *mResourceManager;
     const GLuint mHandle;
+
+    InfoLog mInfoLog;
 };
 }
 
diff --git a/src/libGLESv2/ProgramBinary.cpp b/src/libGLESv2/ProgramBinary.cpp
index be91b20..ac28e51 100644
--- a/src/libGLESv2/ProgramBinary.cpp
+++ b/src/libGLESv2/ProgramBinary.cpp
@@ -24,8 +24,6 @@
 
 namespace gl
 {
-const char *fakepath = "C:\\fakepath";
-
 std::string str(int i)
 {
     char buffer[20];
@@ -66,7 +64,6 @@
     mConstantTablePS = NULL;
     mConstantTableVS = NULL;
 
-    mInfoLog = NULL;
     mValidated = false;
 
     for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++)
@@ -122,8 +119,6 @@
         delete mUniforms.back();
         mUniforms.pop_back();
     }
-
-    delete[] mInfoLog;
 }
 
 IDirect3DPixelShader9 *ProgramBinary::getPixelShader()
@@ -1027,7 +1022,7 @@
 }
 
 // Compiles the HLSL code of the attached shaders into executable binaries
-ID3D10Blob *ProgramBinary::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
+ID3D10Blob *ProgramBinary::compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, ID3DXConstantTable **constantTable)
 {
     if (!hlsl)
     {
@@ -1058,13 +1053,13 @@
 
     ID3D10Blob *binary = NULL;
     ID3D10Blob *errorMessage = NULL;
-    result = D3DCompile(hlsl, strlen(hlsl), fakepath, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
+    result = D3DCompile(hlsl, strlen(hlsl), g_fakepath, NULL, NULL, "main", profile, flags, 0, &binary, &errorMessage);
 
     if (errorMessage)
     {
         const char *message = (const char*)errorMessage->GetBufferPointer();
 
-        appendToInfoLogSanitized(message);
+        infoLog.appendSanitized(message);
         TRACE("\n%s", hlsl);
         TRACE("\n%s", message);
 
@@ -1101,7 +1096,7 @@
 
 // Packs varyings into generic varying registers, using the algorithm from [OpenGL ES Shading Language 1.00 rev. 17] appendix A section 7 page 111
 // Returns the number of used varying registers, or -1 if unsuccesful
-int ProgramBinary::packVaryings(const Varying *packing[][4], FragmentShader *fragmentShader)
+int ProgramBinary::packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader)
 {
     Context *context = getContext();
     const int maxVaryingVectors = context->getMaximumVaryingVectors();
@@ -1229,7 +1224,7 @@
 
         if (!success)
         {
-            appendToInfoLog("Could not pack varying %s", varying->name.c_str());
+            infoLog.append("Could not pack varying %s", varying->name.c_str());
 
             return -1;
         }
@@ -1249,7 +1244,7 @@
     return registers;
 }
 
-bool ProgramBinary::linkVaryings(std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
+bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader)
 {
     if (pixelHLSL.empty() || vertexHLSL.empty())
     {
@@ -1271,7 +1266,7 @@
 
     // Map the varyings to the register file
     const Varying *packing[MAX_VARYING_VECTORS_SM3][4] = {NULL};
-    int registers = packVaryings(packing, fragmentShader);
+    int registers = packVaryings(infoLog, packing, fragmentShader);
 
     if (registers < 0)
     {
@@ -1285,7 +1280,7 @@
 
     if (registers == maxVaryingVectors && fragmentShader->mUsesFragCoord)
     {
-        appendToInfoLog("No varying registers left to support gl_FragCoord");
+        infoLog.append("No varying registers left to support gl_FragCoord");
 
         return false;
     }
@@ -1300,7 +1295,7 @@
             {
                 if (output->type != input->type || output->size != input->size)
                 {
-                    appendToInfoLog("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
+                    infoLog.append("Type of vertex varying %s does not match that of the fragment varying", output->name.c_str());
 
                     return false;
                 }
@@ -1315,7 +1310,7 @@
 
         if (!matched)
         {
-            appendToInfoLog("Fragment varying %s does not match any vertex varying", input->name.c_str());
+            infoLog.append("Fragment varying %s does not match any vertex varying", input->name.c_str());
 
             return false;
         }
@@ -1590,7 +1585,7 @@
     return true;
 }
 
-bool ProgramBinary::link(const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
+bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
 {
     if (!fragmentShader || !fragmentShader->isCompiled())
     {
@@ -1605,7 +1600,7 @@
     std::string pixelHLSL = fragmentShader->getHLSL();
     std::string vertexHLSL = vertexShader->getHLSL();
 
-    if (!linkVaryings(pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
+    if (!linkVaryings(infoLog, pixelHLSL, vertexHLSL, fragmentShader, vertexShader))
     {
         return false;
     }
@@ -1614,8 +1609,8 @@
     const char *vertexProfile = context->supportsShaderModel3() ? "vs_3_0" : "vs_2_0";
     const char *pixelProfile = context->supportsShaderModel3() ? "ps_3_0" : "ps_2_0";
 
-    ID3D10Blob *vertexBinary = compileToBinary(vertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
-    ID3D10Blob *pixelBinary = compileToBinary(pixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
+    ID3D10Blob *vertexBinary = compileToBinary(infoLog, vertexHLSL.c_str(), vertexProfile, &mConstantTableVS);
+    ID3D10Blob *pixelBinary = compileToBinary(infoLog, pixelHLSL.c_str(), pixelProfile, &mConstantTablePS);
 
     if (vertexBinary && pixelBinary)
     {
@@ -1636,17 +1631,17 @@
 
         if (mVertexExecutable && mPixelExecutable)
         {
-            if (!linkAttributes(attributeBindings, fragmentShader, vertexShader))
+            if (!linkAttributes(infoLog, attributeBindings, fragmentShader, vertexShader))
             {
                 return false;
             }
 
-            if (!linkUniforms(GL_FRAGMENT_SHADER, mConstantTablePS))
+            if (!linkUniforms(infoLog, GL_FRAGMENT_SHADER, mConstantTablePS))
             {
                 return false;
             }
 
-            if (!linkUniforms(GL_VERTEX_SHADER, mConstantTableVS))
+            if (!linkUniforms(infoLog, GL_VERTEX_SHADER, mConstantTableVS))
             {
                 return false;
             }
@@ -1670,7 +1665,7 @@
 }
 
 // Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices
-bool ProgramBinary::linkAttributes(const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
+bool ProgramBinary::linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
 {
     unsigned int usedLocations = 0;
 
@@ -1692,7 +1687,7 @@
 
             if (rows + location > MAX_VERTEX_ATTRIBS)
             {
-                appendToInfoLog("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
+                infoLog.append("Active attribute (%s) at location %d is too big to fit", attribute->name.c_str(), location);
 
                 return false;
             }
@@ -1716,7 +1711,7 @@
 
             if (availableIndex == -1 || availableIndex + rows > MAX_VERTEX_ATTRIBS)
             {
-                appendToInfoLog("Too many active attributes (%s)", attribute->name.c_str());
+                infoLog.append("Too many active attributes (%s)", attribute->name.c_str());
 
                 return false;   // Fail to link
             }
@@ -1739,7 +1734,7 @@
     return true;
 }
 
-bool ProgramBinary::linkUniforms(GLenum shader, ID3DXConstantTable *constantTable)
+bool ProgramBinary::linkUniforms(InfoLog &infoLog, GLenum shader, ID3DXConstantTable *constantTable)
 {
     D3DXCONSTANTTABLE_DESC constantTableDescription;
 
@@ -1754,7 +1749,7 @@
         HRESULT result = constantTable->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount);
         ASSERT(SUCCEEDED(result));
 
-        if (!defineUniform(shader, constantHandle, constantDescription))
+        if (!defineUniform(infoLog, shader, constantHandle, constantDescription))
         {
             return false;
         }
@@ -1765,7 +1760,7 @@
 
 // Adds the description of a constant found in the binary shader to the list of uniforms
 // Returns true if succesful (uniform not already defined)
-bool ProgramBinary::defineUniform(GLenum shader, const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
+bool ProgramBinary::defineUniform(InfoLog &infoLog, GLenum shader, const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name)
 {
     if (constantDescription.RegisterSet == D3DXRS_SAMPLER)
     {
@@ -1787,7 +1782,7 @@
                 }
                 else
                 {
-                    appendToInfoLog("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
+                    infoLog.append("Pixel shader sampler count exceeds MAX_TEXTURE_IMAGE_UNITS (%d).", MAX_TEXTURE_IMAGE_UNITS);
                     return false;
                 }
             }
@@ -1805,7 +1800,7 @@
                 }
                 else
                 {
-                    appendToInfoLog("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
+                    infoLog.append("Vertex shader sampler count exceeds MAX_VERTEX_TEXTURE_IMAGE_UNITS (%d).", getContext()->getMaximumVertexTextureImageUnits());
                     return false;
                 }
             }
@@ -1830,7 +1825,7 @@
 
                     std::string structIndex = (constantDescription.Elements > 1) ? ("[" + str(arrayIndex) + "]") : "";
 
-                    if (!defineUniform(shader, fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
+                    if (!defineUniform(infoLog, shader, fieldHandle, fieldDescription, name + constantDescription.Name + structIndex + "."))
                     {
                         return false;
                     }
@@ -2197,107 +2192,11 @@
     }
 }
 
-// append a santized message to the program info log.
-// The D3D compiler includes a fake file path in some of the warning or error 
-// messages, so lets remove all occurrences of this fake file path from the log.
-void ProgramBinary::appendToInfoLogSanitized(const char *message)
-{
-    std::string msg(message);
-
-    size_t found;
-    do
-    {
-        found = msg.find(fakepath);
-        if (found != std::string::npos)
-        {
-            msg.erase(found, strlen(fakepath));
-        }
-    }
-    while (found != std::string::npos);
-
-    appendToInfoLog("%s\n", msg.c_str());
-}
-
-void ProgramBinary::appendToInfoLog(const char *format, ...)
-{
-    if (!format)
-    {
-        return;
-    }
-
-    char info[1024];
-
-    va_list vararg;
-    va_start(vararg, format);
-    vsnprintf(info, sizeof(info), format, vararg);
-    va_end(vararg);
-
-    size_t infoLength = strlen(info);
-
-    if (!mInfoLog)
-    {
-        mInfoLog = new char[infoLength + 1];
-        strcpy(mInfoLog, info);
-    }
-    else
-    {
-        size_t logLength = strlen(mInfoLog);
-        char *newLog = new char[logLength + infoLength + 1];
-        strcpy(newLog, mInfoLog);
-        strcpy(newLog + logLength, info);
-
-        delete[] mInfoLog;
-        mInfoLog = newLog;
-    }
-}
-
-void ProgramBinary::resetInfoLog()
-{
-    if (mInfoLog)
-    {
-        delete [] mInfoLog;
-        mInfoLog = NULL;
-    }
-}
-
 bool ProgramBinary::isValidated() const 
 {
     return mValidated;
 }
 
-int ProgramBinary::getInfoLogLength() const
-{
-    if (!mInfoLog)
-    {
-        return 0;
-    }
-    else
-    {
-       return strlen(mInfoLog) + 1;
-    }
-}
-
-void ProgramBinary::getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog)
-{
-    int index = 0;
-
-    if (bufSize > 0)
-    {
-        if (mInfoLog)
-        {
-            index = std::min(bufSize - 1, (int)strlen(mInfoLog));
-            memcpy(infoLog, mInfoLog, index);
-        }
-
-        infoLog[index] = '\0';
-    }
-
-    if (length)
-    {
-        *length = index;
-    }
-}
-
 void ProgramBinary::getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
 {
     // Skip over inactive attributes
@@ -2448,12 +2347,10 @@
     return maxLength;
 }
 
-void ProgramBinary::validate()
+void ProgramBinary::validate(InfoLog &infoLog)
 {
-    resetInfoLog();
-
     applyUniforms();
-    if (!validateSamplers(true))
+    if (!validateSamplers(&infoLog))
     {
         mValidated = false;
     }
@@ -2463,7 +2360,7 @@
     }
 }
 
-bool ProgramBinary::validateSamplers(bool logErrors)
+bool ProgramBinary::validateSamplers(InfoLog *infoLog)
 {
     // if any two active samplers in a program are of different types, but refer to the same
     // texture image unit, and this is the current program, then ValidateProgram will fail, and
@@ -2485,9 +2382,9 @@
             
             if (unit >= maxCombinedTextureImageUnits)
             {
-                if (logErrors)
+                if (infoLog)
                 {
-                    appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
+                    infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
                 }
 
                 return false;
@@ -2497,9 +2394,9 @@
             {
                 if (mSamplersPS[i].textureType != textureUnitType[unit])
                 {
-                    if (logErrors)
+                    if (infoLog)
                     {
-                        appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+                        infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
                     }
 
                     return false;
@@ -2520,9 +2417,9 @@
             
             if (unit >= maxCombinedTextureImageUnits)
             {
-                if (logErrors)
+                if (infoLog)
                 {
-                    appendToInfoLog("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
+                    infoLog->append("Sampler uniform (%d) exceeds MAX_COMBINED_TEXTURE_IMAGE_UNITS (%d)", unit, maxCombinedTextureImageUnits);
                 }
 
                 return false;
@@ -2532,9 +2429,9 @@
             {
                 if (mSamplersVS[i].textureType != textureUnitType[unit])
                 {
-                    if (logErrors)
+                    if (infoLog)
                     {
-                        appendToInfoLog("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
+                        infoLog->append("Samplers of conflicting types refer to the same texture image unit (%d).", unit);
                     }
 
                     return false;
diff --git a/src/libGLESv2/ProgramBinary.h b/src/libGLESv2/ProgramBinary.h
index cdc7172..1e9c5e2 100644
--- a/src/libGLESv2/ProgramBinary.h
+++ b/src/libGLESv2/ProgramBinary.h
@@ -128,9 +128,7 @@
     void dirtyAllUniforms();
     void applyUniforms();
 
-    bool link(const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
-    int getInfoLogLength() const;
-    void getInfoLog(GLsizei bufSize, GLsizei *length, char *infoLog);
+    bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
     void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
 
     void getActiveAttribute(GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);
@@ -141,8 +139,8 @@
     GLint getActiveUniformCount();
     GLint getActiveUniformMaxLength();
 
-    void validate();
-    bool validateSamplers(bool logErrors);
+    void validate(InfoLog &infoLog);
+    bool validateSamplers(InfoLog *infoLog);
     bool isValidated() const;
 
     static std::string decorateAttribute(const std::string &name);    // Prepend an underscore
@@ -151,15 +149,15 @@
   private:
     DISALLOW_COPY_AND_ASSIGN(ProgramBinary);
 
-    ID3D10Blob *compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable);
+    ID3D10Blob *compileToBinary(InfoLog &infoLog, const char *hlsl, const char *profile, ID3DXConstantTable **constantTable);
 
-    int packVaryings(const Varying *packing[][4], FragmentShader *fragmentShader);
-    bool linkVaryings(std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader);
+    int packVaryings(InfoLog &infoLog, const Varying *packing[][4], FragmentShader *fragmentShader);
+    bool linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::string& vertexHLSL, FragmentShader *fragmentShader, VertexShader *vertexShader);
 
-    bool linkAttributes(const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
+    bool linkAttributes(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
 
-    bool linkUniforms(GLenum shader, ID3DXConstantTable *constantTable);
-    bool defineUniform(GLenum shader, const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name = "");
+    bool linkUniforms(InfoLog &infoLog, GLenum shader, ID3DXConstantTable *constantTable);
+    bool defineUniform(InfoLog &infoLog, GLenum shader, const D3DXHANDLE &constantHandle, const D3DXCONSTANT_DESC &constantDescription, std::string name = "");
     bool defineUniform(GLenum shader, const D3DXCONSTANT_DESC &constantDescription, const std::string &name);
     Uniform *createUniform(const D3DXCONSTANT_DESC &constantDescription, const std::string &name);
     bool applyUniformnfv(Uniform *targetUniform, const GLfloat *v);
@@ -170,12 +168,6 @@
     void applyUniformniv(Uniform *targetUniform, GLsizei count, const D3DXVECTOR4 *vector);
     void applyUniformnbv(Uniform *targetUniform, GLsizei count, int width, const GLboolean *v);
 
-    void appendToInfoLogSanitized(const char *message);
-    void appendToInfoLog(const char *info, ...);
-    void resetInfoLog();
-
-    static unsigned int issueSerial();
-
     IDirect3DDevice9 *mDevice;
 
     IDirect3DPixelShader9 *mPixelExecutable;
@@ -212,7 +204,6 @@
     GLint mDxFrontCCWLocation;
     GLint mDxPointsOrLinesLocation;
 
-    char *mInfoLog;
     bool mValidated;
 };
 }
diff --git a/src/libGLESv2/libGLESv2.cpp b/src/libGLESv2/libGLESv2.cpp
index 95db580..fba253d 100644
--- a/src/libGLESv2/libGLESv2.cpp
+++ b/src/libGLESv2/libGLESv2.cpp
@@ -6444,13 +6444,7 @@
                 }
             }
 
-            gl::ProgramBinary *programBinary = programObject->getProgramBinary();
-            if (!programBinary)
-            {
-                return;
-            }
-
-            programBinary->validate();
+            programObject->validate();
         }
     }
     catch(std::bad_alloc&)