Bug 1325699 - Fix uniform block handling. - r=daoshengmu draft
authorJeff Gilbert <jgilbert@mozilla.com>
Fri, 23 Dec 2016 13:29:07 -0800
changeset 453824 a8a07602d470c80dc8aaa1b120131477ece9623c
parent 453823 f71c807f413d906de11826589a9579a8c8898334
child 453825 7a245c9b2260bd93515140c96f98b03596655691
push id39739
push userbmo:jgilbert@mozilla.com
push dateSun, 25 Dec 2016 06:53:30 +0000
reviewersdaoshengmu
bugs1325699
milestone53.0a1
Bug 1325699 - Fix uniform block handling. - r=daoshengmu MozReview-Commit-ID: 7ujb7sP0TsB
dom/canvas/WebGLProgram.cpp
dom/canvas/WebGLProgram.h
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
@@ -167,17 +167,17 @@ webgl::UniformInfo::UniformInfo(WebGLAct
 {
     if (mSamplerTexList) {
         mSamplerValues.assign(mActiveInfo->mElemCount, 0);
     }
 }
 
 //////////
 
-//#define DUMP_SHADERVAR_MAPPINGS
+#define DUMP_SHADERVAR_MAPPINGS
 
 static already_AddRefed<const webgl::LinkedProgramInfo>
 QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
 {
     WebGLContext* const webgl = prog->mContext;
 
     RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
 
@@ -233,36 +233,38 @@ QueryProgramInfo(WebGLProgram* prog, gl:
                              &elemCount, &elemType, mappedName.BeginWriting());
         GLenum error = gl->fGetError();
         if (error != LOCAL_GL_NO_ERROR) {
             gfxCriticalNote << "Failed to do glGetActiveAttrib: " << error;
         }
 
         mappedName.SetLength(lengthWithoutNull);
 
+        if (mappedName.Find("gl_") == 0) {
+#ifdef DUMP_SHADERVAR_MAPPINGS
+          printf_stderr("[attrib %u/%u] <skipping %s>\n", i, numActiveAttribs,
+                        mappedName.BeginReading());
+#endif
+            continue;
+        }
+
         // Attribs can't be arrays, so we can skip some of the mess we have in the Uniform
         // path.
         nsDependentCString userName;
         if (!prog->FindAttribUserNameByMappedName(mappedName, &userName))
             userName.Rebind(mappedName, 0);
 
         ///////
 
         const GLint loc = gl->fGetAttribLocation(prog->mGLName,
                                                  mappedName.BeginReading());
-        if (loc == -1) {
-            MOZ_ASSERT(mappedName == "gl_InstanceID",
-                       "Active attrib should have a location.");
-            continue;
-        }
 
 #ifdef DUMP_SHADERVAR_MAPPINGS
-        printf_stderr("[attrib %i: %i] %s/%s\n", i, loc, mappedName.BeginReading(),
-                      userName.BeginReading());
-        printf_stderr("    lengthWithoutNull: %d\n", lengthWithoutNull);
+        printf_stderr("[attrib %u/%u] @%u %s->%s\n", i, numActiveAttribs, loc,
+                      userName.BeginReading(), mappedName.BeginReading());
 #endif
 
         ///////
 
         const bool isArray = false;
         const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
                                                                        elemType, isArray,
                                                                        userName,
@@ -286,16 +288,17 @@ QueryProgramInfo(WebGLProgram* prog, gl:
 
         GLsizei lengthWithoutNull = 0;
         GLint elemCount = 0; // `size`
         GLenum elemType = 0; // `type`
         gl->fGetActiveUniform(prog->mGLName, i, mappedName.Length()+1, &lengthWithoutNull,
                               &elemCount, &elemType, mappedName.BeginWriting());
 
         mappedName.SetLength(lengthWithoutNull);
+        MOZ_ASSERT(mappedName.Find("gl_") != 0);
 
         ///////
 
         nsAutoCString baseMappedName;
         bool isArray;
         size_t arrayIndex;
         if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
             MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
@@ -321,21 +324,18 @@ QueryProgramInfo(WebGLProgram* prog, gl:
                 if (loc != -1)
                     isArray = true;
             }
         }
 
         ///////
 
 #ifdef DUMP_SHADERVAR_MAPPINGS
-        printf_stderr("[uniform %i] %s/%i/%s/%s\n", i, mappedName.BeginReading(),
-                      (int)isArray, baseMappedName.BeginReading(),
-                      baseUserName.BeginReading());
-        printf_stderr("    lengthWithoutNull: %d\n", lengthWithoutNull);
-        printf_stderr("    isArray: %d\n", (int)isArray);
+        printf_stderr("[uniform %u/%u] %s->%s\n", i, numActiveUniforms,
+                      baseUserName.BeginReading(), mappedName.BeginReading());
 #endif
 
         ///////
 
         const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl, elemCount,
                                                                        elemType, isArray,
                                                                        baseUserName,
                                                                        baseMappedName);
@@ -360,55 +360,38 @@ QueryProgramInfo(WebGLProgram* prog, gl:
             nsAutoCString mappedName;
             mappedName.SetLength(maxUniformBlockLenWithNull - 1);
 
             GLint lengthWithoutNull;
             gl->fGetActiveUniformBlockiv(prog->mGLName, i, LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH, &lengthWithoutNull);
             gl->fGetActiveUniformBlockName(prog->mGLName, i, maxUniformBlockLenWithNull, &lengthWithoutNull, mappedName.BeginWriting());
             mappedName.SetLength(lengthWithoutNull);
 
-            nsAutoCString baseMappedName;
-            bool isArray;
-            size_t arrayIndex;
-            if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
-                MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
+            MOZ_ASSERT(mappedName.Find("gl_") != 0);
+
+            ////
 
-            nsAutoCString baseUserName;
-            if (!prog->FindUniformBlockByMappedName(baseMappedName, &baseUserName,
-                                                    &isArray))
-            {
-                baseUserName = baseMappedName;
+            nsCString userName;
+            if (!prog->UnmapUniformBlockName(mappedName, &userName))
+                continue;
 
-                if (needsCheckForArrays && !isArray) {
-                    std::string mappedNameStr = baseMappedName.BeginReading();
-                    mappedNameStr += "[0]";
-
-                    GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName,
-                                                           mappedNameStr.c_str());
-                    if (loc != LOCAL_GL_INVALID_INDEX)
-                        isArray = true;
-                }
-            }
+#ifdef DUMP_SHADERVAR_MAPPINGS
+            printf_stderr("[uniform block %u/%u] %s->%s\n", i, numActiveUniformBlocks,
+                          userName.BeginReading(), mappedName.BeginReading());
+#endif
 
             ////
 
             GLuint dataSize = 0;
             gl->fGetActiveUniformBlockiv(prog->mGLName, i,
                                          LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE,
                                          (GLint*)&dataSize);
 
-#ifdef DUMP_SHADERVAR_MAPPINGS
-            printf_stderr("[uniform block %i] %s/%i/%s/%s\n", i,
-                          mappedName.BeginReading(), (int)isArray,
-                          baseMappedName.BeginReading(), baseUserName.BeginReading());
-            printf_stderr("    lengthWithoutNull: %d\n", lengthWithoutNull);
-            printf_stderr("    isArray: %d\n", (int)isArray);
-#endif
 
-            auto* block = new webgl::UniformBlockInfo(webgl, baseUserName, baseMappedName,
+            auto* block = new webgl::UniformBlockInfo(webgl, userName, mappedName,
                                                       dataSize);
             info->uniformBlocks.push_back(block);
         }
     }
 
     // Transform feedback varyings
 
     if (gl->IsSupported(gl::GLFeature::transform_feedback2)) {
@@ -424,42 +407,39 @@ QueryProgramInfo(WebGLProgram* prog, gl:
             GLsizei elemCount;
             GLenum elemType;
             gl->fGetTransformFeedbackVarying(prog->mGLName, i,
                                              maxTransformFeedbackVaryingLenWithNull,
                                              &lengthWithoutNull, &elemCount, &elemType,
                                              mappedName.BeginWriting());
             mappedName.SetLength(lengthWithoutNull);
 
+            // Allowed to start with "gl_".
+
             ////
 
             nsAutoCString baseMappedName;
             bool isArray;
             size_t arrayIndex;
             if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
                 MOZ_CRASH("GFX: Failed to parse `mappedName` received from driver.");
 
-
             nsAutoCString baseUserName;
             if (!prog->FindVaryingByMappedName(mappedName, &baseUserName, &isArray)) {
                 baseUserName = baseMappedName;
-
-                if (needsCheckForArrays && !isArray) {
-                    std::string mappedNameStr = baseMappedName.BeginReading();
-                    mappedNameStr += "[0]";
-
-                    GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName,
-                                                           mappedNameStr.c_str());
-                    if (loc != LOCAL_GL_INVALID_INDEX)
-                        isArray = true;
-                }
             }
 
             ////
 
+#ifdef DUMP_SHADERVAR_MAPPINGS
+            printf_stderr("[transform feedback varying %u/%u] %s->%s\n", i,
+                          numTransformFeedbackVaryings, baseUserName.BeginReading(),
+                          mappedName.BeginReading());
+#endif
+
             const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(webgl,
                                                                            elemCount,
                                                                            elemType,
                                                                            isArray,
                                                                            baseUserName,
                                                                            mappedName);
             info->transformFeedbackVaryings.push_back(activeInfo);
         }
