Bug 1048747 - Cleanup how uniform interface blocks are handled. r=jgilbert
authorDan Glastonbury <dglastonbury@mozilla.com>
Wed, 18 Mar 2015 13:30:52 +1000
changeset 258396 7e2bf34ef49d70c69b5086ed5d34a84174f15eaa
parent 258378 1ff8096ab54b9b8e198f1cd8334503f3d752ecb5
child 258397 760d5062419a4974c25f9e13fabf410791843085
push id1636
push userahalberstadt@mozilla.com
push dateTue, 21 Apr 2015 14:13:18 +0000
reviewersjgilbert
bugs1048747
milestone40.0a1
Bug 1048747 - Cleanup how uniform interface blocks are handled. r=jgilbert
dom/canvas/WebGL2ContextUniforms.cpp
dom/canvas/WebGLActiveInfo.cpp
dom/canvas/WebGLProgram.cpp
dom/canvas/WebGLProgram.h
dom/canvas/WebGLShader.cpp
dom/canvas/WebGLShader.h
--- a/dom/canvas/WebGL2ContextUniforms.cpp
+++ b/dom/canvas/WebGL2ContextUniforms.cpp
@@ -6,18 +6,17 @@
 #include "WebGL2Context.h"
 #include "GLContext.h"
 #include "WebGLContext.h"
 #include "WebGLProgram.h"
 #include "WebGLVertexArray.h"
 #include "WebGLVertexAttribData.h"
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 
-using namespace mozilla;
-using namespace mozilla::dom;
+namespace mozilla {
 
 typedef union { GLint i; GLfloat f; GLuint u; } fi_t;
 
 static inline
 GLfloat PuntToFloat(GLint i)
 {
    fi_t tmp;
    tmp.i = i;
@@ -533,134 +532,70 @@ WebGL2Context::GetUniformBlockIndex(WebG
                                     const nsAString& uniformBlockName)
 {
     if (IsContextLost())
         return 0;
 
     if (!ValidateObject("getUniformBlockIndex: program", program))
         return 0;
 
-    // Leave this unchecked for now.
-
-    const NS_LossyConvertUTF16toASCII cname(uniformBlockName);
-
-    GLuint progname = program->mGLName;
-
-    MakeContextCurrent();
-    return gl->fGetUniformBlockIndex(progname, cname.BeginReading());
-}
-
-static bool
-GetUniformBlockActiveUniforms(gl::GLContext* gl, JSContext* cx,
-                              WebGL2Context* owner, GLuint progname,
-                              GLuint uniformBlockIndex,
-                              JS::MutableHandleObject out_array)
-{
-    GLint length = 0;
-    gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex,
-                                 LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &length);
-    JS::RootedObject obj(cx, Uint32Array::Create(cx, owner, length, nullptr));
-    if (!obj)
-        return false;
-
-    Uint32Array result;
-    DebugOnly<bool> inited = result.Init(obj);
-    MOZ_ASSERT(inited);
-    result.ComputeLengthAndData();
-    gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex,
-                                 LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
-                                 (GLint*) result.Data());
-
-    out_array.set(obj);
-    return true;
+    return program->GetUniformBlockIndex(uniformBlockName);
 }
 
 void
 WebGL2Context::GetActiveUniformBlockParameter(JSContext* cx, WebGLProgram* program,
                                               GLuint uniformBlockIndex, GLenum pname,
                                               Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval,
                                               ErrorResult& rv)
 {
     retval.SetNull();
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getActiveUniformBlockParameter: program", program))
         return;
 
-    GLuint progname = program->mGLName;
-    GLint param = 0;
-
     MakeContextCurrent();
 
     switch(pname) {
     case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
     case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
-        gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, pname, &param);
-        retval.SetValue().SetAsBoolean() = (param != 0);
-        return;
-
     case LOCAL_GL_UNIFORM_BLOCK_BINDING:
     case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE:
-    case LOCAL_GL_UNIFORM_BLOCK_NAME_LENGTH:
     case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
-        gl->fGetActiveUniformBlockiv(progname, uniformBlockIndex, pname, &param);
-        retval.SetValue().SetAsUnsignedLong() = param;
+        program->GetActiveUniformBlockParam(uniformBlockIndex, pname, retval);
         return;
 
     case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
-        JS::RootedObject array(cx);
-        if (!GetUniformBlockActiveUniforms(gl, cx, this, progname, uniformBlockIndex,
-                                           &array))
-        {
-            rv = NS_ERROR_OUT_OF_MEMORY;
-            return;
-        }
-
-        DebugOnly<bool> inited = retval.SetValue().SetAsUint32Array().Init(array);
-        MOZ_ASSERT(inited);
-
+        program->GetActiveUniformBlockActiveUniforms(cx, uniformBlockIndex, retval, rv);
         return;
     }
 
     ErrorInvalidEnumInfo("getActiveUniformBlockParameter: parameter", pname);
 }
 
