gfx/gl/GLContextProviderEGL.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "mozilla/ArrayUtils.h"
     8 #include "GLContextEGL.h"
    10 #if defined(XP_UNIX)
    12 #ifdef MOZ_WIDGET_GTK
    13 #include <gdk/gdkx.h>
    14 // we're using default display for now
    15 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW))
    16 #elif defined(MOZ_WIDGET_QT)
    17 #define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW))
    18 #elif defined(MOZ_WIDGET_GONK)
    19 #define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW))
    20 #include "HwcComposer2D.h"
    21 #include "libdisplay/GonkDisplay.h"
    22 #endif
    24 #if defined(ANDROID)
    25 /* from widget */
    26 #if defined(MOZ_WIDGET_ANDROID)
    27 #include "AndroidBridge.h"
    28 #include "nsSurfaceTexture.h"
    29 #endif
    31 #include <android/log.h>
    32 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args)
    34 # if defined(MOZ_WIDGET_GONK)
    35 #  include "cutils/properties.h"
    36 #  include <ui/GraphicBuffer.h>
    38 using namespace android;
    39 # endif
    41 #endif
    43 #define GLES2_LIB "libGLESv2.so"
    44 #define GLES2_LIB2 "libGLESv2.so.2"
    46 #elif defined(XP_WIN)
    48 #include "nsIFile.h"
    50 #define GLES2_LIB "libGLESv2.dll"
    52 #ifndef WIN32_LEAN_AND_MEAN
    53 #define WIN32_LEAN_AND_MEAN 1
    54 #endif
    56 #include <windows.h>
    58 // a little helper
    59 class AutoDestroyHWND {
    60 public:
    61     AutoDestroyHWND(HWND aWnd = nullptr)
    62         : mWnd(aWnd)
    63     {
    64     }
    66     ~AutoDestroyHWND() {
    67         if (mWnd) {
    68             ::DestroyWindow(mWnd);
    69         }
    70     }
    72     operator HWND() {
    73         return mWnd;
    74     }
    76     HWND forget() {
    77         HWND w = mWnd;
    78         mWnd = nullptr;
    79         return w;
    80     }
    82     HWND operator=(HWND aWnd) {
    83         if (mWnd && mWnd != aWnd) {
    84             ::DestroyWindow(mWnd);
    85         }
    86         mWnd = aWnd;
    87         return mWnd;
    88     }
    90     HWND mWnd;
    91 };
    93 #else
    95 #error "Platform not recognized"
    97 #endif
    99 #include "mozilla/Preferences.h"
   100 #include "gfxUtils.h"
   101 #include "gfxFailure.h"
   102 #include "gfxASurface.h"
   103 #include "gfxPlatform.h"
   104 #include "GLContextProvider.h"
   105 #include "GLLibraryEGL.h"
   106 #include "TextureImageEGL.h"
   107 #include "nsDebug.h"
   108 #include "nsThreadUtils.h"
   110 #include "nsIWidget.h"
   112 #include "gfxCrashReporterUtils.h"
   114 #include "ScopedGLHelpers.h"
   115 #include "GLBlitHelper.h"
   117 using namespace mozilla::gfx;
   119 #ifdef MOZ_WIDGET_GONK
   120 extern nsIntRect gScreenBounds;
   121 #endif
   123 namespace mozilla {
   124 namespace gl {
   126 #define ADD_ATTR_2(_array, _k, _v) do {         \
   127     (_array).AppendElement(_k);                 \
   128     (_array).AppendElement(_v);                 \
   129 } while (0)
   131 #define ADD_ATTR_1(_array, _k) do {             \
   132     (_array).AppendElement(_k);                 \
   133 } while (0)
   135 static bool
   136 CreateConfig(EGLConfig* aConfig);
   138 // append three zeros at the end of attribs list to work around
   139 // EGL implementation bugs that iterate until they find 0, instead of
   140 // EGL_NONE. See bug 948406.
   141 #define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \
   142      LOCAL_EGL_NONE, 0, 0, 0
   144 static EGLint gTerminationAttribs[] = {
   145     EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
   146 };
   148 static EGLint gContextAttribs[] = {
   149     LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
   150     EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
   151 };
   153 static EGLint gContextAttribsRobustness[] = {
   154     LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2,
   155     //LOCAL_EGL_CONTEXT_ROBUST_ACCESS_EXT, LOCAL_EGL_TRUE,
   156     LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT, LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT,
   157     EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
   158 };
   160 static int
   161 next_power_of_two(int v)
   162 {
   163     v--;
   164     v |= v >> 1;
   165     v |= v >> 2;
   166     v |= v >> 4;
   167     v |= v >> 8;
   168     v |= v >> 16;
   169     v++;
   171     return v;
   172 }
   174 static bool
   175 is_power_of_two(int v)
   176 {
   177     NS_ASSERTION(v >= 0, "bad value");
   179     if (v == 0)
   180         return true;
   182     return (v & (v-1)) == 0;
   183 }
   185 static void
   186 DestroySurface(EGLSurface oldSurface) {
   187     if (oldSurface != EGL_NO_SURFACE) {
   188         sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
   189                                  EGL_NO_SURFACE, EGL_NO_SURFACE,
   190                                  EGL_NO_CONTEXT);
   191         sEGLLibrary.fDestroySurface(EGL_DISPLAY(), oldSurface);
   192     }
   193 }
   195 static EGLSurface
   196 CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) {
   197     EGLSurface newSurface = EGL_NO_SURFACE;
   199     #ifdef MOZ_ANDROID_OMTC
   200         mozilla::AndroidBridge::Bridge()->RegisterCompositor();
   201         newSurface = mozilla::AndroidBridge::Bridge()->CreateEGLSurfaceForCompositor();
   202         if (newSurface == EGL_NO_SURFACE) {
   203             return EGL_NO_SURFACE;
   204         }
   205     #else
   206         MOZ_ASSERT(widget != nullptr);
   207         newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(widget), 0);
   208         #ifdef MOZ_WIDGET_GONK
   209             gScreenBounds.x = 0;
   210             gScreenBounds.y = 0;
   211             sEGLLibrary.fQuerySurface(EGL_DISPLAY(), newSurface, LOCAL_EGL_WIDTH, &gScreenBounds.width);
   212             sEGLLibrary.fQuerySurface(EGL_DISPLAY(), newSurface, LOCAL_EGL_HEIGHT, &gScreenBounds.height);
   213         #endif
   214     #endif
   215     return newSurface;
   216 }
   218 GLContextEGL::GLContextEGL(
   219                   const SurfaceCaps& caps,
   220                   GLContext* shareContext,
   221                   bool isOffscreen,
   222                   EGLConfig config,
   223                   EGLSurface surface,
   224                   EGLContext context)
   225     : GLContext(caps, shareContext, isOffscreen)
   226     , mConfig(config)
   227     , mSurface(surface)
   228     , mSurfaceOverride(EGL_NO_SURFACE)
   229     , mContext(context)
   230     , mThebesSurface(nullptr)
   231     , mBound(false)
   232     , mIsPBuffer(false)
   233     , mIsDoubleBuffered(false)
   234     , mCanBindToTexture(false)
   235     , mShareWithEGLImage(false)
   236     , mOwnsContext(true)
   237 {
   238     // any EGL contexts will always be GLESv2
   239     SetProfileVersion(ContextProfile::OpenGLES, 200);
   241 #ifdef DEBUG
   242     printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
   243 #endif
   244 #if defined(MOZ_WIDGET_GONK)
   245     if (!mIsOffscreen) {
   246         mHwc = HwcComposer2D::GetInstance();
   247         MOZ_ASSERT(!mHwc->Initialized());
   249         if (mHwc->Init(EGL_DISPLAY(), mSurface)) {
   250             NS_WARNING("HWComposer initialization failed!");
   251             mHwc = nullptr;
   252         }
   253     }
   254 #endif
   255 }
   257 GLContextEGL::~GLContextEGL()
   258 {
   259     MarkDestroyed();
   261     // Wrapped context should not destroy eglContext/Surface
   262     if (!mOwnsContext) {
   263         return;
   264     }
   266 #ifdef DEBUG
   267     printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
   268 #endif
   270     sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
   272 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 17
   273     if (!mIsOffscreen) {
   274       // In ICS, SurfaceFlinger's DisplayHardware::fini() does not destroy the EGLSurface associated with the
   275       // native framebuffer. Destroying it causes crashes in the ICS emulator
   276       // EGL implementation, specifically because the egl_window_surface_t dtor
   277       // calls nativeWindow->cancelBuffer and FramebufferNativeWindow does not initialize
   278       // the cancelBuffer function pointer, see bug 986836
   279       return;
   280     }
   281 #endif
   283     mozilla::gl::DestroySurface(mSurface);
   284 }
   286 bool
   287 GLContextEGL::Init()
   288 {
   289 #if defined(ANDROID)
   290     // We can't use LoadApitraceLibrary here because the GLContext
   291     // expects its own handle to the GL library
   292     if (!OpenLibrary(APITRACE_LIB))
   293 #endif
   294         if (!OpenLibrary(GLES2_LIB)) {
   295 #if defined(XP_UNIX)
   296             if (!OpenLibrary(GLES2_LIB2)) {
   297                 NS_WARNING("Couldn't load GLES2 LIB.");
   298                 return false;
   299             }
   300 #endif
   301         }
   303     SetupLookupFunction();
   304     if (!InitWithPrefix("gl", true))
   305         return false;
   307     bool current = MakeCurrent();
   308     if (!current) {
   309         gfx::LogFailure(NS_LITERAL_CSTRING(
   310             "Couldn't get device attachments for device."));
   311         return false;
   312     }
   314     PR_STATIC_ASSERT(sizeof(GLint) >= sizeof(int32_t));
   315     mMaxTextureImageSize = INT32_MAX;
   317     mShareWithEGLImage = sEGLLibrary.HasKHRImageBase() &&
   318                           sEGLLibrary.HasKHRImageTexture2D() &&
   319                           IsExtensionSupported(OES_EGL_image);
   321     return true;
   322 }
   324 bool
   325 GLContextEGL::BindTexImage()
   326 {
   327     if (!mSurface)
   328         return false;
   330     if (mBound && !ReleaseTexImage())
   331         return false;
   333     EGLBoolean success = sEGLLibrary.fBindTexImage(EGL_DISPLAY(),
   334         (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER);
   335     if (success == LOCAL_EGL_FALSE)
   336         return false;
   338     mBound = true;
   339     return true;
   340 }
   342 bool
   343 GLContextEGL::ReleaseTexImage()
   344 {
   345     if (!mBound)
   346         return true;
   348     if (!mSurface)
   349         return false;
   351     EGLBoolean success;
   352     success = sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(),
   353                                             (EGLSurface)mSurface,
   354                                             LOCAL_EGL_BACK_BUFFER);
   355     if (success == LOCAL_EGL_FALSE)
   356         return false;
   358     mBound = false;
   359     return true;
   360 }
   362 void
   363 GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
   364     if (Screen()) {
   365         /* Blit `draw` to `read` if we need to, before we potentially juggle
   366           * `read` around. If we don't, we might attach a different `read`,
   367           * and *then* hit AssureBlitted, which will blit a dirty `draw` onto
   368           * the wrong `read`!
   369           */
   370         Screen()->AssureBlitted();
   371     }
   373     mSurfaceOverride = surf ? (EGLSurface) surf : mSurface;
   374     MakeCurrent(true);
   375 }
   377 bool
   378 GLContextEGL::MakeCurrentImpl(bool aForce) {
   379     bool succeeded = true;
   381     // Assume that EGL has the same problem as WGL does,
   382     // where MakeCurrent with an already-current context is
   383     // still expensive.
   384     if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) {
   385         EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE
   386                               ? mSurfaceOverride
   387                               : mSurface;
   388         if (surface == EGL_NO_SURFACE) {
   389             return false;
   390         }
   391         succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(),
   392                                               surface, surface,
   393                                               mContext);
   394         if (!succeeded) {
   395             int eglError = sEGLLibrary.fGetError();
   396             if (eglError == LOCAL_EGL_CONTEXT_LOST) {
   397                 mContextLost = true;
   398                 NS_WARNING("EGL context has been lost.");
   399             } else {
   400                 NS_WARNING("Failed to make GL context current!");
   401 #ifdef DEBUG
   402                 printf_stderr("EGL Error: 0x%04x\n", eglError);
   403 #endif
   404             }
   405         }
   406     }
   408     return succeeded;
   409 }
   411 bool
   412 GLContextEGL::IsCurrent() {
   413     return sEGLLibrary.fGetCurrentContext() == mContext;
   414 }
   416 bool
   417 GLContextEGL::RenewSurface() {
   418     if (!mOwnsContext) {
   419         return false;
   420     }
   421 #ifndef MOZ_WIDGET_ANDROID
   422     MOZ_CRASH("unimplemented");
   423     // to support this on non-Android platforms, need to keep track of the nsIWidget that
   424     // this GLContext was created for (with CreateForWindow) so that we know what to
   425     // pass again to CreateSurfaceForWindow below.
   426     // The reason why Android doesn't need this is that it delegates EGLSurface creation to
   427     // Java code which is the only thing that knows about our actual widget.
   428 #endif
   429     // unconditionally release the surface and create a new one. Don't try to optimize this away.
   430     // If we get here, then by definition we know that we want to get a new surface.
   431     ReleaseSurface();
   432     mSurface = mozilla::gl::CreateSurfaceForWindow(nullptr, mConfig); // the nullptr here is where we assume Android.
   433     if (mSurface == EGL_NO_SURFACE) {
   434         return false;
   435     }
   436     return MakeCurrent(true);
   437 }
   439 void
   440 GLContextEGL::ReleaseSurface() {
   441     if (mOwnsContext) {
   442         DestroySurface(mSurface);
   443     }
   444     mSurface = EGL_NO_SURFACE;
   445 }
   447 bool
   448 GLContextEGL::SetupLookupFunction()
   449 {
   450     mLookupFunc = (PlatformLookupFunction)sEGLLibrary.mSymbols.fGetProcAddress;
   451     return true;
   452 }
   454 bool
   455 GLContextEGL::SwapBuffers()
   456 {
   457     if (mSurface) {
   458 #ifdef MOZ_WIDGET_GONK
   459         if (!mIsOffscreen) {
   460             if (mHwc) {
   461                 return mHwc->Render(EGL_DISPLAY(), mSurface);
   462             } else {
   463                 return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), mSurface);
   464             }
   465         } else
   466 #endif
   467             return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface);
   468     } else {
   469         return false;
   470     }
   471 }
   473 // hold a reference to the given surface
   474 // for the lifetime of this context.
   475 void
   476 GLContextEGL::HoldSurface(gfxASurface *aSurf) {
   477     mThebesSurface = aSurf;
   478 }
   480 already_AddRefed<GLContextEGL>
   481 GLContextEGL::CreateGLContext(const SurfaceCaps& caps,
   482                 GLContextEGL *shareContext,
   483                 bool isOffscreen,
   484                 EGLConfig config,
   485                 EGLSurface surface)
   486 {
   487     if (sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) {
   488         NS_WARNING("Failed to bind API to GLES!");
   489         return nullptr;
   490     }
   492     EGLContext eglShareContext = shareContext ? shareContext->mContext
   493                                               : EGL_NO_CONTEXT;
   494     EGLint* attribs = sEGLLibrary.HasRobustness() ? gContextAttribsRobustness
   495                                                   : gContextAttribs;
   497     EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
   498                                                     config,
   499                                                     eglShareContext,
   500                                                     attribs);
   501     if (!context && shareContext) {
   502         shareContext = nullptr;
   503         context = sEGLLibrary.fCreateContext(EGL_DISPLAY(),
   504                                               config,
   505                                               EGL_NO_CONTEXT,
   506                                               attribs);
   507     }
   508     if (!context) {
   509         NS_WARNING("Failed to create EGLContext!");
   510         return nullptr;
   511     }
   513     nsRefPtr<GLContextEGL> glContext = new GLContextEGL(caps,
   514                                                         shareContext,
   515                                                         isOffscreen,
   516                                                         config,
   517                                                         surface,
   518                                                         context);
   520     if (!glContext->Init())
   521         return nullptr;
   523     return glContext.forget();
   524 }
   526 EGLSurface
   527 GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config,
   528                                                    EGLenum bindToTextureFormat,
   529                                                    gfxIntSize& pbsize)
   530 {
   531     nsTArray<EGLint> pbattrs(16);
   532     EGLSurface surface = nullptr;
   534 TRY_AGAIN_POWER_OF_TWO:
   535     pbattrs.Clear();
   536     pbattrs.AppendElement(LOCAL_EGL_WIDTH); pbattrs.AppendElement(pbsize.width);
   537     pbattrs.AppendElement(LOCAL_EGL_HEIGHT); pbattrs.AppendElement(pbsize.height);
   539     if (bindToTextureFormat != LOCAL_EGL_NONE) {
   540         pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET);
   541         pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D);
   543         pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT);
   544         pbattrs.AppendElement(bindToTextureFormat);
   545     }
   547     for (size_t i = 0; i < MOZ_ARRAY_LENGTH(gTerminationAttribs); i++) {
   548       pbattrs.AppendElement(gTerminationAttribs[i]);
   549     }
   551     surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), config, &pbattrs[0]);
   552     if (!surface) {
   553         if (!is_power_of_two(pbsize.width) ||
   554             !is_power_of_two(pbsize.height))
   555         {
   556             if (!is_power_of_two(pbsize.width))
   557                 pbsize.width = next_power_of_two(pbsize.width);
   558             if (!is_power_of_two(pbsize.height))
   559                 pbsize.height = next_power_of_two(pbsize.height);
   561             NS_WARNING("Failed to create pbuffer, trying power of two dims");
   562             goto TRY_AGAIN_POWER_OF_TWO;
   563         }
   565         NS_WARNING("Failed to create pbuffer surface");
   566         return nullptr;
   567     }
   569     return surface;
   570 }
   572 static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = {
   573     LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_PBUFFER_BIT,
   574     LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
   575     // Old versions of llvmpipe seem to need this to properly create the pbuffer (bug 981856)
   576     LOCAL_EGL_RED_SIZE,        8,
   577     LOCAL_EGL_GREEN_SIZE,      8,
   578     LOCAL_EGL_BLUE_SIZE,       8,
   579     LOCAL_EGL_ALPHA_SIZE,      0,
   580     EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
   581 };
   583 static const EGLint kEGLConfigAttribsRGB16[] = {
   584     LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_WINDOW_BIT,
   585     LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
   586     LOCAL_EGL_RED_SIZE,        5,
   587     LOCAL_EGL_GREEN_SIZE,      6,
   588     LOCAL_EGL_BLUE_SIZE,       5,
   589     LOCAL_EGL_ALPHA_SIZE,      0,
   590     EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
   591 };
   593 static const EGLint kEGLConfigAttribsRGB24[] = {
   594     LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_WINDOW_BIT,
   595     LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
   596     LOCAL_EGL_RED_SIZE,        8,
   597     LOCAL_EGL_GREEN_SIZE,      8,
   598     LOCAL_EGL_BLUE_SIZE,       8,
   599     LOCAL_EGL_ALPHA_SIZE,      0,
   600     EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
   601 };
   603 static const EGLint kEGLConfigAttribsRGBA32[] = {
   604     LOCAL_EGL_SURFACE_TYPE,    LOCAL_EGL_WINDOW_BIT,
   605     LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
   606     LOCAL_EGL_RED_SIZE,        8,
   607     LOCAL_EGL_GREEN_SIZE,      8,
   608     LOCAL_EGL_BLUE_SIZE,       8,
   609     LOCAL_EGL_ALPHA_SIZE,      8,
   610 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
   611     LOCAL_EGL_FRAMEBUFFER_TARGET_ANDROID, LOCAL_EGL_TRUE,
   612 #endif
   613     EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
   614 };
   616 static bool
   617 CreateConfig(EGLConfig* aConfig, int32_t depth)
   618 {
   619     EGLConfig configs[64];
   620     const EGLint* attribs;
   621     EGLint ncfg = ArrayLength(configs);
   623     switch (depth) {
   624         case 16:
   625             attribs = kEGLConfigAttribsRGB16;
   626             break;
   627         case 24:
   628             attribs = kEGLConfigAttribsRGB24;
   629             break;
   630         case 32:
   631             attribs = kEGLConfigAttribsRGBA32;
   632             break;
   633         default:
   634             NS_ERROR("Unknown pixel depth");
   635             return false;
   636     }
   638     if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs,
   639                                    configs, ncfg, &ncfg) ||
   640         ncfg < 1) {
   641         return false;
   642     }
   644     for (int j = 0; j < ncfg; ++j) {
   645         EGLConfig config = configs[j];
   646         EGLint r, g, b, a;
   648         if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
   649                                          LOCAL_EGL_RED_SIZE, &r) &&
   650             sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
   651                                          LOCAL_EGL_GREEN_SIZE, &g) &&
   652             sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
   653                                          LOCAL_EGL_BLUE_SIZE, &b) &&
   654             sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config,
   655                                          LOCAL_EGL_ALPHA_SIZE, &a) &&
   656             ((depth == 16 && r == 5 && g == 6 && b == 5) ||
   657              (depth == 24 && r == 8 && g == 8 && b == 8) ||
   658              (depth == 32 && r == 8 && g == 8 && b == 8 && a == 8)))
   659         {
   660             *aConfig = config;
   661             return true;
   662         }
   663     }
   664     return false;
   665 }
   667 // Return true if a suitable EGLConfig was found and pass it out
   668 // through aConfig.  Return false otherwise.
   669 //
   670 // NB: It's entirely legal for the returned EGLConfig to be valid yet
   671 // have the value null.
   672 static bool
   673 CreateConfig(EGLConfig* aConfig)
   674 {
   675     int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth();
   676     if (!CreateConfig(aConfig, depth)) {
   677 #ifdef MOZ_WIDGET_ANDROID
   678         // Bug 736005
   679         // Android doesn't always support 16 bit so also try 24 bit
   680         if (depth == 16) {
   681             return CreateConfig(aConfig, 24);
   682         }
   683         // Bug 970096
   684         // Some devices that have 24 bit screens only support 16 bit OpenGL?
   685         if (depth == 24) {
   686             return CreateConfig(aConfig, 16);
   687         }
   688 #endif
   689         return false;
   690     } else {
   691         return true;
   692     }
   693 }
   695 already_AddRefed<GLContext>
   696 GLContextProviderEGL::CreateWrappingExisting(void* aContext, void* aSurface)
   697 {
   698     if (!sEGLLibrary.EnsureInitialized()) {
   699         MOZ_CRASH("Failed to load EGL library!\n");
   700         return nullptr;
   701     }
   703     if (aContext && aSurface) {
   704         SurfaceCaps caps = SurfaceCaps::Any();
   705         EGLConfig config = EGL_NO_CONFIG;
   706         nsRefPtr<GLContextEGL> glContext =
   707             new GLContextEGL(caps,
   708                              nullptr, false,
   709                              config, (EGLSurface)aSurface, (EGLContext)aContext);
   711         glContext->SetIsDoubleBuffered(true);
   712         glContext->mOwnsContext = false;
   714         return glContext.forget();
   715     }
   717     return nullptr;
   718 }
   720 already_AddRefed<GLContext>
   721 GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget)
   722 {
   723     if (!sEGLLibrary.EnsureInitialized()) {
   724         MOZ_CRASH("Failed to load EGL library!\n");
   725         return nullptr;
   726     }
   728     bool doubleBuffered = true;
   730     EGLConfig config;
   731     if (!CreateConfig(&config)) {
   732         MOZ_CRASH("Failed to create EGLConfig!\n");
   733         return nullptr;
   734     }
   736     EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config);
   738     if (surface == EGL_NO_SURFACE) {
   739         MOZ_CRASH("Failed to create EGLSurface!\n");
   740         return nullptr;
   741     }
   743     SurfaceCaps caps = SurfaceCaps::Any();
   744     nsRefPtr<GLContextEGL> glContext =
   745         GLContextEGL::CreateGLContext(caps,
   746                                       nullptr, false,
   747                                       config, surface);
   749     if (!glContext) {
   750         MOZ_CRASH("Failed to create EGLContext!\n");
   751         DestroySurface(surface);
   752         return nullptr;
   753     }
   755     glContext->MakeCurrent();
   756     glContext->SetIsDoubleBuffered(doubleBuffered);
   758     return glContext.forget();
   759 }
   761 already_AddRefed<GLContextEGL>
   762 GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size)
   763 {
   764     EGLConfig config;
   765     EGLSurface surface;
   767     const EGLint numConfigs = 1; // We only need one.
   768     EGLConfig configs[numConfigs];
   769     EGLint foundConfigs = 0;
   770     if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
   771                                    kEGLConfigAttribsOffscreenPBuffer,
   772                                    configs, numConfigs,
   773                                    &foundConfigs)
   774         || foundConfigs == 0)
   775     {
   776         NS_WARNING("No EGL Config for minimal PBuffer!");
   777         return nullptr;
   778     }
   780     // We absolutely don't care, so just pick the first one.
   781     config = configs[0];
   782     if (GLContext::DebugMode())
   783         sEGLLibrary.DumpEGLConfig(config);
   785     gfxIntSize pbSize(size);
   786     surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
   787                                                                  LOCAL_EGL_NONE,
   788                                                                  pbSize);
   789     if (!surface) {
   790         NS_WARNING("Failed to create PBuffer for context!");
   791         return nullptr;
   792     }
   794     SurfaceCaps dummyCaps = SurfaceCaps::Any();
   795     nsRefPtr<GLContextEGL> glContext =
   796         GLContextEGL::CreateGLContext(dummyCaps,
   797                                       nullptr, true,
   798                                       config, surface);
   799     if (!glContext) {
   800         NS_WARNING("Failed to create GLContext from PBuffer");
   801         sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
   802         return nullptr;
   803     }
   805     if (!glContext->Init()) {
   806         NS_WARNING("Failed to initialize GLContext!");
   807         // GLContextEGL::dtor will destroy |surface| for us.
   808         return nullptr;
   809     }
   811     return glContext.forget();
   812 }
   814 already_AddRefed<GLContextEGL>
   815 GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
   816 {
   817     gfxASurface *thebesSurface = nullptr;
   818     EGLNativePixmapType pixmap = 0;
   820     if (!pixmap) {
   821         return nullptr;
   822     }
   824     EGLSurface surface = 0;
   825     EGLConfig config = 0;
   827     if (!config) {
   828         return nullptr;
   829     }
   830     MOZ_ASSERT(surface);
   832     SurfaceCaps dummyCaps = SurfaceCaps::Any();
   833     nsRefPtr<GLContextEGL> glContext =
   834         GLContextEGL::CreateGLContext(dummyCaps,
   835                                       nullptr, true,
   836                                       config, surface);
   837     if (!glContext) {
   838         NS_WARNING("Failed to create GLContext from XSurface");
   839         sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface);
   840         return nullptr;
   841     }
   843     if (!glContext->Init()) {
   844         NS_WARNING("Failed to initialize GLContext!");
   845         // GLContextEGL::dtor will destroy |surface| for us.
   846         return nullptr;
   847     }
   849     glContext->HoldSurface(thebesSurface);
   851     return glContext.forget();
   852 }
   854 // Under EGL, on Android, pbuffers are supported fine, though
   855 // often without the ability to texture from them directly.
   856 already_AddRefed<GLContext>
   857 GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
   858                                       const SurfaceCaps& caps)
   859 {
   860     if (!sEGLLibrary.EnsureInitialized()) {
   861         return nullptr;
   862     }
   864     gfxIntSize dummySize = gfxIntSize(16, 16);
   865     nsRefPtr<GLContextEGL> glContext;
   866     glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize);
   868     if (!glContext)
   869         return nullptr;
   871     if (!glContext->InitOffscreen(ToIntSize(size), caps))
   872         return nullptr;
   874     return glContext.forget();
   875 }
   877 // Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225)
   878 // and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257)
   879 // and 3) each EGL context eats 750k on B2G (bug 813783)
   880 GLContext *
   881 GLContextProviderEGL::GetGlobalContext()
   882 {
   883     return nullptr;
   884 }
   886 void
   887 GLContextProviderEGL::Shutdown()
   888 {
   889 }
   891 } /* namespace gl */
   892 } /* namespace mozilla */
   894 #undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS

mercurial