diff --git a/dom/canvas/WebGLContext.cpp b/dom/canvas/WebGLContext.cpp index 1b4e099678fb..b6ccede08bca 100644 --- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -434,12 +434,15 @@ WebGLContext::GetHeight() const */ static bool -IsFeatureInBlacklist(const nsCOMPtr& gfxInfo, int32_t feature, nsACString* const out_failureId) +IsFeatureInBlacklist(const nsCOMPtr& 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; } @@ -562,15 +565,15 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl) // Done with baseCaps construction. - bool forceAllowAA = gfxPrefs::WebGLForceMSAA(); - nsCOMPtr 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 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; @@ -580,8 +583,7 @@ BaseCaps(const WebGLContextOptions& options, WebGLContext* webgl) static already_AddRefed CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, - WebGLContext* webgl, nsACString* const out_failReason, - nsACString* const out_failureId) + WebGLContext* webgl, std::vector* const out_failReasons) { const gfx::IntSize dummySize(16, 16); RefPtr gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps, @@ -591,13 +593,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; } @@ -606,8 +603,7 @@ CreateGLWithEGL(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, static already_AddRefed CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, - WebGLContext* webgl, nsACString* const out_failReason, - nsACString* const out_failureId) + WebGLContext* webgl, std::vector* const out_failReasons) { const gfx::IntSize dummySize(16, 16); RefPtr gl = gl::GLContextProviderEGL::CreateOffscreen(dummySize, caps, @@ -617,13 +613,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; } @@ -632,22 +623,9 @@ CreateGLWithANGLE(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, static already_AddRefed CreateGLWithDefault(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, - WebGLContext* webgl, nsACString* const out_failReason, - nsACString* const out_failureId) + WebGLContext* webgl, + std::vector* const out_failReasons) { - nsCOMPtr 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 gl = gl::GLContextProvider::CreateOffscreen(dummySize, caps, flags, out_failureId); @@ -657,13 +635,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; } @@ -676,8 +649,7 @@ bool WebGLContext::CreateAndInitGLWith(FnCreateGL_T fnCreateGL, const gl::SurfaceCaps& baseCaps, gl::CreateContextFlags flags, - nsACString* const out_failReason, - nsACString* const out_failureId) + std::vector* const out_failReasons) { std::queue fallbackCaps; PopulateCapFallbackQueue(baseCaps, &fallbackCaps); @@ -685,9 +657,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; @@ -696,9 +667,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; } @@ -706,16 +679,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* const out_failReasons) { - const bool useEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL"); + bool blacklistOpenGL = false; + if (!forceEnabled) { + const nsCOMPtr 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; @@ -725,13 +712,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: @@ -929,12 +937,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 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; } diff --git a/dom/canvas/WebGLContext.h b/dom/canvas/WebGLContext.h index e21662e915c4..9fdce12edcae 100644 --- a/dom/canvas/WebGLContext.h +++ b/dom/canvas/WebGLContext.h @@ -1201,19 +1201,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* const out_failReasons); + bool ResizeBackbuffer(uint32_t width, uint32_t height); typedef already_AddRefed FnCreateGL_T(const gl::SurfaceCaps& caps, gl::CreateContextFlags flags, WebGLContext* webgl, - nsACString* const out_failReason, - nsACString* const out_failureId); + std::vector* 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* const out_failReasons); + void ThrowEvent_WebGLContextCreationError(const nsACString& text); // -------------------------------------------------------------------------