-#define WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH 256
-
 void
 WebGL2Context::GetActiveUniformBlockName(WebGLProgram* program, GLuint uniformBlockIndex,
                                          nsAString& retval)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("getActiveUniformBlockName: program", program))
         return;
 
-    GLuint progname = program->mGLName;
-    GLchar nameBuffer[WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH];
-    GLsizei length = 0;
-
-    MakeContextCurrent();
-    gl->fGetActiveUniformBlockName(progname, uniformBlockIndex,
-                                   WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH, &length,
-                                   nameBuffer);
-    retval.Assign(NS_ConvertASCIItoUTF16(nsDependentCString(nameBuffer)));
+    program->GetActiveUniformBlockName(uniformBlockIndex, retval);
 }
 
-#undef WEBGL_MAX_UNIFORM_BLOCK_NAME_LENGTH
-
 void
 WebGL2Context::UniformBlockBinding(WebGLProgram* program, GLuint uniformBlockIndex,
                                    GLuint uniformBlockBinding)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObject("uniformBlockBinding: program", program))
         return;
 
-    GLuint progname = program->mGLName;
+    program->UniformBlockBinding(uniformBlockIndex, uniformBlockBinding);
+}
 
-    MakeContextCurrent();
-    gl->fUniformBlockBinding(progname, uniformBlockIndex, uniformBlockBinding);
-}
+} // namespace mozilla
--- a/dom/canvas/WebGLActiveInfo.cpp
+++ b/dom/canvas/WebGLActiveInfo.cpp
@@ -24,19 +24,19 @@ ElemSizeFromType(GLenum elemType)
     case LOCAL_GL_SAMPLER_2D_ARRAY:
     case LOCAL_GL_SAMPLER_2D_ARRAY_SHADOW:
     case LOCAL_GL_SAMPLER_CUBE_SHADOW:
     case LOCAL_GL_INT_SAMPLER_2D:
     case LOCAL_GL_INT_SAMPLER_3D:
     case LOCAL_GL_INT_SAMPLER_CUBE:
     case LOCAL_GL_INT_SAMPLER_2D_ARRAY:
     case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D:
-    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
     case LOCAL_GL_UNSIGNED_INT_SAMPLER_3D:
     case LOCAL_GL_UNSIGNED_INT_SAMPLER_CUBE:
+    case LOCAL_GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
         return 1;
 
     case LOCAL_GL_BOOL_VEC2:
     case LOCAL_GL_FLOAT_VEC2:
     case LOCAL_GL_INT_VEC2:
     case LOCAL_GL_UNSIGNED_INT_VEC2:
         return 2;
 
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -73,16 +73,26 @@ AddActiveInfo(WebGLContext* webgl, GLint
     nsRefPtr<WebGLActiveInfo> info = new WebGLActiveInfo(webgl, elemCount, elemType,
                                                          isArray, baseUserName,
                                                          baseMappedName);
     activeInfoList->push_back(info);
 
     infoLocMap->insert(std::make_pair(info->mBaseUserName, info.get()));
 }
 
