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 148596 ab3c575381b2f1d831b8552f8bbad7a80e107108
parent 148595 25fa0d94a5073f5bf1890dc65c9d9c249e4ac4d1
child 148597 d449bcecd71eab5a0d0714157fc049d6679d780a
push id4085
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 20:29:25 +0000
treeherdermozilla-aurora@ede8780a15bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs899264
milestone25.0a1
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);