@@ -783,23 +763,30 @@ WebGLProgram::GetUniformBlockIndex(const
 
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("getUniformBlockIndex: `program` must be linked.");
         return LOCAL_GL_INVALID_INDEX;
     }
 
     const NS_LossyConvertUTF16toASCII userName(userName_wide);
 
-    nsCString mappedName;
-    if (!LinkInfo()->MapUniformBlockName(userName, &mappedName))
+    const webgl::UniformBlockInfo* info = nullptr;
+    for (const auto& cur : LinkInfo()->uniformBlocks) {
+        if (cur->mUserName == userName) {
+            info = cur;
+            break;
+        }
+    }
+    if (!info)
         return LOCAL_GL_INVALID_INDEX;
 
+    const auto& mappedName = info->mMappedName;
+
     gl::GLContext* gl = mContext->GL();
     gl->MakeCurrent();
-
     return gl->fGetUniformBlockIndex(mGLName, mappedName.BeginReading());
 }
 
 void
 WebGLProgram::GetActiveUniformBlockName(GLuint uniformBlockIndex, nsAString& retval) const
 {
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
@@ -808,19 +795,18 @@ WebGLProgram::GetActiveUniformBlockName(
 
     const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
     GLuint uniformBlockCount = (GLuint) linkInfo->uniformBlocks.size();
     if (uniformBlockIndex >= uniformBlockCount) {
         mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
         return;
     }
 
-    const webgl::UniformBlockInfo* blockInfo = linkInfo->uniformBlocks[uniformBlockIndex];
-
-    retval.Assign(NS_ConvertASCIItoUTF16(blockInfo->mBaseUserName));
+    const auto& blockInfo = linkInfo->uniformBlocks[uniformBlockIndex];
+    retval.Assign(NS_ConvertASCIItoUTF16(blockInfo->mUserName));
 }
 
 JS::Value
 WebGLProgram::GetActiveUniformBlockParam(GLuint uniformBlockIndex, GLenum pname) const
 {
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked.");
         return JS::NullValue();
@@ -1494,27 +1480,34 @@ WebGLProgram::GetTransformFeedbackVaryin
         return nullptr;
     }
 
     RefPtr<WebGLActiveInfo> ret = LinkInfo()->transformFeedbackVaryings[index];
     return ret.forget();
 }
 
 bool
