Bug 1207288. Ask ANGLE for the correct output version. r=jgilbert
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Fri, 27 Nov 2015 15:54:50 -0500
changeset 309409 cb6196bdba35102ff645918e1139199a4def84c2
parent 309408 c6bacc29209b5a8afb28b296b1647ab461478ba6
child 309410 232826e2ee72cfaf2bb192d44c3ef04d7a57f8a7
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-beta@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1207288
milestone45.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1207288. Ask ANGLE for the correct output version. r=jgilbert
dom/canvas/WebGLShader.cpp
dom/canvas/WebGLShaderValidator.cpp
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
--- a/dom/canvas/WebGLShader.cpp
+++ b/dom/canvas/WebGLShader.cpp
@@ -88,21 +88,19 @@ TranslateWithoutValidation(const nsACStr
         glesslVersion = 100;
     }
 
     std::string reversionedSource = source;
     reversionedSource.erase(versionStrStart, versionStrLen);
 
     switch (glesslVersion) {
     case 100:
-        if (!versionStrLen) {
-            /* According to ARB_ES2_compatibility extension glsl
-             * should accept #version 100 for ES 2 shaders. */
-            reversionedSource.insert(versionStrStart, "#version 100\n");
-        }
+        /* According to ARB_ES2_compatibility extension glsl
+         * should accept #version 100 for ES 2 shaders. */
+        reversionedSource.insert(versionStrStart, "#version 100\n");
         break;
     case 300:
         reversionedSource.insert(versionStrStart, "#version 330\n");
         break;
     default:
         MOZ_CRASH("Bad `glesslVersion`.");
     }
 
--- a/dom/canvas/WebGLShaderValidator.cpp
+++ b/dom/canvas/WebGLShaderValidator.cpp
@@ -88,26 +88,52 @@ ChooseValidatorCompileOptions(const ShBu
 
     return options;
 }
 
 } // namespace webgl
 
 ////////////////////////////////////////
 
