Bug 1136455 - Validate built-in varyings for invariance. - r=mtseng
authorJeff Gilbert <jgilbert@mozilla.com>
Sun, 17 Jul 2016 23:11:57 -0700
changeset 330734 b5bb0ea5c5c89315744395a6b8d1b88a735cc7eb
parent 330733 2d8e504f0e0c7f27c7caa913449e2036a2528f95
child 330735 2641a97051be6313b066d4dfc42321c380c005f4
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmtseng
bugs1136455
milestone50.0a1
Bug 1136455 - Validate built-in varyings for invariance. - r=mtseng MozReview-Commit-ID: KxIxc9MhPp8
dom/canvas/WebGLShaderValidator.cpp
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -6,17 +6,16 @@
 #include "WebGLShaderValidator.h"
 
 #include "angle/ShaderLang.h"
 #include "gfxPrefs.h"
 #include "GLContext.h"
 #include "mozilla/Preferences.h"
 #include "MurmurHash3.h"
 #include "nsPrintfCString.h"
-#include "nsTArray.h"
 #include <string>
 #include <vector>
 #include "WebGLContext.h"
 
 namespace mozilla {
 namespace webgl {
 
 uint64_t
@@ -284,81 +283,127 @@ ShaderValidator::CanLinkTo(const ShaderV
                     *out_log = error;
                     return false;
                 }
 
                 break;
             }
         }
     }
+
+    const auto& vertVaryings = ShGetVaryings(prev->mHandle);
+    const auto& fragVaryings = ShGetVaryings(mHandle);
+    if (!vertVaryings || !fragVaryings) {
+        nsPrintfCString error("Could not create varying list.");
+        *out_log = error;
+        return false;
+    }
+
     {
-        const std::vector<sh::Varying>* vertPtr = ShGetVaryings(prev->mHandle);
-        const std::vector<sh::Varying>* fragPtr = ShGetVaryings(mHandle);
-        if (!vertPtr || !fragPtr) {
-            nsPrintfCString error("Could not create varying list.");
-            *out_log = error;
-            return false;
-        }
+        std::vector<ShVariableInfo> staticUseVaryingList;
 
-        nsTArray<ShVariableInfo> staticUseVaryingList;
-
-        for (auto itrFrag = fragPtr->begin(); itrFrag != fragPtr->end(); ++itrFrag) {
-            const ShVariableInfo varInfo = { itrFrag->type,
-                                             (int)itrFrag->elementCount() };
+        for (const auto& fragVarying : *fragVaryings) {
+            const ShVariableInfo varInfo = { fragVarying.type,
+                                             (int)fragVarying.elementCount() };
 
             static const char prefix[] = "gl_";
-            if (StartsWith(itrFrag->name, prefix)) {
-                if (itrFrag->staticUse)
-                    staticUseVaryingList.AppendElement(varInfo);
-
+            if (StartsWith(fragVarying.name, prefix)) {
+                if (fragVarying.staticUse) {
+                    staticUseVaryingList.push_back(varInfo);
+                }
                 continue;
             }
 
             bool definedInVertShader = false;
             bool staticVertUse = false;
 
-            for (auto itrVert = vertPtr->begin(); itrVert != vertPtr->end(); ++itrVert) {
-                if (itrVert->name != itrFrag->name)
+            for (const auto& vertVarying : *vertVaryings) {
+                if (vertVarying.name != fragVarying.name)
                     continue;
 
-                if (!itrVert->isSameVaryingAtLinkTime(*itrFrag)) {
+                if (!vertVarying.isSameVaryingAtLinkTime(fragVarying)) {
                     nsPrintfCString error("Varying `%s`is not linkable between"
                                           " attached shaders.",
-                                          itrFrag->name.c_str());
+                                          fragVarying.name.c_str());
                     *out_log = error;
                     return false;
                 }
 
                 definedInVertShader = true;
-                staticVertUse = itrVert->staticUse;
+                staticVertUse = vertVarying.staticUse;
                 break;
             }
 
-            if (!definedInVertShader && itrFrag->staticUse) {
+            if (!definedInVertShader && fragVarying.staticUse) {
                 nsPrintfCString error("Varying `%s` has static-use in the frag"
                                       " shader, but is undeclared in the vert"
-                                      " shader.", itrFrag->name.c_str());
+                                      " shader.", fragVarying.name.c_str());
                 *out_log = error;
                 return false;
             }
 
-            if (staticVertUse && itrFrag->staticUse)
-                staticUseVaryingList.AppendElement(varInfo);
+            if (staticVertUse && fragVarying.staticUse) {
+                staticUseVaryingList.push_back(varInfo);
+            }
         }
 
         if (!ShCheckVariablesWithinPackingLimits(mMaxVaryingVectors,
-                                                 staticUseVaryingList.Elements(),
-                                                 staticUseVaryingList.Length()))
+                                                 staticUseVaryingList.data(),
+                                                 staticUseVaryingList.size()))
         {
             *out_log = "Statically used varyings do not fit within packing limits. (see"
                        " GLSL ES Specification 1.0.17, p111)";
             return false;
         }
     }
 
+    {
+        bool isInvariant_Position = false;
+        bool isInvariant_PointSize = false;
+        bool isInvariant_FragCoord = false;
+        bool isInvariant_PointCoord = false;
+
+        for (const auto& varying : *vertVaryings) {
+            if (varying.name == "gl_Position") {
+                isInvariant_Position = varying.isInvariant;
+            } else if (varying.name == "gl_PointSize") {
+                isInvariant_PointSize = varying.isInvariant;
+            }
+        }
+
+        for (const auto& varying : *fragVaryings) {
+            if (varying.name == "gl_FragCoord") {
+                isInvariant_FragCoord = varying.isInvariant;
+            } else if (varying.name == "gl_PointCoord") {
+                isInvariant_PointCoord = varying.isInvariant;
+            }
+        }
+
+        ////
+
+        const auto fnCanBuiltInsLink = [](bool vertIsInvariant, bool fragIsInvariant) {
+            if (vertIsInvariant)
+                return true;
+
+            return !fragIsInvariant;
+        };
+
+        if (!fnCanBuiltInsLink(isInvariant_Position, isInvariant_FragCoord)) {
+            *out_log = "gl_Position must be invariant if gl_FragCoord is. (see GLSL ES"
+                       " Specification 1.0.17, p39)";
+            return false;
+        }
+
+        if (!fnCanBuiltInsLink(isInvariant_PointSize, isInvariant_PointCoord)) {
+            *out_log = "gl_PointSize must be invariant if gl_PointCoord is. (see GLSL ES"
+                       " Specification 1.0.17, p39)";
+            return false;
+        }
+    }
+
     return true;
 }
 
 size_t
 ShaderValidator::CalcNumSamplerUniforms() const
 {
     size_t accum = 0;