-WebGLProgram::FindUniformBlockByMappedName(const nsACString& mappedName,
-                                           nsCString* const out_userName,
-                                           bool* const out_isArray) const
+WebGLProgram::UnmapUniformBlockName(const nsCString& mappedName,
+                                    nsCString* const out_userName) const
 {
-    if (mVertShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray))
-        return true;
+    nsCString baseMappedName;
+    bool isArray;
+    size_t arrayIndex;
+    if (!ParseName(mappedName, &baseMappedName, &isArray, &arrayIndex))
+        return false;
 
-    if (mFragShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray))
-        return true;
+    nsCString baseUserName;
+    if (!mVertShader->UnmapUniformBlockName(baseMappedName, &baseUserName) &&
+        !mFragShader->UnmapUniformBlockName(baseMappedName, &baseUserName))
+    {
+        return false;
+    }
 
-    return false;
+    AssembleName(baseUserName, isArray, arrayIndex, out_userName);
+    return true;
 }
 
 void
 WebGLProgram::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const
 {
     MOZ_ASSERT(mFragShader);
 
     mFragShader->EnumerateFragOutputs(out_FragOutputs);
@@ -1573,41 +1566,16 @@ webgl::LinkedProgramInfo::FindUniform(co
     AssembleName(baseMappedName, isArray, arrayIndex, out_mappedName);
 
     *out_arrayIndex = arrayIndex;
     *out_info = info;
     return true;
 }
 
 bool
-webgl::LinkedProgramInfo::MapUniformBlockName(const nsCString& userName,
-                                              nsCString* const out_mappedName) const
-{
-    nsCString baseUserName;
-    bool isArray;
-    size_t arrayIndex;
-    if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
-        return false;
-
-    const webgl::UniformBlockInfo* info = nullptr;
-    for (const auto& block : uniformBlocks) {
-        if (block->mBaseUserName == baseUserName) {
-            info = block;
-            break;
-        }
-    }
-    if (!info)
-        return false;
-
-    const auto& baseMappedName = info->mBaseMappedName;
-    AssembleName(baseMappedName, isArray, arrayIndex, out_mappedName);
-    return true;
-}
-
-bool
 webgl::LinkedProgramInfo::MapFragDataName(const nsCString& userName,
                                           nsCString* const out_mappedName) const
 {
     // FS outputs can be arrays, but not structures.
 
     if (!fragDataMap.size()) {
         // No mappings map from validation, so just forward it.
         *out_mappedName = userName;
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -55,26 +55,26 @@ protected:
     GetTexList(WebGLActiveInfo* activeInfo);
 
 public:
     explicit UniformInfo(WebGLActiveInfo* activeInfo);
 };
 
 struct UniformBlockInfo final
 {
-    const nsCString mBaseUserName;
-    const nsCString mBaseMappedName;
+    const nsCString mUserName;
+    const nsCString mMappedName;
     const uint32_t mDataSize;
 
     const IndexedBufferBinding* mBinding;
 
-    UniformBlockInfo(WebGLContext* webgl, const nsACString& baseUserName,
-                     const nsACString& baseMappedName, uint32_t dataSize)
-        : mBaseUserName(baseUserName)
-        , mBaseMappedName(baseMappedName)
+    UniformBlockInfo(WebGLContext* webgl, const nsACString& userName,
+                     const nsACString& mappedName, uint32_t dataSize)
+        : mUserName(userName)
+        , mMappedName(mappedName)
         , mDataSize(dataSize)
         , mBinding(&webgl->mIndexedUniformBufferBindings[0])
     { }
 };
 
 struct LinkedProgramInfo final
     : public RefCounted<LinkedProgramInfo>
     , public SupportsWeakPtr<LinkedProgramInfo>
@@ -104,18 +104,16 @@ struct LinkedProgramInfo final
     std::map<nsCString, const nsCString> fragDataMap;
 
     explicit LinkedProgramInfo(WebGLProgram* prog);
     ~LinkedProgramInfo();
 
     bool FindAttrib(const nsCString& userName, const AttribInfo** const out_info) const;
     bool FindUniform(const nsCString& userName, nsCString* const out_mappedName,
                      size_t* const out_arrayIndex, UniformInfo** const out_info) const;
-    bool MapUniformBlockName(const nsCString& userName,
-                             nsCString* const out_mappedName) const;
     bool MapFragDataName(const nsCString& userName,
                          nsCString* const out_mappedName) const;
 };
 
 } // namespace webgl
 
 class WebGLProgram final
     : public nsWrapperCache