+static ShShaderOutput
+ShaderOutput(gl::GLContext* gl)
+{
+    if (gl->IsGLES()) {
+        return SH_ESSL_OUTPUT;
+    } else {
+        uint32_t version = gl->ShadingLanguageVersion();
+        switch (version) {
+        case 100: return SH_GLSL_COMPATIBILITY_OUTPUT;
+        case 120: return SH_GLSL_COMPATIBILITY_OUTPUT;
+        case 130: return SH_GLSL_130_OUTPUT;
+        case 140: return SH_GLSL_140_OUTPUT;
+        case 150: return SH_GLSL_150_CORE_OUTPUT;
+        case 330: return SH_GLSL_330_CORE_OUTPUT;
+        case 400: return SH_GLSL_400_CORE_OUTPUT;
+        case 410: return SH_GLSL_410_CORE_OUTPUT;
+        case 420: return SH_GLSL_420_CORE_OUTPUT;
+        case 430: return SH_GLSL_430_CORE_OUTPUT;
+        case 440: return SH_GLSL_440_CORE_OUTPUT;
+        case 450: return SH_GLSL_450_CORE_OUTPUT;
+        default:
+            MOZ_CRASH("Unexpected GLSL version.");
+        }
+    }
+
+    return SH_GLSL_OUTPUT;
+}
+
 webgl::ShaderValidator*
 WebGLContext::CreateShaderValidator(GLenum shaderType) const
 {
     if (mBypassShaderValidation)
         return nullptr;
 
     ShShaderSpec spec = IsWebGL2() ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC;
-    ShShaderOutput outputLanguage = gl->IsGLES() ? SH_ESSL_OUTPUT
-                                                 : SH_GLSL_OUTPUT;
-
+    ShShaderOutput outputLanguage = ShaderOutput(gl);
     ShBuiltInResources resources;
     memset(&resources, 0, sizeof(resources));
     ShInitBuiltInResources(&resources);
 
     resources.HashFunction = webgl::IdentifierHashFunc;
 
     resources.MaxVertexAttribs = mGLMaxVertexAttribs;
     resources.MaxVertexUniformVectors = mGLMaxVertexUniformVectors;
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -175,16 +175,107 @@ static const char *sExtensionNames[] = {
     "GL_OES_texture_float_linear",
     "GL_OES_texture_half_float",
     "GL_OES_texture_half_float_linear",
     "GL_OES_texture_npot",
     "GL_OES_vertex_array_object"
 };
 
 static bool
+ParseGLSLVersion(GLContext* gl, uint32_t* out_version)
+{
+    if (gl->fGetError() != LOCAL_GL_NO_ERROR) {
+        MOZ_ASSERT(false, "An OpenGL error has been triggered before.");
+        return false;
+    }
+
+    /**
+     * OpenGL 2.x, 3.x, 4.x specifications:
+     *  The VERSION and SHADING_LANGUAGE_VERSION strings are laid out as follows:
+     *
+     *    <version number><space><vendor-specific information>
+     *
+     *  The version number is either of the form major_number.minor_number or
+     *  major_number.minor_number.release_number, where the numbers all have
+     *  one or more digits.
+     *
+     * SHADING_LANGUAGE_VERSION is *almost* identical to VERSION. The
+     * difference is that the minor version always has two digits and the
+     * prefix has an additional 'GLSL ES'
+     *
+     *
+     * OpenGL ES 2.0, 3.0 specifications:
+     *  The VERSION string is laid out as follows:
+     *
+     *     "OpenGL ES N.M vendor-specific information"
+     *
+     *  The version number is either of the form major_number.minor_number or
+     *  major_number.minor_number.release_number, where the numbers all have
+     *  one or more digits.
+     *
+     *
+     * Note:
+     *  We don't care about release_number.
+     */
+    const char* versionString = (const char*) gl->fGetString(LOCAL_GL_SHADING_LANGUAGE_VERSION);
+
+    if (gl->fGetError() != LOCAL_GL_NO_ERROR) {
+        MOZ_ASSERT(false, "glGetString(GL_SHADING_LANGUAGE_VERSION) has generated an error");
+        return false;
+    }
+
+    if (!versionString) {
+        // This happens on the Android emulators. We'll just return 100
+        *out_version = 100;
+        return true;
+    }
+
+    const char kGLESVersionPrefix[] = "OpenGL ES GLSL ES";
+    if (strncmp(versionString, kGLESVersionPrefix, strlen(kGLESVersionPrefix)) == 0)
+        versionString += strlen(kGLESVersionPrefix);
+
+    const char* itr = versionString;
+    char* end = nullptr;
+    auto majorVersion = strtol(itr, &end, 10);
+
+    if (!end) {
+        MOZ_ASSERT(false, "Failed to parse the GL major version number.");
+        return false;
+    }
+
+    if (*end != '.') {
+        MOZ_ASSERT(false, "Failed to parse GL's major-minor version number separator.");
+        return false;
+    }
+
+    // we skip the '.' between the major and the minor version
+    itr = end + 1;
+    end = nullptr;
+
+    auto minorVersion = strtol(itr, &end, 10);
+    if (!end) {
+        MOZ_ASSERT(false, "Failed to parse GL's minor version number.");
+        return false;
+    }
+
+    if (majorVersion <= 0 || majorVersion >= 100) {
+        MOZ_ASSERT(false, "Invalid major version.");
+        return false;
+    }
+
+    if (minorVersion < 0 || minorVersion >= 100) {
+        MOZ_ASSERT(false, "Invalid minor version.");
+        return false;
+    }
+
+    *out_version = (uint32_t) majorVersion * 100 + (uint32_t) minorVersion;
+    return true;
+}
+
+static bool
 ParseGLVersion(GLContext* gl, uint32_t* out_version)
 {
     if (gl->fGetError() != LOCAL_GL_NO_ERROR) {
         MOZ_ASSERT(false, "An OpenGL error has been triggered before.");
         return false;
     }
 
     /**
@@ -298,16 +389,17 @@ ParseGLVersion(GLContext* gl, uint32_t* 
 GLContext::GLContext(const SurfaceCaps& caps,
           GLContext* sharedContext,
           bool isOffscreen)
   : mInitialized(false),
     mIsOffscreen(isOffscreen),
     mContextLost(false),
     mVersion(0),
     mProfile(ContextProfile::Unknown),
+    mShadingLanguageVersion(0),
     mVendor(GLVendor::Other),
     mRenderer(GLRenderer::Other),
     mHasRobustness(false),
     mTopError(LOCAL_GL_NO_ERROR),
     mSharedContext(sharedContext),
     mCaps(caps),
     mScreen(nullptr),
     mLockedSurface(nullptr),
@@ -510,25 +602,30 @@ GLContext::InitWithPrefix(const char *pr
     mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
     MakeCurrent();
     if (mInitialized) {
         MOZ_ASSERT(mProfile != ContextProfile::Unknown);
 
         uint32_t version = 0;
         ParseGLVersion(this, &version);
 
+        uint32_t shadingLangVersion = 100;
+        ParseGLSLVersion(this, &shadingLangVersion);
+
         if (ShouldSpew()) {
             printf_stderr("OpenGL version detected: %u\n", version);
+            printf_stderr("OpenGL shading language version detected: %u\n", shadingLangVersion);
             printf_stderr("OpenGL vendor: %s\n", fGetString(LOCAL_GL_VENDOR));
             printf_stderr("OpenGL renderer: %s\n", fGetString(LOCAL_GL_RENDERER));
         }
 
         if (version >= mVersion) {
             mVersion = version;
         }
+
         // Don't fail if version < mVersion, see bug 999445,
         // Mac OSX 10.6/10.7 machines with Intel GPUs claim only OpenGL 1.4 but
         // have all the GL2+ extensions that we need.
     }
 
     // Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
     if (mInitialized) {
         if (IsGLES()) {
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -297,16 +297,20 @@ public:
     inline uint32_t Version() const {
         return mVersion;
     }
 
     const char* VersionString() const {
         return mVersionString.get();
     }
 
+    inline uint32_t ShadingLanguageVersion() const {
+        return mShadingLanguageVersion;
+    }
+
     GLVendor Vendor() const {
         return mVendor;
     }
 
     GLRenderer Renderer() const {
         return mRenderer;
     }
 
@@ -341,16 +345,18 @@ protected:
     /**
      * mVersion store the OpenGL's version, multiplied by 100. For example, if
      * the context is an OpenGL 2.1 context, mVersion value will be 210.
      */
     uint32_t mVersion;
     nsCString mVersionString;
     ContextProfile mProfile;
 
+    uint32_t mShadingLanguageVersion;
+
     GLVendor mVendor;
     GLRenderer mRenderer;
 
     void SetProfileVersion(ContextProfile profile, uint32_t version) {
         MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before"
                                   " initialization!");
         MOZ_ASSERT(profile != ContextProfile::Unknown &&
                    profile != ContextProfile::OpenGL,