bug 899264 - Add OpenGL version and profile support in GLContext - r=jgilbert
authorGuillaume Abadie <gabadie@mozilla.com>
Thu, 01 Aug 2013 19:43:27 -0400
changeset 153302 ab3c575381b2f1d831b8552f8bbad7a80e107108
parent 153301 25fa0d94a5073f5bf1890dc65c9d9c249e4ac4d1
child 153303 d449bcecd71eab5a0d0714157fc049d6679d780a
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs899264
milestone25.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 899264 - Add OpenGL version and profile support in GLContext - r=jgilbert
gfx/gl/GLContext.cpp
gfx/gl/GLContext.h
gfx/gl/GLContextProviderCGL.mm
gfx/gl/GLContextProviderEGL.cpp
gfx/gl/GLContextProviderGLX.cpp
gfx/gl/GLContextProviderWGL.cpp
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -288,17 +288,17 @@ GLContext::InitWithPrefix(const char *pr
         { nullptr, { nullptr } },
 
     };
 
     mInitialized = LoadSymbols(&symbols[0], trygl, prefix);
 
     // Load OpenGL ES 2.0 symbols, or desktop if we aren't using ES 2.
     if (mInitialized) {
-        if (mIsGLES2) {
+        if (IsGLES2()) {
             SymLoadStruct symbols_ES2[] = {
                 { (PRFuncPtr*) &mSymbols.fGetShaderPrecisionFormat, { "GetShaderPrecisionFormat", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fClearDepthf, { "ClearDepthf", nullptr } },
                 { (PRFuncPtr*) &mSymbols.fDepthRangef, { "DepthRangef", nullptr } },
                 { nullptr, { nullptr } },
             };
 
             if (!LoadSymbols(&symbols_ES2[0], trygl, prefix)) {
@@ -1016,47 +1016,47 @@ GLContext::UpdatePixelFormat()
 GLFormats
 GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
 {
     GLFormats formats;
 
     // If we're on ES2 hardware and we have an explicit request for 16 bits of color or less
     // OR we don't support full 8-bit color, return a 4444 or 565 format.
     bool bpp16 = caps.bpp16;
-    if (mIsGLES2) {
+    if (IsGLES2()) {
         if (!IsExtensionSupported(OES_rgb8_rgba8))
             bpp16 = true;
     } else {
         // RGB565 is uncommon on desktop, requiring ARB_ES2_compatibility.
         // Since it's also vanishingly useless there, let's not support it.
         bpp16 = false;
     }
 
     if (bpp16) {
-        MOZ_ASSERT(mIsGLES2);
+        MOZ_ASSERT(IsGLES2());
         if (caps.alpha) {
             formats.color_texInternalFormat = LOCAL_GL_RGBA;
             formats.color_texFormat = LOCAL_GL_RGBA;
             formats.color_texType   = LOCAL_GL_UNSIGNED_SHORT_4_4_4_4;
             formats.color_rbFormat  = LOCAL_GL_RGBA4;
         } else {
             formats.color_texInternalFormat = LOCAL_GL_RGB;
             formats.color_texFormat = LOCAL_GL_RGB;
             formats.color_texType   = LOCAL_GL_UNSIGNED_SHORT_5_6_5;
             formats.color_rbFormat  = LOCAL_GL_RGB565;
         }
     } else {
         formats.color_texType = LOCAL_GL_UNSIGNED_BYTE;
 
         if (caps.alpha) {
-            formats.color_texInternalFormat = mIsGLES2 ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
+            formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGBA : LOCAL_GL_RGBA8;
             formats.color_texFormat = LOCAL_GL_RGBA;
             formats.color_rbFormat  = LOCAL_GL_RGBA8;
         } else {
-            formats.color_texInternalFormat = mIsGLES2 ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
+            formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
             formats.color_texFormat = LOCAL_GL_RGB;
             formats.color_rbFormat  = LOCAL_GL_RGB8;
         }
     }
 
     uint32_t msaaLevel = Preferences::GetUint("gl.msaa-level", 2);
     GLsizei samples = msaaLevel * msaaLevel;
     samples = std::min(samples, mMaxSamples);
@@ -1065,22 +1065,22 @@ GLContext::ChooseGLFormats(const Surface
     if (WorkAroundDriverBugs() && samples == 1) {
         samples = 0;
     }
     formats.samples = samples;
 
 
     // Be clear that these are 0 if unavailable.
     formats.depthStencil = 0;
-    if (!mIsGLES2 || IsExtensionSupported(OES_packed_depth_stencil)) {
+    if (!IsGLES2() || IsExtensionSupported(OES_packed_depth_stencil)) {
         formats.depthStencil = LOCAL_GL_DEPTH24_STENCIL8;
     }
 
     formats.depth = 0;
-    if (mIsGLES2) {
+    if (IsGLES2()) {
         if (IsExtensionSupported(OES_depth24)) {
             formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
         } else {
             formats.depth = LOCAL_GL_DEPTH_COMPONENT16;
         }
     } else {
         formats.depth = LOCAL_GL_DEPTH_COMPONENT24;
     }
@@ -2318,17 +2318,17 @@ static GLint GetAddressAlignment(ptrdiff
 }
 
 void
 GLContext::TexImage2D(GLenum target, GLint level, GLint internalformat,
                       GLsizei width, GLsizei height, GLsizei stride,
                       GLint pixelsize, GLint border, GLenum format,
                       GLenum type, const GLvoid *pixels)
 {
-    if (mIsGLES2) {
+    if (IsGLES2()) {
 
         NS_ASSERTION(format == (GLenum)internalformat,
                     "format and internalformat not the same for glTexImage2D on GLES2");
 
         if (!CanUploadNonPowerOfTwo()
             && (stride != width * pixelsize
             || !IsPowerOfTwo(width)
             || !IsPowerOfTwo(height))) {
@@ -2425,17 +2425,17 @@ GLContext::TexImage2D(GLenum target, GLi
 
 void
 GLContext::TexSubImage2D(GLenum target, GLint level,
                          GLint xoffset, GLint yoffset,
                          GLsizei width, GLsizei height, GLsizei stride,
                          GLint pixelsize, GLenum format,
                          GLenum type, const GLvoid* pixels)
 {
-    if (mIsGLES2) {
+    if (IsGLES2()) {
         if (stride == width * pixelsize) {
             fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT,
                     std::min(GetAddressAlignment((ptrdiff_t)pixels),
                             GetAddressAlignment((ptrdiff_t)stride)));
             fTexSubImage2D(target,
                           level,
                           xoffset,
                           yoffset,
--- a/gfx/gl/GLContext.h
+++ b/gfx/gl/GLContext.h
@@ -79,16 +79,25 @@ namespace mozilla {
         class LayerManagerOGL;
     }
 }
 
 namespace mozilla {
 namespace gl {
 typedef uintptr_t SharedTextureHandle;
 
+MOZ_BEGIN_ENUM_CLASS(ContextProfile, uint8_t)
+    Unknown = 0,
+    OpenGL, // only for IsAtLeast's <profile> parameter
+    OpenGLCore,
+    OpenGLCompatibility,
+    OpenGLES
+MOZ_END_ENUM_CLASS(ContextProfile)
+
+
 class GLContext
     : public GLLibraryLoader
     , public GenericAtomicRefCounted
 {
 // -----------------------------------------------------------------------------
 // basic enums
 public:
 
@@ -135,16 +144,95 @@ public:
     /**
      * Returns true if the context is using ANGLE. This should only be overridden
      * for an ANGLE implementation.
      */
     virtual bool IsANGLE() {
         return false;
     }
 
+    /**
+     * Return true if we are running on a OpenGL core profile context
+     */
+    inline bool IsCoreProfile() const {
+        MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile");
+
+        return mProfile == ContextProfile::OpenGLCore;
+    }
+
+    /**
+     * Return true if we are running on a OpenGL compatibility profile context
+     * (legacy profile 2.1 on Max OS X)
+     */
+    inline bool IsCompatibilityProfile() const {
+        MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile");
+
+        return mProfile == ContextProfile::OpenGLCompatibility;
+    }
+
+    /**
+     * Return true if the context is a true OpenGL ES context or an ANGLE context
+     */
+    inline bool IsGLES() const {
+        MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile");
+
+        return mProfile == ContextProfile::OpenGLES;
+    }
+
+    static const char* GetProfileName(ContextProfile profile)
+    {
+        switch (profile)
+        {
+            case ContextProfile::OpenGL:
+                return "OpenGL";
+            case ContextProfile::OpenGLCore:
+                return "OpenGL Core";
+            case ContextProfile::OpenGLCompatibility:
+                return "OpenGL Compatibility";
+            case ContextProfile::OpenGLES:
+                return "OpenGL ES";
+            default:
+                break;
+        }
+
+        MOZ_ASSERT(profile != ContextProfile::Unknown, "unknown context profile");
+        return "OpenGL unknown profile";
+    }
+
+    /**
+     * Return true if the context is compatible with given parameters
+     *
+     * IsAtLeast(ContextProfile::OpenGL, N) is exactly same as
+     * IsAtLeast(ContextProfile::OpenGLCore, N) || IsAtLeast(ContextProfile::OpenGLCompatibility, N)
+     */
+    inline bool IsAtLeast(ContextProfile profile, unsigned int version) const
+    {
+        MOZ_ASSERT(profile != ContextProfile::Unknown, "IsAtLeast: bad <profile> parameter");
+        MOZ_ASSERT(mProfile != ContextProfile::Unknown, "unknown context profile");
+        MOZ_ASSERT(mVersion != 0, "unknown context version");
+
+        if (profile == ContextProfile::OpenGL) {
+            return (profile == ContextProfile::OpenGLCore ||
+                    profile == ContextProfile::OpenGLCompatibility) &&
+                   version >= mVersion;
+        }
+
+        return profile == mProfile &&
+               version >= mVersion;
+    }
+
+    /**
+     * Return the version of the context.
+     * Example :
+     *   If this a OpenGL 2.1, that will return 210
+     */
+    inline unsigned int Version() const {
+        return mVersion;
+    }
+
     int Vendor() const {
         return mVendor;
     }
 
     int Renderer() const {
         return mRenderer;
     }
 
@@ -166,17 +254,17 @@ public:
     virtual bool IsCurrent() = 0;
 
     /**
      * If this context is the GLES2 API, returns TRUE.
      * This means that various GLES2 restrictions might be in effect (modulo
      * extensions).
      */
     inline bool IsGLES2() const {
-        return mIsGLES2;
+        return IsAtLeast(ContextProfile::OpenGLES, 200);
     }
 
     /**
      * Returns true if either this is the GLES2 API, or had the GL_ARB_ES2_compatibility extension
      * We would like to introduce a XXX_ES2_compatibility
      */
     bool HasES2Compatibility() const {
         return IsGLES2() || IsExtensionSupported(ARB_ES2_compatibility);
@@ -184,24 +272,34 @@ public:
 
 
 protected:
 
     bool mInitialized;
     bool mIsOffscreen;
     bool mIsGlobalSharedContext;
     bool mContextLost;
-    bool mIsGLES2;
+
+    /**
+     * 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.
+     */
+    unsigned int mVersion;
+    ContextProfile mProfile;
 
     int32_t mVendor;
     int32_t mRenderer;
 
-    inline void SetIsGLES2(bool isGLES2) {
-        MOZ_ASSERT(!mInitialized, "SetIsGLES2 can only be called before initialization!");
-        mIsGLES2 = isGLES2;
+    inline void SetProfileVersion(ContextProfile profile, unsigned int version) {
+        MOZ_ASSERT(!mInitialized, "SetProfileVersion can only be called before initialization!");
+        MOZ_ASSERT(profile != ContextProfile::Unknown && profile != ContextProfile::OpenGL, "Invalid `profile` for SetProfileVersion");
+        MOZ_ASSERT(version >= 100, "Invalid `version` for SetProfileVersion");
+
+        mVersion = version;
+        mProfile = profile;
     }
 
 
 // -----------------------------------------------------------------------------
 // Extensions management
 /**
  * This mechanism is designed to know if an extension is supported. In the long
  * term, we would like to only use the extension group queries XXX_* to have
@@ -2114,17 +2212,18 @@ public:
 protected:
     GLContext(const SurfaceCaps& caps,
               GLContext* sharedContext = nullptr,
               bool isOffscreen = false)
       : mInitialized(false),
         mIsOffscreen(isOffscreen),
         mIsGlobalSharedContext(false),
         mContextLost(false),
-        mIsGLES2(false),
+        mVersion(0),
+        mProfile(ContextProfile::Unknown),
         mVendor(-1),
         mRenderer(-1),
         mHasRobustness(false),
 #ifdef DEBUG
         mGLError(LOCAL_GL_NO_ERROR),
 #endif
         mTexBlit_Buffer(0),
         mTexBlit_VertShader(0),
--- a/gfx/gl/GLContextProviderCGL.mm
+++ b/gfx/gl/GLContextProviderCGL.mm
@@ -89,17 +89,19 @@ class GLContextCGL : public GLContext
 public:
     GLContextCGL(const SurfaceCaps& caps,
                  GLContext *shareContext,
                  NSOpenGLContext *context,
                  bool isOffscreen = false)
         : GLContext(caps, shareContext, isOffscreen),
           mContext(context),
           mTempTextureName(0)
-    {}
+    {
+        SetProfileVersion(ContextProfile::OpenGLCompatibility, 210);
+    }
 
     ~GLContextCGL()
     {
         MarkDestroyed();
 
         if (mContext)
             [mContext release];
     }
--- a/gfx/gl/GLContextProviderEGL.cpp
+++ b/gfx/gl/GLContextProviderEGL.cpp
@@ -265,17 +265,17 @@ public:
         , mBound(false)
         , mIsPBuffer(false)
         , mIsDoubleBuffered(false)
         , mCanBindToTexture(false)
         , mShareWithEGLImage(false)
         , mTemporaryEGLImageTexture(0)
     {
         // any EGL contexts will always be GLESv2
-        SetIsGLES2(true);
+        SetProfileVersion(ContextProfile::OpenGLES, 200);
 
 #ifdef DEBUG
         printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
 #endif
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION <= 15
         if (!mIsOffscreen) {
             mHwc = HwcComposer2D::GetInstance();
             MOZ_ASSERT(!mHwc->Initialized());
--- a/gfx/gl/GLContextProviderGLX.cpp
+++ b/gfx/gl/GLContextProviderGLX.cpp
@@ -961,16 +961,18 @@ private:
           mDrawable(aDrawable),
           mDeleteDrawable(aDeleteDrawable),
           mDoubleBuffered(aDoubleBuffered),
           mLibType(libType),
           mGLX(&sGLXLibrary[libType]),
           mPixmap(aPixmap)
     {
         MOZ_ASSERT(mGLX);
+        // See 899855
+        SetProfileVersion(ContextProfile::OpenGLCompatibility, 200);
     }
 
     GLXContext mContext;
     Display *mDisplay;
     GLXDrawable mDrawable;
     bool mDeleteDrawable;
     bool mDoubleBuffered;
 
--- a/gfx/gl/GLContextProviderWGL.cpp
+++ b/gfx/gl/GLContextProviderWGL.cpp
@@ -267,16 +267,18 @@ public:
           mDC(aDC),
           mContext(aContext),
           mWnd(aWindow),
           mPBuffer(nullptr),
           mPixelFormat(0),
           mLibType(aLibUsed),
           mIsDoubleBuffered(false)
     {
+        // See 899855
+        SetProfileVersion(ContextProfile::OpenGLCompatibility, 200);
     }
 
     // From PBuffer
     GLContextWGL(const SurfaceCaps& caps,
                  GLContext* sharedContext,
                  bool isOffscreen,
                  HANDLE aPbuffer,
                  HDC aDC,
@@ -287,16 +289,18 @@ public:
           mDC(aDC),
           mContext(aContext),
           mWnd(nullptr),
           mPBuffer(aPbuffer),
           mPixelFormat(aPixelFormat),
           mLibType(aLibUsed),
           mIsDoubleBuffered(false)
     {
+        // See 899855
+        SetProfileVersion(ContextProfile::OpenGLCompatibility, 200);
     }
 
     ~GLContextWGL()
     {
         MarkDestroyed();
 
         sWGLLib[mLibType].fDeleteContext(mContext);