Backed out changeset 58fe5a3d3c40 (bug 1290774) for causing build bustages on WebGLContextDraw. CLOSED TREE
authorCosmin Sabou <csabou@mozilla.com>
Fri, 01 Feb 2019 05:58:38 +0200
changeset 456358 d6cd114bf585f724c94c3b97959785230911cd51
parent 456357 36d845cdb7f0c001f0a8c38e87a41f8bceb71b3a
child 456359 9402c046690e11ebecc172778a24ec808ddbfb28
push idunknown
push userunknown
push dateunknown
bugs1290774
milestone67.0a1
backs out58fe5a3d3c403199b9ff87d2f5051fd6e0564a45
Backed out changeset 58fe5a3d3c40 (bug 1290774) for causing build bustages on WebGLContextDraw. CLOSED TREE
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextDraw.cpp
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/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -1514,17 +1514,16 @@ class WebGLContext : public nsICanvasRen
   uint32_t mGLMaxDrawBuffers = 0;
 
   uint32_t mGLMaxViewportDims[2];
 
  public:
   GLenum LastColorAttachmentEnum() const {
     return LOCAL_GL_COLOR_ATTACHMENT0 + mGLMaxColorAttachments - 1;
   }
-  const auto& GLMaxDrawBuffers() const { return mGLMaxDrawBuffers; }
 
   const decltype(mOptions)& Options() const { return mOptions; }
 
  protected:
   // Texture sizes are often not actually the GL values. Let's be explicit that
   // these are implementation limits.
   uint32_t mGLMaxTextureSize = 0;
   uint32_t mGLMaxCubeMapTextureSize = 0;
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -306,60 +306,16 @@ const webgl::CachedDrawFetchLimits* Vali
       // Technically we don't know that this will be updated yet, but we can
       // speculatively mark it.
       buffer->ResetLastUpdateFenceId();
     }
   }
 
   // -
 