@@ -163,19 +161,18 @@ public:
     bool FindAttribUserNameByMappedName(const nsACString& mappedName,
                                         nsDependentCString* const out_userName) const;
     bool FindVaryingByMappedName(const nsACString& mappedName,
                                  nsCString* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformByMappedName(const nsACString& mappedName,
                                  nsCString* const out_userName,
                                  bool* const out_isArray) const;
-    bool FindUniformBlockByMappedName(const nsACString& mappedName,
-                                      nsCString* const out_userName,
-                                      bool* const out_isArray) const;
+    bool UnmapUniformBlockName(const nsCString& mappedName,
+                               nsCString* const out_userName) const;
 
     void TransformFeedbackVaryings(const dom::Sequence<nsString>& varyings,
                                    GLenum bufferMode);
     already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(GLuint index) const;
 
     void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
 
     bool IsLinked() const { return mMostRecentLinkInfo; }
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -375,30 +375,25 @@ WebGLShader::FindUniformByMappedName(con
     if (!mValidator->FindUniformByMappedName(mappedNameStr, &userNameStr, out_isArray))
         return false;
 
     *out_userName = userNameStr.c_str();
     return true;
 }
 
 bool
-WebGLShader::FindUniformBlockByMappedName(const nsACString& mappedName,
-                                          nsCString* const out_userName,
-                                          bool* const out_isArray) const
+WebGLShader::UnmapUniformBlockName(const nsACString& baseMappedName,
+                                   nsCString* const out_baseUserName) const
 {
-    if (!mValidator)
-        return false;
+    if (!mValidator) {
+        *out_baseUserName = baseMappedName;
+        return true;
+    }
 
-    const std::string mappedNameStr(mappedName.BeginReading(), mappedName.Length());
-    std::string userNameStr;
-    if (!mValidator->FindUniformBlockByMappedName(mappedNameStr, &userNameStr))
-        return false;
-
-    *out_userName = userNameStr.c_str();
-    return true;
+    return mValidator->UnmapUniformBlockName(baseMappedName, out_baseUserName);
 }
 
 void
 WebGLShader::EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const
 {
     out_FragOutputs.clear();
 
     if (!mValidator) {
--- a/dom/canvas/WebGLShader.h
+++ b/dom/canvas/WebGLShader.h
@@ -54,19 +54,18 @@ public:
     bool FindAttribUserNameByMappedName(const nsACString& mappedName,
                                         nsDependentCString* const out_userName) const;
     bool FindVaryingByMappedName(const nsACString& mappedName,
                                  nsCString* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformByMappedName(const nsACString& mappedName,
                                  nsCString* const out_userName,
                                  bool* const out_isArray) const;
-    bool FindUniformBlockByMappedName(const nsACString& mappedName,
-                                      nsCString* const out_userName,
-                                      bool* const out_isArray) const;
+    bool UnmapUniformBlockName(const nsACString& baseMappedName,
+                               nsCString* const out_baseUserName) const;
 
     void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
 
     bool IsCompiled() const {
         return mTranslationSuccessful && mCompilationSuccessful;
     }
 
 private:
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -540,23 +540,25 @@ ShaderValidator::FindUniformByMappedName
             return true;
         }
     }
 
     return false;
 }
 
 bool
-ShaderValidator::FindUniformBlockByMappedName(const std::string& mappedName,
-                                              std::string* const out_userName) const
+ShaderValidator::UnmapUniformBlockName(const nsACString& baseMappedName,
+                                       nsCString* const out_baseUserName) const
 {
     const std::vector<sh::InterfaceBlock>& interfaces = *ShGetInterfaceBlocks(mHandle);
     for (const auto& interface : interfaces) {
-        if (mappedName == interface.mappedName) {
-            *out_userName = interface.name;
+        const nsDependentCString interfaceMappedName(interface.mappedName.data(),
+                                                     interface.mappedName.size());
+        if (baseMappedName == interfaceMappedName) {
+            *out_baseUserName = interface.name.data();
             return true;
         }
     }
 
     return false;
 }
 
 void
--- a/dom/canvas/WebGLShaderValidator.h
+++ b/dom/canvas/WebGLShaderValidator.h
@@ -56,18 +56,18 @@ public:
                                          const std::string** const out_mappedName) const;
 
     bool FindVaryingByMappedName(const std::string& mappedName,
                                  std::string* const out_userName,
                                  bool* const out_isArray) const;
     bool FindUniformByMappedName(const std::string& mappedName,
                                  std::string* const out_userName,
                                  bool* const out_isArray) const;
-    bool FindUniformBlockByMappedName(const std::string& mappedName,
-                                      std::string* const out_userName) const;
+    bool UnmapUniformBlockName(const nsACString& baseMappedName,
+                               nsCString* const out_baseUserName) const;
 
     void EnumerateFragOutputs(std::map<nsCString, const nsCString> &out_FragOutputs) const;
 
     bool ValidateTransformFeedback(const std::vector<nsString>& userNames,
                                    uint32_t maxComponents, nsCString* const out_errorText,
                                    std::vector<std::string>* const out_mappedNames);
 };