+static void
+AddActiveBlockInfo(const nsACString& baseUserName,
+                   const nsACString& baseMappedName,
+                   std::vector<RefPtr<webgl::UniformBlockInfo>>* activeInfoList)
+{
+    RefPtr<webgl::UniformBlockInfo> info = new webgl::UniformBlockInfo(baseUserName, baseMappedName);
+
+    activeInfoList->push_back(info);
+}
+
 //#define DUMP_SHADERVAR_MAPPINGS
 
 static TemporaryRef<const webgl::LinkedProgramInfo>
 QueryProgramInfo(WebGLProgram* prog, gl::GLContext* gl)
 {
     RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
 
     GLuint maxAttribLenWithNull = 0;
@@ -92,19 +102,28 @@ QueryProgramInfo(WebGLProgram* prog, gl:
         maxAttribLenWithNull = 1;
 
     GLuint maxUniformLenWithNull = 0;
     gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH,
                       (GLint*)&maxUniformLenWithNull);
     if (maxUniformLenWithNull < 1)
         maxUniformLenWithNull = 1;
 
+    GLuint maxUniformBlockLenWithNull = 0;
+    if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
+        gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH,
+                          (GLint*)&maxUniformBlockLenWithNull);
+        if (maxUniformBlockLenWithNull < 1)
+            maxUniformBlockLenWithNull = 1;
+    }
+
 #ifdef DUMP_SHADERVAR_MAPPINGS
     printf_stderr("maxAttribLenWithNull: %d\n", maxAttribLenWithNull);
     printf_stderr("maxUniformLenWithNull: %d\n", maxUniformLenWithNull);
+    printf_stderr("maxUniformBlockLenWithNull: %d\n", maxUniformBlockLenWithNull);
 #endif
 
     // Attribs
 
     GLuint numActiveAttribs = 0;
     gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_ATTRIBUTES,
                       (GLint*)&numActiveAttribs);
 
@@ -199,16 +218,64 @@ QueryProgramInfo(WebGLProgram* prog, gl:
         printf_stderr("    lengthWithoutNull: %d\n", lengthWithoutNull);
         printf_stderr("    isArray: %d\n", (int)isArray);
 #endif
 
         AddActiveInfo(prog->Context(), elemCount, elemType, isArray, baseUserName,
                       baseMappedName, &info->activeUniforms, &info->uniformMap);
     }
 
+    // Uniform Blocks
+
+    if (gl->IsSupported(gl::GLFeature::uniform_buffer_object)) {
+        GLuint numActiveUniformBlocks = 0;
+        gl->fGetProgramiv(prog->mGLName, LOCAL_GL_ACTIVE_UNIFORM_BLOCKS,
+                          (GLint*)&numActiveUniformBlocks);
+
+        for (GLuint i = 0; i < numActiveAttribs; i++) {
+            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("Failed to parse `mappedName` received from driver.");
+
+            nsAutoCString baseUserName;
+            if (!prog->FindUniformBlockByMappedName(baseMappedName, &baseUserName, &isArray)) {
+                baseUserName = baseMappedName;
+
+                if (needsCheckForArrays && !isArray) {
+                    std::string mappedName = baseMappedName.BeginReading();
+                    mappedName += "[0]";
+
+                    GLuint loc = gl->fGetUniformBlockIndex(prog->mGLName, mappedName.c_str());
+                    if (loc != LOCAL_GL_INVALID_INDEX)
+                        isArray = true;
+                }
+            }
+
+#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
+
+            AddActiveBlockInfo(baseUserName, baseMappedName, &info->uniformBlocks);
+        }
+    }
+
     return info.forget();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 
 webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* aProg)
     : prog(aProg)
@@ -491,16 +558,151 @@ WebGLProgram::GetProgramParameter(GLenum
 
     default:
         mContext->ErrorInvalidEnumInfo("getProgramParameter: `pname`",
                                        pname);
         return JS::NullValue();
     }
 }
 
