Bug 996266 - Fall back from failed WebGL context creation attribs. - r=kamidphish,bjacob

This commit is contained in:
Jeff Gilbert 2014-08-27 16:16:22 -07:00
parent fd5e2abf5a
commit 9451a4fa01
13 changed files with 455 additions and 206 deletions

View File

@ -72,6 +72,8 @@
#include "mozilla/layers/ShadowLayers.h" #include "mozilla/layers/ShadowLayers.h"
#endif #endif
#include <queue>
using namespace mozilla; using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
using namespace mozilla::gfx; using namespace mozilla::gfx;
@ -435,12 +437,10 @@ WebGLContext::SetContextOptions(JSContext* aCx, JS::Handle<JS::Value> aOptions)
newOpts.premultipliedAlpha = attributes.mPremultipliedAlpha; newOpts.premultipliedAlpha = attributes.mPremultipliedAlpha;
newOpts.antialias = attributes.mAntialias; newOpts.antialias = attributes.mAntialias;
newOpts.preserveDrawingBuffer = attributes.mPreserveDrawingBuffer; newOpts.preserveDrawingBuffer = attributes.mPreserveDrawingBuffer;
if (attributes.mAlpha.WasPassed()) {
newOpts.alpha = attributes.mAlpha.Value();
}
// enforce that if stencil is specified, we also give back depth if (attributes.mAlpha.WasPassed()) {
newOpts.depth |= newOpts.stencil; newOpts.alpha = attributes.mAlpha.Value();
}
// Don't do antialiasing if we've disabled MSAA. // Don't do antialiasing if we've disabled MSAA.
if (!gfxPrefs::MSAALevel()) { if (!gfxPrefs::MSAALevel()) {
@ -471,36 +471,333 @@ WebGLContext::SetContextOptions(JSContext* aCx, JS::Handle<JS::Value> aOptions)
int32_t int32_t
WebGLContext::GetWidth() const WebGLContext::GetWidth() const
{ {
return mWidth; return mWidth;
} }
int32_t int32_t
WebGLContext::GetHeight() const WebGLContext::GetHeight() const
{ {
return mHeight; return mHeight;
} }
#endif #endif
/* So there are a number of points of failure here. We might fail based
* on EGL vs. WGL, or we might fail to alloc a too-large size, or we
* might not be able to create a context with a certain combo of context
* creation attribs.
*
* We don't want to test the complete fallback matrix. (for now, at
* least) Instead, attempt creation in this order:
* 1. By platform API. (e.g. EGL vs. WGL)
* 2. By context creation attribs.
* 3. By size.
*
* That is, try to create headless contexts based on the platform API.
* Next, create dummy-sized backbuffers for the contexts with the right
* caps. Finally, resize the backbuffer to an acceptable size given the
* requested size.
*/
static bool
IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
{
int32_t status;
if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(feature, &status)))
return false;
return status != nsIGfxInfo::FEATURE_STATUS_OK;
}
static already_AddRefed<GLContext>
CreateHeadlessNativeGL(bool forceEnabled,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
{
if (!forceEnabled &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL))
{
webgl->GenerateWarning("Refused to create native OpenGL context"
" because of blacklisting.");
return nullptr;
}
nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless();
if (!gl) {
webgl->GenerateWarning("Error during native OpenGL init.");
return nullptr;
}
MOZ_ASSERT(!gl->IsANGLE());
return gl.forget();
}
// Note that we have a separate call for ANGLE and EGL, even though
// right now, we get ANGLE implicitly by using EGL on Windows.
// Eventually, we want to be able to pick ANGLE-EGL or native EGL.
static already_AddRefed<GLContext>
CreateHeadlessANGLE(bool forceEnabled,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
#ifdef XP_WIN
if (!forceEnabled &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_ANGLE))
{
webgl->GenerateWarning("Refused to create ANGLE OpenGL context"
" because of blacklisting.");
return nullptr;
}
gl = gl::GLContextProviderEGL::CreateHeadless();
if (!gl) {
webgl->GenerateWarning("Error during ANGLE OpenGL init.");
return nullptr;
}
MOZ_ASSERT(gl->IsANGLE());
#endif
return gl.forget();
}
static already_AddRefed<GLContext>
CreateHeadlessEGL(bool forceEnabled,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
#ifdef ANDROID
gl = gl::GLContextProviderEGL::CreateHeadless();
if (!gl) {
webgl->GenerateWarning("Error during EGL OpenGL init.");
return nullptr;
}
MOZ_ASSERT(!gl->IsANGLE());
#endif
return gl.forget();
}
static already_AddRefed<GLContext>
CreateHeadlessGL(bool forceEnabled,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
{
bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL");
bool disableANGLE = Preferences::GetBool("webgl.disable-angle", false);
if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) {
disableANGLE = true;
}
nsRefPtr<GLContext> gl;
if (preferEGL)
gl = CreateHeadlessEGL(forceEnabled, gfxInfo, webgl);
if (!gl && !disableANGLE)
gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, webgl);
if (!gl)
gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo, webgl);
return gl.forget();
}
// Try to create a dummy offscreen with the given caps.
static bool
CreateOffscreenWithCaps(GLContext* gl, const SurfaceCaps& caps)
{
gfx::IntSize dummySize(16, 16);
return gl->InitOffscreen(dummySize, caps);
}
static void
PopulateCapFallbackQueue(const SurfaceCaps& baseCaps,
std::queue<SurfaceCaps>* fallbackCaps)
{
fallbackCaps->push(baseCaps);
// Dropping antialias drops our quality, but not our correctness.
// The user basically doesn't have to handle if this fails, they
// just get reduced quality.
if (baseCaps.antialias) {
SurfaceCaps nextCaps(baseCaps);
nextCaps.antialias = false;
PopulateCapFallbackQueue(nextCaps, fallbackCaps);
}
// If we have to drop one of depth or stencil, we'd prefer to keep
// depth. However, the client app will need to handle if this
// doesn't work.
if (baseCaps.stencil) {
SurfaceCaps nextCaps(baseCaps);
nextCaps.stencil = false;
PopulateCapFallbackQueue(nextCaps, fallbackCaps);
}
if (baseCaps.depth) {
SurfaceCaps nextCaps(baseCaps);
nextCaps.depth = false;
PopulateCapFallbackQueue(nextCaps, fallbackCaps);
}
}
static bool
CreateOffscreen(GLContext* gl,
const WebGLContextOptions& options,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl,
layers::ISurfaceAllocator* surfAllocator)
{
SurfaceCaps baseCaps;
baseCaps.color = true;
baseCaps.alpha = options.alpha;
baseCaps.antialias = options.antialias;
baseCaps.depth = options.depth;
baseCaps.preserve = options.preserveDrawingBuffer;
baseCaps.stencil = options.stencil;
// we should really have this behind a
// |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
// for now it's just behind a pref for testing/evaluation.
baseCaps.bpp16 = Preferences::GetBool("webgl.prefer-16bpp", false);
#ifdef MOZ_WIDGET_GONK
baseCaps.surfaceAllocator = surfAllocator;
#endif
// Done with baseCaps construction.
bool forceAllowAA = Preferences::GetBool("webgl.msaa-force", false);
if (!forceAllowAA &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA))
{
webgl->GenerateWarning("Disallowing antialiased backbuffers due"
" to blacklisting.");
baseCaps.antialias = false;
}
std::queue<SurfaceCaps> fallbackCaps;
PopulateCapFallbackQueue(baseCaps, &fallbackCaps);
bool created = false;
while (!fallbackCaps.empty()) {
SurfaceCaps& caps = fallbackCaps.front();
created = CreateOffscreenWithCaps(gl, caps);
if (created)
break;
fallbackCaps.pop();
}
return created;
}
bool
WebGLContext::CreateOffscreenGL(bool forceEnabled)
{
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
layers::ISurfaceAllocator* surfAllocator = nullptr;
#ifdef MOZ_WIDGET_GONK
nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc());
if (docWidget) {
layers::LayerManager* layerManager = docWidget->GetLayerManager();
if (layerManager) {
// XXX we really want "AsSurfaceAllocator" here for generality
layers::ShadowLayerForwarder* forwarder = layerManager->AsShadowForwarder();
if (forwarder) {
surfAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
}
}
}
#endif
gl = CreateHeadlessGL(forceEnabled, gfxInfo, this);
do {
if (!gl)
break;
if (!CreateOffscreen(gl, mOptions, gfxInfo, this, surfAllocator))
break;
if (!InitAndValidateGL())
break;
return true;
} while (false);
gl = nullptr;
return false;
}
// Fallback for resizes:
bool
WebGLContext::ResizeBackbuffer(uint32_t requestedWidth, uint32_t requestedHeight)
{
uint32_t width = requestedWidth;
uint32_t height = requestedHeight;
bool resized = false;
while (width || height) {
width = width ? width : 1;
height = height ? height : 1;
gfx::IntSize curSize(width, height);
if (gl->ResizeOffscreen(curSize)) {
resized = true;
break;
}
width /= 2;
height /= 2;
}
if (!resized)
return false;
mWidth = gl->OffscreenSize().width;
mHeight = gl->OffscreenSize().height;
MOZ_ASSERT((uint32_t)mWidth == width);
MOZ_ASSERT((uint32_t)mHeight == height);
if (width != requestedWidth ||
height != requestedHeight)
{
GenerateWarning("Requested size %dx%d was too large, but resize"
" to %dx%d succeeded.",
requestedWidth, requestedHeight,
width, height);
}
return true;
}
NS_IMETHODIMP NS_IMETHODIMP
WebGLContext::SetDimensions(int32_t width, int32_t height) WebGLContext::SetDimensions(int32_t sWidth, int32_t sHeight)
{ {
// Early error return cases // Early error return cases
if (!GetCanvas())
return NS_ERROR_FAILURE;
if (width < 0 || height < 0) { if (sWidth < 0 || sHeight < 0) {
GenerateWarning("Canvas size is too large (seems like a negative value wrapped)"); GenerateWarning("Canvas size is too large (seems like a negative value wrapped)");
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
if (!GetCanvas()) uint32_t width = sWidth;
return NS_ERROR_FAILURE; uint32_t height = sHeight;
// Early success return cases // Early success return cases
GetCanvas()->InvalidateCanvas(); GetCanvas()->InvalidateCanvas();
if (gl && mWidth == width && mHeight == height)
return NS_OK;
// Zero-sized surfaces can cause problems. // Zero-sized surfaces can cause problems.
if (width == 0) { if (width == 0) {
width = 1; width = 1;
@ -511,20 +808,29 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// If we already have a gl context, then we just need to resize it // If we already have a gl context, then we just need to resize it
if (gl) { if (gl) {
if ((uint32_t)mWidth == width &&
(uint32_t)mHeight == height)
{
return NS_OK;
}
if (IsContextLost())
return NS_OK;
MakeContextCurrent(); MakeContextCurrent();
// If we've already drawn, we should commit the current buffer. // If we've already drawn, we should commit the current buffer.
PresentScreenBuffer(); PresentScreenBuffer();
// ResizeOffscreen scraps the current prod buffer before making a new one. // ResizeOffscreen scraps the current prod buffer before making a new one.
gl->ResizeOffscreen(gfx::IntSize(width, height)); // Doesn't matter if it succeeds (soft-fail) if (!ResizeBackbuffer(width, height)) {
// It's unlikely that we'll get a proper-sized context if we recreate if we didn't on resize GenerateWarning("WebGL context failed to resize.");
ForceLoseContext();
return NS_OK;
}
// everything's good, we're done here // everything's good, we're done here
mWidth = gl->OffscreenSize().width;
mHeight = gl->OffscreenSize().height;
mResetLayer = true; mResetLayer = true;
mBackbufferNeedsClear = true; mBackbufferNeedsClear = true;
return NS_OK; return NS_OK;
@ -541,27 +847,6 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// and that is what can fail if we already have too many. // and that is what can fail if we already have too many.
LoseOldestWebGLContextIfLimitExceeded(); LoseOldestWebGLContextIfLimitExceeded();
// Get some prefs for some preferred/overriden things
NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
#ifdef XP_WIN
bool preferEGL =
Preferences::GetBool("webgl.prefer-egl", false);
bool preferOpenGL =
Preferences::GetBool("webgl.prefer-native-gl", false);
#endif
bool forceEnabled =
Preferences::GetBool("webgl.force-enabled", false);
bool disabled =
Preferences::GetBool("webgl.disabled", false);
bool prefer16bit =
Preferences::GetBool("webgl.prefer-16bpp", false);
ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
if (disabled)
return NS_ERROR_FAILURE;
// We're going to create an entirely new context. If our // We're going to create an entirely new context. If our
// generation is not 0 right now (that is, if this isn't the first // generation is not 0 right now (that is, if this isn't the first
// context we're creating), we may have to dispatch a context lost // context we're creating), we may have to dispatch a context lost
@ -570,111 +855,32 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// If incrementing the generation would cause overflow, // If incrementing the generation would cause overflow,
// don't allow it. Allowing this would allow us to use // don't allow it. Allowing this would allow us to use
// resource handles created from older context generations. // resource handles created from older context generations.
if (!(mGeneration + 1).isValid()) if (!(mGeneration + 1).isValid()) {
GenerateWarning("Too many WebGL contexts created this run.");
return NS_ERROR_FAILURE; // exit without changing the value of mGeneration return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
SurfaceCaps caps;
caps.color = true;
caps.alpha = mOptions.alpha;
caps.depth = mOptions.depth;
caps.stencil = mOptions.stencil;
// we should really have this behind a
// |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
// for now it's just behind a pref for testing/evaluation.
caps.bpp16 = prefer16bit;
caps.preserve = mOptions.preserveDrawingBuffer;
#ifdef MOZ_WIDGET_GONK
nsIWidget *docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc());
if (docWidget) {
layers::LayerManager *layerManager = docWidget->GetLayerManager();
if (layerManager) {
// XXX we really want "AsSurfaceAllocator" here for generality
layers::ShadowLayerForwarder *forwarder = layerManager->AsShadowForwarder();
if (forwarder) {
caps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
}
}
}
#endif
bool forceMSAA =
Preferences::GetBool("webgl.msaa-force", false);
int32_t status;
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
if (mOptions.antialias &&
gfxInfo &&
NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_MSAA, &status))) {
if (status == nsIGfxInfo::FEATURE_STATUS_OK || forceMSAA) {
caps.antialias = true;
}
} }
#ifdef XP_WIN // Get some prefs for some preferred/overriden things
if (PR_GetEnv("MOZ_WEBGL_PREFER_EGL")) { NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
preferEGL = true;
}
#endif
// Ask GfxInfo about what we should use bool disabled = Preferences::GetBool("webgl.disabled", false);
bool useOpenGL = true; if (disabled) {
GenerateWarning("WebGL creation is disabled, and so disallowed here.");
#ifdef XP_WIN return NS_ERROR_FAILURE;
bool useANGLE = true;
#endif
if (gfxInfo && !forceEnabled) {
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_OPENGL, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
useOpenGL = false;
}
}
#ifdef XP_WIN
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_ANGLE, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
useANGLE = false;
}
}
#endif
} }
#ifdef XP_WIN // Alright, now let's start trying.
// allow forcing GL and not EGL/ANGLE bool forceEnabled = Preferences::GetBool("webgl.force-enabled", false);
if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) { ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
preferEGL = false;
useANGLE = false; if (!CreateOffscreenGL(forceEnabled)) {
useOpenGL = true; GenerateWarning("WebGL creation failed.");
return NS_ERROR_FAILURE;
} }
#endif MOZ_ASSERT(gl);
gfxIntSize size(width, height); if (!ResizeBackbuffer(width, height)) {
GenerateWarning("Initializing WebGL backbuffer failed.");
#ifdef XP_WIN
// if we want EGL, try it now
if (!gl && (preferEGL || useANGLE) && !preferOpenGL) {
gl = gl::GLContextProviderEGL::CreateOffscreen(size, caps);
if (!gl || !InitAndValidateGL()) {
GenerateWarning("Error during ANGLE OpenGL ES initialization");
return NS_ERROR_FAILURE;
}
}
#endif
// try the default provider, whatever that is
if (!gl && useOpenGL) {
gl = gl::GLContextProvider::CreateOffscreen(size, caps);
if (gl && !InitAndValidateGL()) {
GenerateWarning("Error during OpenGL initialization");
return NS_ERROR_FAILURE;
}
}
if (!gl) {
GenerateWarning("Can't get a usable WebGL context");
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -684,23 +890,18 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
} }
#endif #endif
mWidth = width;
mHeight = height;
mViewportWidth = width;
mViewportHeight = height;
mResetLayer = true; mResetLayer = true;
mOptionsFrozen = true; mOptionsFrozen = true;
// increment the generation number // increment the generation number
++mGeneration; ++mGeneration;
#if 0
if (mGeneration > 0) {
// XXX dispatch context lost event
}
#endif
MakeContextCurrent(); MakeContextCurrent();
gl->fViewport(0, 0, mWidth, mHeight);
mViewportWidth = mWidth;
mViewportHeight = mHeight;
// Make sure that we clear this out, otherwise // Make sure that we clear this out, otherwise
// we'll end up displaying random memory // we'll end up displaying random memory
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
@ -715,12 +916,12 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
mShouldPresent = true; mShouldPresent = true;
MOZ_ASSERT(gl->Caps().color == caps.color); MOZ_ASSERT(gl->Caps().color);
MOZ_ASSERT(gl->Caps().alpha == caps.alpha); MOZ_ASSERT(gl->Caps().alpha == mOptions.alpha);
MOZ_ASSERT(gl->Caps().depth == caps.depth || !gl->Caps().depth); MOZ_ASSERT(gl->Caps().depth == mOptions.depth || !gl->Caps().depth);
MOZ_ASSERT(gl->Caps().stencil == caps.stencil || !gl->Caps().stencil); MOZ_ASSERT(gl->Caps().stencil == mOptions.stencil || !gl->Caps().stencil);
MOZ_ASSERT(gl->Caps().antialias == caps.antialias || !gl->Caps().antialias); MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias || !gl->Caps().antialias);
MOZ_ASSERT(gl->Caps().preserve == caps.preserve); MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
AssertCachedBindings(); AssertCachedBindings();
AssertCachedState(); AssertCachedState();
@ -1211,7 +1412,7 @@ WebGLContext::PresentScreenBuffer()
gl->MakeCurrent(); gl->MakeCurrent();
MOZ_ASSERT(!mBackbufferNeedsClear); MOZ_ASSERT(!mBackbufferNeedsClear);
if (!gl->PublishFrame()) { if (!gl->PublishFrame()) {
this->ForceLoseContext(); ForceLoseContext();
return false; return false;
} }

