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.

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

mercurial