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
Родитель 5a27646a69
Коммит e417babf90
2 изменённых файлов: 96 добавлений и 80 удалений

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

@ -434,12 +434,15 @@ WebGLContext::GetHeight() const
*/ */
static bool 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; int32_t status;
if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature, if (!NS_SUCCEEDED(gfxUtils::ThreadSafeGetFeatureStatus(gfxInfo, feature,
*out_failureId, &status))) *out_blacklistId, &status)))
{
return false; return false;
}
return status != nsIGfxInfo::FEATURE_STATUS_OK; return status != nsIGfxInfo::FEATURE_STATUS_OK;
} }
@ -562,16 +565,16 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
// Done with baseCaps construction. // Done with baseCaps construction.
bool forceAllowAA = gfxPrefs::WebGLForceMSAA(); if (!gfxPrefs::WebGLForceMSAA()) {
nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo(); const nsCOMPtr<nsIGfxInfo> gfxInfo = services::GetGfxInfo();
nsCString discardFailureId;
if (!forceAllowAA && nsCString blocklistId;
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA, &discardFailureId)) if (IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA, &blocklistId)) {
{
webgl->GenerateWarning("Disallowing antialiased backbuffers due" webgl->GenerateWarning("Disallowing antialiased backbuffers due"
" to blacklisting."); " to blacklisting.");
baseCaps.antialias = false; baseCaps.antialias = false;
} }
}
return baseCaps; return baseCaps;
} }
@ -580,8 +583,7 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl)
static already_AddRefed<gl::GLContext> static already_AddRefed<gl::GLContext>
CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
WebGLContext* webgl, nsACString* const out_failReason, WebGLContext* webgl, std::vector<FailureReason>* const out_failReasons)
nsACString* const out_failureId)
{ {
const gfx::IntSize dummySize(16, 16); const gfx::IntSize dummySize(16, 16);
RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps, RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
@ -591,13 +593,8 @@ CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
} }
if (!gl) { if (!gl) {
if (out_failReason->Length()) { out_failReasons->push_back({ "FEATURE_FAILURE_WEBGL_EGL_INIT",
out_failReason->AppendLiteral("\n"); "Error during EGL OpenGL init." });
}
out_failReason->AppendLiteral("Error during EGL OpenGL init.");
if (out_failureId->IsEmpty()) {
*out_failureId = "FEATURE_FAILURE_WEBGL_EGL_INIT";
}
return nullptr; return nullptr;
} }
@ -606,8 +603,7 @@ CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
static already_AddRefed<GLContext> static already_AddRefed<GLContext>
CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
WebGLContext* webgl, nsACString* const out_failReason, WebGLContext* webgl, std::vector<FailureReason>* const out_failReasons)
nsACString* const out_failureId)
{ {
const gfx::IntSize dummySize(16, 16); const gfx::IntSize dummySize(16, 16);
RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps, RefPtr<GLContext> gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps,
@ -617,13 +613,8 @@ CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
} }
if (!gl) { if (!gl) {
if (out_failReason->Length()) { out_failReasons->push_back({ "FEATURE_FAILURE_WEBGL_ANGLE_INIT",
out_failReason->AppendLiteral("\n"); "Error during ANGLE OpenGL init." });
}
out_failReason->AppendLiteral("Error during ANGLE OpenGL init.");
if (out_failureId->IsEmpty()) {
*out_failureId = "FEATURE_FAILURE_WEBGL_ANGLE_INIT";
}
return nullptr; return nullptr;
} }
@ -632,22 +623,9 @@ CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
static already_AddRefed<gl::GLContext> static already_AddRefed<gl::GLContext>
CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
WebGLContext* webgl, nsACString* const out_failReason, WebGLContext* webgl,
nsACString* const out_failureId) 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); const gfx::IntSize dummySize(16, 16);
RefPtr<GLContext> gl = gl::GLContextProvider::CreateOffscreen(dummySize, caps, RefPtr<GLContext> gl = gl::GLContextProvider::CreateOffscreen(dummySize, caps,
flags, out_failureId); flags, out_failureId);
@ -657,13 +635,8 @@ CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags,
} }
if (!gl) { if (!gl) {
if (out_failReason->Length()) { out_failReasons->push_back({ "FEATURE_FAILURE_WEBGL_DEFAULT_INIT",
out_failReason->AppendASCII("\n"); "Error during native OpenGL init." });
}
out_failReason->AppendASCII("Error during native OpenGL init.");
if (out_failureId->IsEmpty()) {
*out_failureId = "FEATURE_FAILURE_WEBGL_DEFAULT_INIT";
}
return nullptr; return nullptr;
} }
@ -676,8 +649,7 @@ bool
WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL, WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
const gl::SurfaceCaps& baseCaps, const gl::SurfaceCaps& baseCaps,
gl::CreateContextFlags flags, gl::CreateContextFlags flags,
nsACString* const out_failReason, std::vector<FailureReason>* const out_failReasons)
nsACString* const out_failureId)
{ {
std::queue<gl::SurfaceCaps> fallbackCaps; std::queue<gl::SurfaceCaps> fallbackCaps;
PopulateCapFallbackQueue(baseCaps, &fallbackCaps); PopulateCapFallbackQueue(baseCaps, &fallbackCaps);
@ -685,9 +657,8 @@ WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
MOZ_RELEASE_ASSERT(!gl, "GFX: Already have a context."); MOZ_RELEASE_ASSERT(!gl, "GFX: Already have a context.");
gl = nullptr; gl = nullptr;
while (!fallbackCaps.empty()) { while (!fallbackCaps.empty()) {
gl::SurfaceCaps& caps = fallbackCaps.front(); const gl::SurfaceCaps& caps = fallbackCaps.front();
gl = fnCreateGL(caps, flags, this, out_failReasons);
gl = fnCreateGL(caps, flags, this, out_failReason, out_failureId);
if (gl) if (gl)
break; break;
@ -696,9 +667,11 @@ WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
if (!gl) if (!gl)
return false; 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. // The fail reason here should be specific enough for now.
gl = nullptr; gl = nullptr;
out_failReasons->push_back(reason);
return false; return false;
} }
@ -706,16 +679,30 @@ WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL,
} }
bool 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; FailureReason reason;
#ifdef XP_WIN if (IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL,
const bool disableANGLE = (gfxPrefs::WebGLDisableANGLE() || &reason.key))
PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")); {
useANGLE = !disableANGLE; blacklistOpenGL = true;
#endif
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; gl::CreateContextFlags flags = gl::CreateContextFlags::NO_VALIDATION;
@ -725,13 +712,34 @@ WebGLContext::CreateAndInitGL(bool forceEnabled, nsACString* const out_failReaso
const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this); const gl::SurfaceCaps baseCaps = BaseCaps(mOptions, this);
//////
if (!blacklistOpenGL) {
const bool useEGL = PR_GetEnv("MOZ_WEBGL_FORCE_EGL");
if (useEGL) if (useEGL)
return CreateAndInitGLWith(CreateGLWithEGL, baseCaps, flags, out_failReason, out_failureId); 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) 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: // Fallback for resizes:
@ -929,12 +937,15 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
ScopedGfxFeatureReporter reporter("WebGL", forceEnabled); ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
MOZ_ASSERT(!gl); MOZ_ASSERT(!gl);
nsCString failReason; std::vector<FailureReason> failReasons;
nsCString failureId; if (!CreateAndInitGL(forceEnabled, &failReasons)) {
if (!CreateAndInitGL(forceEnabled, &failReason, &failureId)) { nsCString text("WebGL creation failed: ");
Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, failureId); for (const auto& cur : failReasons) {
const nsPrintfCString text("WebGL creation failed: %s", Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_FAILURE_ID, cur.key);
failReason.BeginReading());
text.AppendASCII("\n* ");
text.Append(cur.info);
}
ThrowEvent_WebGLContextCreationError(text); ThrowEvent_WebGLContextCreationError(text);
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }

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

@ -1201,19 +1201,24 @@ public:
protected: protected:
bool InitWebGL2(nsACString* const out_failReason, nsACString* const out_failureId); 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); bool ResizeBackbuffer(uint32_t width, uint32_t height);
typedef already_AddRefed<gl::GLContext> FnCreateGL_T(const gl::SurfaceCaps& caps, typedef already_AddRefed<gl::GLContext> FnCreateGL_T(const gl::SurfaceCaps& caps,
gl::CreateContextFlags flags, gl::CreateContextFlags flags,
WebGLContext* webgl, WebGLContext* webgl,
nsACString* const out_failReason, std::vector<FailureReason>* const out_failReasons);
nsACString* const out_failureId);
bool CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps, bool CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps,
gl::CreateContextFlags flags, gl::CreateContextFlags flags,
nsACString* const out_failReason, std::vector<FailureReason>* const out_failReasons);
nsACString* const out_failureId);
void ThrowEvent_WebGLContextCreationError(const nsACString& text); void ThrowEvent_WebGLContextCreationError(const nsACString& text);
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------