+GLuint
+WebGLProgram::GetUniformBlockIndex(const nsAString& userName_wide) const
+{
+    if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformBlockIndex"))
+        return LOCAL_GL_INVALID_INDEX;
+
+    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;
+
+    RefPtr<const webgl::UniformBlockInfo> info;
+    if (!LinkInfo()->FindUniformBlock(baseUserName, &info)) {
+        return LOCAL_GL_INVALID_INDEX;
+    }
+
+    const nsCString& baseMappedName = info->mBaseMappedName;
+    nsAutoCString mappedName(baseMappedName);
+    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
+WebGLProgram::GetActiveUniformBlockName(GLuint uniformBlockIndex, nsAString& retval) const
+{
+    if (!IsLinked()) {
+        mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
+        return;
+    }
+
+    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));
+}
+
+void
+WebGLProgram::GetActiveUniformBlockParam(GLuint uniformBlockIndex, GLenum pname,
+                                         Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval) const
+{
+    retval.SetNull();
+    if (!IsLinked()) {
+        mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked.");
+        return;
+    }
+
+    const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
+    GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
+    if (uniformBlockIndex >= uniformBlockCount) {
+        mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex);
+        return;
+    }
+
+    gl::GLContext* gl = mContext->GL();
+    GLint param = 0;
+
+    switch (pname) {
+    case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
+    case LOCAL_GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
+        gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, &param);
+        retval.SetValue().SetAsBoolean() = (param != 0);
+        return;
+
+    case LOCAL_GL_UNIFORM_BLOCK_BINDING:
+    case LOCAL_GL_UNIFORM_BLOCK_DATA_SIZE:
+    case LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
+        gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex, pname, &param);
+        retval.SetValue().SetAsUnsignedLong() = param;
+        return;
+    }
+}
+
+void
+WebGLProgram::GetActiveUniformBlockActiveUniforms(JSContext* cx, GLuint uniformBlockIndex,
+                                                  Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval,
+                                                  ErrorResult& rv) const
+{
+    if (!IsLinked()) {
+        mContext->ErrorInvalidOperation("getActiveUniformBlockParameter: `program` must be linked.");
+        return;
+    }
+
+    const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
+    GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
+    if (uniformBlockIndex >= uniformBlockCount) {
+        mContext->ErrorInvalidValue("getActiveUniformBlockParameter: index %u invalid.", uniformBlockIndex);
+        return;
+    }
+
+    gl::GLContext* gl = mContext->GL();
+    GLint activeUniformCount = 0;
+    gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex,
+                                 LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS,
+                                 &activeUniformCount);
+    JS::RootedObject obj(cx, dom::Uint32Array::Create(cx, mContext, activeUniformCount,
+                                                      nullptr));
+    if (!obj) {
+        rv = NS_ERROR_OUT_OF_MEMORY;
+        return;
+    }
+
+    dom::Uint32Array result;
+    DebugOnly<bool> inited = result.Init(obj);
+    MOZ_ASSERT(inited);
+    result.ComputeLengthAndData();
+    gl->fGetActiveUniformBlockiv(mGLName, uniformBlockIndex,
+                                 LOCAL_GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES,
+                                 (GLint*)result.Data());
+
+    inited = retval.SetValue().SetAsUint32Array().Init(obj);
+    MOZ_ASSERT(inited);
+}
+
 already_AddRefed<WebGLUniformLocation>
 WebGLProgram::GetUniformLocation(const nsAString& userName_wide) const
 {
     if (!ValidateGLSLVariableName(userName_wide, mContext, "getUniformLocation"))
         return nullptr;
 
     if (!IsLinked()) {
         mContext->ErrorInvalidOperation("getUniformLocation: `program` must be linked.");
@@ -535,16 +737,41 @@ WebGLProgram::GetUniformLocation(const n
     if (loc == -1)
         return nullptr;
 
     nsRefPtr<WebGLUniformLocation> locObj = new WebGLUniformLocation(mContext, LinkInfo(),
                                                                      loc, activeInfo);
     return locObj.forget();
 }
 
+void
+WebGLProgram::UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const
+{
+    if (!IsLinked()) {
+        mContext->ErrorInvalidOperation("getActiveUniformBlockName: `program` must be linked.");
+        return;
+    }
+
+    const webgl::LinkedProgramInfo* linkInfo = LinkInfo();
+    GLuint uniformBlockCount = (GLuint)linkInfo->uniformBlocks.size();
+    if (uniformBlockIndex >= uniformBlockCount) {
+        mContext->ErrorInvalidValue("getActiveUniformBlockName: index %u invalid.", uniformBlockIndex);
+        return;
+    }
+
+    if (uniformBlockBinding > mContext->mGLMaxUniformBufferBindings) {
+        mContext->ErrorInvalidEnum("getActiveUniformBlockName: binding %u invalid.", uniformBlockBinding);
+        return;
+    }
+
+    gl::GLContext* gl = mContext->GL();
+    gl->MakeCurrent();
+    gl->fUniformBlockBinding(mGLName, uniformBlockIndex, uniformBlockBinding);
+}
+
 bool
 WebGLProgram::LinkProgram()
 {
     mContext->InvalidateBufferFetching(); // we do it early in this function
     // as some of the validation below changes program state
 
     mLinkLog.Truncate();
     mMostRecentLinkInfo = nullptr;
@@ -702,16 +929,30 @@ WebGLProgram::FindUniformByMappedName(co
         return true;
 
     if (mFragShader->FindUniformByMappedName(mappedName, out_userName, out_isArray))
         return true;
 
     return false;
 }
 
+bool
+WebGLProgram::FindUniformBlockByMappedName(const nsACString& mappedName,
+                                           nsCString* const out_userName,
+                                           bool* const out_isArray) const
+{
+    if (mVertShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray))
+        return true;
+
+    if (mFragShader->FindUniformBlockByMappedName(mappedName, out_userName, out_isArray))
+        return true;
+
+    return false;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 JSObject*
 WebGLProgram::WrapObject(JSContext* js, JS::Handle<JSObject*> aGivenProto)
 {
     return dom::WebGLProgramBinding::Wrap(js, this, aGivenProto);
 }
 
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -4,47 +4,65 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGL_PROGRAM_H_
 #define WEBGL_PROGRAM_H_
 
 #include <map>
 #include "mozilla/CheckedInt.h"
 #include "mozilla/LinkedList.h"
+#include "mozilla/dom/WebGL2RenderingContextBinding.h"
 #include "nsString.h"
 #include "nsWrapperCache.h"
 #include <set>
 #include <vector>
 #include "WebGLObjectModel.h"
 #include "WebGLShader.h"
 
 namespace mozilla {
 
 class WebGLActiveInfo;
 class WebGLProgram;
 class WebGLUniformLocation;
 
 namespace webgl {
 
+struct UniformBlockInfo final
+    : public RefCounted<UniformBlockInfo>
+{
+    MOZ_DECLARE_REFCOUNTED_TYPENAME(UniformBlockInfo);
+
+    const nsCString mBaseUserName;
+    const nsCString mBaseMappedName;
+
+    UniformBlockInfo(const nsACString& baseUserName,
+                     const nsACString& baseMappedName)
+        : mBaseUserName(baseUserName)
+        , mBaseMappedName(baseMappedName)
+    {}
+};
+
 struct LinkedProgramInfo final
     : public RefCounted<LinkedProgramInfo>
     , public SupportsWeakPtr<LinkedProgramInfo>
 {
     MOZ_DECLARE_REFCOUNTED_TYPENAME(LinkedProgramInfo)
 
     WebGLProgram* const prog;
     std::vector<nsRefPtr<WebGLActiveInfo>> activeAttribs;
     std::vector<nsRefPtr<WebGLActiveInfo>> activeUniforms;
 
     // Needed for Get{Attrib,Uniform}Location. The keys for these are non-mapped
     // user-facing `GLActiveInfo::name`s, without any final "[0]".
     std::map<nsCString, const WebGLActiveInfo*> attribMap;
     std::map<nsCString, const WebGLActiveInfo*> uniformMap;
     std::map<nsCString, const nsCString>* fragDataMap;
 
+    std::vector<RefPtr<UniformBlockInfo>> uniformBlocks;
+
     // Needed for draw call validation.
     std::set<GLuint> activeAttribLocs;
 
     explicit LinkedProgramInfo(WebGLProgram* aProg);
 
     bool FindAttrib(const nsCString& baseUserName,
                     const WebGLActiveInfo** const out_activeInfo) const
     {
@@ -62,16 +80,30 @@ struct LinkedProgramInfo final
         auto itr = uniformMap.find(baseUserName);
         if (itr == uniformMap.end())
             return false;
 
         *out_activeInfo = itr->second;
         return true;
     }
 
+    bool FindUniformBlock(const nsCString& baseUserName,
+                          RefPtr<const UniformBlockInfo>* const out_info) const
+    {
+        const size_t count = uniformBlocks.size();
+        for (size_t i = 0; i < count; i++) {
+            if (baseUserName == uniformBlocks[i]->mBaseUserName) {
+                *out_info = uniformBlocks[i].get();
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     bool FindFragData(const nsCString& baseUserName,
                       nsCString* const out_baseMappedName) const
     {
         if (!fragDataMap) {
             *out_baseMappedName = baseUserName;
             return true;
         }
 
@@ -110,28 +142,40 @@ public:
     void DetachShader(WebGLShader* shader);
     already_AddRefed<WebGLActiveInfo> GetActiveAttrib(GLuint index) const;
     already_AddRefed<WebGLActiveInfo> GetActiveUniform(GLuint index) const;
     void GetAttachedShaders(nsTArray<nsRefPtr<WebGLShader>>* const out) const;
     GLint GetAttribLocation(const nsAString& name) const;
     GLint GetFragDataLocation(const nsAString& name) const;
     void GetProgramInfoLog(nsAString* const out) const;
     JS::Value GetProgramParameter(GLenum pname) const;
+    GLuint GetUniformBlockIndex(const nsAString& name) const;
+    void GetActiveUniformBlockName(GLuint uniformBlockIndex, nsAString& name) const;
+    void GetActiveUniformBlockParam(GLuint uniformBlockIndex, GLenum pname,
+                                    Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval) const;
+    void GetActiveUniformBlockActiveUniforms(JSContext* cx, GLuint uniformBlockIndex,
+                                             Nullable<dom::OwningUnsignedLongOrUint32ArrayOrBoolean>& retval,
+                                             ErrorResult& rv) const;
     already_AddRefed<WebGLUniformLocation> GetUniformLocation(const nsAString& name) const;
+    void UniformBlockBinding(GLuint uniformBlockIndex, GLuint uniformBlockBinding) const;
+
     bool LinkProgram();
     bool UseProgram() const;
     void ValidateProgram() 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,
+                                      bool* const out_isArray) const;
 
     bool IsLinked() const { return mMostRecentLinkInfo; }
 
     const webgl::LinkedProgramInfo* LinkInfo() const {
         return mMostRecentLinkInfo.get();
     }
 
     WebGLContext* GetParentObject() const {
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -340,16 +340,25 @@ WebGLShader::FindUniformByMappedName(con
     std::string userNameStr;
     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
+{
+    // TODO: Extract block information from shader validator.
+    return false;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Boilerplate
 
 JSObject*
 WebGLShader::WrapObject(JSContext* js, JS::Handle<JSObject*> aGivenProto)
 {
     return dom::WebGLShaderBinding::Wrap(js, this, aGivenProto);
 }
--- a/dom/canvas/WebGLShader.h
+++ b/dom/canvas/WebGLShader.h
@@ -46,16 +46,19 @@ public:
     bool CanLinkTo(const WebGLShader* prev, nsCString* const out_log) const;
     size_t CalcNumSamplerUniforms() 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,
+                                      bool* const out_isArray) const;
 
     bool IsCompiled() const {
         return mTranslationSuccessful && mCompilationSuccessful;
     }
 
     // Other funcs
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
     void Delete();