View File

@ -1036,7 +1036,9 @@ protected:
// Validation functions (implemented in WebGLContextValidate.cpp) // Validation functions (implemented in WebGLContextValidate.cpp)
GLenum BaseTexFormat(GLenum internalFormat) const; GLenum BaseTexFormat(GLenum internalFormat) const;
bool CreateOffscreenGL(bool forceEnabled);
bool InitAndValidateGL(); bool InitAndValidateGL();
bool ResizeBackbuffer(uint32_t width, uint32_t height);
bool ValidateBlendEquationEnum(GLenum cap, const char *info); bool ValidateBlendEquationEnum(GLenum cap, const char *info);
bool ValidateBlendFuncDstEnum(GLenum mode, const char *info); bool ValidateBlendFuncDstEnum(GLenum mode, const char *info);
bool ValidateBlendFuncSrcEnum(GLenum mode, const char *info); bool ValidateBlendFuncSrcEnum(GLenum mode, const char *info);

View File

@ -175,10 +175,10 @@ skip-if(winWidget) pref(webgl.prefer-16bpp,true)
skip-if(winWidget) pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-color-test.html?16bpp&readback wrapper.html?colors.png skip-if(winWidget) pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-color-test.html?16bpp&readback wrapper.html?colors.png
# Force native GL (Windows): # Force native GL (Windows):
skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-clear-test.html?native-gl wrapper.html?green.png skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-clear-test.html?native-gl wrapper.html?green.png
skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-orientation-test.html?native-gl wrapper.html?white-top-left.png skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-orientation-test.html?native-gl wrapper.html?white-top-left.png
skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-color-test.html?native-gl wrapper.html?colors.png skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-color-test.html?native-gl wrapper.html?colors.png
skip-if(!winWidget) pref(webgl.prefer-native-gl,true) pref(webgl.prefer-16bpp,true) == webgl-color-test.html?native-gl&16bpp wrapper.html?colors.png skip-if(!winWidget) pref(webgl.disable-angle,true) pref(webgl.prefer-16bpp,true) == webgl-color-test.html?native-gl&16bpp wrapper.html?colors.png
# Non-WebGL Reftests! # Non-WebGL Reftests!

View File

@ -1112,6 +1112,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize); raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize);
raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize); raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
raw_fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
#ifdef XP_MACOSX #ifdef XP_MACOSX
if (mWorkAroundDriverBugs) { if (mWorkAroundDriverBugs) {
@ -1127,8 +1128,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
// See bug 879656. 8192 fails, 8191 works. // See bug 879656. 8192 fails, 8191 works.
mMaxTextureSize = std::min(mMaxTextureSize, 8191); mMaxTextureSize = std::min(mMaxTextureSize, 8191);
mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 8191); mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 8191);
} } else {
else {
// See bug 877949. // See bug 877949.
mMaxTextureSize = std::min(mMaxTextureSize, 4096); mMaxTextureSize = std::min(mMaxTextureSize, 4096);
mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096); mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);

View File

@ -2985,6 +2985,7 @@ protected:
GLint mMaxCubeMapTextureSize; GLint mMaxCubeMapTextureSize;
GLint mMaxTextureImageSize; GLint mMaxTextureImageSize;
GLint mMaxRenderbufferSize; GLint mMaxRenderbufferSize;
GLint mMaxViewportDims[2];
GLsizei mMaxSamples; GLsizei mMaxSamples;
bool mNeedsTextureSizeChecks; bool mNeedsTextureSizeChecks;
bool mWorkAroundDriverBugs; bool mWorkAroundDriverBugs;

