Bug 1562812 - For powerPreference:Default, only keep dGPU active for consistently active contexts. r=lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D36565

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Jeff Gilbert 2019-07-02 16:45:22 +00:00
Родитель d93c3f8638
Коммит 406b3a60f1
4 изменённых файлов: 167 добавлений и 17 удалений

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

@ -12,6 +12,7 @@
#include "gfxConfig.h"
#include "gfxContext.h"
#include "gfxCrashReporterUtils.h"
#include "gfxEnv.h"
#include "gfxPattern.h"
#include "gfxUtils.h"
#include "MozFramebuffer.h"
@ -289,6 +290,8 @@ void WebGLContext::DestroyResourcesAndContext() {
gl->MarkDestroyed();
mGL_OnlyClearInDestroyResourcesAndContext = nullptr;
MOZ_ASSERT(!gl);
mDynDGpuManager = nullptr;
}
void WebGLContext::Invalidate() {
@ -484,8 +487,20 @@ bool WebGLContext::CreateAndInitGL(
}
{
bool highPower = false;
switch (mOptions.powerPreference) {
auto powerPref = mOptions.powerPreference;
// If "Use hardware acceleration when available" option is disabled:
if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
powerPref = dom::WebGLPowerPreference::Low_power;
}
if (StaticPrefs::webgl_default_low_power() &&
powerPref == dom::WebGLPowerPreference::Default) {
powerPref = dom::WebGLPowerPreference::Low_power;
}
bool highPower;
switch (powerPref) {
case dom::WebGLPowerPreference::Low_power:
highPower = false;
break;
@ -503,23 +518,14 @@ bool WebGLContext::CreateAndInitGL(
// - Same origin with root page (try to stem bleeding from WebGL
// ads/trackers)
default:
highPower = true;
if (StaticPrefs::webgl_default_low_power()) {
highPower = false;
} else if (mCanvasElement && !mCanvasElement->GetParentNode()) {
GenerateWarning(
"WebGLContextAttributes.powerPreference: 'default' when <canvas>"
" has no parent Element defaults to 'low-power'.");
highPower = false;
highPower = false;
mDynDGpuManager = webgl::DynDGpuManager::Get();
if (!mDynDGpuManager) {
highPower = true;
}
break;
}
// If "Use hardware acceleration when available" option is disabled:
if (!gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
highPower = false;
}
if (highPower) {
flags |= gl::CreateContextFlags::HIGH_POWER;
}
@ -1397,6 +1403,7 @@ bool WebGLContext::PresentScreenBuffer(GLScreenBuffer* const targetScreen) {
if (IsContextLost()) return false;
if (!mShouldPresent) return false;
ReportActivity();
if (!ValidateAndInitFB(nullptr)) return false;
@ -2407,6 +2414,101 @@ nsresult webgl::AvailabilityRunnable::Run() {
return NS_OK;
}
// ---------------
namespace webgl {
/*static*/
std::shared_ptr<DynDGpuManager> DynDGpuManager::Get() {
#ifndef XP_MACOSX
if (true) return nullptr;
#endif
static std::weak_ptr<DynDGpuManager> sCurrent;
auto ret = sCurrent.lock();
if (!ret) {
ret.reset(new DynDGpuManager);
sCurrent = ret;
}
return ret;
}
DynDGpuManager::DynDGpuManager() : mMutex("DynDGpuManager") {}
DynDGpuManager::~DynDGpuManager() = default;
void DynDGpuManager::SetState(const MutexAutoLock&, const State newState) {
if (gfxEnv::GpuSwitchingSpew()) {
printf_stderr(
"[MOZ_GPU_SWITCHING_SPEW] DynDGpuManager::SetState(%u -> %u)\n",
uint32_t(mState), uint32_t(newState));
}
if (newState == State::Active) {
if (!mDGpuContext) {
const auto flags = gl::CreateContextFlags::HIGH_POWER;
nsCString failureId;
mDGpuContext = gl::GLContextProvider::CreateHeadless(flags, &failureId);
}
} else {
mDGpuContext = nullptr;
}
mState = newState;
}
void DynDGpuManager::ReportActivity(
const std::shared_ptr<DynDGpuManager>& strong) {
MOZ_ASSERT(strong.get() == this);
const MutexAutoLock lock(mMutex);
if (mActivityThisTick) return;
mActivityThisTick = true;
// Promote!
switch (mState) {
case State::Inactive:
SetState(lock, State::Primed);
DispatchTick(strong); // Initial tick
break;
case State::Primed:
SetState(lock, State::Active);
break;
case State::Active:
if (!mDGpuContext) {
SetState(lock, State::Active);
}
break;
}
}
void DynDGpuManager::Tick(const std::shared_ptr<DynDGpuManager>& strong) {
MOZ_ASSERT(strong.get() == this);
const MutexAutoLock lock(mMutex);
MOZ_ASSERT(mState != State::Inactive);
if (!mActivityThisTick) {
SetState(lock, State::Inactive);
return;
}
mActivityThisTick = false; // reset
DispatchTick(strong);
}
void DynDGpuManager::DispatchTick(
const std::shared_ptr<DynDGpuManager>& strong) {
MOZ_ASSERT(strong.get() == this);
const auto fnTick = [strong]() { strong->Tick(strong); };
already_AddRefed<mozilla::Runnable> event =
NS_NewRunnableFunction("DynDGpuManager fnWeakTick", fnTick);
NS_DelayedDispatchToCurrentThread(std::move(event), TICK_MS);
}
} // namespace webgl
////////////////////////////////////////////////////////////////////////////////
// XPCOM goop

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

@ -21,6 +21,7 @@
#include "mozilla/ErrorResult.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/LinkedList.h"
#include "mozilla/Mutex.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"
#include "nsCycleCollectionNoteChild.h"
@ -272,6 +273,36 @@ struct BufferAndIndex final {
uint32_t id = -1;
};
// -
class DynDGpuManager final {
static constexpr uint32_t TICK_MS = 3000;
enum class State {
Inactive,
Primed,
Active,
};
Mutex mMutex;
bool mActivityThisTick = false;
State mState = State::Inactive;
RefPtr<gl::GLContext> mDGpuContext;
public:
static std::shared_ptr<DynDGpuManager> Get();
DynDGpuManager();
~DynDGpuManager();
void ReportActivity(const std::shared_ptr<DynDGpuManager>& strong);
private:
void SetState(const MutexAutoLock&, State);
void Tick(const std::shared_ptr<DynDGpuManager>& strong);
void DispatchTick(const std::shared_ptr<DynDGpuManager>& strong);
};
} // namespace webgl
////////////////////////////////////////////////////////////////////////////////
@ -332,6 +363,18 @@ class WebGLContext : public nsICanvasRenderingContextInternal,
// Grab a const reference so we can see changes, but can't make changes.
const decltype(mGL_OnlyClearInDestroyResourcesAndContext)& gl;
private:
std::shared_ptr<webgl::DynDGpuManager> mDynDGpuManager;
void ReportActivity() const {
if (mDynDGpuManager) {
mDynDGpuManager->ReportActivity(mDynDGpuManager);
}
}
public:
void CheckForInactivity();
protected:
const uint32_t mMaxPerfWarnings;
mutable uint64_t mNumPerfWarnings;

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

@ -30,12 +30,14 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLExtensionBase, Release)
// -
WebGLExtensionExplicitPresent::WebGLExtensionExplicitPresent(WebGLContext* const webgl)
WebGLExtensionExplicitPresent::WebGLExtensionExplicitPresent(
WebGLContext* const webgl)
: WebGLExtensionBase(webgl) {
MOZ_ASSERT(IsSupported(webgl), "Don't construct extension if unsupported.");
}
bool WebGLExtensionExplicitPresent::IsSupported(const WebGLContext* const webgl) {
bool WebGLExtensionExplicitPresent::IsSupported(
const WebGLContext* const webgl) {
return StaticPrefs::webgl_enable_draft_extensions();
}

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

@ -89,6 +89,9 @@ class gfxEnv final {
// Very noisy GLContext and GLContextProviderEGL
DECL_GFX_ENV("MOZ_GL_SPEW", GlSpew);
//
DECL_GFX_ENV("MOZ_GPU_SWITCHING_SPEW", GpuSwitchingSpew);
// Do extra work before and after each GLX call in GLContextProviderGLX
DECL_GFX_ENV("MOZ_GLX_DEBUG", GlxDebug);