2017-10-28 02:10:06 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2017-01-06 21:10:15 +03:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
2017-06-09 06:56:13 +03:00
|
|
|
#include "base/task.h"
|
|
|
|
#include "GeckoProfiler.h"
|
2017-01-06 21:10:15 +03:00
|
|
|
#include "RenderThread.h"
|
|
|
|
#include "nsThreadUtils.h"
|
2017-07-03 15:08:22 +03:00
|
|
|
#include "mtransport/runnable_utils.h"
|
2018-05-28 18:29:41 +03:00
|
|
|
#include "mozilla/layers/AsyncImagePipelineManager.h"
|
2018-06-13 18:01:06 +03:00
|
|
|
#include "mozilla/gfx/GPUParent.h"
|
2017-01-27 23:30:18 +03:00
|
|
|
#include "mozilla/layers/CompositorThread.h"
|
|
|
|
#include "mozilla/layers/CompositorBridgeParent.h"
|
2019-06-19 19:14:56 +03:00
|
|
|
#include "mozilla/layers/CompositorManagerParent.h"
|
2018-09-08 21:41:34 +03:00
|
|
|
#include "mozilla/layers/WebRenderBridgeParent.h"
|
2018-04-23 14:57:17 +03:00
|
|
|
#include "mozilla/layers/SharedSurfacesParent.h"
|
2017-01-06 21:10:15 +03:00
|
|
|
#include "mozilla/StaticPtr.h"
|
2018-06-25 17:55:26 +03:00
|
|
|
#include "mozilla/Telemetry.h"
|
2017-03-07 13:37:28 +03:00
|
|
|
#include "mozilla/webrender/RendererOGL.h"
|
2017-03-31 17:29:14 +03:00
|
|
|
#include "mozilla/webrender/RenderTextureHost.h"
|
2017-03-07 13:37:28 +03:00
|
|
|
#include "mozilla/widget/CompositorWidget.h"
|
2017-01-06 21:10:15 +03:00
|
|
|
|
2018-03-29 05:21:47 +03:00
|
|
|
#ifdef XP_WIN
|
2018-10-04 05:54:50 +03:00
|
|
|
# include "GLLibraryEGL.h"
|
2018-03-29 05:21:47 +03:00
|
|
|
# include "mozilla/widget/WinCompositorWindowThread.h"
|
|
|
|
#endif
|
|
|
|
|
2019-03-20 14:51:33 +03:00
|
|
|
#ifdef MOZ_WIDGET_ANDROID
|
|
|
|
# include "GLLibraryEGL.h"
|
2019-06-19 19:14:56 +03:00
|
|
|
# include "GeneratedJNIWrappers.h"
|
2019-03-20 14:51:33 +03:00
|
|
|
#endif
|
|
|
|
|
2018-10-04 05:54:50 +03:00
|
|
|
using namespace mozilla;
|
|
|
|
|
|
|
|
static already_AddRefed<gl::GLContext> CreateGLContext();
|
|
|
|
|
2018-12-01 06:05:56 +03:00
|
|
|
MOZ_DEFINE_MALLOC_SIZE_OF(WebRenderRendererMallocSizeOf)
|
|
|
|
|
2017-01-06 21:10:15 +03:00
|
|
|
namespace mozilla {
|
2017-01-17 03:22:09 +03:00
|
|
|
namespace wr {
|
2017-01-06 21:10:15 +03:00
|
|
|
|
|
|
|
static StaticRefPtr<RenderThread> sRenderThread;
|
|
|
|
|
|
|
|
RenderThread::RenderThread(base::Thread* aThread)
|
2017-01-25 00:06:17 +03:00
|
|
|
: mThread(aThread),
|
2019-01-17 02:25:35 +03:00
|
|
|
mWindowInfos("RenderThread.mWindowInfos"),
|
2017-03-07 13:37:28 +03:00
|
|
|
mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
|
2017-07-03 15:08:22 +03:00
|
|
|
mHasShutdown(false),
|
2019-06-19 19:14:56 +03:00
|
|
|
mHandlingDeviceReset(false),
|
|
|
|
mHandlingWebRenderError(false) {}
|
2017-01-06 21:10:15 +03:00
|
|
|
|
|
|
|
RenderThread::~RenderThread() {
|
2018-06-15 01:18:48 +03:00
|
|
|
MOZ_ASSERT(mRenderTexturesDeferred.empty());
|
2017-01-06 21:10:15 +03:00
|
|
|
delete mThread;
|
|
|
|
}
|
|
|
|
|
2017-01-17 03:22:09 +03:00
|
|
|
// static
|
2017-01-06 21:10:15 +03:00
|
|
|
RenderThread* RenderThread::Get() { return sRenderThread; }
|
|
|
|
|
|
|
|
// static
|
|
|
|
void RenderThread::Start() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(!sRenderThread);
|
|
|
|
|
2017-01-11 15:51:27 +03:00
|
|
|
base::Thread* thread = new base::Thread("Renderer");
|
2017-01-06 21:10:15 +03:00
|
|
|
|
|
|
|
base::Thread::Options options;
|
|
|
|
// TODO(nical): The compositor thread has a bunch of specific options, see
|
|
|
|
// which ones make sense here.
|
|
|
|
if (!thread->StartWithOptions(options)) {
|
|
|
|
delete thread;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sRenderThread = new RenderThread(thread);
|
2018-03-29 05:21:47 +03:00
|
|
|
#ifdef XP_WIN
|
|
|
|
widget::WinCompositorWindowThread::Start();
|
|
|
|
#endif
|
2018-04-23 14:57:17 +03:00
|
|
|
layers::SharedSurfacesParent::Initialize();
|
2018-05-31 09:07:34 +03:00
|
|
|
|
2018-10-04 05:54:50 +03:00
|
|
|
RefPtr<Runnable> runnable = WrapRunnable(
|
|
|
|
RefPtr<RenderThread>(sRenderThread.get()), &RenderThread::InitDeviceTask);
|
|
|
|
sRenderThread->Loop()->PostTask(runnable.forget());
|
2017-01-06 21:10:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
void RenderThread::ShutDown() {
|
|
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
MOZ_ASSERT(sRenderThread);
|
|
|
|
|
2017-07-03 15:08:22 +03:00
|
|
|
{
|
|
|
|
MutexAutoLock lock(sRenderThread->mRenderTextureMapLock);
|
|
|
|
sRenderThread->mHasShutdown = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
layers::SynchronousTask task("RenderThread");
|
|
|
|
RefPtr<Runnable> runnable =
|
|
|
|
WrapRunnable(RefPtr<RenderThread>(sRenderThread.get()),
|
|
|
|
&RenderThread::ShutDownTask, &task);
|
|
|
|
sRenderThread->Loop()->PostTask(runnable.forget());
|
|
|
|
task.Wait();
|
2017-01-06 21:10:15 +03:00
|
|
|
|
|
|
|
sRenderThread = nullptr;
|
2018-03-29 05:21:47 +03:00
|
|
|
#ifdef XP_WIN
|
2019-05-26 05:17:10 +03:00
|
|
|
if (widget::WinCompositorWindowThread::Get()) {
|
|
|
|
widget::WinCompositorWindowThread::ShutDown();
|
|
|
|
}
|
2018-03-29 05:21:47 +03:00
|
|
|
#endif
|
2017-01-06 21:10:15 +03:00
|
|
|
}
|
|
|
|
|
2018-04-25 05:24:55 +03:00
|
|
|
extern void ClearAllBlobImageResources();
|
|
|
|
|
2017-07-03 15:08:22 +03:00
|
|
|
void RenderThread::ShutDownTask(layers::SynchronousTask* aTask) {
|
|
|
|
layers::AutoCompleteTask complete(aTask);
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
2018-04-23 14:57:17 +03:00
|
|
|
|
2019-07-01 18:24:32 +03:00
|
|
|
// Let go of our handle to the (internally ref-counted) thread pool.
|
|
|
|
mThreadPool.Release();
|
|
|
|
|
2018-04-23 14:57:17 +03:00
|
|
|
// Releasing on the render thread will allow us to avoid dispatching to remove
|
|
|
|
// remaining textures from the texture map.
|
|
|
|
layers::SharedSurfacesParent::Shutdown();
|
2018-04-25 05:24:55 +03:00
|
|
|
|
|
|
|
ClearAllBlobImageResources();
|
2018-10-04 05:54:50 +03:00
|
|
|
ClearSharedGL();
|
2017-07-03 15:08:22 +03:00
|
|
|
}
|
|
|
|
|
2017-01-06 21:10:15 +03:00
|
|
|
// static
|
|
|
|
MessageLoop* RenderThread::Loop() {
|
|
|
|
return sRenderThread ? sRenderThread->mThread->message_loop() : nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
bool RenderThread::IsInRenderThread() {
|
|
|
|
return sRenderThread &&
|
|
|
|
sRenderThread->mThread->thread_id() == PlatformThread::CurrentId();
|
|
|
|
}
|
|
|
|
|
2018-09-08 02:03:13 +03:00
|
|
|
void RenderThread::DoAccumulateMemoryReport(
|
|
|
|
MemoryReport aReport,
|
|
|
|
const RefPtr<MemoryReportPromise::Private>& aPromise) {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
2018-11-13 06:15:51 +03:00
|
|
|
|
2018-09-08 02:03:13 +03:00
|
|
|
for (auto& r : mRenderers) {
|
2018-11-13 06:15:51 +03:00
|
|
|
r.second->AccumulateMemoryReport(&aReport);
|
2018-09-08 02:03:13 +03:00
|
|
|
}
|
|
|
|
|
2018-12-01 06:05:56 +03:00
|
|
|
// Note memory used by the shader cache, which is shared across all WR
|
|
|
|
// instances.
|
|
|
|
MOZ_ASSERT(aReport.shader_cache == 0);
|
|
|
|
if (mProgramCache) {
|
|
|
|
aReport.shader_cache = wr_program_cache_report_memory(
|
|
|
|
mProgramCache->Raw(), &WebRenderRendererMallocSizeOf);
|
|
|
|
}
|
2018-10-31 01:13:32 +03:00
|
|
|
|
2018-09-08 02:03:13 +03:00
|
|
|
aPromise->Resolve(aReport, __func__);
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
RefPtr<MemoryReportPromise> RenderThread::AccumulateMemoryReport(
|
|
|
|
MemoryReport aInitial) {
|
|
|
|
RefPtr<MemoryReportPromise::Private> p =
|
|
|
|
new MemoryReportPromise::Private(__func__);
|
|
|
|
MOZ_ASSERT(!IsInRenderThread());
|
2018-09-26 23:44:59 +03:00
|
|
|
if (!Get() || !Get()->Loop()) {
|
2018-09-28 08:36:30 +03:00
|
|
|
// This happens when the GPU process fails to start and we fall back to the
|
|
|
|
// basic compositor in the parent process. We could assert against this if
|
|
|
|
// we made the webrender detection code in gfxPlatform.cpp smarter. See bug
|
|
|
|
// 1494430 comment 12.
|
2018-09-26 23:44:59 +03:00
|
|
|
NS_WARNING("No render thread, returning empty memory report");
|
|
|
|
p->Resolve(aInitial, __func__);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2018-09-08 02:03:13 +03:00
|
|
|
Get()->Loop()->PostTask(
|
|
|
|
NewRunnableMethod<MemoryReport, RefPtr<MemoryReportPromise::Private>>(
|
|
|
|
"wr::RenderThread::DoAccumulateMemoryReport", Get(),
|
|
|
|
&RenderThread::DoAccumulateMemoryReport, aInitial, p));
|
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2017-01-17 03:22:09 +03:00
|
|
|
void RenderThread::AddRenderer(wr::WindowId aWindowId,
|
|
|
|
UniquePtr<RendererOGL> aRenderer) {
|
2017-01-16 17:22:47 +03:00
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
2017-07-03 15:08:22 +03:00
|
|
|
|
|
|
|
if (mHasShutdown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-30 22:15:35 +03:00
|
|
|
mRenderers[aWindowId] = std::move(aRenderer);
|
2017-05-19 03:21:38 +03:00
|
|
|
|
2019-01-18 19:48:22 +03:00
|
|
|
auto windows = mWindowInfos.Lock();
|
|
|
|
windows->emplace(AsUint64(aWindowId), new WindowInfo());
|
2017-01-06 21:10:15 +03:00
|
|
|
}
|
|
|
|
|
2017-01-17 03:22:09 +03:00
|
|
|
void RenderThread::RemoveRenderer(wr::WindowId aWindowId) {
|
2017-01-16 17:22:47 +03:00
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
2017-07-03 15:08:22 +03:00
|
|
|
|
|
|
|
if (mHasShutdown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:10:15 +03:00
|
|
|
mRenderers.erase(aWindowId);
|
2019-05-31 03:31:39 +03:00
|
|
|
mCompositionRecorders.erase(aWindowId);
|
2017-05-19 03:21:38 +03:00
|
|
|
|
2018-06-13 18:01:06 +03:00
|
|
|
if (mRenderers.size() == 0 && mHandlingDeviceReset) {
|
|
|
|
mHandlingDeviceReset = false;
|
|
|
|
}
|
|
|
|
|
2019-01-17 02:25:35 +03:00
|
|
|
auto windows = mWindowInfos.Lock();
|
|
|
|
auto it = windows->find(AsUint64(aWindowId));
|
|
|
|
MOZ_ASSERT(it != windows->end());
|
2018-06-25 17:55:19 +03:00
|
|
|
WindowInfo* toDelete = it->second;
|
2019-01-17 02:25:35 +03:00
|
|
|
windows->erase(it);
|
2018-06-25 17:55:19 +03:00
|
|
|
delete toDelete;
|
2017-01-06 21:10:15 +03:00
|
|
|
}
|
|
|
|
|
2017-01-17 03:22:09 +03:00
|
|
|
RendererOGL* RenderThread::GetRenderer(wr::WindowId aWindowId) {
|
2017-01-16 17:22:47 +03:00
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
|
|
|
|
auto it = mRenderers.find(aWindowId);
|
|
|
|
MOZ_ASSERT(it != mRenderers.end());
|
|
|
|
|
|
|
|
if (it == mRenderers.end()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-01-25 00:20:54 +03:00
|
|
|
return it->second.get();
|
2017-01-16 17:22:47 +03:00
|
|
|
}
|
2017-01-06 21:10:15 +03:00
|
|
|
|
2018-06-13 18:01:06 +03:00
|
|
|
size_t RenderThread::RendererCount() {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
return mRenderers.size();
|
|
|
|
}
|
|
|
|
|
2019-05-31 03:31:39 +03:00
|
|
|
void RenderThread::SetCompositionRecorderForWindow(
|
|
|
|
wr::WindowId aWindowId,
|
2019-07-31 21:28:47 +03:00
|
|
|
UniquePtr<layers::WebRenderCompositionRecorder> aCompositionRecorder) {
|
2019-05-31 03:31:39 +03:00
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
MOZ_ASSERT(GetRenderer(aWindowId));
|
2019-07-31 21:28:47 +03:00
|
|
|
MOZ_ASSERT(mCompositionRecorders.find(aWindowId) ==
|
|
|
|
mCompositionRecorders.end());
|
2019-05-31 03:31:52 +03:00
|
|
|
|
2019-05-31 03:31:39 +03:00
|
|
|
mCompositionRecorders[aWindowId] = std::move(aCompositionRecorder);
|
|
|
|
}
|
|
|
|
|
2019-07-31 21:28:34 +03:00
|
|
|
void RenderThread::WriteCollectedFramesForWindow(wr::WindowId aWindowId) {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
2019-07-31 21:28:47 +03:00
|
|
|
|
|
|
|
RendererOGL* renderer = GetRenderer(aWindowId);
|
|
|
|
MOZ_ASSERT(renderer);
|
2019-07-31 21:28:34 +03:00
|
|
|
|
|
|
|
auto it = mCompositionRecorders.find(aWindowId);
|
|
|
|
MOZ_DIAGNOSTIC_ASSERT(
|
|
|
|
it != mCompositionRecorders.end(),
|
|
|
|
"Attempted to write frames from a window that was not recording.");
|
|
|
|
if (it != mCompositionRecorders.end()) {
|
|
|
|
it->second->WriteCollectedFrames();
|
|
|
|
|
2019-07-31 21:28:47 +03:00
|
|
|
if (renderer) {
|
|
|
|
wr_renderer_release_composition_recorder_structures(
|
|
|
|
renderer->GetRenderer());
|
|
|
|
}
|
|
|
|
|
2019-07-31 21:28:34 +03:00
|
|
|
mCompositionRecorders.erase(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-06 10:01:15 +03:00
|
|
|
void RenderThread::HandleFrameOneDoc(wr::WindowId aWindowId, bool aRender) {
|
2017-07-03 15:08:22 +03:00
|
|
|
if (mHasShutdown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:10:15 +03:00
|
|
|
if (!IsInRenderThread()) {
|
2018-10-02 06:13:22 +03:00
|
|
|
Loop()->PostTask(NewRunnableMethod<wr::WindowId, bool>(
|
2019-08-06 10:01:15 +03:00
|
|
|
"wr::RenderThread::HandleFrameOneDoc", this,
|
|
|
|
&RenderThread::HandleFrameOneDoc, aWindowId, aRender));
|
2017-01-06 21:10:15 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-06 10:01:15 +03:00
|
|
|
bool render = false;
|
2019-08-05 15:07:29 +03:00
|
|
|
PendingFrameInfo frame;
|
|
|
|
bool hadSlowFrame;
|
2019-08-06 10:01:15 +03:00
|
|
|
{ // scope lock
|
|
|
|
auto windows = mWindowInfos.Lock();
|
|
|
|
auto it = windows->find(AsUint64(aWindowId));
|
|
|
|
if (it == windows->end()) {
|
|
|
|
MOZ_ASSERT(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-05 15:07:29 +03:00
|
|
|
WindowInfo* info = it->second;
|
|
|
|
PendingFrameInfo& frameInfo = info->mPendingFrames.front();
|
|
|
|
frameInfo.mDocFramesSeen++;
|
|
|
|
frameInfo.mFrameNeedsRender |= aRender;
|
|
|
|
if (frameInfo.mDocFramesSeen < frameInfo.mDocFramesTotal) {
|
2019-08-06 10:01:15 +03:00
|
|
|
return;
|
|
|
|
}
|
2019-08-05 15:07:29 +03:00
|
|
|
|
|
|
|
MOZ_ASSERT(frameInfo.mDocFramesSeen == frameInfo.mDocFramesTotal);
|
|
|
|
render = frameInfo.mFrameNeedsRender;
|
|
|
|
info->mIsRendering = true;
|
|
|
|
|
|
|
|
frame = frameInfo;
|
|
|
|
hadSlowFrame = info->mHadSlowFrame;
|
2019-08-06 10:01:15 +03:00
|
|
|
}
|
|
|
|
|
2017-11-24 12:34:50 +03:00
|
|
|
if (IsDestroyed(aWindowId)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-13 18:01:06 +03:00
|
|
|
if (mHandlingDeviceReset) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-08-06 10:01:15 +03:00
|
|
|
UpdateAndRender(aWindowId, frame.mStartId, frame.mStartTime, render,
|
2018-12-08 02:28:41 +03:00
|
|
|
/* aReadbackSize */ Nothing(),
|
2019-04-30 20:49:30 +03:00
|
|
|
/* aReadbackFormat */ Nothing(),
|
2018-11-04 23:35:36 +03:00
|
|
|
/* aReadbackBuffer */ Nothing(), hadSlowFrame);
|
2018-04-27 14:41:03 +03:00
|
|
|
FrameRenderingComplete(aWindowId);
|
2017-01-06 21:10:15 +03:00
|
|
|
}
|
|
|
|
|
2018-02-13 22:08:54 +03:00
|
|
|
void RenderThread::WakeUp(wr::WindowId aWindowId) {
|
|
|
|
if (mHasShutdown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsInRenderThread()) {
|
|
|
|
Loop()->PostTask(NewRunnableMethod<wr::WindowId>(
|
|
|
|
"wr::RenderThread::WakeUp", this, &RenderThread::WakeUp, aWindowId));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsDestroyed(aWindowId)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-13 18:01:06 +03:00
|
|
|
if (mHandlingDeviceReset) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-13 22:08:54 +03:00
|
|
|
auto it = mRenderers.find(aWindowId);
|
|
|
|
MOZ_ASSERT(it != mRenderers.end());
|
|
|
|
if (it != mRenderers.end()) {
|
|
|
|
it->second->Update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-17 03:22:09 +03:00
|
|
|
void RenderThread::RunEvent(wr::WindowId aWindowId,
|
|
|
|
UniquePtr<RendererEvent> aEvent) {
|
2017-01-06 21:10:15 +03:00
|
|
|
if (!IsInRenderThread()) {
|
2017-06-12 22:34:10 +03:00
|
|
|
Loop()->PostTask(
|
|
|
|
NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
|
|
|
|
"wr::RenderThread::RunEvent", this, &RenderThread::RunEvent,
|
2018-05-30 22:15:35 +03:00
|
|
|
aWindowId, std::move(aEvent)));
|
2017-01-11 15:51:27 +03:00
|
|
|
return;
|
2017-01-06 21:10:15 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
aEvent->Run(*this, aWindowId);
|
|
|
|
aEvent = nullptr;
|
|
|
|
}
|
|
|
|
|
2018-05-28 18:29:41 +03:00
|
|
|
static void NotifyDidRender(layers::CompositorBridgeParent* aBridge,
|
2018-11-12 04:36:13 +03:00
|
|
|
RefPtr<WebRenderPipelineInfo> aInfo,
|
2018-12-08 02:28:41 +03:00
|
|
|
VsyncId aCompositeStartId,
|
2018-11-16 05:13:56 +03:00
|
|
|
TimeStamp aCompositeStart, TimeStamp aRenderStart,
|
|
|
|
TimeStamp aEnd, bool aRender,
|
2018-11-16 02:09:05 +03:00
|
|
|
RendererStats aStats) {
|
2018-10-23 07:21:02 +03:00
|
|
|
if (aRender && aBridge->GetWrBridge()) {
|
|
|
|
// We call this here to mimic the behavior in LayerManagerComposite, as to
|
|
|
|
// not change what Talos measures. That is, we do not record an empty frame
|
|
|
|
// as a frame.
|
2018-09-08 21:41:34 +03:00
|
|
|
aBridge->GetWrBridge()->RecordFrame();
|
|
|
|
}
|
|
|
|
|
2018-11-12 04:36:13 +03:00
|
|
|
auto info = aInfo->Raw();
|
|
|
|
|
|
|
|
for (uintptr_t i = 0; i < info.epochs.length; i++) {
|
2018-12-08 02:28:41 +03:00
|
|
|
aBridge->NotifyPipelineRendered(
|
|
|
|
info.epochs.data[i].pipeline_id, info.epochs.data[i].epoch,
|
|
|
|
aCompositeStartId, aCompositeStart, aRenderStart, aEnd, &aStats);
|
2018-11-29 21:30:06 +03:00
|
|
|
}
|
2018-12-28 18:48:06 +03:00
|
|
|
|
2018-12-10 22:31:12 +03:00
|
|
|
if (aBridge->GetWrBridge()) {
|
|
|
|
aBridge->GetWrBridge()->CompositeIfNeeded();
|
|
|
|
}
|
2017-01-27 23:30:18 +03:00
|
|
|
}
|
2017-01-06 21:10:15 +03:00
|
|
|
|
2018-12-07 01:19:03 +03:00
|
|
|
static void NotifyDidStartRender(layers::CompositorBridgeParent* aBridge) {
|
2019-08-05 15:02:38 +03:00
|
|
|
// Starting a render will change mIsRendering, and potentially
|
2018-12-07 01:19:03 +03:00
|
|
|
// change whether we can allow the bridge to intiate another frame.
|
|
|
|
if (aBridge->GetWrBridge()) {
|
|
|
|
aBridge->GetWrBridge()->CompositeIfNeeded();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-14 10:18:03 +03:00
|
|
|
void RenderThread::UpdateAndRender(
|
|
|
|
wr::WindowId aWindowId, const VsyncId& aStartId,
|
|
|
|
const TimeStamp& aStartTime, bool aRender,
|
|
|
|
const Maybe<gfx::IntSize>& aReadbackSize,
|
|
|
|
const Maybe<wr::ImageFormat>& aReadbackFormat,
|
|
|
|
const Maybe<Range<uint8_t>>& aReadbackBuffer, bool aHadSlowFrame) {
|
2019-01-18 18:40:15 +03:00
|
|
|
AUTO_PROFILER_TRACING("Paint", "Composite", GRAPHICS);
|
2017-01-16 17:22:47 +03:00
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
2018-10-17 01:54:01 +03:00
|
|
|
MOZ_ASSERT(aRender || aReadbackBuffer.isNothing());
|
2017-01-16 17:22:47 +03:00
|
|
|
|
2017-01-06 21:10:15 +03:00
|
|
|
auto it = mRenderers.find(aWindowId);
|
|
|
|
MOZ_ASSERT(it != mRenderers.end());
|
|
|
|
if (it == mRenderers.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-16 05:13:56 +03:00
|
|
|
TimeStamp start = TimeStamp::Now();
|
|
|
|
|
2017-01-06 21:10:15 +03:00
|
|
|
auto& renderer = it->second;
|
2018-12-07 01:19:03 +03:00
|
|
|
|
|
|
|
layers::CompositorThreadHolder::Loop()->PostTask(
|
|
|
|
NewRunnableFunction("NotifyDidStartRenderRunnable", &NotifyDidStartRender,
|
|
|
|
renderer->GetCompositorBridge()));
|
|
|
|
|
2018-11-12 04:36:13 +03:00
|
|
|
bool rendered = false;
|
2018-11-16 02:09:05 +03:00
|
|
|
RendererStats stats = {0};
|
2018-10-02 06:13:22 +03:00
|
|
|
if (aRender) {
|
2019-05-14 10:18:03 +03:00
|
|
|
rendered = renderer->UpdateAndRender(
|
|
|
|
aReadbackSize, aReadbackFormat, aReadbackBuffer, aHadSlowFrame, &stats);
|
2018-10-02 06:13:22 +03:00
|
|
|
} else {
|
|
|
|
renderer->Update();
|
2017-07-04 13:25:24 +03:00
|
|
|
}
|
2018-10-23 06:14:45 +03:00
|
|
|
// Check graphics reset status even when rendering is skipped.
|
|
|
|
renderer->CheckGraphicsResetStatus();
|
2017-01-27 23:30:18 +03:00
|
|
|
|
|
|
|
TimeStamp end = TimeStamp::Now();
|
2019-05-31 03:31:39 +03:00
|
|
|
RefPtr<WebRenderPipelineInfo> info = renderer->FlushPipelineInfo();
|
2018-05-28 18:29:41 +03:00
|
|
|
|
2017-01-27 23:30:18 +03:00
|
|
|
layers::CompositorThreadHolder::Loop()->PostTask(
|
2017-10-27 23:39:28 +03:00
|
|
|
NewRunnableFunction("NotifyDidRenderRunnable", &NotifyDidRender,
|
2018-12-08 02:28:41 +03:00
|
|
|
renderer->GetCompositorBridge(), info, aStartId,
|
|
|
|
aStartTime, start, end, aRender, stats));
|
2018-11-12 04:36:13 +03:00
|
|
|
|
2019-05-31 03:31:39 +03:00
|
|
|
if (rendered) {
|
|
|
|
auto recorderIt = mCompositionRecorders.find(aWindowId);
|
|
|
|
if (recorderIt != mCompositionRecorders.end()) {
|
2019-07-31 21:28:47 +03:00
|
|
|
recorderIt->second->MaybeRecordFrame(renderer->GetRenderer(), info.get());
|
2019-05-31 03:31:39 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-12 04:36:13 +03:00
|
|
|
if (rendered) {
|
|
|
|
// Wait for GPU after posting NotifyDidRender, since the wait is not
|
|
|
|
// necessary for the NotifyDidRender.
|
|
|
|
// The wait is necessary for Textures recycling of AsyncImagePipelineManager
|
|
|
|
// and for avoiding GPU queue is filled with too much tasks.
|
|
|
|
// WaitForGPU's implementation is different for each platform.
|
|
|
|
renderer->WaitForGPU();
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<layers::AsyncImagePipelineManager> pipelineMgr =
|
|
|
|
renderer->GetCompositorBridge()->GetAsyncImagePipelineManager();
|
|
|
|
// pipelineMgr should always be non-null here because it is only nulled out
|
|
|
|
// after the WebRenderAPI instance for the CompositorBridgeParent is
|
|
|
|
// destroyed, and that destruction blocks until the renderer thread has
|
|
|
|
// 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);
|
2018-11-16 16:01:01 +03:00
|
|
|
pipelineMgr->NotifyPipelinesUpdated(info, aRender);
|
2017-01-06 21:10:15 +03:00
|
|
|
}
|
|
|
|
|
2017-04-05 17:12:11 +03:00
|
|
|
void RenderThread::Pause(wr::WindowId aWindowId) {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
|
|
|
|
auto it = mRenderers.find(aWindowId);
|
|
|
|
MOZ_ASSERT(it != mRenderers.end());
|
|
|
|
if (it == mRenderers.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto& renderer = it->second;
|
|
|
|
renderer->Pause();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RenderThread::Resume(wr::WindowId aWindowId) {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
|
|
|
|
auto it = mRenderers.find(aWindowId);
|
|
|
|
MOZ_ASSERT(it != mRenderers.end());
|
|
|
|
if (it == mRenderers.end()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
auto& renderer = it->second;
|
|
|
|
return renderer->Resume();
|
|
|
|
}
|
|
|
|
|
2017-11-03 05:22:28 +03:00
|
|
|
bool RenderThread::TooManyPendingFrames(wr::WindowId aWindowId) {
|
|
|
|
const int64_t maxFrameCount = 1;
|
|
|
|
|
|
|
|
// Too many pending frames if pending frames exit more than maxFrameCount
|
|
|
|
// or if RenderBackend is still processing a frame.
|
|
|
|
|
2019-01-17 02:25:35 +03:00
|
|
|
auto windows = mWindowInfos.Lock();
|
|
|
|
auto it = windows->find(AsUint64(aWindowId));
|
|
|
|
if (it == windows->end()) {
|
2017-11-03 05:22:28 +03:00
|
|
|
MOZ_ASSERT(false);
|
|
|
|
return true;
|
|
|
|
}
|
2018-06-25 17:55:19 +03:00
|
|
|
WindowInfo* info = it->second;
|
2017-11-03 05:22:28 +03:00
|
|
|
|
2019-08-05 14:59:35 +03:00
|
|
|
if (info->PendingCount() > maxFrameCount) {
|
2017-11-24 12:34:50 +03:00
|
|
|
return true;
|
|
|
|
}
|
2019-08-05 15:02:38 +03:00
|
|
|
MOZ_ASSERT(info->PendingCount() >= info->RenderingCount());
|
|
|
|
return info->PendingCount() > info->RenderingCount();
|
2017-11-24 12:34:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bool RenderThread::IsDestroyed(wr::WindowId aWindowId) {
|
2019-01-17 02:25:35 +03:00
|
|
|
auto windows = mWindowInfos.Lock();
|
|
|
|
auto it = windows->find(AsUint64(aWindowId));
|
|
|
|
if (it == windows->end()) {
|
2017-11-03 05:22:28 +03:00
|
|
|
return true;
|
|
|
|
}
|
2017-11-24 12:34:50 +03:00
|
|
|
|
2018-06-25 17:55:19 +03:00
|
|
|
return it->second->mIsDestroyed;
|
2017-11-24 12:34:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void RenderThread::SetDestroyed(wr::WindowId aWindowId) {
|
2019-01-17 02:25:35 +03:00
|
|
|
auto windows = mWindowInfos.Lock();
|
|
|
|
auto it = windows->find(AsUint64(aWindowId));
|
|
|
|
if (it == windows->end()) {
|
2017-11-24 12:34:50 +03:00
|
|
|
MOZ_ASSERT(false);
|
|
|
|
return;
|
|
|
|
}
|
2018-06-25 17:55:19 +03:00
|
|
|
it->second->mIsDestroyed = true;
|
2017-05-19 03:21:38 +03:00
|
|
|
}
|
|
|
|
|
2018-06-25 17:55:26 +03:00
|
|
|
void RenderThread::IncPendingFrameCount(wr::WindowId aWindowId,
|
2018-12-08 02:28:41 +03:00
|
|
|
const VsyncId& aStartId,
|
2019-03-22 21:28:42 +03:00
|
|
|
const TimeStamp& aStartTime,
|
|
|
|
uint8_t aDocFrameCount) {
|
2019-01-17 02:25:35 +03:00
|
|
|
auto windows = mWindowInfos.Lock();
|
|
|
|
auto it = windows->find(AsUint64(aWindowId));
|
|
|
|
if (it == windows->end()) {
|
2017-05-19 03:21:38 +03:00
|
|
|
MOZ_ASSERT(false);
|
|
|
|
return;
|
|
|
|
}
|
2019-08-05 15:07:29 +03:00
|
|
|
it->second->mPendingFrames.push(
|
|
|
|
PendingFrameInfo{aStartTime, aStartId, 0, aDocFrameCount, false});
|
2017-11-03 05:22:28 +03:00
|
|
|
}
|
|
|
|
|
2018-04-27 14:41:03 +03:00
|
|
|
void RenderThread::FrameRenderingComplete(wr::WindowId aWindowId) {
|
2019-01-17 02:25:35 +03:00
|
|
|
auto windows = mWindowInfos.Lock();
|
|
|
|
auto it = windows->find(AsUint64(aWindowId));
|
|
|
|
if (it == windows->end()) {
|
2017-05-19 03:21:38 +03:00
|
|
|
MOZ_ASSERT(false);
|
|
|
|
return;
|
|
|
|
}
|
2018-06-25 17:55:19 +03:00
|
|
|
WindowInfo* info = it->second;
|
2019-08-05 14:59:35 +03:00
|
|
|
MOZ_ASSERT(info->PendingCount() > 0);
|
2019-08-05 15:02:38 +03:00
|
|
|
MOZ_ASSERT(info->mIsRendering);
|
2019-08-05 14:59:35 +03:00
|
|
|
if (info->PendingCount() <= 0) {
|
2017-05-19 03:21:38 +03:00
|
|
|
return;
|
|
|
|
}
|
2019-08-05 14:54:31 +03:00
|
|
|
|
|
|
|
PendingFrameInfo frame = std::move(info->mPendingFrames.front());
|
|
|
|
info->mPendingFrames.pop();
|
2019-08-05 15:02:38 +03:00
|
|
|
info->mIsRendering = false;
|
2018-11-19 10:55:28 +03:00
|
|
|
|
2018-06-25 17:55:26 +03:00
|
|
|
// The start time is from WebRenderBridgeParent::CompositeToTarget. From that
|
|
|
|
// point until now (when the frame is finally pushed to the screen) is
|
|
|
|
// equivalent to the COMPOSITE_TIME metric in the non-WR codepath.
|
|
|
|
mozilla::Telemetry::AccumulateTimeDelta(mozilla::Telemetry::COMPOSITE_TIME,
|
2019-08-05 14:54:31 +03:00
|
|
|
frame.mStartTime);
|
2017-05-19 03:21:38 +03:00
|
|
|
}
|
|
|
|
|
2018-11-04 23:35:36 +03:00
|
|
|
void RenderThread::NotifySlowFrame(wr::WindowId aWindowId) {
|
2019-01-17 02:25:35 +03:00
|
|
|
auto windows = mWindowInfos.Lock();
|
|
|
|
auto it = windows->find(AsUint64(aWindowId));
|
|
|
|
if (it == windows->end()) {
|
2018-11-04 23:35:36 +03:00
|
|
|
MOZ_ASSERT(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
WindowInfo* info = it->second;
|
|
|
|
info->mHadSlowFrame = true;
|
|
|
|
}
|
|
|
|
|
2017-06-07 18:44:05 +03:00
|
|
|
void RenderThread::RegisterExternalImage(
|
|
|
|
uint64_t aExternalImageId, already_AddRefed<RenderTextureHost> aTexture) {
|
2017-03-07 13:37:28 +03:00
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
2017-06-07 18:44:05 +03:00
|
|
|
|
2017-07-03 15:08:22 +03:00
|
|
|
if (mHasShutdown) {
|
|
|
|
return;
|
|
|
|
}
|
2018-07-10 12:15:47 +03:00
|
|
|
MOZ_ASSERT(mRenderTextures.find(aExternalImageId) == mRenderTextures.end());
|
|
|
|
mRenderTextures.emplace(aExternalImageId, std::move(aTexture));
|
2017-03-07 13:37:28 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void RenderThread::UnregisterExternalImage(uint64_t aExternalImageId) {
|
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
2017-07-03 15:08:22 +03:00
|
|
|
if (mHasShutdown) {
|
|
|
|
return;
|
|
|
|
}
|
2018-07-10 12:15:47 +03:00
|
|
|
auto it = mRenderTextures.find(aExternalImageId);
|
|
|
|
MOZ_ASSERT(it != mRenderTextures.end());
|
2018-07-30 04:16:03 +03:00
|
|
|
if (it == mRenderTextures.end()) {
|
|
|
|
return;
|
|
|
|
}
|
2017-06-07 18:44:05 +03:00
|
|
|
if (!IsInRenderThread()) {
|
|
|
|
// The RenderTextureHost should be released in render thread. So, post the
|
|
|
|
// deletion task here.
|
|
|
|
// The shmem and raw buffer are owned by compositor ipc channel. It's
|
|
|
|
// possible that RenderTextureHost is still exist after the shmem/raw buffer
|
|
|
|
// deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
|
|
|
|
// for this situation. Gecko will only release the buffer if WR doesn't need
|
|
|
|
// it. So, no one will access the invalid buffer in RenderTextureHost.
|
2018-07-10 12:15:47 +03:00
|
|
|
RefPtr<RenderTextureHost> texture = it->second;
|
|
|
|
mRenderTextures.erase(it);
|
2018-06-15 01:18:48 +03:00
|
|
|
mRenderTexturesDeferred.emplace_back(std::move(texture));
|
|
|
|
Loop()->PostTask(NewRunnableMethod(
|
|
|
|
"RenderThread::DeferredRenderTextureHostDestroy", this,
|
2017-06-07 18:44:05 +03:00
|
|
|
&RenderThread::DeferredRenderTextureHostDestroy));
|
|
|
|
} else {
|
2018-07-10 12:15:47 +03:00
|
|
|
mRenderTextures.erase(it);
|
2017-06-07 18:44:05 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-04 01:05:27 +03:00
|
|
|
void RenderThread::PrepareForUse(uint64_t aExternalImageId) {
|
|
|
|
if (!IsInRenderThread()) {
|
|
|
|
Loop()->PostTask(NewRunnableMethod<uint64_t>(
|
|
|
|
"RenderThread::PrepareForUse", this, &RenderThread::PrepareForUse,
|
|
|
|
aExternalImageId));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
|
|
|
if (mHasShutdown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto it = mRenderTextures.find(aExternalImageId);
|
|
|
|
MOZ_ASSERT(it != mRenderTextures.end());
|
|
|
|
if (it == mRenderTextures.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<RenderTextureHost> texture = it->second;
|
|
|
|
texture->PrepareForUse();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RenderThread::NotifyNotUsed(uint64_t aExternalImageId) {
|
|
|
|
if (!IsInRenderThread()) {
|
|
|
|
Loop()->PostTask(NewRunnableMethod<uint64_t>(
|
|
|
|
"RenderThread::NotifyNotUsed", this, &RenderThread::NotifyNotUsed,
|
|
|
|
aExternalImageId));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
|
|
|
if (mHasShutdown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto it = mRenderTextures.find(aExternalImageId);
|
2019-07-05 00:35:02 +03:00
|
|
|
#ifndef MOZ_WIDGET_ANDROID
|
|
|
|
// This assert fails on GeckoView intermittently. Bug 1559958 tracks it.
|
2019-04-04 01:05:27 +03:00
|
|
|
MOZ_ASSERT(it != mRenderTextures.end());
|
2019-07-05 00:35:02 +03:00
|
|
|
#endif
|
2019-04-04 01:05:27 +03:00
|
|
|
if (it == mRenderTextures.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefPtr<RenderTextureHost> texture = it->second;
|
|
|
|
texture->NotifyNotUsed();
|
|
|
|
}
|
|
|
|
|
2019-04-26 10:48:54 +03:00
|
|
|
void RenderThread::NofityForUse(uint64_t aExternalImageId) {
|
|
|
|
MOZ_ASSERT(RenderThread::IsInRenderThread());
|
|
|
|
|
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
|
|
|
if (mHasShutdown) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto it = mRenderTextures.find(aExternalImageId);
|
|
|
|
if (it == mRenderTextures.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
it->second->NofityForUse();
|
|
|
|
}
|
|
|
|
|
2018-04-23 14:57:17 +03:00
|
|
|
void RenderThread::UnregisterExternalImageDuringShutdown(
|
|
|
|
uint64_t aExternalImageId) {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
|
|
|
MOZ_ASSERT(mHasShutdown);
|
2018-07-10 12:15:47 +03:00
|
|
|
MOZ_ASSERT(mRenderTextures.find(aExternalImageId) != mRenderTextures.end());
|
|
|
|
mRenderTextures.erase(aExternalImageId);
|
2018-04-23 14:57:17 +03:00
|
|
|
}
|
|
|
|
|
2018-06-15 01:18:48 +03:00
|
|
|
void RenderThread::DeferredRenderTextureHostDestroy() {
|
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
|
|
|
mRenderTexturesDeferred.clear();
|
2017-03-07 13:37:28 +03:00
|
|
|
}
|
|
|
|
|
2017-06-28 02:20:36 +03:00
|
|
|
RenderTextureHost* RenderThread::GetRenderTexture(
|
|
|
|
wr::WrExternalImageId aExternalImageId) {
|
2017-06-07 18:44:05 +03:00
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
|
2017-03-07 13:37:28 +03:00
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
2018-07-10 12:15:47 +03:00
|
|
|
auto it = mRenderTextures.find(aExternalImageId.mHandle);
|
|
|
|
MOZ_ASSERT(it != mRenderTextures.end());
|
|
|
|
if (it == mRenderTextures.end()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return it->second;
|
2017-03-07 13:37:28 +03:00
|
|
|
}
|
|
|
|
|
2018-10-10 06:20:20 +03:00
|
|
|
void RenderThread::InitDeviceTask() {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
MOZ_ASSERT(!mSharedGL);
|
|
|
|
|
|
|
|
mSharedGL = CreateGLContext();
|
2019-03-16 03:31:38 +03:00
|
|
|
if (gfx::gfxVars::UseWebRenderProgramBinaryDisk()) {
|
|
|
|
mProgramCache = MakeUnique<WebRenderProgramCache>(ThreadPool().Raw());
|
2018-10-10 06:20:20 +03:00
|
|
|
}
|
|
|
|
// Query the shared GL context to force the
|
|
|
|
// lazy initialization to happen now.
|
|
|
|
SharedGL();
|
2018-05-31 09:07:34 +03:00
|
|
|
}
|
|
|
|
|
2018-06-19 13:27:37 +03:00
|
|
|
void RenderThread::HandleDeviceReset(const char* aWhere, bool aNotify) {
|
2018-06-13 18:01:06 +03:00
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
|
|
|
|
if (mHandlingDeviceReset) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-19 13:27:37 +03:00
|
|
|
if (aNotify) {
|
|
|
|
gfxCriticalNote << "GFX: RenderThread detected a device reset in "
|
|
|
|
<< aWhere;
|
|
|
|
if (XRE_IsGPUProcess()) {
|
|
|
|
gfx::GPUParent::GetSingleton()->NotifyDeviceReset();
|
|
|
|
}
|
2018-06-13 18:01:06 +03:00
|
|
|
}
|
|
|
|
|
2018-06-15 01:18:48 +03:00
|
|
|
{
|
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
|
|
|
mRenderTexturesDeferred.clear();
|
2018-07-10 12:15:47 +03:00
|
|
|
for (const auto& entry : mRenderTextures) {
|
|
|
|
entry.second->ClearCachedResources();
|
2018-06-15 01:18:48 +03:00
|
|
|
}
|
2018-06-13 18:01:06 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
mHandlingDeviceReset = true;
|
|
|
|
// All RenderCompositors will be destroyed by
|
|
|
|
// GPUChild::RecvNotifyDeviceReset()
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RenderThread::IsHandlingDeviceReset() {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
return mHandlingDeviceReset;
|
|
|
|
}
|
|
|
|
|
2018-06-19 13:27:37 +03:00
|
|
|
void RenderThread::SimulateDeviceReset() {
|
|
|
|
if (!IsInRenderThread()) {
|
|
|
|
Loop()->PostTask(NewRunnableMethod("RenderThread::SimulateDeviceReset",
|
|
|
|
this,
|
|
|
|
&RenderThread::SimulateDeviceReset));
|
|
|
|
} else {
|
|
|
|
// When this function is called GPUProcessManager::SimulateDeviceReset()
|
|
|
|
// already triggers destroying all CompositorSessions before re-creating
|
|
|
|
// them.
|
|
|
|
HandleDeviceReset("SimulateDeviceReset", /* aNotify */ false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-19 19:14:56 +03:00
|
|
|
static void DoNotifyWebRenderError(WebRenderError aError) {
|
|
|
|
layers::CompositorManagerParent::NotifyWebRenderError(aError);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RenderThread::HandleWebRenderError(WebRenderError aError) {
|
|
|
|
if (mHandlingWebRenderError) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
|
|
|
|
"DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
|
|
|
|
{
|
|
|
|
MutexAutoLock lock(mRenderTextureMapLock);
|
|
|
|
mRenderTexturesDeferred.clear();
|
|
|
|
for (const auto& entry : mRenderTextures) {
|
|
|
|
entry.second->ClearCachedResources();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mHandlingWebRenderError = true;
|
|
|
|
// WebRender is going to be disabled by
|
|
|
|
// GPUProcessManager::NotifyWebRenderError()
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RenderThread::IsHandlingWebRenderError() {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
return mHandlingWebRenderError;
|
|
|
|
}
|
|
|
|
|
2018-10-10 06:20:20 +03:00
|
|
|
gl::GLContext* RenderThread::SharedGL() {
|
2018-10-04 05:54:50 +03:00
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
|
|
|
if (!mSharedGL) {
|
|
|
|
mSharedGL = CreateGLContext();
|
2018-10-10 06:20:20 +03:00
|
|
|
mShaders = nullptr;
|
|
|
|
}
|
|
|
|
if (mSharedGL && !mShaders) {
|
|
|
|
mShaders = MakeUnique<WebRenderShaders>(mSharedGL, mProgramCache.get());
|
2018-10-04 05:54:50 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return mSharedGL.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void RenderThread::ClearSharedGL() {
|
|
|
|
MOZ_ASSERT(IsInRenderThread());
|
2018-10-10 06:20:20 +03:00
|
|
|
mShaders = nullptr;
|
2018-10-04 05:54:50 +03:00
|
|
|
mSharedGL = nullptr;
|
|
|
|
}
|
|
|
|
|
2018-10-10 06:20:20 +03:00
|
|
|
WebRenderShaders::WebRenderShaders(gl::GLContext* gl,
|
|
|
|
WebRenderProgramCache* programCache) {
|
|
|
|
mGL = gl;
|
|
|
|
mShaders = wr_shaders_new(gl, programCache ? programCache->Raw() : nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
WebRenderShaders::~WebRenderShaders() {
|
|
|
|
wr_shaders_delete(mShaders, mGL.get());
|
|
|
|
}
|
2018-10-04 05:54:50 +03:00
|
|
|
|
2018-11-12 04:36:13 +03:00
|
|
|
WebRenderPipelineInfo::WebRenderPipelineInfo(wr::WrPipelineInfo aPipelineInfo)
|
|
|
|
: mPipelineInfo(aPipelineInfo) {}
|
|
|
|
|
|
|
|
WebRenderPipelineInfo::~WebRenderPipelineInfo() {
|
|
|
|
wr_pipeline_info_delete(mPipelineInfo);
|
|
|
|
}
|
|
|
|
|
2017-06-13 18:57:16 +03:00
|
|
|
WebRenderThreadPool::WebRenderThreadPool() {
|
|
|
|
mThreadPool = wr_thread_pool_new();
|
|
|
|
}
|
|
|
|
|
2019-07-12 01:36:44 +03:00
|
|
|
WebRenderThreadPool::~WebRenderThreadPool() { Release(); }
|
2017-06-13 18:57:16 +03:00
|
|
|
|
2019-07-01 18:24:32 +03:00
|
|
|
void WebRenderThreadPool::Release() {
|
|
|
|
if (mThreadPool) {
|
|
|
|
wr_thread_pool_delete(mThreadPool);
|
|
|
|
mThreadPool = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-31 09:07:34 +03:00
|
|
|
WebRenderProgramCache::WebRenderProgramCache(wr::WrThreadPool* aThreadPool) {
|
|
|
|
MOZ_ASSERT(aThreadPool);
|
|
|
|
|
|
|
|
nsAutoString path;
|
|
|
|
if (gfxVars::UseWebRenderProgramBinaryDisk()) {
|
|
|
|
path.Append(gfx::gfxVars::ProfDirectory());
|
|
|
|
}
|
|
|
|
mProgramCache = wr_program_cache_new(&path, aThreadPool);
|
2018-12-04 03:10:01 +03:00
|
|
|
if (gfxVars::UseWebRenderProgramBinaryDisk()) {
|
2019-07-09 13:20:04 +03:00
|
|
|
wr_try_load_startup_shaders_from_disk(mProgramCache);
|
2018-12-04 03:10:01 +03:00
|
|
|
}
|
2017-11-24 14:58:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
WebRenderProgramCache::~WebRenderProgramCache() {
|
|
|
|
wr_program_cache_delete(mProgramCache);
|
|
|
|
}
|
|
|
|
|
2017-01-25 00:06:17 +03:00
|
|
|
} // namespace wr
|
|
|
|
} // namespace mozilla
|
2017-01-06 21:10:15 +03:00
|
|
|
|
2018-10-04 05:54:50 +03:00
|
|
|
#ifdef XP_WIN
|
|
|
|
static already_AddRefed<gl::GLContext> CreateGLContextANGLE() {
|
|
|
|
nsCString discardFailureId;
|
|
|
|
if (!gl::GLLibraryEGL::EnsureInitialized(/* forceAccel */ true,
|
|
|
|
&discardFailureId)) {
|
|
|
|
gfxCriticalNote << "Failed to load EGL library: " << discardFailureId.get();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto* egl = gl::GLLibraryEGL::Get();
|
|
|
|
auto flags = gl::CreateContextFlags::PREFER_ES3;
|
|
|
|
|
2018-09-27 08:31:30 +03:00
|
|
|
if (egl->IsExtensionSupported(
|
|
|
|
gl::GLLibraryEGL::MOZ_create_context_provoking_vertex_dont_care)) {
|
|
|
|
flags |= gl::CreateContextFlags::PROVOKING_VERTEX_DONT_CARE;
|
|
|
|
}
|
|
|
|
|
2018-10-04 05:54:50 +03:00
|
|
|
// Create GLContext with dummy EGLSurface, the EGLSurface is not used.
|
|
|
|
// Instread we override it with EGLSurface of SwapChain's back buffer.
|
|
|
|
RefPtr<gl::GLContext> gl =
|
|
|
|
gl::GLContextProviderEGL::CreateHeadless(flags, &discardFailureId);
|
|
|
|
if (!gl || !gl->IsANGLE()) {
|
|
|
|
gfxCriticalNote << "Failed ANGLE GL context creation for WebRender: "
|
|
|
|
<< gfx::hexa(gl.get());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gl->MakeCurrent()) {
|
|
|
|
gfxCriticalNote << "Failed GL context creation for WebRender: "
|
|
|
|
<< gfx::hexa(gl.get());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gl.forget();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-04-12 11:08:03 +03:00
|
|
|
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WAYLAND)
|
2019-03-20 14:51:33 +03:00
|
|
|
static already_AddRefed<gl::GLContext> CreateGLContextEGL() {
|
|
|
|
nsCString discardFailureId;
|
|
|
|
if (!gl::GLLibraryEGL::EnsureInitialized(/* forceAccel */ true,
|
|
|
|
&discardFailureId)) {
|
|
|
|
gfxCriticalNote << "Failed to load EGL library: " << discardFailureId.get();
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
// Create GLContext with dummy EGLSurface.
|
|
|
|
RefPtr<gl::GLContext> gl =
|
|
|
|
gl::GLContextProviderEGL::CreateForCompositorWidget(
|
|
|
|
nullptr, /* aWebRender */ true, /* aForceAccelerated */ true);
|
|
|
|
if (!gl || !gl->MakeCurrent()) {
|
|
|
|
gfxCriticalNote << "Failed GL context creation for WebRender: "
|
|
|
|
<< gfx::hexa(gl.get());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return gl.forget();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-10-04 05:54:50 +03:00
|
|
|
static already_AddRefed<gl::GLContext> CreateGLContext() {
|
|
|
|
#ifdef XP_WIN
|
|
|
|
if (gfx::gfxVars::UseWebRenderANGLE()) {
|
|
|
|
return CreateGLContextANGLE();
|
|
|
|
}
|
|
|
|
#endif
|
2019-03-20 14:51:33 +03:00
|
|
|
|
2019-04-12 11:08:03 +03:00
|
|
|
#if defined(MOZ_WIDGET_ANDROID)
|
|
|
|
return CreateGLContextEGL();
|
|
|
|
#elif defined(MOZ_WAYLAND)
|
|
|
|
if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
|
|
|
|
return CreateGLContextEGL();
|
|
|
|
}
|
2019-03-20 14:51:33 +03:00
|
|
|
#endif
|
2018-10-04 05:54:50 +03:00
|
|
|
// We currently only support a shared GLContext
|
|
|
|
// with ANGLE.
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:10:15 +03:00
|
|
|
extern "C" {
|
|
|
|
|
2018-02-08 18:49:25 +03:00
|
|
|
void wr_notifier_wake_up(mozilla::wr::WrWindowId aWindowId) {
|
2018-04-27 14:41:03 +03:00
|
|
|
mozilla::wr::RenderThread::Get()->WakeUp(aWindowId);
|
2018-02-08 18:49:25 +03:00
|
|
|
}
|
|
|
|
|
2018-01-17 19:19:39 +03:00
|
|
|
void wr_notifier_new_frame_ready(mozilla::wr::WrWindowId aWindowId) {
|
2019-08-06 10:01:15 +03:00
|
|
|
mozilla::wr::RenderThread::Get()->HandleFrameOneDoc(aWindowId,
|
|
|
|
/* aRender */ true);
|
2018-01-17 19:19:39 +03:00
|
|
|
}
|
|
|
|
|
2018-04-27 14:41:03 +03:00
|
|
|
void wr_notifier_nop_frame_done(mozilla::wr::WrWindowId aWindowId) {
|
2019-08-06 10:01:15 +03:00
|
|
|
mozilla::wr::RenderThread::Get()->HandleFrameOneDoc(aWindowId,
|
|
|
|
/* aRender */ false);
|
2017-01-06 21:10:15 +03:00
|
|
|
}
|
|
|
|
|
2017-06-28 02:20:36 +03:00
|
|
|
void wr_notifier_external_event(mozilla::wr::WrWindowId aWindowId,
|
|
|
|
size_t aRawEvent) {
|
2017-01-17 03:22:09 +03:00
|
|
|
mozilla::UniquePtr<mozilla::wr::RendererEvent> evt(
|
|
|
|
reinterpret_cast<mozilla::wr::RendererEvent*>(aRawEvent));
|
|
|
|
mozilla::wr::RenderThread::Get()->RunEvent(mozilla::wr::WindowId(aWindowId),
|
2018-05-30 22:15:35 +03:00
|
|
|
std::move(evt));
|
2017-01-06 21:10:15 +03:00
|
|
|
}
|
|
|
|
|
2019-03-22 21:28:42 +03:00
|
|
|
void wr_schedule_render(mozilla::wr::WrWindowId aWindowId,
|
2019-04-16 01:34:13 +03:00
|
|
|
const mozilla::wr::WrDocumentId* aDocumentIds,
|
|
|
|
size_t aDocumentIdsCount) {
|
2018-12-21 01:52:07 +03:00
|
|
|
RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
|
|
|
|
CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
|
|
|
|
if (cbp) {
|
2019-04-17 18:12:10 +03:00
|
|
|
wr::RenderRootSet renderRoots;
|
2019-04-16 01:34:13 +03:00
|
|
|
for (size_t i = 0; i < aDocumentIdsCount; ++i) {
|
2019-04-17 18:12:10 +03:00
|
|
|
renderRoots += wr::RenderRootFromId(aDocumentIds[i]);
|
2019-04-16 01:34:13 +03:00
|
|
|
}
|
|
|
|
cbp->ScheduleRenderOnCompositorThread(renderRoots);
|
2018-12-21 01:52:07 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void NotifyDidSceneBuild(RefPtr<layers::CompositorBridgeParent> aBridge,
|
2019-04-16 01:34:13 +03:00
|
|
|
const nsTArray<wr::RenderRoot>& aRenderRoots,
|
2018-12-21 01:52:07 +03:00
|
|
|
RefPtr<wr::WebRenderPipelineInfo> aInfo) {
|
2019-04-16 01:34:13 +03:00
|
|
|
aBridge->NotifyDidSceneBuild(aRenderRoots, aInfo);
|
2018-12-21 01:43:01 +03:00
|
|
|
}
|
|
|
|
|
2018-12-21 01:52:07 +03:00
|
|
|
void wr_finished_scene_build(mozilla::wr::WrWindowId aWindowId,
|
2019-04-16 01:34:13 +03:00
|
|
|
const mozilla::wr::WrDocumentId* aDocumentIds,
|
|
|
|
size_t aDocumentIdsCount,
|
2018-12-21 01:52:07 +03:00
|
|
|
mozilla::wr::WrPipelineInfo aInfo) {
|
2018-05-11 16:09:16 +03:00
|
|
|
RefPtr<mozilla::layers::CompositorBridgeParent> cbp = mozilla::layers::
|
|
|
|
CompositorBridgeParent::GetCompositorBridgeParentFromWindowId(aWindowId);
|
2018-12-21 01:52:07 +03:00
|
|
|
RefPtr<wr::WebRenderPipelineInfo> info = new wr::WebRenderPipelineInfo(aInfo);
|
2018-05-11 16:09:16 +03:00
|
|
|
if (cbp) {
|
2019-07-10 06:30:18 +03:00
|
|
|
nsTArray<wr::RenderRoot> renderRoots;
|
2019-04-16 01:34:13 +03:00
|
|
|
renderRoots.SetLength(aDocumentIdsCount);
|
|
|
|
for (size_t i = 0; i < aDocumentIdsCount; ++i) {
|
|
|
|
renderRoots[i] = wr::RenderRootFromId(aDocumentIds[i]);
|
|
|
|
}
|
2018-12-21 01:52:07 +03:00
|
|
|
layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
|
2019-04-16 01:34:13 +03:00
|
|
|
"NotifyDidSceneBuild", &NotifyDidSceneBuild, cbp, renderRoots, info));
|
2018-05-11 16:09:16 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:10:15 +03:00
|
|
|
} // extern C
|