Bug 1453501 - Allow GLContextEGL to be used without a surface r=jgilbert

Right now GLContextProviderEGL requires the widget to have a valid
EGLSurface when creating a non-offscreen GLContext. This patch falls
back to a dummy pbuffer surface or EGL_NO_SURFACE if supported, allowing
the GLContext creation to succeed. This will give us some more flexibility
on Android where the widget surface is not always readily available.

Additinally, we use the fallback surface any time MakeCurrent() is
called without a valid surface. This is needed to allow things like
Compositor shutdown when there is no widget surface available.

MozReview-Commit-ID: 1kbLIGNiOkV
This commit is contained in:
James Willcox 2018-04-25 14:30:27 -05:00
Родитель 2079f15ee0
Коммит 5c6878f58e
4 изменённых файлов: 51 добавлений и 14 удалений

Просмотреть файл

@ -117,6 +117,7 @@ public:
const EGLConfig mConfig;
protected:
EGLSurface mSurface;
const EGLSurface mFallbackSurface;
public:
const EGLContext mContext;
protected:

Просмотреть файл

@ -131,10 +131,35 @@ DestroySurface(EGLSurface oldSurface) {
}
static EGLSurface
CreateSurfaceFromNativeWindow(EGLNativeWindowType window, const EGLConfig& config) {
EGLSurface newSurface = nullptr;
CreateFallbackSurface(const EGLConfig& config)
{
if (sEGLLibrary.IsExtensionSupported(GLLibraryEGL::KHR_surfaceless_context)) {
// We don't need a PBuffer surface in this case
return EGL_NO_SURFACE;
}
std::vector<EGLint> pbattrs;
pbattrs.push_back(LOCAL_EGL_WIDTH); pbattrs.push_back(1);
pbattrs.push_back(LOCAL_EGL_HEIGHT); pbattrs.push_back(1);
for (const auto& cur : kTerminationAttribs) {
pbattrs.push_back(cur);
}
EGLSurface surface = sEGLLibrary.fCreatePbufferSurface(EGL_DISPLAY(), config, pbattrs.data());
if (!surface) {
MOZ_CRASH("Failed to create fallback EGLSurface");
}
return surface;
}
static EGLSurface
CreateSurfaceFromNativeWindow(EGLNativeWindowType window, const EGLConfig& config)
{
MOZ_ASSERT(window);
EGLSurface newSurface = EGL_NO_SURFACE;
#ifdef MOZ_WIDGET_ANDROID
JNIEnv* const env = jni::GetEnvForThread();
ANativeWindow* const nativeWindow = ANativeWindow_fromSurface(
@ -168,7 +193,6 @@ already_AddRefed<GLContext>
GLContextEGLFactory::Create(EGLNativeWindowType aWindow,
bool aWebRender)
{
MOZ_ASSERT(aWindow);
nsCString discardFailureId;
if (!sEGLLibrary.EnsureInitialized(false, &discardFailureId)) {
gfxCriticalNote << "Failed to load EGL library 3!";
@ -193,11 +217,9 @@ GLContextEGLFactory::Create(EGLNativeWindowType aWindow,
}
}
EGLSurface surface = mozilla::gl::CreateSurfaceFromNativeWindow(aWindow, config);
if (!surface) {
gfxCriticalNote << "Failed to create EGLSurface!";
return nullptr;
EGLSurface surface = EGL_NO_SURFACE;
if (aWindow) {
surface = mozilla::gl::CreateSurfaceFromNativeWindow(aWindow, config);
}
CreateContextFlags flags = CreateContextFlags::NONE;
@ -228,6 +250,7 @@ GLContextEGL::GLContextEGL(CreateContextFlags flags, const SurfaceCaps& caps,
: GLContext(flags, caps, nullptr, isOffscreen, false)
, mConfig(config)
, mSurface(surface)
, mFallbackSurface(CreateFallbackSurface(config))
, mContext(context)
, mSurfaceOverride(EGL_NO_SURFACE)
, mThebesSurface(nullptr)
@ -259,6 +282,7 @@ GLContextEGL::~GLContextEGL()
sEGLLibrary.fDestroyContext(EGL_DISPLAY(), mContext);
mozilla::gl::DestroySurface(mSurface);
mozilla::gl::DestroySurface(mFallbackSurface);
}
bool
@ -356,8 +380,12 @@ GLContextEGL::SetEGLSurfaceOverride(EGLSurface surf) {
bool
GLContextEGL::MakeCurrentImpl() const
{
const EGLSurface surface = (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride
: mSurface;
EGLSurface surface = (mSurfaceOverride != EGL_NO_SURFACE) ? mSurfaceOverride
: mSurface;
if (!surface) {
surface = mFallbackSurface;
}
const bool succeeded = sEGLLibrary.fMakeCurrent(EGL_DISPLAY(), surface, surface,
mContext);
if (!succeeded) {
@ -391,10 +419,16 @@ GLContextEGL::RenewSurface(CompositorWidget* aWidget) {
// If we get here, then by definition we know that we want to get a new surface.
ReleaseSurface();
MOZ_ASSERT(aWidget);
mSurface = mozilla::gl::CreateSurfaceFromNativeWindow(GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget), mConfig);
if (!mSurface) {
return false;
void* nativeWindow = GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aWidget);
if (nativeWindow) {
mSurface = mozilla::gl::CreateSurfaceFromNativeWindow(nativeWindow, mConfig);
if (!mSurface) {
NS_WARNING("Failed to create EGLSurface from native window");
return false;
}
}
return MakeCurrent(true);
}

Просмотреть файл

@ -61,6 +61,7 @@ static const char* sEGLExtensionNames[] = {
"EGL_ANGLE_stream_producer_d3d_texture",
"EGL_ANGLE_device_creation",
"EGL_ANGLE_device_creation_d3d11",
"EGL_KHR_surfaceless_context"
};
#if defined(ANDROID)

Просмотреть файл

@ -75,7 +75,7 @@ public:
* IsExtensionSupported. The results of this are cached, and as
* such it's safe to use this even in performance critical code.
* If you add to this array, remember to add to the string names
* in GLContext.cpp.
* in GLLibraryEGL.cpp.
*/
enum EGLExtensions {
KHR_image_base,
@ -99,6 +99,7 @@ public:
ANGLE_stream_producer_d3d_texture,
ANGLE_device_creation,
ANGLE_device_creation_d3d11,
KHR_surfaceless_context,
Extensions_Max
};