View File

@ -247,25 +247,33 @@ CreateOffscreenFBOContext(bool aShare = true)
return glContext.forget(); return glContext.forget();
} }
already_AddRefed<GLContext>
GLContextProviderCGL::CreateHeadless()
{
nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext();
if (!glContext)
return nullptr;
if (!glContext->Init())
return nullptr;
return glContext.forget();
}
already_AddRefed<GLContext> already_AddRefed<GLContext>
GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size, GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps) const SurfaceCaps& caps)
{ {
nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext(); nsRefPtr<GLContext> glContext = CreateHeadless();
if (glContext && if (!glContext->InitOffscreen(ToIntSize(size), caps))
glContext->Init() && return nullptr;
glContext->InitOffscreen(ToIntSize(size), caps))
{
return glContext.forget();
}
// everything failed return glContext.forget();
return nullptr;
} }
static nsRefPtr<GLContext> gGlobalContext; static nsRefPtr<GLContext> gGlobalContext;
GLContext * GLContext*
GLContextProviderCGL::GetGlobalContext() GLContextProviderCGL::GetGlobalContext()
{ {
if (!sCGLLibrary.EnsureInitialized()) { if (!sCGLLibrary.EnsureInitialized()) {

View File

@ -878,20 +878,29 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
return glContext.forget(); return glContext.forget();
} }
// Under EGL, on Android, pbuffers are supported fine, though
// often without the ability to texture from them directly.
already_AddRefed<GLContext> already_AddRefed<GLContext>
GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size, GLContextProviderEGL::CreateHeadless()
const SurfaceCaps& caps)
{ {
if (!sEGLLibrary.EnsureInitialized()) { if (!sEGLLibrary.EnsureInitialized()) {
return nullptr; return nullptr;
} }
gfxIntSize dummySize = gfxIntSize(16, 16); gfxIntSize dummySize = gfxIntSize(16, 16);
nsRefPtr<GLContextEGL> glContext; nsRefPtr<GLContext> glContext;
glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize); glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize);
if (!glContext)
return nullptr;
return glContext.forget();
}
// Under EGL, on Android, pbuffers are supported fine, though
// often without the ability to texture from them directly.
already_AddRefed<GLContext>
GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
if (!glContext) if (!glContext)
return nullptr; return nullptr;
@ -904,7 +913,7 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
// Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225) // Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225)
// and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257) // and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257)
// and 3) each EGL context eats 750k on B2G (bug 813783) // and 3) each EGL context eats 750k on B2G (bug 813783)
GLContext * GLContext*
GLContextProviderEGL::GetGlobalContext() GLContextProviderEGL::GetGlobalContext()
{ {
return nullptr; return nullptr;

View File

@ -1212,14 +1212,22 @@ DONE_CREATING_PIXMAP:
return glContext.forget(); return glContext.forget();
} }
already_AddRefed<GLContext>
GLContextProviderGLX::CreateHeadless()
{
gfxIntSize dummySize = gfxIntSize(16, 16);
nsRefPtr<GLContext> glContext = CreateOffscreenPixmapContext(dummySize);
if (!glContext)
return nullptr;
return glContext.forget();
}
already_AddRefed<GLContext> already_AddRefed<GLContext>
GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size, GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps) const SurfaceCaps& caps)
{ {
gfxIntSize dummySize = gfxIntSize(16, 16); nsRefPtr<GLContext> glContext = CreateHeadless();
nsRefPtr<GLContextGLX> glContext =
CreateOffscreenPixmapContext(dummySize);
if (!glContext) if (!glContext)
return nullptr; return nullptr;

View File

@ -60,6 +60,10 @@ public:
CreateOffscreen(const gfxIntSize& size, CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps); const SurfaceCaps& caps);
// Just create a context. We'll add offscreen stuff ourselves.
static already_AddRefed<GLContext>
CreateHeadless();
/** /**
* Create wrapping Gecko GLContext for external gl context. * Create wrapping Gecko GLContext for external gl context.
* *

View File

@ -22,8 +22,13 @@ GLContextProviderNull::CreateWrappingExisting(void*, void*)
already_AddRefed<GLContext> already_AddRefed<GLContext>
GLContextProviderNull::CreateOffscreen(const gfxIntSize&, GLContextProviderNull::CreateOffscreen(const gfxIntSize&,
const SurfaceCaps&, const SurfaceCaps&)
ContextFlags) {
return nullptr;
}
already_AddRefed<GLContext>
GLContextProviderNull::CreateHeadless()
{ {
return nullptr; return nullptr;
} }

View File

@ -607,8 +607,7 @@ CreateWindowOffscreenContext()
} }
already_AddRefed<GLContext> already_AddRefed<GLContext>
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size, GLContextProviderWGL::CreateHeadless()
const SurfaceCaps& caps)
{ {
if (!sWGLLib.EnsureInitialized()) { if (!sWGLLib.EnsureInitialized()) {
return nullptr; return nullptr;
@ -636,6 +635,18 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
return nullptr; return nullptr;
} }
nsRefPtr<GLContext> retGL = glContext;
return retGL.forget();
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
if (!glContext)
return nullptr;
if (!glContext->InitOffscreen(ToIntSize(size), caps)) if (!glContext->InitOffscreen(ToIntSize(size), caps))
return nullptr; return nullptr;

View File

@ -12,42 +12,42 @@ namespace gl {
SurfaceCaps::SurfaceCaps() SurfaceCaps::SurfaceCaps()
{ {
Clear(); Clear();
} }
SurfaceCaps::SurfaceCaps(const SurfaceCaps& other) SurfaceCaps::SurfaceCaps(const SurfaceCaps& other)
{ {
*this = other; *this = other;
} }
SurfaceCaps& SurfaceCaps&
SurfaceCaps::operator=(const SurfaceCaps& other) SurfaceCaps::operator=(const SurfaceCaps& other)
{ {
any = other.any; any = other.any;
color = other.color; color = other.color;
alpha = other.alpha; alpha = other.alpha;
bpp16 = other.bpp16; bpp16 = other.bpp16;
depth = other.depth; depth = other.depth;
stencil = other.stencil; stencil = other.stencil;
antialias = other.antialias; antialias = other.antialias;
preserve = other.preserve; preserve = other.preserve;
surfaceAllocator = other.surfaceAllocator; surfaceAllocator = other.surfaceAllocator;
return *this; return *this;
} }
void void
SurfaceCaps::Clear() SurfaceCaps::Clear()
{ {
any = false; any = false;
color = false; color = false;
alpha = false; alpha = false;
bpp16 = false; bpp16 = false;
depth = false; depth = false;
stencil = false; stencil = false;
antialias = false; antialias = false;
preserve = false; preserve = false;
surfaceAllocator = nullptr; surfaceAllocator = nullptr;
} }
SurfaceCaps::~SurfaceCaps() SurfaceCaps::~SurfaceCaps()

View File

@ -3712,7 +3712,7 @@ pref("gl.msaa-level", 2);
pref("webgl.force-enabled", false); pref("webgl.force-enabled", false);
pref("webgl.disabled", false); pref("webgl.disabled", false);
pref("webgl.shader_validator", true); pref("webgl.shader_validator", true);
pref("webgl.prefer-native-gl", false); pref("webgl.disable-angle", false);
pref("webgl.min_capability_mode", false); pref("webgl.min_capability_mode", false);
pref("webgl.disable-extensions", false); pref("webgl.disable-extensions", false);
pref("webgl.msaa-force", false); pref("webgl.msaa-force", false);