Skip to content

Commit 8fe2e48

Browse files
committed
[PageLifecycle] Release WebGL GCGLContext on freeze and recreate on resume.
1 parent 61cfd4f commit 8fe2e48

2 files changed

Lines changed: 59 additions & 7 deletions

File tree

Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,8 +1308,9 @@ void WebGLRenderingContextBase::destroyGraphicsContextGL()
13081308
removeActivityStateChangeObserver();
13091309

13101310
if (m_context) {
1311-
// first release the big textures allocated for the FBOs
1312-
m_context->reshape(0,0);
1311+
// first release the big textures allocated for the FBOs. Need to set (1, 1) because
1312+
// (0, 0) produces an error on the GL layer.
1313+
m_context->reshape(1, 1);
13131314
m_context->setClient(nullptr);
13141315
m_context = nullptr;
13151316
removeActiveContext(*this);
@@ -6786,14 +6787,44 @@ const char* WebGLRenderingContextBase::activeDOMObjectName() const
67866787
return "WebGLRenderingContext";
67876788
}
67886789

6789-
void WebGLRenderingContextBase::suspend(ReasonForSuspension)
6790+
void WebGLRenderingContextBase::suspend(ReasonForSuspension reason)
67906791
{
6792+
if (reason != ReasonForSuspension::BackForwardCache)
6793+
return;
6794+
6795+
// forceLostContext() will queue a task to dispatch the contextLost event. This task won't
6796+
// be executed until resume, when the events are enabled again.
6797+
forceLostContext(WebGLRenderingContextBase::SyntheticLostContext);
6798+
destroyGraphicsContextGL();
67916799
m_isSuspended = true;
67926800
}
67936801

67946802
void WebGLRenderingContextBase::resume()
67956803
{
67966804
m_isSuspended = false;
6805+
6806+
// The composition requirements update for the page, which will set the appropriate proxy to the
6807+
// GraphicsLayer created for this WebGL context, will be updated after this function, but before
6808+
// any task that we may schedule. Due to this, we need to create the GCGLContext now, we cannot
6809+
// call forceRestoreContext() that will use a timer to call maybeRestoreContext(), we
6810+
// need to call maybeRestoreContext() directly.
6811+
6812+
// At some point after this function ends, the task to dispatch the contextLost event that was scheduled
6813+
// on suspend will run. The problem is that maybeRestoreContext() later in this function will create a new
6814+
// GCGLContext now, so when the task runs, context is not lost anymore and the event won't be sent. Set
6815+
// m_forceDispatchContextLostEvent so the task sends the event even if the context was already restored.
6816+
m_forceDispatchContextLostEvent = true;
6817+
6818+
// Set restoreRequested to true so maybeRestoreContext() really performs the restore.
6819+
m_contextLostState->restoreRequested = true;
6820+
6821+
// Set m_queueContextRestoredEvent so maybeRestoreContext() doesn't send the contextRestored
6822+
// event immediately, but queues it. We need to do this because the contextRestored event that was
6823+
// queued on suspension hasn't run yet, and needs ro run before the contextRestored event is
6824+
// dispatched.
6825+
m_queueContextRestoredEvent = true;
6826+
6827+
maybeRestoreContext();
67976828
}
67986829

67996830
bool WebGLRenderingContextBase::getBooleanParameter(GCGLenum pname)
@@ -7961,10 +7992,14 @@ void WebGLRenderingContextBase::scheduleTaskToDispatchContextLostEvent()
79617992

79627993
// It is safe to capture |this| because we keep the canvas element alive and it owns |this|.
79637994
queueTaskKeepingObjectAlive(*canvas, TaskSource::WebGL, [this, canvas] {
7964-
if (isContextStopped())
7965-
return;
7966-
if (!isContextLost())
7967-
return;
7995+
if (m_forceDispatchContextLostEvent)
7996+
m_forceDispatchContextLostEvent = false;
7997+
else {
7998+
if (isContextStopped())
7999+
return;
8000+
if (!isContextLost())
8001+
return;
8002+
}
79688003
auto event = WebGLContextEvent::create(eventNames().webglcontextlostEvent, Event::CanBubble::No, Event::IsCancelable::Yes, emptyString());
79698004
canvas->dispatchEvent(event);
79708005
m_contextLostState->restoreRequested = event->defaultPrevented();
@@ -8016,6 +8051,21 @@ void WebGLRenderingContextBase::maybeRestoreContext()
80168051
m_contextLostState = std::nullopt;
80178052
setupFlags();
80188053
initializeNewContext();
8054+
8055+
if (m_queueContextRestoredEvent) {
8056+
m_queueContextRestoredEvent = false;
8057+
8058+
// It is safe to capture |this| because we keep the canvas element alive and it owns |this|.
8059+
queueTaskKeepingObjectAlive(*canvas, TaskSource::WebGL, [this, canvas] {
8060+
if (isContextStopped())
8061+
return;
8062+
if (isContextLost())
8063+
return;
8064+
canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, Event::CanBubble::No, Event::IsCancelable::Yes, emptyString()));
8065+
});
8066+
return;
8067+
}
8068+
80198069
if (!isContextLost())
80208070
canvas->dispatchEvent(WebGLContextEvent::create(eventNames().webglcontextrestoredEvent, Event::CanBubble::No, Event::IsCancelable::Yes, emptyString()));
80218071
}

Source/WebCore/html/canvas/WebGLRenderingContextBase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,8 @@ class WebGLRenderingContextBase : public GraphicsContextGL::Client, public GPUBa
12131213
#endif
12141214
// The ordinal number of when the context was last active (drew, read pixels).
12151215
uint64_t m_activeOrdinal { 0 };
1216+
bool m_queueContextRestoredEvent { false };
1217+
bool m_forceDispatchContextLostEvent { false };
12161218
};
12171219

12181220
#if !USE(ANGLE)

0 commit comments

Comments
 (0)