mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 998916 - check the visibility change event to defer the webgl context restore. r=jgilbert,smaug
This commit is contained in:
parent
1cf0c94a29
commit
03ac645b5b
@ -52,6 +52,7 @@
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/dom/WebGLRenderingContextBinding.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
@ -71,24 +72,111 @@ using namespace mozilla::gfx;
|
||||
using namespace mozilla::gl;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLMemoryPressureObserver::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aSomeData)
|
||||
WebGLObserver::WebGLObserver(WebGLContext* aContext)
|
||||
: mContext(aContext)
|
||||
{
|
||||
if (strcmp(aTopic, "memory-pressure"))
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool wantToLoseContext = true;
|
||||
WebGLObserver::~WebGLObserver()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::Destroy()
|
||||
{
|
||||
UnregisterMemoryPressureEvent();
|
||||
UnregisterVisibilityChangeEvent();
|
||||
mContext = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::RegisterVisibilityChangeEvent()
|
||||
{
|
||||
if (!mContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
HTMLCanvasElement* canvasElement = mContext->GetCanvas();
|
||||
|
||||
MOZ_ASSERT(canvasElement);
|
||||
|
||||
if (canvasElement) {
|
||||
nsIDocument* document = canvasElement->OwnerDoc();
|
||||
|
||||
document->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
|
||||
this,
|
||||
true,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::UnregisterVisibilityChangeEvent()
|
||||
{
|
||||
if (!mContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
HTMLCanvasElement* canvasElement = mContext->GetCanvas();
|
||||
|
||||
if (canvasElement) {
|
||||
nsIDocument* document = canvasElement->OwnerDoc();
|
||||
|
||||
document->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
|
||||
this,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::RegisterMemoryPressureEvent()
|
||||
{
|
||||
if (!mContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
MOZ_ASSERT(observerService);
|
||||
|
||||
if (observerService) {
|
||||
observerService->AddObserver(this, "memory-pressure", false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLObserver::UnregisterMemoryPressureEvent()
|
||||
{
|
||||
if (!mContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
|
||||
MOZ_ASSERT(observerService);
|
||||
|
||||
if (observerService) {
|
||||
observerService->RemoveObserver(this, "memory-pressure");
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLObserver::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aSomeData)
|
||||
{
|
||||
if (!mContext || strcmp(aTopic, "memory-pressure")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool wantToLoseContext = mContext->mLoseContextOnMemoryPressure;
|
||||
|
||||
if (!mContext->mCanLoseContextInForeground &&
|
||||
ProcessPriorityManager::CurrentProcessIsForeground())
|
||||
{
|
||||
wantToLoseContext = false;
|
||||
} else if (!nsCRT::strcmp(aSomeData,
|
||||
MOZ_UTF16("heap-minimize")))
|
||||
{
|
||||
wantToLoseContext = mContext->mLoseContextOnHeapMinimize;
|
||||
}
|
||||
|
||||
if (wantToLoseContext) {
|
||||
@ -98,6 +186,26 @@ WebGLMemoryPressureObserver::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLObserver::HandleEvent(nsIDOMEvent* aEvent)
|
||||
{
|
||||
nsAutoString type;
|
||||
aEvent->GetType(type);
|
||||
if (!mContext || !type.EqualsLiteral("visibilitychange")) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
HTMLCanvasElement* canvasElement = mContext->GetCanvas();
|
||||
|
||||
MOZ_ASSERT(canvasElement);
|
||||
|
||||
if (canvasElement && !canvasElement->OwnerDoc()->Hidden()) {
|
||||
mContext->ForceRestoreContext();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
WebGLContextOptions::WebGLContextOptions()
|
||||
: alpha(true), depth(true), stencil(false),
|
||||
premultipliedAlpha(true), antialias(true),
|
||||
@ -177,8 +285,9 @@ WebGLContext::WebGLContext()
|
||||
mRunContextLossTimerAgain = false;
|
||||
mContextRestorer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
mContextStatus = ContextNotLost;
|
||||
mLoseContextOnHeapMinimize = false;
|
||||
mLoseContextOnMemoryPressure = false;
|
||||
mCanLoseContextInForeground = true;
|
||||
mRestoreWhenVisible = false;
|
||||
|
||||
mAlreadyGeneratedWarnings = 0;
|
||||
mAlreadyWarnedAboutFakeVertexAttrib0 = false;
|
||||
@ -190,6 +299,9 @@ WebGLContext::WebGLContext()
|
||||
mMaxWarnings = 0;
|
||||
}
|
||||
|
||||
mContextObserver = new WebGLObserver(this);
|
||||
MOZ_RELEASE_ASSERT(mContextObserver, "Can't alloc WebGLContextObserver");
|
||||
|
||||
mLastUseIndex = 0;
|
||||
|
||||
InvalidateBufferFetching();
|
||||
@ -203,6 +315,8 @@ WebGLContext::WebGLContext()
|
||||
|
||||
WebGLContext::~WebGLContext()
|
||||
{
|
||||
mContextObserver->Destroy();
|
||||
|
||||
DestroyResourcesAndContext();
|
||||
WebGLMemoryTracker::RemoveWebGLContext(this);
|
||||
TerminateContextLossTimer();
|
||||
@ -212,15 +326,7 @@ WebGLContext::~WebGLContext()
|
||||
void
|
||||
WebGLContext::DestroyResourcesAndContext()
|
||||
{
|
||||
if (mMemoryPressureObserver) {
|
||||
nsCOMPtr<nsIObserverService> observerService
|
||||
= mozilla::services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->RemoveObserver(mMemoryPressureObserver,
|
||||
"memory-pressure");
|
||||
}
|
||||
mMemoryPressureObserver = nullptr;
|
||||
}
|
||||
mContextObserver->UnregisterMemoryPressureEvent();
|
||||
|
||||
if (!gl)
|
||||
return;
|
||||
@ -1281,6 +1387,10 @@ WebGLContext::UpdateContextLossStatus()
|
||||
if (mLastLossWasSimulated)
|
||||
return;
|
||||
|
||||
// Restore when the app is visible
|
||||
if (mRestoreWhenVisible)
|
||||
return;
|
||||
|
||||
ForceRestoreContext();
|
||||
return;
|
||||
}
|
||||
@ -1314,16 +1424,22 @@ WebGLContext::UpdateContextLossStatus()
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ForceLoseContext()
|
||||
WebGLContext::ForceLoseContext(bool simulateLosing)
|
||||
{
|
||||
printf_stderr("WebGL(%p)::ForceLoseContext\n", this);
|
||||
MOZ_ASSERT(!IsContextLost());
|
||||
mContextStatus = ContextLostAwaitingEvent;
|
||||
mContextLostErrorSet = false;
|
||||
mLastLossWasSimulated = false;
|
||||
|
||||
// Burn it all!
|
||||
DestroyResourcesAndContext();
|
||||
mLastLossWasSimulated = simulateLosing;
|
||||
|
||||
// Register visibility change observer to defer the context restoring.
|
||||
// Restore the context when the app is visible.
|
||||
if (mRestoreWhenVisible && !mLastLossWasSimulated) {
|
||||
mContextObserver->RegisterVisibilityChangeEvent();
|
||||
}
|
||||
|
||||
// Queue up a task, since we know the status changed.
|
||||
EnqueueUpdateContextLossStatus();
|
||||
@ -1336,6 +1452,8 @@ WebGLContext::ForceRestoreContext()
|
||||
mContextStatus = ContextLostAwaitingRestore;
|
||||
mAllowContextRestore = true; // Hey, you did say 'force'.
|
||||
|
||||
mContextObserver->UnregisterVisibilityChangeEvent();
|
||||
|
||||
// Queue up a task, since we know the status changed.
|
||||
EnqueueUpdateContextLossStatus();
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "mozilla/dom/HTMLCanvasElement.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIDOMEventListener.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
|
||||
#include "GLContextProvider.h"
|
||||
@ -60,7 +61,7 @@ class nsIDocShell;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLMemoryPressureObserver;
|
||||
class WebGLObserver;
|
||||
class WebGLContextBoundObject;
|
||||
class WebGLActiveInfo;
|
||||
class WebGLExtensionBase;
|
||||
@ -146,7 +147,7 @@ class WebGLContext :
|
||||
friend class WebGLExtensionDrawBuffers;
|
||||
friend class WebGLExtensionLoseContext;
|
||||
friend class WebGLExtensionVertexArray;
|
||||
friend class WebGLMemoryPressureObserver;
|
||||
friend class WebGLObserver;
|
||||
friend class WebGLMemoryTracker;
|
||||
|
||||
enum {
|
||||
@ -917,8 +918,9 @@ protected:
|
||||
bool mMinCapability;
|
||||
bool mDisableExtensions;
|
||||
bool mIsMesa;
|
||||
bool mLoseContextOnHeapMinimize;
|
||||
bool mLoseContextOnMemoryPressure;
|
||||
bool mCanLoseContextInForeground;
|
||||
bool mRestoreWhenVisible;
|
||||
bool mShouldPresent;
|
||||
bool mBackbufferNeedsClear;
|
||||
bool mDisableFragHighP;
|
||||
@ -1162,7 +1164,7 @@ protected:
|
||||
GLenum type,
|
||||
const GLvoid *data);
|
||||
|
||||
void ForceLoseContext();
|
||||
void ForceLoseContext(bool simulateLosing = false);
|
||||
void ForceRestoreContext();
|
||||
|
||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
|
||||
@ -1273,7 +1275,7 @@ protected:
|
||||
ForceDiscreteGPUHelperCGL mForceDiscreteGPUHelper;
|
||||
#endif
|
||||
|
||||
nsRefPtr<WebGLMemoryPressureObserver> mMemoryPressureObserver;
|
||||
nsRefPtr<WebGLObserver> mContextObserver;
|
||||
|
||||
public:
|
||||
// console logging helpers
|
||||
@ -1371,19 +1373,29 @@ WebGLContext::ValidateObject(const char* info, ObjectType *aObject)
|
||||
return ValidateObjectAssumeNonNull(info, aObject);
|
||||
}
|
||||
|
||||
class WebGLMemoryPressureObserver MOZ_FINAL
|
||||
// Listen visibilitychange and memory-pressure event for context lose/restore
|
||||
class WebGLObserver MOZ_FINAL
|
||||
: public nsIObserver
|
||||
, public nsIDOMEventListener
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
WebGLMemoryPressureObserver(WebGLContext *context)
|
||||
: mContext(context)
|
||||
{}
|
||||
WebGLObserver(WebGLContext* aContext);
|
||||
~WebGLObserver();
|
||||
|
||||
void Destroy();
|
||||
|
||||
void RegisterVisibilityChangeEvent();
|
||||
void UnregisterVisibilityChangeEvent();
|
||||
|
||||
void RegisterMemoryPressureEvent();
|
||||
void UnregisterMemoryPressureEvent();
|
||||
|
||||
private:
|
||||
WebGLContext *mContext;
|
||||
WebGLContext* mContext;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -3878,8 +3878,7 @@ WebGLContext::LoseContext()
|
||||
if (IsContextLost())
|
||||
return ErrorInvalidOperation("loseContext: Context is already lost.");
|
||||
|
||||
ForceLoseContext();
|
||||
mLastLossWasSimulated = true;
|
||||
ForceLoseContext(true);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS(WebGLMemoryPressureObserver, nsIObserver)
|
||||
NS_IMPL_ISUPPORTS(WebGLObserver, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebGLMemoryTracker::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
|
@ -1553,8 +1553,9 @@ WebGLContext::InitAndValidateGL()
|
||||
|
||||
mMinCapability = Preferences::GetBool("webgl.min_capability_mode", false);
|
||||
mDisableExtensions = Preferences::GetBool("webgl.disable-extensions", false);
|
||||
mLoseContextOnHeapMinimize = Preferences::GetBool("webgl.lose-context-on-heap-minimize", false);
|
||||
mLoseContextOnMemoryPressure = Preferences::GetBool("webgl.lose-context-on-memory-preasure", false);
|
||||
mCanLoseContextInForeground = Preferences::GetBool("webgl.can-lose-context-in-foreground", true);
|
||||
mRestoreWhenVisible = Preferences::GetBool("webgl.restore-context-when-visible", true);
|
||||
|
||||
if (MinCapabilityMode()) {
|
||||
mDisableFragHighP = true;
|
||||
@ -1778,19 +1779,13 @@ WebGLContext::InitAndValidateGL()
|
||||
VertexAttrib4f(index, 0, 0, 0, 1);
|
||||
}
|
||||
|
||||
mMemoryPressureObserver
|
||||
= new WebGLMemoryPressureObserver(this);
|
||||
nsCOMPtr<nsIObserverService> observerService
|
||||
= mozilla::services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->AddObserver(mMemoryPressureObserver,
|
||||
"memory-pressure",
|
||||
false);
|
||||
}
|
||||
|
||||
mDefaultVertexArray = WebGLVertexArray::Create(this);
|
||||
mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
|
||||
mBoundVertexArray = mDefaultVertexArray;
|
||||
|
||||
if (mLoseContextOnMemoryPressure) {
|
||||
mContextObserver->RegisterMemoryPressureEvent();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -3716,8 +3716,9 @@ pref("webgl.msaa-force", false);
|
||||
pref("webgl.prefer-16bpp", false);
|
||||
pref("webgl.default-no-alpha", false);
|
||||
pref("webgl.force-layers-readback", false);
|
||||
pref("webgl.lose-context-on-heap-minimize", false);
|
||||
pref("webgl.lose-context-on-memory-preasure", false);
|
||||
pref("webgl.can-lose-context-in-foreground", true);
|
||||
pref("webgl.restore-context-when-visible", true);
|
||||
pref("webgl.max-warnings-per-context", 32);
|
||||
pref("webgl.enable-draft-extensions", false);
|
||||
pref("webgl.enable-privileged-extensions", false);
|
||||
|
Loading…
Reference in New Issue
Block a user