Bug 1191042 - Establish correct EGLConfig at GLContext creation. r=jrmuizel

This commit is contained in:
Jeff Gilbert 2015-08-27 10:38:45 -04:00 committed by Andrew Comminos
parent 17485a8da3
commit 49821ec279
6 changed files with 141 additions and 173 deletions

View File

@ -571,6 +571,24 @@ CreateHeadlessANGLE(CreateContextFlags flags, const nsCOMPtr<nsIGfxInfo>& gfxInf
{
nsRefPtr<GLContext> gl;
// ANGLE doesn't really support non-alpha backbuffers.
flags |= CreateContextFlags::SUPPORT_ALPHA;
// ANGLE also doesn't really support depth without stencil, and vice-versa.
// While we could fake that we don't have one or the other, instead, we *should* just
// fail to create a context without both. However, since the defaults are depth:true,
// stencil:false, many demos that rely on the implicit depth allocation will fail.
// Thus we must limp along for depth:true, stencil:false, but we shouldn't support
// depth:false, stencil:true.
// That is, if there's depth, give depth+stencil, else give neither.
if (flags & CreateContextFlags::SUPPORT_DEPTH) {
flags |= CreateContextFlags::SUPPORT_STENCIL;
} else {
flags &= ~CreateContextFlags::SUPPORT_DEPTH;
flags &= ~CreateContextFlags::SUPPORT_STENCIL;
}
#ifdef XP_WIN
gl = gl::GLContextProviderEGL::CreateHeadless(flags);
if (!gl) {
@ -758,6 +776,16 @@ WebGLContext::CreateOffscreenGL(bool forceEnabled)
CreateContextFlags flags = forceEnabled ? CreateContextFlags::FORCE_ENABLE_HARDWARE :
CreateContextFlags::NONE;
if (mOptions.alpha)
flags |= CreateContextFlags::SUPPORT_ALPHA;
if (!mOptions.antialias) {
if (mOptions.depth)
flags |= CreateContextFlags::SUPPORT_DEPTH;
if (mOptions.stencil)
flags |= CreateContextFlags::SUPPORT_STENCIL;
}
gl = CreateHeadlessGL(flags, gfxInfo, this);
do {

View File

@ -92,15 +92,19 @@ public:
// for the lifetime of this context.
void HoldSurface(gfxASurface *aSurf);
EGLContext GetEGLContext() {
EGLContext GetEGLContext() const {
return mContext;
}
EGLSurface GetEGLSurface() {
EGLConfig GetEGLConfig() const {
return mConfig;
}
EGLSurface GetEGLSurface() const {
return mSurface;
}
EGLDisplay GetEGLDisplay() {
EGLDisplay GetEGLDisplay() const {
return EGL_DISPLAY();
}
@ -112,7 +116,7 @@ public:
CreateEGLPixmapOffscreenContext(const gfx::IntSize& size);
static already_AddRefed<GLContextEGL>
CreateEGLPBufferOffscreenContext(const gfx::IntSize& size);
CreateEGLPBufferOffscreenContext(CreateContextFlags flags, const gfx::IntSize& size);
protected:
friend class GLContextProviderEGL;

View File

@ -9,7 +9,6 @@
#include "GLContextTypes.h"
#include "nsAutoPtr.h"
#include "SurfaceTypes.h"
#include "mozilla/TypedEnumBits.h"
#include "nsSize.h" // for gfx::IntSize (needed by GLContextProviderImpl.h below)
@ -18,16 +17,6 @@ class nsIWidget;
namespace mozilla {
namespace gl {
enum class CreateContextFlags : int8_t {
NONE = 0,
REQUIRE_COMPAT_PROFILE = 1 << 0,
// Force the use of hardware backed GL, don't allow software implementations.
FORCE_ENABLE_HARDWARE = 1 << 1,
/* Don't force discrete GPU to be used (if applicable) */
ALLOW_OFFLINE_RENDERER = 1 << 2,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags)
#define IN_GL_CONTEXT_PROVIDER_H
// Null is always there

View File

@ -593,17 +593,6 @@ TRY_AGAIN_POWER_OF_TWO:
return surface;
}
static const EGLint kEGLConfigAttribsOffscreenPBuffer[] = {
LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT,
LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
// Old versions of llvmpipe seem to need this to properly create the pbuffer (bug 981856)
LOCAL_EGL_RED_SIZE, 8,
LOCAL_EGL_GREEN_SIZE, 8,
LOCAL_EGL_BLUE_SIZE, 8,
LOCAL_EGL_ALPHA_SIZE, 0,
EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
};
static const EGLint kEGLConfigAttribsRGB16[] = {
LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_WINDOW_BIT,
LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT,
@ -839,18 +828,72 @@ GLContextProviderEGL::DestroyEGLSurface(EGLSurface surface)
}
#endif // defined(ANDROID)
already_AddRefed<GLContextEGL>
GLContextEGL::CreateEGLPBufferOffscreenContext(const mozilla::gfx::IntSize& size)
{
EGLConfig config;
EGLSurface surface;
const EGLint numConfigs = 1; // We only need one.
EGLConfig configs[numConfigs];
static void
FillContextAttribs(bool alpha, bool depth, bool stencil, std::vector<EGLint>* out)
{
out->push_back(LOCAL_EGL_SURFACE_TYPE);
out->push_back(LOCAL_EGL_PBUFFER_BIT);
out->push_back(LOCAL_EGL_RENDERABLE_TYPE);
out->push_back(LOCAL_EGL_OPENGL_ES2_BIT);
out->push_back(LOCAL_EGL_RED_SIZE);
out->push_back(8);
out->push_back(LOCAL_EGL_GREEN_SIZE);
out->push_back(8);
out->push_back(LOCAL_EGL_BLUE_SIZE);
out->push_back(8);
out->push_back(LOCAL_EGL_ALPHA_SIZE);
out->push_back(alpha ? 8 : 0);
out->push_back(LOCAL_EGL_DEPTH_SIZE);
out->push_back(depth ? 24 : 0);
out->push_back(LOCAL_EGL_STENCIL_SIZE);
out->push_back(stencil ? 8 : 0);
// EGL_ATTRIBS_LIST_SAFE_TERMINATION_WORKING_AROUND_BUGS
out->push_back(LOCAL_EGL_NONE);
out->push_back(0);
out->push_back(0);
out->push_back(0);
}
static bool
DoesAttribPresenceMatch(GLLibraryEGL& egl, EGLConfig config, EGLint attrib,
bool shouldHaveBits)
{
EGLint bits = 0;
egl.fGetConfigAttrib(egl.Display(), config, attrib, &bits);
MOZ_ASSERT(egl.fGetError() == LOCAL_EGL_SUCCESS);
return bool(bits) == shouldHaveBits;
}
already_AddRefed<GLContextEGL>
GLContextEGL::CreateEGLPBufferOffscreenContext(CreateContextFlags flags,
const mozilla::gfx::IntSize& size)
{
const bool alpha = (flags & CreateContextFlags::SUPPORT_ALPHA);
const bool depth = (flags & CreateContextFlags::SUPPORT_DEPTH);
const bool stencil = (flags & CreateContextFlags::SUPPORT_STENCIL);
std::vector<EGLint> configAttribVec;
FillContextAttribs(alpha, depth, stencil, &configAttribVec);
const EGLint* configAttribs = configAttribVec.data();
const EGLint kMaxConfigs = 256;
EGLConfig configs[kMaxConfigs];
EGLint foundConfigs = 0;
if (!sEGLLibrary.fChooseConfig(EGL_DISPLAY(),
kEGLConfigAttribsOffscreenPBuffer,
configs, numConfigs,
configAttribs,
configs, kMaxConfigs,
&foundConfigs)
|| foundConfigs == 0)
{
@ -858,15 +901,33 @@ GLContextEGL::CreateEGLPBufferOffscreenContext(const mozilla::gfx::IntSize& size
return nullptr;
}
// We absolutely don't care, so just pick the first one.
config = configs[0];
EGLConfig config = EGL_NO_CONFIG;
for (EGLint i = 0; i < foundConfigs; i++) {
EGLConfig& cur = configs[i];
bool doesMatch = true;
doesMatch &= DoesAttribPresenceMatch(sEGLLibrary, cur, LOCAL_EGL_ALPHA_SIZE, alpha);
doesMatch &= DoesAttribPresenceMatch(sEGLLibrary, cur, LOCAL_EGL_DEPTH_SIZE, depth);
doesMatch &= DoesAttribPresenceMatch(sEGLLibrary, cur, LOCAL_EGL_STENCIL_SIZE, stencil);
if (doesMatch) {
config = cur;
break;
}
}
if (config == EGL_NO_CONFIG) {
NS_WARNING("Failed to find a compatible config.");
return nullptr;
}
if (GLContext::ShouldSpew())
sEGLLibrary.DumpEGLConfig(config);
mozilla::gfx::IntSize pbSize(size);
surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
LOCAL_EGL_NONE,
pbSize);
EGLSurface surface = GLContextEGL::CreatePBufferSurfaceTryingPowerOfTwo(config,
LOCAL_EGL_NONE,
pbSize);
if (!surface) {
NS_WARNING("Failed to create PBuffer for context!");
return nullptr;
@ -941,7 +1002,7 @@ GLContextProviderEGL::CreateHeadless(CreateContextFlags flags)
mozilla::gfx::IntSize dummySize = mozilla::gfx::IntSize(16, 16);
nsRefPtr<GLContext> glContext;
glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize);
glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(flags, dummySize);
if (!glContext)
return nullptr;

View File

@ -7,6 +7,7 @@
#define GLCONTEXT_TYPES_H_
#include "GLTypes.h"
#include "mozilla/TypedEnumBits.h"
namespace mozilla {
namespace gl {
@ -43,6 +44,22 @@ struct GLFormats
GLsizei samples;
};
enum class CreateContextFlags : int8_t {
NONE = 0,
REQUIRE_COMPAT_PROFILE = 1 << 0,
// Force the use of hardware backed GL, don't allow software implementations.
FORCE_ENABLE_HARDWARE = 1 << 1,
// Don't force discrete GPU to be used. (if applicable)
ALLOW_OFFLINE_RENDERER = 1 << 2,
// Ensure that later we'll be able to attach a backbuffer with these properties:
SUPPORT_ALPHA = 1 << 3,
SUPPORT_DEPTH = 1 << 4,
SUPPORT_STENCIL = 1 << 5,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CreateContextFlags)
} /* namespace gl */
} /* namespace mozilla */

View File

@ -281,137 +281,6 @@ SharedSurface_ANGLEShareHandle::ToSurfaceDescriptor(layers::SurfaceDescriptor* c
////////////////////////////////////////////////////////////////////////////////
// Factory
static void
FillPBufferAttribs_ByBits(nsTArray<EGLint>& aAttrs,
int redBits, int greenBits,
int blueBits, int alphaBits,
int depthBits, int stencilBits)
{
aAttrs.Clear();
#if defined(A1) || defined(A2)
#error The temp-macro names we want are already defined.
#endif
#define A1(_x) do { aAttrs.AppendElement(_x); } while (0)
#define A2(_x,_y) do { A1(_x); A1(_y); } while (0)
A2(LOCAL_EGL_RENDERABLE_TYPE, LOCAL_EGL_OPENGL_ES2_BIT);
A2(LOCAL_EGL_SURFACE_TYPE, LOCAL_EGL_PBUFFER_BIT);
A2(LOCAL_EGL_RED_SIZE, redBits);
A2(LOCAL_EGL_GREEN_SIZE, greenBits);
A2(LOCAL_EGL_BLUE_SIZE, blueBits);
A2(LOCAL_EGL_ALPHA_SIZE, alphaBits);
A2(LOCAL_EGL_DEPTH_SIZE, depthBits);
A2(LOCAL_EGL_STENCIL_SIZE, stencilBits);
A1(LOCAL_EGL_NONE);
#undef A1
#undef A2
}
static void
FillPBufferAttribs_BySizes(nsTArray<EGLint>& attribs,
bool bpp16, bool hasAlpha,
int depthBits, int stencilBits)
{
int red = 0;
int green = 0;
int blue = 0;
int alpha = 0;
if (bpp16) {
if (hasAlpha) {
red = green = blue = alpha = 4;
} else {
red = 5;
green = 6;
blue = 5;
}
} else {
red = green = blue = 8;
if (hasAlpha)
alpha = 8;
}
FillPBufferAttribs_ByBits(attribs, red, green, blue, alpha, depthBits,
stencilBits);
}
static bool
DoesAttribBitsMatchCapBool(GLLibraryEGL* egl, EGLConfig config, EGLint attrib,
bool capBool)
{
EGLint bits = 0;
egl->fGetConfigAttrib(egl->Display(), config, attrib, &bits);
MOZ_ASSERT(egl->fGetError() == LOCAL_EGL_SUCCESS);
bool hasBits = !!bits;
return hasBits == capBool;
}
static EGLConfig
ChooseConfig(GLContext* gl, GLLibraryEGL* egl, const SurfaceCaps& caps)
{
MOZ_ASSERT(egl);
MOZ_ASSERT(caps.color);
// We might want 24-bit depth, but we're only (fairly) sure to get 16-bit.
int depthBits = caps.depth ? 16 : 0;
int stencilBits = caps.stencil ? 8 : 0;
// Ok, now we have everything.
nsTArray<EGLint> attribs(32);
FillPBufferAttribs_BySizes(attribs, caps.bpp16, caps.alpha, depthBits,
stencilBits);
// Time to try to get this config:
EGLConfig configs[64];
int numConfigs = sizeof(configs)/sizeof(EGLConfig);
int foundConfigs = 0;
if (!egl->fChooseConfig(egl->Display(), attribs.Elements(), configs,
numConfigs, &foundConfigs) ||
!foundConfigs)
{
NS_WARNING("No configs found for the requested formats.");
return EGL_NO_CONFIG;
}
// The requests passed to ChooseConfig are treated as minimums. If you ask
// for 0 bits of alpha, we might still get 8 bits.
EGLConfig config = EGL_NO_CONFIG;
for (int i = 0; i < foundConfigs; i++) {
EGLConfig cur = configs[i];
if (!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_ALPHA_SIZE,
caps.alpha) ||
!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_DEPTH_SIZE,
caps.depth) ||
!DoesAttribBitsMatchCapBool(egl, cur, LOCAL_EGL_STENCIL_SIZE,
caps.stencil))
{
continue;
}
config = cur;
break;
}
if (config == EGL_NO_CONFIG) {
NS_WARNING("No acceptable EGLConfig found.");
return EGL_NO_CONFIG;
}
if (gl->DebugMode()) {
egl->DumpEGLConfig(config);
}
return config;
}
/*static*/ UniquePtr<SurfaceFactory_ANGLEShareHandle>
SurfaceFactory_ANGLEShareHandle::Create(GLContext* gl, const SurfaceCaps& caps,
const RefPtr<layers::ISurfaceAllocator>& allocator,
@ -449,7 +318,7 @@ SurfaceFactory_ANGLEShareHandle::SurfaceFactory_ANGLEShareHandle(GLContext* gl,
*out_success = false;
mContext = GLContextEGL::Cast(mProdGL)->GetEGLContext();
mConfig = ChooseConfig(mProdGL, mEGL, mReadCaps);
mConfig = GLContextEGL::Cast(mProdGL)->GetEGLConfig();
if (mConfig == EGL_NO_CONFIG)
return;