Bug 1502789 - Fix Texture release timing of AsyncImagePipelineManager::ProcessPipelineUpdates() r=nical

This commit is contained in:
sotaro 2018-10-31 14:19:41 +09:00
Родитель 09ac74505a
Коммит 683db7acd5
3 изменённых файлов: 82 добавлений и 21 удалений

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

@ -36,6 +36,7 @@ AsyncImagePipelineManager::AsyncImagePipelineManager(already_AddRefed<wr::WebRen
, mWillGenerateFrame(false)
, mDestroyed(false)
, mUpdatesLock("UpdatesLock")
, mUpdatesCount(0)
{
MOZ_COUNT_CTOR(AsyncImagePipelineManager);
}
@ -542,23 +543,40 @@ AsyncImagePipelineManager::HoldExternalImage(const wr::PipelineId& aPipelineId,
}
void
AsyncImagePipelineManager::NotifyPipelinesUpdated(wr::WrPipelineInfo aInfo)
AsyncImagePipelineManager::NotifyPipelinesUpdated(wr::WrPipelineInfo aInfo, bool aRender)
{
// This is called on the render thread, so we just stash the data into
// mUpdatesQueue and process it later on the compositor thread.
// UpdatesQueue and process it later on the compositor thread.
MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
MutexAutoLock lock(mUpdatesLock);
// Increment the count when render happens.
// XXX The count is going to be used to delay releasing TextureHosts for multiple rendering.
// See Bug 1500017.
uint64_t currCount = aRender ? ++mUpdatesCount : mUpdatesCount;
auto updates = MakeUnique<PipelineUpdates>(currCount, aRender);
for (uintptr_t i = 0; i < aInfo.epochs.length; i++) {
mUpdatesQueue.push(std::make_pair(
updates->mQueue.emplace(std::make_pair(
aInfo.epochs.data[i].pipeline_id,
Some(aInfo.epochs.data[i].epoch)));
}
for (uintptr_t i = 0; i < aInfo.removed_pipelines.length; i++) {
mUpdatesQueue.push(std::make_pair(
updates->mQueue.emplace(std::make_pair(
aInfo.removed_pipelines.data[i],
Nothing()));
}
{
// Scope lock to push UpdatesQueue to mUpdatesQueues.
MutexAutoLock lock(mUpdatesLock);
mUpdatesQueues.push(std::move(updates));
}
if (!aRender) {
// Do not post ProcessPipelineUpdate when rendering did not happen.
return;
}
// Queue a runnable on the compositor thread to process the queue
layers::CompositorThreadHolder::Loop()->PostTask(
NewRunnableMethod("ProcessPipelineUpdates",
@ -575,19 +593,41 @@ AsyncImagePipelineManager::ProcessPipelineUpdates()
return;
}
while (true) {
wr::PipelineId pipelineId;
Maybe<wr::Epoch> epoch;
UniquePtr<PipelineUpdates> updates;
{ // scope lock to extract one item from the queue
while (true) {
// Clear updates if it is empty. It is a preparation for next PipelineUpdates handling.
if (updates && updates->mQueue.empty()) {
updates = nullptr;
}
// Get new PipelineUpdates if necessary.
if (!updates) {
// Scope lock to extract UpdatesQueue from mUpdatesQueues.
MutexAutoLock lock(mUpdatesLock);
if (mUpdatesQueue.empty()) {
if (mUpdatesQueues.empty()) {
// No more PipelineUpdates to process for now.
break;
}
pipelineId = mUpdatesQueue.front().first;
epoch = mUpdatesQueue.front().second;
mUpdatesQueue.pop();
// Check if PipelineUpdates is ready to process.
uint64_t currCount = mUpdatesCount;
if (mUpdatesQueues.front()->NeedsToWait(currCount)) {
// PipelineUpdates is not ready for processing for now.
break;
}
updates = std::move(mUpdatesQueues.front());
mUpdatesQueues.pop();
}
MOZ_ASSERT(updates);
if (updates->mQueue.empty()) {
// Try next PipelineUpdates.
continue;
}
wr::PipelineId pipelineId = updates->mQueue.front().first;
Maybe<wr::Epoch> epoch = updates->mQueue.front().second;
updates->mQueue.pop();
if (epoch.isSome()) {
ProcessPipelineRendered(pipelineId, *epoch);

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

@ -56,7 +56,7 @@ public:
// This is called from the Renderer thread to notify this class about the
// pipelines in the most recently completed render. A copy of the update
// information is put into mUpdatesQueue.
void NotifyPipelinesUpdated(wr::WrPipelineInfo aInfo);
void NotifyPipelinesUpdated(wr::WrPipelineInfo aInfo, bool aRender);
// This is run on the compositor thread to process mUpdatesQueue. We make
// this a public entry point because we need to invoke it from other places.
@ -238,12 +238,33 @@ private:
// The lock that protects mUpdatesQueue
Mutex mUpdatesLock;
// Queue to store rendered pipeline epoch information. This is populated from
// the Renderer thread after a render, and is read from the compositor thread
// to free resources (e.g. textures) that are no longer needed. Each entry
// in the queue is a pair that holds the pipeline id and Some(x) for
// a render of epoch x, or Nothing() for a removed pipeline.
std::queue<std::pair<wr::PipelineId, Maybe<wr::Epoch>>> mUpdatesQueue;
// Used for checking if PipelineUpdates could be processed.
Atomic<uint64_t> mUpdatesCount;
struct PipelineUpdates {
PipelineUpdates(const uint64_t aUpdatesCount, const bool aRendered)
: mUpdatesCount(aUpdatesCount)
, mRendered(aRendered)
{}
bool NeedsToWait(const uint64_t aUpdatesCount) {
MOZ_ASSERT(mUpdatesCount <= aUpdatesCount);
// XXX Add support of delaying releasing TextureHosts for multiple rendering.
// See Bug 1500017.
if (mUpdatesCount == aUpdatesCount && !mRendered) {
// RenderTextureHosts related to this might be still used by GPU.
return true;
}
return false;
}
const uint64_t mUpdatesCount;
const bool mRendered;
// Queue to store rendered pipeline epoch information. This is populated from
// the Renderer thread after a render, and is read from the compositor thread
// to free resources (e.g. textures) that are no longer needed. Each entry
// in the queue is a pair that holds the pipeline id and Some(x) for
// a render of epoch x, or Nothing() for a removed pipeline.
std::queue<std::pair<wr::PipelineId, Maybe<wr::Epoch>>> mQueue;
};
std::queue<UniquePtr<PipelineUpdates>> mUpdatesQueues;
};
} // namespace layers

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

@ -394,7 +394,7 @@ RenderThread::UpdateAndRender(wr::WindowId aWindowId,
// removed the relevant renderer. And after that happens we should never reach
// this code at all; it would bail out at the mRenderers.find check above.
MOZ_ASSERT(pipelineMgr);
pipelineMgr->NotifyPipelinesUpdated(info);
pipelineMgr->NotifyPipelinesUpdated(info, aRender);
layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
"NotifyDidRenderRunnable",