Bug 777028 - WebGL: allow only 16 samplers per program on Mesa - r=jgilbert, a=lsblakk
authorBenoit Jacob <bjacob@mozilla.com>
Thu, 09 Aug 2012 22:30:17 -0400
changeset 100478 43237bc782d7a9453cfd0fe5319c9813fc12e5e8
parent 100477 3bb3b14f262a0f3559b922484b228b1f44141f26
child 100479 50f5c2689179782da8321ba49bb5c9fda6ae5b56
push id1260
push userbjacob@mozilla.com
push dateFri, 10 Aug 2012 21:31:00 +0000
treeherdermozilla-beta@43237bc782d7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert, lsblakk
bugs777028
milestone15.0
Bug 777028 - WebGL: allow only 16 samplers per program on Mesa - r=jgilbert, a=lsblakk
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextValidate.cpp
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -1116,16 +1116,17 @@ protected:
     WebGLContextOptions mOptions;
 
     bool mInvalidated;
     bool mResetLayer;
     bool mOptionsFrozen;
     bool mMinCapability;
     bool mDisableExtensions;
     bool mHasRobustness;
+    bool mIsMesa;
 
     template<typename WebGLObjectType>
     void DeleteWebGLObjectsArray(nsTArray<WebGLObjectType>& array);
 
     WebGLuint mActiveTexture;
     WebGLenum mWebGLError;
 
     // whether shader validation is supported
@@ -2312,16 +2313,34 @@ public:
     }
 
     bool HasBothShaderTypesAttached() {
         return
             HasAttachedShaderOfType(LOCAL_GL_VERTEX_SHADER) &&
             HasAttachedShaderOfType(LOCAL_GL_FRAGMENT_SHADER);
     }
 
+    size_t UpperBoundNumSamplerUniforms() {
+        size_t numSamplerUniforms = 0;
+        for (size_t i = 0; i < mAttachedShaders.Length(); ++i) {
+            const WebGLShader *shader = mAttachedShaders[i];
+            if (!shader)
+                continue;
+            for (size_t j = 0; j < shader->mUniformInfos.Length(); ++j) {
+                WebGLUniformInfo u = shader->mUniformInfos[j];
+                if (u.type == SH_SAMPLER_2D ||
+                    u.type == SH_SAMPLER_CUBE)
+                {
+                    numSamplerUniforms += u.arraySize;
+                }
+            }
+        }
+        return numSamplerUniforms;
+    }
+
     bool NextGeneration()
     {
         if (!(mGeneration + 1).isValid())
             return false; // must exit without changing mGeneration
         ++mGeneration;
         return true;
     }
 
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3695,16 +3695,27 @@ WebGLContext::LinkProgram(WebGLProgram *
 
     if (!program->HasBothShaderTypesAttached()) {
         GenerateWarning("linkProgram: this program doesn't have both a vertex shader"
                         " and a fragment shader");
         program->SetLinkStatus(false);
         return;
     }
 
+    // bug 777028
+    // Mesa can't handle more than 16 samplers per program, counting each array entry.
+    if (mIsMesa) {
+        if (program->UpperBoundNumSamplerUniforms() > 16) {
+            GenerateWarning("Programs with more than 16 samplers are disallowed on Mesa drivers "
+                            "to avoid a Mesa crasher.");
+            program->SetLinkStatus(false);
+            return;
+        }
+    }
+
     MakeContextCurrent();
     gl->fLinkProgram(progname);
 
     GLint ok;
     gl->fGetProgramiv(progname, LOCAL_GL_LINK_STATUS, &ok);
     if (ok) {
         bool updateInfoSucceeded = program->UpdateInfo();
         program->SetLinkStatus(updateInfoSucceeded);
@@ -4999,17 +5010,16 @@ WebGLContext::CompileShader(WebGLShader 
         shader->mAttributes.Clear();
         shader->mUniforms.Clear();
         shader->mUniformInfos.Clear();
 
         nsAutoArrayPtr<char> attribute_name(new char[attrib_max_length+1]);
         nsAutoArrayPtr<char> uniform_name(new char[uniform_max_length+1]);
         nsAutoArrayPtr<char> mapped_name(new char[mapped_max_length+1]);
 
-
         for (int i = 0; i < num_uniforms; i++) {
             int length, size;
             ShDataType type;
             ShGetActiveUniform(compiler, i,
                                 &length, &size, &type,
                                 uniform_name,
                                 mapped_name);
             if (useShaderSourceTranslation) {
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -764,16 +764,19 @@ WebGLContext::InitAndValidateGL()
     if (mShaderValidation) {
         if (!ShInitialize()) {
             GenerateWarning("GLSL translator initialization failed!");
             return false;
         }
     }
 #endif
 
+    // Mesa can only be detected with the GL_VERSION string, of the form "2.1 Mesa 7.11.0"
+    mIsMesa = strstr((const char *)(gl->fGetString(LOCAL_GL_VERSION)), "Mesa");
+
     // notice that the point of calling GetAndClearError here is not only to check for error,
     // it is also to reset the error flags so that a subsequent WebGL getError call will give the correct result.
     error = gl->GetAndClearError();
     if (error != LOCAL_GL_NO_ERROR) {
         GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
         return false;
     }