Bug 1325240 - Handle arrays in glsl variable location queries properly. - r=daoshengmu a=lizzard
authorJeff Gilbert <jgilbert@mozilla.com>
Wed, 21 Dec 2016 16:40:42 -0800
changeset 359217 8bb474c25c02804a6d7326329c4407490ae974cd
parent 359216 cfb3a4b0c3a31fab27b38ac17ce2ef8ac7c15a71
child 359218 a0d4562b3a8358dfd03db9b22a4fdc1ae4fd57fd
push id1324
push usermtabara@mozilla.com
push dateMon, 16 Jan 2017 13:07:44 +0000
treeherdermozilla-release@a01c49833940 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdaoshengmu, lizzard
bugs1325240
milestone51.0
Bug 1325240 - Handle arrays in glsl variable location queries properly. - r=daoshengmu a=lizzard MozReview-Commit-ID: 1XYwvh9QGmA
dom/canvas/WebGLProgram.cpp
dom/canvas/WebGLProgram.h
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -25,28 +25,29 @@ namespace mozilla {
  *     `out_baseName`: "foo"
  *     `out_isArray`: true
  *     `out_index`: 3
  *
  * If `name`: "foo"
  * Then returns true, with
  *     `out_baseName`: "foo"
  *     `out_isArray`: false
- *     `out_index`: <not written>
+ *     `out_index`: 0
  */
 static bool
 ParseName(const nsCString& name, nsCString* const out_baseName,
           bool* const out_isArray, size_t* const out_arrayIndex)
 {
     int32_t indexEnd = name.RFind("]");
     if (indexEnd == -1 ||
         (uint32_t)indexEnd != name.Length() - 1)
     {
         *out_baseName = name;
         *out_isArray = false;
+        *out_arrayIndex = 0;
         return true;
     }
 
     int32_t indexOpenBracket = name.RFind("[");
     if (indexOpenBracket == -1)
         return false;
 
     uint32_t indexStart = indexOpenBracket + 1;
@@ -65,16 +66,28 @@ ParseName(const nsCString& name, nsCStri
         return false;
 
     *out_baseName = StringHead(name, indexOpenBracket);
     *out_isArray = true;
     *out_arrayIndex = indexNum;
     return true;
 }
 
+static void
+AssembleName(const nsCString& baseName, bool isArray, size_t arrayIndex,
+             nsCString* const out_name)
+{
+    *out_name = baseName;
+    if (isArray) {
+        out_name->Append('[');
+        out_name->AppendInt(uint64_t(arrayIndex));
+        out_name->Append(']');
+    }
+}
+
 //////////
 
 /*static*/ const webgl::UniformInfo::TexListT*
 webgl::UniformInfo::GetTexList(WebGLActiveInfo* activeInfo)
 {
     const auto& webgl = activeInfo->mWebGL;
 
     switch (activeInfo->mElemType) {
@@ -646,24 +659,21 @@ WebGLProgram::GetFragDataLocation(const 
 
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("getFragDataLocation: `program` must be linked.");
         return -1;
     }
 
     const NS_LossyConvertUTF16toASCII userName(userName_wide);
     nsCString mappedName;
-
-    if (!LinkInfo()->FindFragData(userName, &mappedName)) {
-        mappedName = userName;
-    }
+    if (!LinkInfo()->MapFragDataName(userName, &mappedName))
+        return -1;
 
     gl::GLContext* gl = mContext->GL();
     gl->MakeCurrent();
-
     return gl->fGetFragDataLocation(mGLName, mappedName.BeginReading());
 }
 
 void
 WebGLProgram::GetProgramInfoLog(nsAString* const out) const
 {
     CopyASCIItoUTF16(mLinkLog, *out);
 }
@@ -730,33 +740,19 @@ WebGLProgram::GetUniformBlockIndex(const
 
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("getUniformBlockIndex: `program` must be linked.");
         return LOCAL_GL_INVALID_INDEX;
     }
 
     const NS_LossyConvertUTF16toASCII userName(userName_wide);
 
-    nsDependentCString baseUserName;
-    bool isArray;
-    size_t arrayIndex;
-    if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
-        return LOCAL_GL_INVALID_INDEX;
-
-    const webgl::UniformBlockInfo* info;
-    if (!LinkInfo()->FindUniformBlock(baseUserName, &info)) {
+    nsCString mappedName;
+    if (!LinkInfo()->MapUniformBlockName(userName, &mappedName))
         return LOCAL_GL_INVALID_INDEX;
-    }
-
-    nsAutoCString mappedName(info->mBaseMappedName);
-    if (isArray) {
-        mappedName.AppendLiteral("[");
-        mappedName.AppendInt(uint32_t(arrayIndex));
-        mappedName.AppendLiteral("]");
-    }
 
     gl::GLContext* gl = mContext->GL();
     gl->MakeCurrent();
 
     return gl->fGetUniformBlockIndex(mGLName, mappedName.BeginReading());
 }
 
 void
@@ -862,39 +858,26 @@ WebGLProgram::GetUniformLocation(const n
 
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("getUniformLocation: `program` must be linked.");
         return nullptr;
     }
 
     const NS_LossyConvertUTF16toASCII userName(userName_wide);
 
-    nsDependentCString baseUserName;
-    bool isArray = false;
     // GLES 2.0.25, Section 2.10, p35
     // If the the uniform location is an array, then the location of the first
     // element of that array can be retrieved by either using the name of the
     // uniform array, or the name of the uniform array appended with "[0]".
-    // The ParseName() can't recognize this rule. So always initialize
-    // arrayIndex with 0.
-    size_t arrayIndex = 0;
-    if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
-        return nullptr;
-
+    nsCString mappedName;
+    size_t arrayIndex;
     webgl::UniformInfo* info;
-    if (!LinkInfo()->FindUniform(baseUserName, &info))
+    if (!LinkInfo()->FindUniform(userName, &mappedName, &arrayIndex, &info))
         return nullptr;
 
-    nsAutoCString mappedName(info->mActiveInfo->mBaseMappedName);
-    if (isArray) {
-        mappedName.AppendLiteral("[");
-        mappedName.AppendInt(uint32_t(arrayIndex));
-        mappedName.AppendLiteral("]");
-    }
-
     gl::GLContext* gl = mContext->GL();
     gl->MakeCurrent();
 
     GLint loc = gl->fGetUniformLocation(mGLName, mappedName.BeginReading());
     if (loc == -1)
         return nullptr;
 
     RefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
@@ -916,46 +899,32 @@ WebGLProgram::GetUniformIndices(const do
     nsTArray<GLuint>& arr = retval.SetValue();
 
     gl::GLContext* gl = mContext->GL();
     gl->MakeCurrent();
 
     for (size_t i = 0; i < count; i++) {
         const NS_LossyConvertUTF16toASCII userName(uniformNames[i]);
 
-        nsDependentCString baseUserName;
-        bool isArray;
+        nsCString mappedName;
         size_t arrayIndex;
-        if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex)) {
-            arr.AppendElement(LOCAL_GL_INVALID_INDEX);
-            continue;
-        }
-
         webgl::UniformInfo* info;
-        if (!LinkInfo()->FindUniform(baseUserName, &info)) {
+        if (!LinkInfo()->FindUniform(userName, &mappedName, &arrayIndex, &info)) {
             arr.AppendElement(LOCAL_GL_INVALID_INDEX);
             continue;
         }
 
-        nsAutoCString mappedName(info->mActiveInfo->mBaseMappedName);
-        if (isArray) {
-            mappedName.AppendLiteral("[");
-            mappedName.AppendInt(uint32_t(arrayIndex));
-            mappedName.AppendLiteral("]");
-        }
+        const GLchar* const mappedNameBegin = mappedName.get();
 
-        const GLchar* mappedNameBytes = mappedName.BeginReading();
-
-        GLuint index = 0;
-        gl->fGetUniformIndices(mGLName, 1, &mappedNameBytes, &index);
+        GLuint index = LOCAL_GL_INVALID_INDEX;
+        gl->fGetUniformIndices(mGLName, 1, &mappedNameBegin, &index);
         arr.AppendElement(index);
     }
 }
 
-
 void
 WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex,
                                   GLuint uniformBlockBinding) const
 {
     const char funcName[] = "getActiveUniformBlockName";
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("%s: `program` must be linked.", funcName);
         return;
@@ -1506,55 +1475,120 @@ WebGLProgram::EnumerateFragOutputs(std::
     MOZ_ASSERT(mFragShader);
 
     mFragShader->EnumerateFragOutputs(out_FragOutputs);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 bool
-webgl::LinkedProgramInfo::FindAttrib(const nsCString& baseUserName,
+IsBaseName(const nsCString& name)
+{
+    if (!name.Length())
+        return true;
+
+    return name[name.Length() - 1] != ']'; // Doesn't end in ']'.
+}
+
+bool
+webgl::LinkedProgramInfo::FindAttrib(const nsCString& userName,
                                      const webgl::AttribInfo** const out) const
 {
+    // VS inputs cannot be arrays or structures.
+    // `userName` is thus always `baseUserName`.
     for (const auto& attrib : attribs) {
-        if (attrib.mActiveInfo->mBaseUserName == baseUserName) {
+        if (attrib.mActiveInfo->mBaseUserName == userName) {
             *out = &attrib;
             return true;
         }
     }
 
     return false;
 }
 
 bool
-webgl::LinkedProgramInfo::FindUniform(const nsCString& baseUserName,
-                                      webgl::UniformInfo** const out) const
+webgl::LinkedProgramInfo::FindUniform(const nsCString& userName,
+                                      nsCString* const out_mappedName,
+                                      size_t* const out_arrayIndex,
+                                      webgl::UniformInfo** const out_info) const
 {
+    nsCString baseUserName;
+    bool isArray;
+    size_t arrayIndex;
+    if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
+        return false;
+
+    webgl::UniformInfo* info = nullptr;
     for (const auto& uniform : uniforms) {
         if (uniform->mActiveInfo->mBaseUserName == baseUserName) {
-            *out = uniform;
-            return true;
+            info = uniform;
+            break;
         }
     }
+    if (!info)
+        return false;
 
-    return false;
+    const auto& baseMappedName = info->mActiveInfo->mBaseMappedName;
+    AssembleName(baseMappedName, isArray, arrayIndex, out_mappedName);
+
+    *out_arrayIndex = arrayIndex;
+    *out_info = info;
+    return true;
 }
 
 bool
-webgl::LinkedProgramInfo::FindUniformBlock(const nsCString& baseUserName,
-                                           const webgl::UniformBlockInfo** const out) const
+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) {
-            *out = block;
-            return true;
+            info = block;
+            break;
         }
     }
+    if (!info)
+        return false;
 
-    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;
+        return true;
+    }
+
+    nsCString baseUserName;
+    bool isArray;
+    size_t arrayIndex;
+    if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex))
+        return false;
+
+    const auto itr = fragDataMap.find(baseUserName);
+    if (itr == fragDataMap.end())
+        return false;
+
+    const auto& baseMappedName = itr->second;
+    AssembleName(baseMappedName, isArray, arrayIndex, out_mappedName);
+    return true;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 JSObject*
 WebGLProgram::WrapObject(JSContext* js, JS::Handle<JSObject*> givenProto)
 {
     return dom::WebGLProgramBinding::Wrap(js, this, givenProto);
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -100,33 +100,23 @@ struct LinkedProgramInfo final
     //////
 
     // The maps for the frag data names to the translated names.
     std::map<nsCString, const nsCString> fragDataMap;
 
     explicit LinkedProgramInfo(WebGLProgram* prog);
     ~LinkedProgramInfo();
 
-    bool FindAttrib(const nsCString& baseUserName, const AttribInfo** const out) const;
-    bool FindUniform(const nsCString& baseUserName, UniformInfo** const out) const;
-    bool FindUniformBlock(const nsCString& baseUserName,
-                          const UniformBlockInfo** const out) const;
-
-    bool
-    FindFragData(const nsCString& baseUserName,
-                 nsCString* const out_baseMappedName) const
-    {
-        const auto itr = fragDataMap.find(baseUserName);
-        if (itr == fragDataMap.end()) {
-            return false;
-        }
-
-        *out_baseMappedName = itr->second;
-        return true;
-    }
+    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
     , public WebGLRefCountedObject<WebGLProgram>
     , public LinkedListElement<WebGLProgram>