1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/gl/GLContextProviderEGL.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,894 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "mozilla/ArrayUtils.h" 1.10 + 1.11 +#include "GLContextEGL.h" 1.12 + 1.13 +#if defined(XP_UNIX) 1.14 + 1.15 +#ifdef MOZ_WIDGET_GTK 1.16 +#include <gdk/gdkx.h> 1.17 +// we're using default display for now 1.18 +#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)GDK_WINDOW_XID((GdkWindow *) aWidget->GetNativeData(NS_NATIVE_WINDOW)) 1.19 +#elif defined(MOZ_WIDGET_QT) 1.20 +#define GET_NATIVE_WINDOW(aWidget) (EGLNativeWindowType)(aWidget->GetNativeData(NS_NATIVE_SHAREABLE_WINDOW)) 1.21 +#elif defined(MOZ_WIDGET_GONK) 1.22 +#define GET_NATIVE_WINDOW(aWidget) ((EGLNativeWindowType)aWidget->GetNativeData(NS_NATIVE_WINDOW)) 1.23 +#include "HwcComposer2D.h" 1.24 +#include "libdisplay/GonkDisplay.h" 1.25 +#endif 1.26 + 1.27 +#if defined(ANDROID) 1.28 +/* from widget */ 1.29 +#if defined(MOZ_WIDGET_ANDROID) 1.30 +#include "AndroidBridge.h" 1.31 +#include "nsSurfaceTexture.h" 1.32 +#endif 1.33 + 1.34 +#include <android/log.h> 1.35 +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) 1.36 + 1.37 +# if defined(MOZ_WIDGET_GONK) 1.38 +# include "cutils/properties.h" 1.39 +# include <ui/GraphicBuffer.h> 1.40 + 1.41 +using namespace android; 1.42 +# endif 1.43 + 1.44 +#endif 1.45 + 1.46 +#define GLES2_LIB "libGLESv2.so" 1.47 +#define GLES2_LIB2 "libGLESv2.so.2" 1.48 + 1.49 +#elif defined(XP_WIN) 1.50 + 1.51 +#include "nsIFile.h" 1.52 + 1.53 +#define GLES2_LIB "libGLESv2.dll" 1.54 + 1.55 +#ifndef WIN32_LEAN_AND_MEAN 1.56 +#define WIN32_LEAN_AND_MEAN 1 1.57 +#endif 1.58 + 1.59 +#include <windows.h> 1.60 + 1.61 +// a little helper 1.62 +class AutoDestroyHWND { 1.63 +public: 1.64 + AutoDestroyHWND(HWND aWnd = nullptr) 1.65 + : mWnd(aWnd) 1.66 + { 1.67 + } 1.68 + 1.69 + ~AutoDestroyHWND() { 1.70 + if (mWnd) { 1.71 + ::DestroyWindow(mWnd); 1.72 + } 1.73 + } 1.74 + 1.75 + operator HWND() { 1.76 + return mWnd; 1.77 + } 1.78 + 1.79 + HWND forget() { 1.80 + HWND w = mWnd; 1.81 + mWnd = nullptr; 1.82 + return w; 1.83 + } 1.84 + 1.85 + HWND operator=(HWND aWnd) { 1.86 + if (mWnd && mWnd != aWnd) { 1.87 + ::DestroyWindow(mWnd); 1.88 + } 1.89 + mWnd = aWnd; 1.90 + return mWnd; 1.91 + } 1.92 + 1.93 + HWND mWnd; 1.94 +}; 1.95 + 1.96 +#else 1.97 + 1.98 +#error "Platform not recognized" 1.99 + 1.100 +#endif 1.101 + 1.102 +#include "mozilla/Preferences.h" 1.103 +#include "gfxUtils.h" 1.104 +#include "gfxFailure.h" 1.105 +#include "gfxASurface.h" 1.106 +#include "gfxPlatform.h" 1.107 +#include "GLContextProvider.h" 1.108 +#include "GLLibraryEGL.h" 1.109 +#include "TextureImageEGL.h" 1.110 +#include "nsDebug.h" 1.111 +#include "nsThreadUtils.h" 1.112 + 1.113 +#include "nsIWidget.h" 1.114 + 1.115 +#include "gfxCrashReporterUtils.h" 1.116 + 1.117 +#include "ScopedGLHelpers.h" 1.118 +#include "GLBlitHelper.h" 1.119 + 1.120 +using namespace mozilla::gfx; 1.121 + 1.122 +#ifdef MOZ_WIDGET_GONK 1.123 +extern nsIntRect gScreenBounds; 1.124 +#endif 1.125 + 1.126 +namespace mozilla { 1.127 +namespace gl { 1.128 + 1.129 +#define ADD_ATTR_2(_array, _k, _v) do { \ 1.130 + (_array).AppendElement(_k); \ 1.131 + (_array).AppendElement(_v); \ 1.132 +} while (0) 1.133 + 1.134 +#define ADD_ATTR_1(_array, _k) do { \ 1.135 + (_array).AppendElement(_k); \ 1.136 +} while (0) 1.137 + 1.138 +static bool 1.139 +CreateConfig(EGLConfig* aConfig); 1.140 + 1.141 +// append three zeros at the end of attribs list to work around 1.142 +// EGL implementation bugs that iterate until they find 0, instead of 1.143 +// EGL_NONE. See bug 948406. 1.144 +#define EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS \ 1.145 + LOCAL_EGL_NONE, 0, 0, 0 1.146 + 1.147 +static EGLint gTerminationAttribs[] = { 1.148 + EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS 1.149 +}; 1.150 + 1.151 +static EGLint gContextAttribs[] = { 1.152 + LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2, 1.153 + EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS 1.154 +}; 1.155 + 1.156 +static EGLint gContextAttribsRobustness[] = { 1.157 + LOCAL_EGL_CONTEXT_CLIENT_VERSION, 2, 1.158 + //LOCAL_EGL_CONTEXT_ROBUST_ACCESS_EXT, LOCAL_EGL_TRUE, 1.159 + LOCAL_EGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_EXT, LOCAL_EGL_LOSE_CONTEXT_ON_RESET_EXT, 1.160 + EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS 1.161 +}; 1.162 + 1.163 +static int 1.164 +next_power_of_two(int v) 1.165 +{ 1.166 + v--; 1.167 + v |= v >> 1; 1.168 + v |= v >> 2; 1.169 + v |= v >> 4; 1.170 + v |= v >> 8; 1.171 + v |= v >> 16; 1.172 + v++; 1.173 + 1.174 + return v; 1.175 +} 1.176 + 1.177 +static bool 1.178 +is_power_of_two(int v) 1.179 +{ 1.180 + NS_ASSERTION(v >= 0, "bad value"); 1.181 + 1.182 + if (v == 0) 1.183 + return true; 1.184 + 1.185 + return (v & (v-1)) == 0; 1.186 +} 1.187 + 1.188 +static void 1.189 +DestroySurface(EGLSurface oldSurface) { 1.190 + if (oldSurface != EGL_NO_SURFACE) { 1.191 + sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), 1.192 + EGL_NO_SURFACE, EGL_NO_SURFACE, 1.193 + EGL_NO_CONTEXT); 1.194 + sEGLLibrary.fDestroySurface(EGL_DISPLAY(), oldSurface); 1.195 + } 1.196 +} 1.197 + 1.198 +static EGLSurface 1.199 +CreateSurfaceForWindow(nsIWidget* widget, const EGLConfig& config) { 1.200 + EGLSurface newSurface = EGL_NO_SURFACE; 1.201 + 1.202 + #ifdef MOZ_ANDROID_OMTC 1.203 + mozilla::AndroidBridge::Bridge()->RegisterCompositor(); 1.204 + newSurface = mozilla::AndroidBridge::Bridge()->CreateEGLSurfaceForCompositor(); 1.205 + if (newSurface == EGL_NO_SURFACE) { 1.206 + return EGL_NO_SURFACE; 1.207 + } 1.208 + #else 1.209 + MOZ_ASSERT(widget != nullptr); 1.210 + newSurface = sEGLLibrary.fCreateWindowSurface(EGL_DISPLAY(), config, GET_NATIVE_WINDOW(widget), 0); 1.211 + #ifdef MOZ_WIDGET_GONK 1.212 + gScreenBounds.x = 0; 1.213 + gScreenBounds.y = 0; 1.214 + sEGLLibrary.fQuerySurface(EGL_DISPLAY(), newSurface, LOCAL_EGL_WIDTH, &gScreenBounds.width); 1.215 + sEGLLibrary.fQuerySurface(EGL_DISPLAY(), newSurface, LOCAL_EGL_HEIGHT, &gScreenBounds.height); 1.216 + #endif 1.217 + #endif 1.218 + return newSurface; 1.219 +} 1.220 + 1.221 +GLContextEGL::GLContextEGL( 1.222 + const SurfaceCaps& caps, 1.223 + GLContext* shareContext, 1.224 + bool isOffscreen, 1.225 + EGLConfig config, 1.226 + EGLSurface surface, 1.227 + EGLContext context) 1.228 + : GLContext(caps, shareContext, isOffscreen) 1.229 + , mConfig(config) 1.230 + , mSurface(surface) 1.231 + , mSurfaceOverride(EGL_NO_SURFACE) 1.232 + , mContext(context) 1.233 + , mThebesSurface(nullptr) 1.234 + , mBound(false) 1.235 + , mIsPBuffer(false) 1.236 + , mIsDoubleBuffered(false) 1.237 + , mCanBindToTexture(false) 1.238 + , mShareWithEGLImage(false) 1.239 + , mOwnsContext(true) 1.240 +{ 1.241 + // any EGL contexts will always be GLESv2 1.242 + SetProfileVersion(ContextProfile::OpenGLES, 200); 1.243 + 1.244 +#ifdef DEBUG 1.245 + printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY()); 1.246 +#endif 1.247 +#if defined(MOZ_WIDGET_GONK) 1.248 + if (!mIsOffscreen) { 1.249 + mHwc = HwcComposer2D::GetInstance(); 1.250 + MOZ_ASSERT(!mHwc->Initialized()); 1.251 + 1.252 + if (mHwc->Init(EGL_DISPLAY(), mSurface)) { 1.253 + NS_WARNING("HWComposer initialization failed!"); 1.254 + mHwc = nullptr; 1.255 + } 1.256 + } 1.257 +#endif 1.258 +} 1.259 + 1.260 +GLContextEGL::~GLContextEGL() 1.261 +{ 1.262 + MarkDestroyed(); 1.263 + 1.264 + // Wrapped context should not destroy eglContext/Surface 1.265 + if (!mOwnsContext) { 1.266 + return; 1.267 + } 1.268 + 1.269 +#ifdef DEBUG 1.270 + printf_stderr("Destroying context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY()); 1.271 +#endif 1.272 + 1.273 + sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext); 1.274 + 1.275 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 17 1.276 + if (!mIsOffscreen) { 1.277 + // In ICS, SurfaceFlinger's DisplayHardware::fini() does not destroy the EGLSurface associated with the 1.278 + // native framebuffer. Destroying it causes crashes in the ICS emulator 1.279 + // EGL implementation, specifically because the egl_window_surface_t dtor 1.280 + // calls nativeWindow->cancelBuffer and FramebufferNativeWindow does not initialize 1.281 + // the cancelBuffer function pointer, see bug 986836 1.282 + return; 1.283 + } 1.284 +#endif 1.285 + 1.286 + mozilla::gl::DestroySurface(mSurface); 1.287 +} 1.288 + 1.289 +bool 1.290 +GLContextEGL::Init() 1.291 +{ 1.292 +#if defined(ANDROID) 1.293 + // We can't use LoadApitraceLibrary here because the GLContext 1.294 + // expects its own handle to the GL library 1.295 + if (!OpenLibrary(APITRACE_LIB)) 1.296 +#endif 1.297 + if (!OpenLibrary(GLES2_LIB)) { 1.298 +#if defined(XP_UNIX) 1.299 + if (!OpenLibrary(GLES2_LIB2)) { 1.300 + NS_WARNING("Couldn't load GLES2 LIB."); 1.301 + return false; 1.302 + } 1.303 +#endif 1.304 + } 1.305 + 1.306 + SetupLookupFunction(); 1.307 + if (!InitWithPrefix("gl", true)) 1.308 + return false; 1.309 + 1.310 + bool current = MakeCurrent(); 1.311 + if (!current) { 1.312 + gfx::LogFailure(NS_LITERAL_CSTRING( 1.313 + "Couldn't get device attachments for device.")); 1.314 + return false; 1.315 + } 1.316 + 1.317 + PR_STATIC_ASSERT(sizeof(GLint) >= sizeof(int32_t)); 1.318 + mMaxTextureImageSize = INT32_MAX; 1.319 + 1.320 + mShareWithEGLImage = sEGLLibrary.HasKHRImageBase() && 1.321 + sEGLLibrary.HasKHRImageTexture2D() && 1.322 + IsExtensionSupported(OES_EGL_image); 1.323 + 1.324 + return true; 1.325 +} 1.326 + 1.327 +bool 1.328 +GLContextEGL::BindTexImage() 1.329 +{ 1.330 + if (!mSurface) 1.331 + return false; 1.332 + 1.333 + if (mBound && !ReleaseTexImage()) 1.334 + return false; 1.335 + 1.336 + EGLBoolean success = sEGLLibrary.fBindTexImage(EGL_DISPLAY(), 1.337 + (EGLSurface)mSurface, LOCAL_EGL_BACK_BUFFER); 1.338 + if (success == LOCAL_EGL_FALSE) 1.339 + return false; 1.340 + 1.341 + mBound = true; 1.342 + return true; 1.343 +} 1.344 + 1.345 +bool 1.346 +GLContextEGL::ReleaseTexImage() 1.347 +{ 1.348 + if (!mBound) 1.349 + return true; 1.350 + 1.351 + if (!mSurface) 1.352 + return false; 1.353 + 1.354 + EGLBoolean success; 1.355 + success = sEGLLibrary.fReleaseTexImage(EGL_DISPLAY(), 1.356 + (EGLSurface)mSurface, 1.357 + LOCAL_EGL_BACK_BUFFER); 1.358 + if (success == LOCAL_EGL_FALSE) 1.359 + return false; 1.360 + 1.361 + mBound = false; 1.362 + return true; 1.363 +} 1.364 + 1.365 +void 1.366 +GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) { 1.367 + if (Screen()) { 1.368 + /* Blit `draw` to `read` if we need to, before we potentially juggle 1.369 + * `read` around. If we don't, we might attach a different `read`, 1.370 + * and *then* hit AssureBlitted, which will blit a dirty `draw` onto 1.371 + * the wrong `read`! 1.372 + */ 1.373 + Screen()->AssureBlitted(); 1.374 + } 1.375 + 1.376 + mSurfaceOverride = surf ? (EGLSurface) surf : mSurface; 1.377 + MakeCurrent(true); 1.378 +} 1.379 + 1.380 +bool 1.381 +GLContextEGL::MakeCurrentImpl(bool aForce) { 1.382 + bool succeeded = true; 1.383 + 1.384 + // Assume that EGL has the same problem as WGL does, 1.385 + // where MakeCurrent with an already-current context is 1.386 + // still expensive. 1.387 + if (aForce || sEGLLibrary.fGetCurrentContext() != mContext) { 1.388 + EGLSurface surface = mSurfaceOverride != EGL_NO_SURFACE 1.389 + ? mSurfaceOverride 1.390 + : mSurface; 1.391 + if (surface == EGL_NO_SURFACE) { 1.392 + return false; 1.393 + } 1.394 + succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), 1.395 + surface, surface, 1.396 + mContext); 1.397 + if (!succeeded) { 1.398 + int eglError = sEGLLibrary.fGetError(); 1.399 + if (eglError == LOCAL_EGL_CONTEXT_LOST) { 1.400 + mContextLost = true; 1.401 + NS_WARNING("EGL context has been lost."); 1.402 + } else { 1.403 + NS_WARNING("Failed to make GL context current!"); 1.404 +#ifdef DEBUG 1.405 + printf_stderr("EGL Error: 0x%04x\n", eglError); 1.406 +#endif 1.407 + } 1.408 + } 1.409 + } 1.410 + 1.411 + return succeeded; 1.412 +} 1.413 + 1.414 +bool 1.415 +GLContextEGL::IsCurrent() { 1.416 + return sEGLLibrary.fGetCurrentContext() == mContext; 1.417 +} 1.418 + 1.419 +bool 1.420 +GLContextEGL::RenewSurface() { 1.421 + if (!mOwnsContext) { 1.422 + return false; 1.423 + } 1.424 +#ifndef MOZ_WIDGET_ANDROID 1.425 + MOZ_CRASH("unimplemented"); 1.426 + // to support this on non-Android platforms, need to keep track of the nsIWidget that 1.427 + // this GLContext was created for (with CreateForWindow) so that we know what to 1.428 + // pass again to CreateSurfaceForWindow below. 1.429 + // The reason why Android doesn't need this is that it delegates EGLSurface creation to 1.430 + // Java code which is the only thing that knows about our actual widget. 1.431 +#endif 1.432 + // unconditionally release the surface and create a new one. Don't try to optimize this away. 1.433 + // If we get here, then by definition we know that we want to get a new surface. 1.434 + ReleaseSurface(); 1.435 + mSurface = mozilla::gl::CreateSurfaceForWindow(nullptr, mConfig); // the nullptr here is where we assume Android. 1.436 + if (mSurface == EGL_NO_SURFACE) { 1.437 + return false; 1.438 + } 1.439 + return MakeCurrent(true); 1.440 +} 1.441 + 1.442 +void 1.443 +GLContextEGL::ReleaseSurface() { 1.444 + if (mOwnsContext) { 1.445 + DestroySurface(mSurface); 1.446 + } 1.447 + mSurface = EGL_NO_SURFACE; 1.448 +} 1.449 + 1.450 +bool 1.451 +GLContextEGL::SetupLookupFunction() 1.452 +{ 1.453 + mLookupFunc = (PlatformLookupFunction)sEGLLibrary.mSymbols.fGetProcAddress; 1.454 + return true; 1.455 +} 1.456 + 1.457 +bool 1.458 +GLContextEGL::SwapBuffers() 1.459 +{ 1.460 + if (mSurface) { 1.461 +#ifdef MOZ_WIDGET_GONK 1.462 + if (!mIsOffscreen) { 1.463 + if (mHwc) { 1.464 + return mHwc->Render(EGL_DISPLAY(), mSurface); 1.465 + } else { 1.466 + return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), mSurface); 1.467 + } 1.468 + } else 1.469 +#endif 1.470 + return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), mSurface); 1.471 + } else { 1.472 + return false; 1.473 + } 1.474 +} 1.475 + 1.476 +// hold a reference to the given surface 1.477 +// for the lifetime of this context. 1.478 +void 1.479 +GLContextEGL::HoldSurface(gfxASurface *aSurf) { 1.480 + mThebesSurface = aSurf; 1.481 +} 1.482 + 1.483 +already_AddRefed<GLContextEGL> 1.484 +GLContextEGL::CreateGLContext(const SurfaceCaps& caps, 1.485 + GLContextEGL *shareContext, 1.486 + bool isOffscreen, 1.487 + EGLConfig config, 1.488 + EGLSurface surface) 1.489 +{ 1.490 + if (sEGLLibrary.fBindAPI(LOCAL_EGL_OPENGL_ES_API) == LOCAL_EGL_FALSE) { 1.491 + NS_WARNING("Failed to bind API to GLES!"); 1.492 + return nullptr; 1.493 + } 1.494 + 1.495 + EGLContext eglShareContext = shareContext ? shareContext->mContext 1.496 + : EGL_NO_CONTEXT; 1.497 + EGLint* attribs = sEGLLibrary.HasRobustness() ? gContextAttribsRobustness 1.498 + : gContextAttribs; 1.499 + 1.500 + EGLContext context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), 1.501 + config, 1.502 + eglShareContext, 1.503 + attribs); 1.504 + if (!context && shareContext) { 1.505 + shareContext = nullptr; 1.506 + context = sEGLLibrary.fCreateContext(EGL_DISPLAY(), 1.507 + config, 1.508 + EGL_NO_CONTEXT, 1.509 + attribs); 1.510 + } 1.511 + if (!context) { 1.512 + NS_WARNING("Failed to create EGLContext!"); 1.513 + return nullptr; 1.514 + } 1.515 + 1.516 + nsRefPtr<GLContextEGL> glContext = new GLContextEGL(caps, 1.517 + shareContext, 1.518 + isOffscreen, 1.519 + config, 1.520 + surface, 1.521 + context); 1.522 + 1.523 + if (!glContext->Init()) 1.524 + return nullptr; 1.525 + 1.526 + return glContext.forget(); 1.527 +} 1.528 + 1.529 +EGLSurface 1.530 +GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(EGLConfig config, 1.531 + EGLenum bindToTextureFormat, 1.532 + gfxIntSize& pbsize) 1.533 +{ 1.534 + nsTArray<EGLint> pbattrs(16); 1.535 + EGLSurface surface = nullptr; 1.536 + 1.537 +TRY_AGAIN_POWER_OF_TWO: 1.538 + pbattrs.Clear(); 1.539 + pbattrs.AppendElement(LOCAL_EGL_WIDTH); pbattrs.AppendElement(pbsize.width); 1.540 + pbattrs.AppendElement(LOCAL_EGL_HEIGHT); pbattrs.AppendElement(pbsize.height); 1.541 + 1.542 + if (bindToTextureFormat != LOCAL_EGL_NONE) { 1.543 + pbattrs.AppendElement(LOCAL_EGL_TEXTURE_TARGET); 1.544 + pbattrs.AppendElement(LOCAL_EGL_TEXTURE_2D); 1.545 + 1.546 + pbattrs.AppendElement(LOCAL_EGL_TEXTURE_FORMAT); 1.547 + pbattrs.AppendElement(bindToTextureFormat); 1.548 + } 1.549 + 1.550 + for (size_t i = 0; i < MOZ_ARRAY_LENGTH(gTerminationAttribs); i++) { 1.551 + pbattrs.AppendElement(gTerminationAttribs[i]); 1.552 + } 1.553 + 1.554 + surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), config, &pbattrs[0]); 1.555 + if (!surface) { 1.556 + if (!is_power_of_two(pbsize.width) || 1.557 + !is_power_of_two(pbsize.height)) 1.558 + { 1.559 + if (!is_power_of_two(pbsize.width)) 1.560 + pbsize.width = next_power_of_two(pbsize.width); 1.561 + if (!is_power_of_two(pbsize.height)) 1.562 + pbsize.height = next_power_of_two(pbsize.height); 1.563 + 1.564 + NS_WARNING("Failed to create pbuffer, trying power of two dims"); 1.565 + goto TRY_AGAIN_POWER_OF_TWO; 1.566 + } 1.567 + 1.568 + NS_WARNING("Failed to create pbuffer surface"); 1.569 + return nullptr; 1.570 + } 1.571 + 1.572 + return surface; 1.573 +} 1.574 + 1.575 +static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = { 1.576 + LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT, 1.577 + LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, 1.578 + // Old versions of llvmpipe seem to need this to properly create the pbuffer (bug 981856) 1.579 + LOCAL_EGL_RED_SIZE, 8, 1.580 + LOCAL_EGL_GREEN_SIZE, 8, 1.581 + LOCAL_EGL_BLUE_SIZE, 8, 1.582 + LOCAL_EGL_ALPHA_SIZE, 0, 1.583 + EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS 1.584 +}; 1.585 + 1.586 +static const EGLint kEGLConfigAttribsRGB16[] = { 1.587 + LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, 1.588 + LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, 1.589 + LOCAL_EGL_RED_SIZE, 5, 1.590 + LOCAL_EGL_GREEN_SIZE, 6, 1.591 + LOCAL_EGL_BLUE_SIZE, 5, 1.592 + LOCAL_EGL_ALPHA_SIZE, 0, 1.593 + EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS 1.594 +}; 1.595 + 1.596 +static const EGLint kEGLConfigAttribsRGB24[] = { 1.597 + LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, 1.598 + LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, 1.599 + LOCAL_EGL_RED_SIZE, 8, 1.600 + LOCAL_EGL_GREEN_SIZE, 8, 1.601 + LOCAL_EGL_BLUE_SIZE, 8, 1.602 + LOCAL_EGL_ALPHA_SIZE, 0, 1.603 + EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS 1.604 +}; 1.605 + 1.606 +static const EGLint kEGLConfigAttribsRGBA32[] = { 1.607 + LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT, 1.608 + LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT, 1.609 + LOCAL_EGL_RED_SIZE, 8, 1.610 + LOCAL_EGL_GREEN_SIZE, 8, 1.611 + LOCAL_EGL_BLUE_SIZE, 8, 1.612 + LOCAL_EGL_ALPHA_SIZE, 8, 1.613 +#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 1.614 + LOCAL_EGL_FRAMEBUFFER_TARGET_ANDROID, LOCAL_EGL_TRUE, 1.615 +#endif 1.616 + EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS 1.617 +}; 1.618 + 1.619 +static bool 1.620 +CreateConfig(EGLConfig* aConfig, int32_t depth) 1.621 +{ 1.622 + EGLConfig configs[64]; 1.623 + const EGLint* attribs; 1.624 + EGLint ncfg = ArrayLength(configs); 1.625 + 1.626 + switch (depth) { 1.627 + case 16: 1.628 + attribs = kEGLConfigAttribsRGB16; 1.629 + break; 1.630 + case 24: 1.631 + attribs = kEGLConfigAttribsRGB24; 1.632 + break; 1.633 + case 32: 1.634 + attribs = kEGLConfigAttribsRGBA32; 1.635 + break; 1.636 + default: 1.637 + NS_ERROR("Unknown pixel depth"); 1.638 + return false; 1.639 + } 1.640 + 1.641 + if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), attribs, 1.642 + configs, ncfg, &ncfg) || 1.643 + ncfg < 1) { 1.644 + return false; 1.645 + } 1.646 + 1.647 + for (int j = 0; j < ncfg; ++j) { 1.648 + EGLConfig config = configs[j]; 1.649 + EGLint r, g, b, a; 1.650 + 1.651 + if (sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config, 1.652 + LOCAL_EGL_RED_SIZE, &r) && 1.653 + sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config, 1.654 + LOCAL_EGL_GREEN_SIZE, &g) && 1.655 + sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config, 1.656 + LOCAL_EGL_BLUE_SIZE, &b) && 1.657 + sEGLLibrary.fGetConfigAttrib(EGL_DISPLAY(), config, 1.658 + LOCAL_EGL_ALPHA_SIZE, &a) && 1.659 + ((depth == 16 && r == 5 && g == 6 && b == 5) || 1.660 + (depth == 24 && r == 8 && g == 8 && b == 8) || 1.661 + (depth == 32 && r == 8 && g == 8 && b == 8 && a == 8))) 1.662 + { 1.663 + *aConfig = config; 1.664 + return true; 1.665 + } 1.666 + } 1.667 + return false; 1.668 +} 1.669 + 1.670 +// Return true if a suitable EGLConfig was found and pass it out 1.671 +// through aConfig. Return false otherwise. 1.672 +// 1.673 +// NB: It's entirely legal for the returned EGLConfig to be valid yet 1.674 +// have the value null. 1.675 +static bool 1.676 +CreateConfig(EGLConfig* aConfig) 1.677 +{ 1.678 + int32_t depth = gfxPlatform::GetPlatform()->GetScreenDepth(); 1.679 + if (!CreateConfig(aConfig, depth)) { 1.680 +#ifdef MOZ_WIDGET_ANDROID 1.681 + // Bug 736005 1.682 + // Android doesn't always support 16 bit so also try 24 bit 1.683 + if (depth == 16) { 1.684 + return CreateConfig(aConfig, 24); 1.685 + } 1.686 + // Bug 970096 1.687 + // Some devices that have 24 bit screens only support 16 bit OpenGL? 1.688 + if (depth == 24) { 1.689 + return CreateConfig(aConfig, 16); 1.690 + } 1.691 +#endif 1.692 + return false; 1.693 + } else { 1.694 + return true; 1.695 + } 1.696 +} 1.697 + 1.698 +already_AddRefed<GLContext> 1.699 +GLContextProviderEGL::CreateWrappingExisting(void* aContext, void* aSurface) 1.700 +{ 1.701 + if (!sEGLLibrary.EnsureInitialized()) { 1.702 + MOZ_CRASH("Failed to load EGL library!\n"); 1.703 + return nullptr; 1.704 + } 1.705 + 1.706 + if (aContext && aSurface) { 1.707 + SurfaceCaps caps = SurfaceCaps::Any(); 1.708 + EGLConfig config = EGL_NO_CONFIG; 1.709 + nsRefPtr<GLContextEGL> glContext = 1.710 + new GLContextEGL(caps, 1.711 + nullptr, false, 1.712 + config, (EGLSurface)aSurface, (EGLContext)aContext); 1.713 + 1.714 + glContext->SetIsDoubleBuffered(true); 1.715 + glContext->mOwnsContext = false; 1.716 + 1.717 + return glContext.forget(); 1.718 + } 1.719 + 1.720 + return nullptr; 1.721 +} 1.722 + 1.723 +already_AddRefed<GLContext> 1.724 +GLContextProviderEGL::CreateForWindow(nsIWidget *aWidget) 1.725 +{ 1.726 + if (!sEGLLibrary.EnsureInitialized()) { 1.727 + MOZ_CRASH("Failed to load EGL library!\n"); 1.728 + return nullptr; 1.729 + } 1.730 + 1.731 + bool doubleBuffered = true; 1.732 + 1.733 + EGLConfig config; 1.734 + if (!CreateConfig(&config)) { 1.735 + MOZ_CRASH("Failed to create EGLConfig!\n"); 1.736 + return nullptr; 1.737 + } 1.738 + 1.739 + EGLSurface surface = mozilla::gl::CreateSurfaceForWindow(aWidget, config); 1.740 + 1.741 + if (surface == EGL_NO_SURFACE) { 1.742 + MOZ_CRASH("Failed to create EGLSurface!\n"); 1.743 + return nullptr; 1.744 + } 1.745 + 1.746 + SurfaceCaps caps = SurfaceCaps::Any(); 1.747 + nsRefPtr<GLContextEGL> glContext = 1.748 + GLContextEGL::CreateGLContext(caps, 1.749 + nullptr, false, 1.750 + config, surface); 1.751 + 1.752 + if (!glContext) { 1.753 + MOZ_CRASH("Failed to create EGLContext!\n"); 1.754 + DestroySurface(surface); 1.755 + return nullptr; 1.756 + } 1.757 + 1.758 + glContext->MakeCurrent(); 1.759 + glContext->SetIsDoubleBuffered(doubleBuffered); 1.760 + 1.761 + return glContext.forget(); 1.762 +} 1.763 + 1.764 +already_AddRefed<GLContextEGL> 1.765 +GLContextEGL::CreateEGLPBufferOffscreenContext(const gfxIntSize& size) 1.766 +{ 1.767 + EGLConfig config; 1.768 + EGLSurface surface; 1.769 + 1.770 + const EGLint numConfigs = 1; // We only need one. 1.771 + EGLConfig configs[numConfigs]; 1.772 + EGLint foundConfigs = 0; 1.773 + if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(), 1.774 + kEGLConfigAttribsOffscreenPBuffer, 1.775 + configs, numConfigs, 1.776 + &foundConfigs) 1.777 + || foundConfigs == 0) 1.778 + { 1.779 + NS_WARNING("No EGL Config for minimal PBuffer!"); 1.780 + return nullptr; 1.781 + } 1.782 + 1.783 + // We absolutely don't care, so just pick the first one. 1.784 + config = configs[0]; 1.785 + if (GLContext::DebugMode()) 1.786 + sEGLLibrary.DumpEGLConfig(config); 1.787 + 1.788 + gfxIntSize pbSize(size); 1.789 + surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config, 1.790 + LOCAL_EGL_NONE, 1.791 + pbSize); 1.792 + if (!surface) { 1.793 + NS_WARNING("Failed to create PBuffer for context!"); 1.794 + return nullptr; 1.795 + } 1.796 + 1.797 + SurfaceCaps dummyCaps = SurfaceCaps::Any(); 1.798 + nsRefPtr<GLContextEGL> glContext = 1.799 + GLContextEGL::CreateGLContext(dummyCaps, 1.800 + nullptr, true, 1.801 + config, surface); 1.802 + if (!glContext) { 1.803 + NS_WARNING("Failed to create GLContext from PBuffer"); 1.804 + sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); 1.805 + return nullptr; 1.806 + } 1.807 + 1.808 + if (!glContext->Init()) { 1.809 + NS_WARNING("Failed to initialize GLContext!"); 1.810 + // GLContextEGL::dtor will destroy |surface| for us. 1.811 + return nullptr; 1.812 + } 1.813 + 1.814 + return glContext.forget(); 1.815 +} 1.816 + 1.817 +already_AddRefed<GLContextEGL> 1.818 +GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size) 1.819 +{ 1.820 + gfxASurface *thebesSurface = nullptr; 1.821 + EGLNativePixmapType pixmap = 0; 1.822 + 1.823 + if (!pixmap) { 1.824 + return nullptr; 1.825 + } 1.826 + 1.827 + EGLSurface surface = 0; 1.828 + EGLConfig config = 0; 1.829 + 1.830 + if (!config) { 1.831 + return nullptr; 1.832 + } 1.833 + MOZ_ASSERT(surface); 1.834 + 1.835 + SurfaceCaps dummyCaps = SurfaceCaps::Any(); 1.836 + nsRefPtr<GLContextEGL> glContext = 1.837 + GLContextEGL::CreateGLContext(dummyCaps, 1.838 + nullptr, true, 1.839 + config, surface); 1.840 + if (!glContext) { 1.841 + NS_WARNING("Failed to create GLContext from XSurface"); 1.842 + sEGLLibrary.fDestroySurface(EGL_DISPLAY(), surface); 1.843 + return nullptr; 1.844 + } 1.845 + 1.846 + if (!glContext->Init()) { 1.847 + NS_WARNING("Failed to initialize GLContext!"); 1.848 + // GLContextEGL::dtor will destroy |surface| for us. 1.849 + return nullptr; 1.850 + } 1.851 + 1.852 + glContext->HoldSurface(thebesSurface); 1.853 + 1.854 + return glContext.forget(); 1.855 +} 1.856 + 1.857 +// Under EGL, on Android, pbuffers are supported fine, though 1.858 +// often without the ability to texture from them directly. 1.859 +already_AddRefed<GLContext> 1.860 +GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size, 1.861 + const SurfaceCaps& caps) 1.862 +{ 1.863 + if (!sEGLLibrary.EnsureInitialized()) { 1.864 + return nullptr; 1.865 + } 1.866 + 1.867 + gfxIntSize dummySize = gfxIntSize(16, 16); 1.868 + nsRefPtr<GLContextEGL> glContext; 1.869 + glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize); 1.870 + 1.871 + if (!glContext) 1.872 + return nullptr; 1.873 + 1.874 + if (!glContext->InitOffscreen(ToIntSize(size), caps)) 1.875 + return nullptr; 1.876 + 1.877 + return glContext.forget(); 1.878 +} 1.879 + 1.880 +// Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225) 1.881 +// and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257) 1.882 +// and 3) each EGL context eats 750k on B2G (bug 813783) 1.883 +GLContext * 1.884 +GLContextProviderEGL::GetGlobalContext() 1.885 +{ 1.886 + return nullptr; 1.887 +} 1.888 + 1.889 +void 1.890 +GLContextProviderEGL::Shutdown() 1.891 +{ 1.892 +} 1.893 + 1.894 +} /* namespace gl */ 1.895 +} /* namespace mozilla */ 1.896 + 1.897 +#undef EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS