Bug 1268638 - Update WebGL creation to allow non-blacklisted native-gl. - r=jrmuizel

Also support accumulating a list of WebGL failure reasons.

MozReview-Commit-ID: I9p0BBrBJ5V
This commit is contained in:
Jeff Gilbert 2016-06-20 20:28:57 -07:00
parent a5edaa87c8
commit 9eb346bfe5
2 changed files with 96 additions and 80 deletions

View File

@ -435,12 +435,15 @@ WebGLContext::GetHeight() const
*/
static bool
IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature, nsACString* const out_failureId)
IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature,
nsCString* const out_blacklistId)
{
int32_t status;
if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature,
*out_failureId, &status)))
*out_blacklistId, &status)))
{
return false;
}
return status != nsIGfxInfo::FEATURE_STATUS_OK;
}
@ -563,15 +566,15 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
// Done with baseCaps construction.
bool forceAllowAA = gfxPrefs::WebGLForceMSAA();
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
nsCString discardFailureId;
if (!forceAllowAA &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA, &discardFailureId))
{
webgl->GenerateWarning("Disallowing antialiased backbuffers due"
" to blacklisting.");
baseCaps.antialias = false;
if (!gfxPrefs::WebGLForceMSAA()) {
const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
nsCString blocklistId;
if (IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA, &blocklistId)) {
webgl->GenerateWarning("Disallowing antialiased backbuffers due"
" to blacklisting.");
baseCaps.antialias = false;
}
}
return baseCaps;
@ -581,8 +584,7 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
static already_AddRefed<gl::GLContext>
CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
WebGLContext* webgl, nsACString* const out_failReason,
nsACString* const out_failureId)
WebGLContext* webgl, std::vector<FailureReason>* const out_failReasons)
{
const gfx::IntSize dummySize(16, 16);
RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
@ -592,13 +594,8 @@ CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
}
if (!gl) {
if (out_failReason->Length()) {
out_failReason->AppendLiteral("\n");
}
out_failReason->AppendLiteral("Error during EGL OpenGL init.");
if (out_failureId->IsEmpty()) {
*out_failureId = "FEATURE_FAILURE_WEBGL_EGL_INIT";
}
out_failReasons->push_back({ "FEATURE_FAILURE_WEBGL_EGL_INIT",
"Error during EGL OpenGL init." });
return nullptr;
}
@ -607,8 +604,7 @@ CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
static already_AddRefed<GLContext>
CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
WebGLContext* webgl, nsACString* const out_failReason,
nsACString* const out_failureId)
WebGLContext* webgl, std::vector<FailureReason>* const out_failReasons)
{
const gfx::IntSize dummySize(16, 16);
RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
@ -618,13 +614,8 @@ CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
}
if (!gl) {
if (out_failReason->Length()) {
out_failReason->AppendLiteral("\n");
}
out_failReason->AppendLiteral("Error during ANGLE OpenGL init.");
if (out_failureId->IsEmpty()) {
*out_failureId = "FEATURE_FAILURE_WEBGL_ANGLE_INIT";
}
out_failReasons->push_back({ "FEATURE_FAILURE_WEBGL_ANGLE_INIT",
"Error during ANGLE OpenGL init." });
return nullptr;
}
@ -633,22 +624,9 @@ CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
static already_AddRefed<gl::GLContext>
CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
WebGLContext* webgl, nsACString* const out_failReason,
nsACString* const out_failureId)
WebGLContext* webgl,
std::vector<FailureReason>* const out_failReasons)
{
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
if (!(flags & CreateContextFlags::FORCE_ENABLE_HARDWARE) &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL, out_failureId))
{
if (out_failReason->Length()) {
out_failReason->AppendASCII("\n");
}
out_failReason->AppendASCII("Refused to create native OpenGL context because of"
" blacklisting.");
return nullptr;
}
const gfx::IntSize dummySize(16, 16);
RefPtr<GLContext> gl = gl::GLContextProvider::CreateOffscreen(dummySize, caps,
flags, out_failureId);
@ -658,13 +636,8 @@ CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
}
if (!gl) {
if (out_failReason->Length()) {
out_failReason->AppendASCII("\n");
}
out_failReason->AppendASCII("Error during native OpenGL init.");
if (out_failureId->IsEmpty()) {
*out_failureId = "FEATURE_FAILURE_WEBGL_DEFAULT_INIT";
}
out_failReasons->push_back({ "FEATURE_FAILURE_WEBGL_DEFAULT_INIT",
"Error during native OpenGL init." });
return nullptr;
}
@ -677,8 +650,7 @@ bool
WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
const gl::SurfaceCaps& baseCaps,
gl::CreateContextFlags flags,
nsACString* const out_failReason,
nsACString* const out_failureId)
std::vector<FailureReason>* const out_failReasons)
{
std::queue<gl::SurfaceCaps> fallbackCaps;
PopulateCapFallbackQueue(baseCaps, &fallbackCaps);
@ -686,9 +658,8 @@ WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
MOZ_RELEASE_ASSERT(!gl, "GFX: Already have a context.");
gl = nullptr;
while (!fallbackCaps.empty()) {
gl::SurfaceCaps& caps = fallbackCaps.front();
gl = fnCreateGL(caps, flags, this, out_failReason, out_failureId);
const gl::SurfaceCaps& caps = fallbackCaps.front();
gl = fnCreateGL(caps, flags, this, out_failReasons);
if (gl)
break;
@ -697,9 +668,11 @@ WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
if (!gl)
return false;
if (!InitAndValidateGL(out_failReason, out_failureId)) {
FailureReason reason;
if (!InitAndValidateGL(&reason.info, &reason.key)) {
// The fail reason here should be specific enough for now.
gl = nullptr;
out_failReasons->push_back(reason);
return false;
}
@ -707,16 +680,30 @@ WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
}
bool
WebGLContext::CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason, nsACString* const out_failureId)
WebGLContext::CreateAndInitGL(bool forceEnabled,
std::vector<FailureReason>* const out_failReasons)
{
const bool useEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL");
bool blacklistOpenGL = false;
if (!forceEnabled) {
const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
bool useANGLE = false;
#ifdef XP_WIN
const bool disableANGLE = (gfxPrefs::WebGLDisableANGLE() ||
PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"));
useANGLE = !disableANGLE;
#endif
FailureReason reason;
if (IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL,
&reason.key))
{
blacklistOpenGL = true;
reason.info = "Refused to create native OpenGL context because of blacklist"
" entry: ";
reason.info.Append(blacklistId);
out_failReasons->push_back(reason);
GenerateWarning(text.BeginReading());
}
}
//////
gl::CreateContextFlags flags = gl::CreateContextFlags::NO_VALIDATION;
@ -726,13 +713,34 @@ WebGLContext::CreateAndInitGL(bool forceEnabled, nsACString* const out_failReaso
const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this);
if (useEGL)
return CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags, out_failReason, out_failureId);
//////
if (!blacklistOpenGL) {
const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL");
if (useEGL)
return CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags, out_failReasons);
if (CreateAndInitGLWith(CreateGLWithNative, baseCaps, flags, out_failReasons))
return true;
}
//////
bool useANGLE = false;
#ifdef XP_WIN
const bool disableANGLE = (gfxPrefs::WebGLDisableANGLE() ||
PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL"));
useANGLE = !disableANGLE;
#endif
if (useANGLE)
return CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags, out_failReason, out_failureId);
return CreateAndInitGLWith(CreateGLWithANGLE, baseCaps, flags, out_failReasons);
return CreateAndInitGLWith(CreateGLWithDefault, baseCaps, flags, out_failReason, out_failureId);
//////
out_failReasons->push_back(nsLiteralCString("Exhausted GL driver options."));
return false;
}
// Fallback for resizes:
@ -930,12 +938,15 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
MOZ_ASSERT(!gl);
nsCString failReason;
nsCString failureId;
if (!CreateAndInitGL(forceEnabled, &failReason, &failureId)) {
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, failureId);
const nsPrintfCString text("WebGL creation failed: %s",
failReason.BeginReading());
std::vector<FailureReason> failReasons;
if (!CreateAndInitGL(forceEnabled, &failReasons)) {
nsCString text("WebGL creation failed: ");
for (const auto& cur : failReasons) {
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, cur.key);
text.AppendASCII("\n* ");
text.Append(cur.info);
}
ThrowEvent_WebGLContextCreationError(text);
return NS_ERROR_FAILURE;
}

View File

@ -1204,19 +1204,24 @@ public:
protected:
bool InitWebGL2(nsACString* const out_failReason, nsACString* const out_failureId);
bool CreateAndInitGL(bool forceEnabled, nsACString* const out_failReason, nsACString* const out_failureId);
struct FailureReason {
nsCString key; // For reporting.
nsCString info;
};
bool CreateAndInitGL(bool forceEnabled,
std::vector<FailureReason>* const out_failReasons);
bool ResizeBackbuffer(uint32_t width, uint32_t height);
typedef already_AddRefed<gl::GLContext> FnCreateGL_T(const gl::SurfaceCaps& caps,
gl::CreateContextFlags flags,
WebGLContext* webgl,
nsACString* const out_failReason,
nsACString* const out_failureId);
std::vector<FailureReason>* const out_failReasons);
bool CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps,
gl::CreateContextFlags flags,
nsACString* const out_failReason,
nsACString* const out_failureId);
std::vector<FailureReason>* const out_failReasons);
void ThrowEvent_WebGLContextCreationError(const nsACString& text);
// -------------------------------------------------------------------------