Bug 1203135 - Terminate linking if maximum vertex attribute count is exceeded on Mesa. r=jgilbert, a=ritu
authorAndrew Comminos <andrew@comminos.com>
Fri, 23 Oct 2015 21:35:16 -0700
changeset 298580 90eff805d2810e9d9ea88f6869335b0500b1a536
parent 298579 730297e459777be8e213fceb86d62bff7e39a57e
child 298581 b9a4e613d4a6f524a1d8b028eb6a108956e5667a
push id962
push userjlund@mozilla.com
push dateFri, 04 Dec 2015 23:28:54 +0000
treeherdermozilla-release@23a2d286e80f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, ritu
bugs1203135
milestone43.0
Bug 1203135 - Terminate linking if maximum vertex attribute count is exceeded on Mesa. r=jgilbert, a=ritu
dom/canvas/WebGLProgram.cpp
dom/canvas/WebGLShader.cpp
dom/canvas/WebGLShader.h
dom/canvas/WebGLShaderValidator.cpp
dom/canvas/WebGLShaderValidator.h
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -807,28 +807,36 @@ WebGLProgram::LinkProgram()
     if (!mFragShader->CanLinkTo(mVertShader, &mLinkLog)) {
         mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
         return false;
     }
 
     gl::GLContext* gl = mContext->gl;
     gl->MakeCurrent();
 
-    // Bug 777028: Mesa can't handle more than 16 samplers per program,
-    // counting each array entry.
-    size_t numSamplerUniforms_upperBound = mVertShader->CalcNumSamplerUniforms() +
-                                           mFragShader->CalcNumSamplerUniforms();
     if (gl->WorkAroundDriverBugs() &&
-        mContext->mIsMesa &&
-        numSamplerUniforms_upperBound > 16)
+        mContext->mIsMesa)
     {
-        mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
-                               " Mesa drivers to avoid crashing.");
-        mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
-        return false;
+        // Bug 777028: Mesa can't handle more than 16 samplers per program,
+        // counting each array entry.
+        size_t numSamplerUniforms_upperBound = mVertShader->CalcNumSamplerUniforms() +
+                                               mFragShader->CalcNumSamplerUniforms();
+        if (numSamplerUniforms_upperBound > 16) {
+            mLinkLog.AssignLiteral("Programs with more than 16 samplers are disallowed on"
+                                   " Mesa drivers to avoid crashing.");
+            mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
+            return false;
+        }
+
+        // Bug 1203135: Mesa crashes internally if we exceed the reported maximum attribute count.
+        if (mVertShader->NumAttributes() > mContext->MaxVertexAttribs()) {
+            mLinkLog.AssignLiteral("Number of attributes exceeds Mesa's reported max attribute count.");
+            mContext->GenerateWarning("linkProgram: %s", mLinkLog.BeginReading());
+            return false;
+        }
     }
 
     // Bind the attrib locations.
     // This can't be done trivially, because we have to deal with mapped attrib names.
     for (auto itr = mBoundAttribLocs.begin(); itr != mBoundAttribLocs.end(); ++itr) {
         const nsCString& name = itr->first;
         GLuint index = itr->second;
 
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -301,16 +301,26 @@ WebGLShader::CalcNumSamplerUniforms() co
 {
     if (mValidator)
         return mValidator->CalcNumSamplerUniforms();
 
     // TODO
     return 0;
 }
 
+size_t
+WebGLShader::NumAttributes() const
+{
+    if (mValidator)
+        return mValidator->NumAttributes();
+
+    // TODO
+    return 0;
+}
+
 void
 WebGLShader::BindAttribLocation(GLuint prog, const nsCString& userName,
                                 GLuint index) const
 {
     std::string userNameStr(userName.BeginReading());
 
     const std::string* mappedNameStr = &userNameStr;
     if (mValidator)
--- a/dom/canvas/WebGLShader.h
+++ b/dom/canvas/WebGLShader.h
@@ -45,16 +45,17 @@ public:
     void GetShaderInfoLog(nsAString* out) const;
     void GetShaderSource(nsAString* out) const;
     void GetShaderTranslatedSource(nsAString* out) const;
     void ShaderSource(const nsAString& source);
 
     // Util funcs
     bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const;
     size_t CalcNumSamplerUniforms() const;
+    size_t NumAttributes() const;
     void BindAttribLocation(GLuint prog, const nsCString& userName, GLuint index) const;
     bool FindAttribUserNameByMappedName(const nsACString& mappedName,
                                         nsDependentCString* const out_userName) const;
     bool FindUniformByMappedName(const nsACString& mappedName,
                                  nsCString* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformBlockByMappedName(const nsACString& mappedName,
                                       nsCString* const out_userName,
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -323,16 +323,22 @@ ShaderValidator::CalcNumSamplerUniforms(
         {
             accum += itr->arraySize;
         }
     }
 
     return accum;
 }
 
+size_t
+ShaderValidator::NumAttributes() const
+{
+  return ShGetAttributes(mHandle)->size();
+}
+
 // Attribs cannot be structs or arrays, and neither can vertex inputs in ES3.
 // Therefore, attrib names are always simple.
 bool
 ShaderValidator::FindAttribUserNameByMappedName(const std::string& mappedName,
                                                 const std::string** const out_userName) const
 {
     const std::vector<sh::Attribute>& attribs = *ShGetAttributes(mHandle);
     for (auto itr = attribs.begin(); itr != attribs.end(); ++itr) {
--- a/dom/canvas/WebGLShaderValidator.h
+++ b/dom/canvas/WebGLShaderValidator.h
@@ -38,16 +38,17 @@ private:
 public:
     ~ShaderValidator();
 
     bool ValidateAndTranslate(const char* source);
     void GetInfoLog(nsACString* out) const;
     void GetOutput(nsACString* out) const;
     bool CanLinkTo(const ShaderValidator* prev, nsCString* const out_log) const;
     size_t CalcNumSamplerUniforms() const;
+    size_t NumAttributes() const;
 
     bool FindAttribUserNameByMappedName(const std::string& mappedName,
                                         const std::string** const out_userName) const;
 
     bool FindAttribMappedNameByUserName(const std::string& userName,
                                         const std::string** const out_mappedName) const;
 
     bool FindUniformByMappedName(const std::string& mappedName,