-  const auto& fragOutputs = linkInfo->fragOutputs;
-  const auto fnValidateFragOutputType =
-      [&](const uint8_t loc, const webgl::TextureBaseType dstBaseType) {
-        const auto itr = fragOutputs.find(loc);
-        if (MOZ_UNLIKELY(itr == fragOutputs.end())) {
-          webgl->ErrorInvalidOperation(
-              "Program has no frag output at location %u, but"
-              " destination draw buffer has an attached"
-              " image.",
-              uint32_t(loc));
-          return false;
-        }
-
-        const auto& info = itr->second;
-        const auto& srcBaseType = info.baseType;
-        if (MOZ_UNLIKELY(dstBaseType != srcBaseType)) {
-          const auto& srcStr = ToString(srcBaseType);
-          const auto& dstStr = ToString(dstBaseType);
-          webgl->ErrorInvalidOperation(
-              "Program frag output at location %u is type %s,"
-              " but destination draw buffer is type %s.",
-              uint32_t(loc), srcStr, dstStr);
-          return false;
-        }
-        return true;
-      };
-
-  const auto& fb = webgl->mBoundDrawFramebuffer;
-  if (fb) {
-    for (const auto& attach : fb->ColorDrawBuffers()) {
-      const auto i =
-          uint8_t(attach->mAttachmentPoint - LOCAL_GL_COLOR_ATTACHMENT0);
-      const auto& imageInfo = attach->GetImageInfo();
-      if (!imageInfo) continue;
-      const auto& dstBaseType = imageInfo->mFormat->format->baseType;
-      if (!fnValidateFragOutputType(i, dstBaseType)) return nullptr;
-    }
-  } else {
-    if (!fnValidateFragOutputType(0, webgl::TextureBaseType::Float))
-      return nullptr;
-  }
-
-  // -
-
   const auto fetchLimits = linkInfo->GetDrawFetchLimits();
   if (!fetchLimits) return nullptr;
 
   if (instanceCount > fetchLimits->maxInstances) {
     webgl->ErrorInvalidOperation(
         "Instance fetch requires %u, but attribs only"
         " supply %u.",
         instanceCount, uint32_t(fetchLimits->maxInstances));
--- a/dom/canvas/WebGLProgram.cpp
+++ b/dom/canvas/WebGLProgram.cpp
@@ -10,17 +10,16 @@
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "mozilla/RefPtr.h"
 #include "nsPrintfCString.h"
 #include "WebGLActiveInfo.h"
 #include "WebGLBuffer.h"
 #include "WebGLContext.h"
 #include "WebGLShader.h"
-#include "WebGLShaderValidator.h"
 #include "WebGLTransformFeedback.h"
 #include "WebGLUniformLocation.h"
 #include "WebGLValidateStrings.h"
 #include "WebGLVertexArray.h"
 
 namespace mozilla {
 
 /* If `name`: "foo[3]"
@@ -157,48 +156,16 @@ webgl::UniformInfo::UniformInfo(WebGLAct
       mIsShadowSampler(IsShadowSampler(mActiveInfo->mElemType)) {
   if (mSamplerTexList) {
     mSamplerValues.assign(mActiveInfo->mElemCount, 0);
   }
 }
 
 //////////
 
-static webgl::TextureBaseType FragOutputBaseType(const GLenum type) {
-  switch (type) {
-    case LOCAL_GL_FLOAT:
-    case LOCAL_GL_FLOAT_VEC2:
-    case LOCAL_GL_FLOAT_VEC3:
-    case LOCAL_GL_FLOAT_VEC4:
-      return webgl::TextureBaseType::Float;
-
-    case LOCAL_GL_INT:
-    case LOCAL_GL_INT_VEC2:
-    case LOCAL_GL_INT_VEC3:
-    case LOCAL_GL_INT_VEC4:
-      return webgl::TextureBaseType::Int;
-
-    case LOCAL_GL_UNSIGNED_INT:
-    case LOCAL_GL_UNSIGNED_INT_VEC2:
-    case LOCAL_GL_UNSIGNED_INT_VEC3:
-    case LOCAL_GL_UNSIGNED_INT_VEC4:
-      return webgl::TextureBaseType::UInt;
-
-    default:
-      break;
-  }
-
-  const auto& str = EnumString(type);
-  gfxCriticalError() << "Unhandled enum for FragOutputBaseType: "
-                     << str.c_str();
-  return webgl::TextureBaseType::Float;
-}
-
-// -
-
 //#define DUMP_SHADERVAR_MAPPINGS
 
 static RefPtr<const webgl::LinkedProgramInfo> QueryProgramInfo(
     WebGLProgram* prog, gl::GLContext* gl) {
   WebGLContext* const webgl = prog->mContext;
 
   RefPtr<webgl::LinkedProgramInfo> info(new webgl::LinkedProgramInfo(prog));
 
@@ -466,76 +433,17 @@ static RefPtr<const webgl::LinkedProgram
       const RefPtr<WebGLActiveInfo> activeInfo = new WebGLActiveInfo(
           webgl, elemCount, elemType, isArray, baseUserName, mappedName);
       info->transformFeedbackVaryings.push_back(activeInfo);
     }
   }
 
   // Frag outputs
 
-  {
-    const auto& fragShader = prog->FragShader();
-    const auto& handle = fragShader->Validator()->Handle();
-    const auto version = sh::GetShaderVersion(handle);
-
-    const auto fnAddInfo = [&](const webgl::FragOutputInfo& x) {
-      info->fragOutputs.insert({x.loc, x});
-    };
-
-    if (version == 300) {
-      const auto& fragOutputs = sh::GetOutputVariables(handle);
-      if (fragOutputs) {
-        for (const auto& cur : *fragOutputs) {
-          auto loc = cur.location;
-          if (loc == -1) loc = 0;
-
-          const auto info = webgl::FragOutputInfo{
-              uint8_t(loc), nsCString(cur.name.c_str()),
-              nsCString(cur.mappedName.c_str()), FragOutputBaseType(cur.type)};
-          if (!cur.isArray()) {
-            fnAddInfo(info);
-            continue;
-          }
-          MOZ_ASSERT(cur.arraySizes.size() == 1);
-          for (uint32_t i = 0; i < cur.arraySizes[0]; ++i) {
-            const auto indexStr = nsPrintfCString("[%u]", i);
-
-            auto userName = info.userName;
-            userName.Append(indexStr);
-            auto mappedName = info.mappedName;
-            mappedName.Append(indexStr);
-
-            const auto indexedInfo = webgl::FragOutputInfo{
-                uint8_t(info.loc + i), userName, mappedName, info.baseType};
-            fnAddInfo(indexedInfo);
-          }
-        }
-      }
-    } else {
-      // ANGLE's translator doesn't tell us about non-user frag outputs. :(
-
-      const auto& translatedSource = fragShader->TranslatedSource();
-      uint32_t drawBuffers = 1;
-      if (translatedSource.Find("(gl_FragData[1]") != -1 ||
-          translatedSource.Find("(webgl_FragData[1]") != -1) {
-        // The matching with the leading '(' prevents cleverly-named user vars breaking this.
-        // Since ANGLE initializes all outputs, if this is an MRT shader,
-        // FragData[1] will be present. FragData[0] is valid for non-MRT
-        // shaders.
-        drawBuffers = webgl->GLMaxDrawBuffers();
-      }
-
-      for (uint32_t i = 0; i < drawBuffers; ++i) {
-        const auto& name = nsPrintfCString("gl_FragData[%u]", i);
-        const auto info = webgl::FragOutputInfo{uint8_t(i), name, name,
-                                                webgl::TextureBaseType::Float};
-        fnAddInfo(info);
-      }
-    }
-  }
+  prog->EnumerateFragOutputs(info->fragDataMap);
 
   return info;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 webgl::LinkedProgramInfo::LinkedProgramInfo(WebGLProgram* prog)
     : prog(prog),
@@ -836,31 +744,53 @@ GLint WebGLProgram::GetAttribLocation(co
   const NS_LossyConvertUTF16toASCII userName(userName_wide);
 
   const webgl::AttribInfo* info;
   if (!LinkInfo()->FindAttrib(userName, &info)) return -1;
 
   return GLint(info->mLoc);
 }
 
+static GLint GetFragDataByUserName(const WebGLProgram* prog,
+                                   const nsCString& userName) {
+  nsCString mappedName;
+  if (!prog->LinkInfo()->MapFragDataName(userName, &mappedName)) return -1;
+
+  return prog->mContext->gl->fGetFragDataLocation(prog->mGLName,
+                                                  mappedName.BeginReading());
+}
+
 GLint WebGLProgram::GetFragDataLocation(const nsAString& userName_wide) const {
   if (!ValidateGLSLVariableName(userName_wide, mContext)) return -1;
 
   if (!IsLinked()) {
     mContext->ErrorInvalidOperation("`program` must be linked.");
     return -1;
   }
 
   const NS_LossyConvertUTF16toASCII userName(userName_wide);
-  const auto& fragOutputs = LinkInfo()->fragOutputs;
-  for (const auto& pair : fragOutputs) {
-    const auto& info = pair.second;
-    if (info.userName == userName) return info.loc;
+#ifdef XP_MACOSX
+  const auto& gl = mContext->gl;
+  if (gl->WorkAroundDriverBugs()) {
+    // OSX doesn't return locs for indexed names, just the base names.
+    // Indicated by failure in:
+    // conformance2/programs/gl-get-frag-data-location.html
+    bool isArray;
+    size_t arrayIndex;
+    nsCString baseUserName;
+    if (!ParseName(userName, &baseUserName, &isArray, &arrayIndex)) return -1;
+
+    if (arrayIndex >= mContext->mGLMaxDrawBuffers) return -1;
+
+    const auto baseLoc = GetFragDataByUserName(this, baseUserName);
+    const auto loc = baseLoc + GLint(arrayIndex);
+    return loc;
   }
-  return -1;
+#endif
+  return GetFragDataByUserName(this, userName);
 }
 
 void WebGLProgram::GetProgramInfoLog(nsAString* const out) const {
   CopyASCIItoUTF16(mLinkLog, *out);
 }
 
 static GLint GetProgramiv(gl::GLContext* gl, GLuint program, GLenum pname) {
   GLint ret = 0;
@@ -1609,16 +1539,23 @@ bool WebGLProgram::UnmapUniformBlockName
       !mFragShader->UnmapUniformBlockName(baseMappedName, &baseUserName)) {
     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);
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 bool IsBaseName(const nsCString& name) {
   if (!name.Length()) return true;
 
   return name[name.Length() - 1] != ']';  // Doesn't end in ']'.
 }
 
@@ -1656,16 +1593,39 @@ bool webgl::LinkedProgramInfo::FindUnifo
   const auto& baseMappedName = info->mActiveInfo->mBaseMappedName;
   AssembleName(baseMappedName, isArray, arrayIndex, out_mappedName);
 
   *out_arrayIndex = arrayIndex;
   *out_info = info;
   return true;
 }
 
+bool webgl::LinkedProgramInfo::MapFragDataName(
+    const nsCString& userName, nsCString* const out_mappedName) const {
+  // FS outputs can be arrays, but not structures.
+
+  if (fragDataMap.empty()) {
+    // 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::WebGLProgram_Binding::Wrap(js, this, givenProto);
 }
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLProgram, mVertShader, mFragShader)
--- a/dom/canvas/WebGLProgram.h
+++ b/dom/canvas/WebGLProgram.h
@@ -72,23 +72,16 @@ struct UniformBlockInfo final {
   UniformBlockInfo(WebGLContext* webgl, const nsACString& userName,
                    const nsACString& mappedName, uint32_t dataSize)
       : mUserName(userName),
         mMappedName(mappedName),
         mDataSize(dataSize),
         mBinding(&webgl->mIndexedUniformBufferBindings[0]) {}
 };
 
-struct FragOutputInfo final {
-  const uint8_t loc;
-  const nsCString userName;
-  const nsCString mappedName;
-  const TextureBaseType baseType;
-};
-
 struct CachedDrawFetchLimits final {
   uint64_t maxVerts;
   uint64_t maxInstances;
 };
 
 struct LinkedProgramInfo final : public RefCounted<LinkedProgramInfo>,
                                  public SupportsWeakPtr<LinkedProgramInfo>,
                                  public CacheInvalidator {
@@ -101,42 +94,48 @@ struct LinkedProgramInfo final : public 
 
   WebGLProgram* const prog;
   const GLenum transformFeedbackBufferMode;
 
   std::vector<AttribInfo> attribs;
   std::vector<UniformInfo*> uniforms;            // Owns its contents.
   std::vector<UniformBlockInfo*> uniformBlocks;  // Owns its contents.
   std::vector<RefPtr<WebGLActiveInfo>> transformFeedbackVaryings;
-  std::unordered_map<uint8_t, const FragOutputInfo> fragOutputs;
 
   // Needed for draw call validation.
   std::vector<UniformInfo*> uniformSamplers;
 
   mutable std::vector<size_t> componentsPerTFVert;
 
   bool attrib0Active;
 
   //////
 
+  // The maps for the frag data names to the translated names.
+  std::map<nsCString, const nsCString> fragDataMap;
+
+  //////
+
   mutable CacheWeakMap<const WebGLVertexArray*, CachedDrawFetchLimits>
       mDrawFetchCache;
 
   const CachedDrawFetchLimits* GetDrawFetchLimits() const;
 
   //////
 
   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 MapFragDataName(const nsCString& userName,
+                       nsCString* const out_mappedName) const;
 };
 
 }  // namespace webgl
 
 class WebGLProgram final : public nsWrapperCache,
                            public WebGLRefCountedObject<WebGLProgram>,
                            public LinkedListElement<WebGLProgram> {
   friend class WebGLTransformFeedback;
@@ -202,18 +201,16 @@ class WebGLProgram final : public nsWrap
       std::map<nsCString, const nsCString>& out_FragOutputs) const;
 
   bool IsLinked() const { return mMostRecentLinkInfo; }
 
   const webgl::LinkedProgramInfo* LinkInfo() const {
     return mMostRecentLinkInfo.get();
   }
 
-  const auto& FragShader() const { return mFragShader; }
-
   WebGLContext* GetParentObject() const { return mContext; }
 
   virtual JSObject* WrapObject(JSContext* js,
                                JS::Handle<JSObject*> givenProto) override;
 
  private:
   ~WebGLProgram();
 
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -341,16 +341,26 @@ bool WebGLShader::UnmapUniformBlockName(
   if (!mValidator) {
     *out_baseUserName = baseMappedName;
     return true;
   }
 
   return mValidator->UnmapUniformBlockName(baseMappedName, out_baseUserName);
 }
 
+void WebGLShader::EnumerateFragOutputs(
+    std::map<nsCString, const nsCString>& out_FragOutputs) const {
+  out_FragOutputs.clear();
+
+  if (!mValidator) {
+    return;
+  }
+  mValidator->EnumerateFragOutputs(out_FragOutputs);
+}
+
 void WebGLShader::MapTransformFeedbackVaryings(
     const std::vector<nsString>& varyings,
     std::vector<std::string>* out_mappedVaryings) const {
   MOZ_ASSERT(mType == LOCAL_GL_VERTEX_SHADER);
   MOZ_ASSERT(out_mappedVaryings);
 
   out_mappedVaryings->clear();
   out_mappedVaryings->reserve(varyings.size());
--- a/dom/canvas/WebGLShader.h
+++ b/dom/canvas/WebGLShader.h
@@ -55,21 +55,22 @@ class WebGLShader final : public nsWrapp
                                nsCString* const out_userName,
                                bool* const out_isArray) const;
   bool FindUniformByMappedName(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;
   }
-  const auto* Validator() const { return mValidator.get(); }
-  const auto& TranslatedSource() const { return mTranslatedSource; }
 
  private:
   void BindAttribLocation(GLuint prog, const nsCString& userName,
                           GLuint index) const;
   void MapTransformFeedbackVaryings(
       const std::vector<nsString>& varyings,
       std::vector<std::string>* out_mappedVaryings) const;
 
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -567,10 +567,22 @@ bool ShaderValidator::UnmapUniformBlockN
       *out_baseUserName = interface.name.data();
       return true;
     }
   }
 
   return false;
 }
 
+void ShaderValidator::EnumerateFragOutputs(
+    std::map<nsCString, const nsCString>& out_FragOutputs) const {
+  const auto* fragOutputs = sh::GetOutputVariables(mHandle);
+
+  if (fragOutputs) {
+    for (const auto& fragOutput : *fragOutputs) {
+      out_FragOutputs.insert({nsCString(fragOutput.name.c_str()),
+                              nsCString(fragOutput.mappedName.c_str())});
+    }
+  }
+}
+
 }  // namespace webgl
 }  // namespace mozilla
--- a/dom/canvas/WebGLShaderValidator.h
+++ b/dom/canvas/WebGLShaderValidator.h
@@ -1,21 +1,20 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGL_SHADER_VALIDATOR_H_
 #define WEBGL_SHADER_VALIDATOR_H_
 
-#include <string>
-
+#include "GLSLANG/ShaderLang.h"
 #include "GLDefs.h"
-#include "GLSLANG/ShaderLang.h"
 #include "nsString.h"
+#include <string>
 
 namespace mozilla {
 namespace webgl {
 
 class ShaderValidator final {
   const ShHandle mHandle;
   const ShCompileOptions mCompileOptions;
   const int mMaxVaryingVectors;
@@ -39,17 +38,16 @@ class ShaderValidator final {
   ~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;
-  const auto& Handle() const { return mHandle; }
 
   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;
@@ -62,16 +60,19 @@ class ShaderValidator final {
                                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 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);
 };
 
 }  // namespace webgl
 }  // namespace mozilla