LCOV - code coverage report
Current view: top level - gfx/webrender_bindings - RenderThread.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 181 0.6 %
Date: 2017-07-14 16:53:18 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "base/task.h"
       7             : #include "GeckoProfiler.h"
       8             : #include "RenderThread.h"
       9             : #include "nsThreadUtils.h"
      10             : #include "mtransport/runnable_utils.h"
      11             : #include "mozilla/layers/CompositorThread.h"
      12             : #include "mozilla/layers/CompositorBridgeParent.h"
      13             : #include "mozilla/StaticPtr.h"
      14             : #include "mozilla/webrender/RendererOGL.h"
      15             : #include "mozilla/webrender/RenderTextureHost.h"
      16             : #include "mozilla/widget/CompositorWidget.h"
      17             : 
      18             : namespace mozilla {
      19             : namespace wr {
      20             : 
      21           3 : static StaticRefPtr<RenderThread> sRenderThread;
      22             : 
      23           0 : RenderThread::RenderThread(base::Thread* aThread)
      24             :   : mThread(aThread)
      25             :   , mPendingFrameCountMapLock("RenderThread.mPendingFrameCountMapLock")
      26             :   , mRenderTextureMapLock("RenderThread.mRenderTextureMapLock")
      27           0 :   , mHasShutdown(false)
      28             : {
      29             : 
      30           0 : }
      31             : 
      32           0 : RenderThread::~RenderThread()
      33             : {
      34           0 :   delete mThread;
      35           0 : }
      36             : 
      37             : // static
      38             : RenderThread*
      39           0 : RenderThread::Get()
      40             : {
      41           0 :   return sRenderThread;
      42             : }
      43             : 
      44             : // static
      45             : void
      46           0 : RenderThread::Start()
      47             : {
      48           0 :   MOZ_ASSERT(NS_IsMainThread());
      49           0 :   MOZ_ASSERT(!sRenderThread);
      50             : 
      51           0 :   base::Thread* thread = new base::Thread("Renderer");
      52             : 
      53           0 :   base::Thread::Options options;
      54             :   // TODO(nical): The compositor thread has a bunch of specific options, see
      55             :   // which ones make sense here.
      56           0 :   if (!thread->StartWithOptions(options)) {
      57           0 :     delete thread;
      58           0 :     return;
      59             :   }
      60             : 
      61           0 :   sRenderThread = new RenderThread(thread);
      62             : }
      63             : 
      64             : // static
      65             : void
      66           0 : RenderThread::ShutDown()
      67             : {
      68           0 :   MOZ_ASSERT(NS_IsMainThread());
      69           0 :   MOZ_ASSERT(sRenderThread);
      70             : 
      71             :   {
      72           0 :     MutexAutoLock lock(sRenderThread->mRenderTextureMapLock);
      73           0 :     sRenderThread->mHasShutdown = true;
      74             :   }
      75             : 
      76           0 :   layers::SynchronousTask task("RenderThread");
      77           0 :   RefPtr<Runnable> runnable = WrapRunnable(
      78           0 :     RefPtr<RenderThread>(sRenderThread.get()),
      79             :     &RenderThread::ShutDownTask,
      80           0 :     &task);
      81           0 :   sRenderThread->Loop()->PostTask(runnable.forget());
      82           0 :   task.Wait();
      83             : 
      84           0 :   sRenderThread = nullptr;
      85           0 : }
      86             : 
      87             : void
      88           0 : RenderThread::ShutDownTask(layers::SynchronousTask* aTask)
      89             : {
      90           0 :   layers::AutoCompleteTask complete(aTask);
      91           0 :   MOZ_ASSERT(IsInRenderThread());
      92           0 : }
      93             : 
      94             : // static
      95             : MessageLoop*
      96           0 : RenderThread::Loop()
      97             : {
      98           0 :   return sRenderThread ? sRenderThread->mThread->message_loop() : nullptr;
      99             : }
     100             : 
     101             : // static
     102             : bool
     103           0 : RenderThread::IsInRenderThread()
     104             : {
     105           0 :   return sRenderThread && sRenderThread->mThread->thread_id() == PlatformThread::CurrentId();
     106             : }
     107             : 
     108             : void
     109           0 : RenderThread::AddRenderer(wr::WindowId aWindowId, UniquePtr<RendererOGL> aRenderer)
     110             : {
     111           0 :   MOZ_ASSERT(IsInRenderThread());
     112             : 
     113           0 :   if (mHasShutdown) {
     114           0 :     return;
     115             :   }
     116             : 
     117           0 :   mRenderers[aWindowId] = Move(aRenderer);
     118             : 
     119           0 :   MutexAutoLock lock(mPendingFrameCountMapLock);
     120           0 :   mPendingFrameCounts.Put(AsUint64(aWindowId), 0);
     121             : }
     122             : 
     123             : void
     124           0 : RenderThread::RemoveRenderer(wr::WindowId aWindowId)
     125             : {
     126           0 :   MOZ_ASSERT(IsInRenderThread());
     127             : 
     128           0 :   if (mHasShutdown) {
     129           0 :     return;
     130             :   }
     131             : 
     132           0 :   mRenderers.erase(aWindowId);
     133             : 
     134           0 :   MutexAutoLock lock(mPendingFrameCountMapLock);
     135           0 :   mPendingFrameCounts.Remove(AsUint64(aWindowId));
     136             : }
     137             : 
     138             : RendererOGL*
     139           0 : RenderThread::GetRenderer(wr::WindowId aWindowId)
     140             : {
     141           0 :   MOZ_ASSERT(IsInRenderThread());
     142             : 
     143           0 :   auto it = mRenderers.find(aWindowId);
     144           0 :   MOZ_ASSERT(it != mRenderers.end());
     145             : 
     146           0 :   if (it == mRenderers.end()) {
     147           0 :     return nullptr;
     148             :   }
     149             : 
     150           0 :   return it->second.get();
     151             : }
     152             : 
     153             : void
     154           0 : RenderThread::NewFrameReady(wr::WindowId aWindowId)
     155             : {
     156           0 :   if (mHasShutdown) {
     157           0 :     return;
     158             :   }
     159             : 
     160           0 :   if (!IsInRenderThread()) {
     161           0 :     Loop()->PostTask(
     162           0 :       NewRunnableMethod<wr::WindowId>("wr::RenderThread::NewFrameReady",
     163             :                                       this,
     164             :                                       &RenderThread::NewFrameReady,
     165           0 :                                       aWindowId));
     166           0 :     return;
     167             :   }
     168             : 
     169           0 :   UpdateAndRender(aWindowId);
     170           0 :   DecPendingFrameCount(aWindowId);
     171             : }
     172             : 
     173             : void
     174           0 : RenderThread::RunEvent(wr::WindowId aWindowId, UniquePtr<RendererEvent> aEvent)
     175             : {
     176           0 :   if (!IsInRenderThread()) {
     177           0 :     Loop()->PostTask(
     178           0 :       NewRunnableMethod<wr::WindowId, UniquePtr<RendererEvent>&&>(
     179             :         "wr::RenderThread::RunEvent",
     180             :         this,
     181             :         &RenderThread::RunEvent,
     182             :         aWindowId,
     183           0 :         Move(aEvent)));
     184           0 :     return;
     185             :   }
     186             : 
     187           0 :   aEvent->Run(*this, aWindowId);
     188           0 :   aEvent = nullptr;
     189             : }
     190             : 
     191             : static void
     192           0 : NotifyDidRender(layers::CompositorBridgeParentBase* aBridge,
     193             :                 WrRenderedEpochs* aEpochs,
     194             :                 TimeStamp aStart,
     195             :                 TimeStamp aEnd)
     196             : {
     197             :   WrPipelineId pipeline;
     198             :   WrEpoch epoch;
     199           0 :   while (wr_rendered_epochs_next(aEpochs, &pipeline, &epoch)) {
     200           0 :     aBridge->NotifyDidCompositeToPipeline(pipeline, epoch, aStart, aEnd);
     201             :   }
     202           0 :   wr_rendered_epochs_delete(aEpochs);
     203           0 : }
     204             : 
     205             : void
     206           0 : RenderThread::UpdateAndRender(wr::WindowId aWindowId)
     207             : {
     208           0 :   AutoProfilerTracing tracing("Paint", "Composite");
     209           0 :   MOZ_ASSERT(IsInRenderThread());
     210             : 
     211           0 :   auto it = mRenderers.find(aWindowId);
     212           0 :   MOZ_ASSERT(it != mRenderers.end());
     213           0 :   if (it == mRenderers.end()) {
     214           0 :     return;
     215             :   }
     216             : 
     217           0 :   auto& renderer = it->second;
     218           0 :   renderer->Update();
     219             : 
     220           0 :   TimeStamp start = TimeStamp::Now();
     221             : 
     222           0 :   bool ret = renderer->Render();
     223           0 :   if (!ret) {
     224             :     // Render did not happen, do not call NotifyDidRender.
     225           0 :     return;
     226             :   }
     227             : 
     228           0 :   TimeStamp end = TimeStamp::Now();
     229             : 
     230           0 :   auto epochs = renderer->FlushRenderedEpochs();
     231           0 :   layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
     232             :     &NotifyDidRender,
     233           0 :     renderer->GetCompositorBridge(),
     234             :     epochs,
     235             :     start, end
     236           0 :   ));
     237             : }
     238             : 
     239             : void
     240           0 : RenderThread::Pause(wr::WindowId aWindowId)
     241             : {
     242           0 :   MOZ_ASSERT(IsInRenderThread());
     243             : 
     244           0 :   auto it = mRenderers.find(aWindowId);
     245           0 :   MOZ_ASSERT(it != mRenderers.end());
     246           0 :   if (it == mRenderers.end()) {
     247           0 :     return;
     248             :   }
     249           0 :   auto& renderer = it->second;
     250           0 :   renderer->Pause();
     251             : }
     252             : 
     253             : bool
     254           0 : RenderThread::Resume(wr::WindowId aWindowId)
     255             : {
     256           0 :   MOZ_ASSERT(IsInRenderThread());
     257             : 
     258           0 :   auto it = mRenderers.find(aWindowId);
     259           0 :   MOZ_ASSERT(it != mRenderers.end());
     260           0 :   if (it == mRenderers.end()) {
     261           0 :     return false;
     262             :   }
     263           0 :   auto& renderer = it->second;
     264           0 :   return renderer->Resume();
     265             : }
     266             : 
     267             : uint32_t
     268           0 : RenderThread::GetPendingFrameCount(wr::WindowId aWindowId)
     269             : {
     270           0 :   MutexAutoLock lock(mPendingFrameCountMapLock);
     271           0 :   uint32_t count = 0;
     272           0 :   MOZ_ASSERT(mPendingFrameCounts.Get(AsUint64(aWindowId), &count));
     273           0 :   mPendingFrameCounts.Get(AsUint64(aWindowId), &count);
     274           0 :   return count;
     275             : }
     276             : 
     277             : void
     278           0 : RenderThread::IncPendingFrameCount(wr::WindowId aWindowId)
     279             : {
     280           0 :   MutexAutoLock lock(mPendingFrameCountMapLock);
     281             :   // Get the old count.
     282           0 :   uint32_t oldCount = 0;
     283           0 :   if (!mPendingFrameCounts.Get(AsUint64(aWindowId), &oldCount)) {
     284           0 :     MOZ_ASSERT(false);
     285             :     return;
     286             :   }
     287             :   // Update pending frame count.
     288           0 :   mPendingFrameCounts.Put(AsUint64(aWindowId), oldCount + 1);
     289           0 : }
     290             : 
     291             : void
     292           0 : RenderThread::DecPendingFrameCount(wr::WindowId aWindowId)
     293             : {
     294           0 :   MutexAutoLock lock(mPendingFrameCountMapLock);
     295             :   // Get the old count.
     296           0 :   uint32_t oldCount = 0;
     297           0 :   if (!mPendingFrameCounts.Get(AsUint64(aWindowId), &oldCount)) {
     298           0 :     MOZ_ASSERT(false);
     299             :     return;
     300             :   }
     301           0 :   MOZ_ASSERT(oldCount > 0);
     302           0 :   if (oldCount <= 0) {
     303           0 :     return;
     304             :   }
     305             :   // Update pending frame count.
     306           0 :   mPendingFrameCounts.Put(AsUint64(aWindowId), oldCount - 1);
     307             : }
     308             : 
     309             : void
     310           0 : RenderThread::RegisterExternalImage(uint64_t aExternalImageId, already_AddRefed<RenderTextureHost> aTexture)
     311             : {
     312           0 :   MutexAutoLock lock(mRenderTextureMapLock);
     313             : 
     314           0 :   if (mHasShutdown) {
     315           0 :     return;
     316             :   }
     317           0 :   MOZ_ASSERT(!mRenderTextures.GetWeak(aExternalImageId));
     318           0 :   mRenderTextures.Put(aExternalImageId, Move(aTexture));
     319             : }
     320             : 
     321             : void
     322           0 : RenderThread::UnregisterExternalImage(uint64_t aExternalImageId)
     323             : {
     324           0 :   MutexAutoLock lock(mRenderTextureMapLock);
     325           0 :   if (mHasShutdown) {
     326           0 :     return;
     327             :   }
     328           0 :   MOZ_ASSERT(mRenderTextures.GetWeak(aExternalImageId));
     329           0 :   if (!IsInRenderThread()) {
     330             :     // The RenderTextureHost should be released in render thread. So, post the
     331             :     // deletion task here.
     332             :     // The shmem and raw buffer are owned by compositor ipc channel. It's
     333             :     // possible that RenderTextureHost is still exist after the shmem/raw buffer
     334             :     // deletion. Then the buffer in RenderTextureHost becomes invalid. It's fine
     335             :     // for this situation. Gecko will only release the buffer if WR doesn't need
     336             :     // it. So, no one will access the invalid buffer in RenderTextureHost.
     337           0 :     RefPtr<RenderTextureHost> texture;
     338           0 :     mRenderTextures.Remove(aExternalImageId, getter_AddRefs(texture));
     339           0 :     Loop()->PostTask(NewRunnableMethod<RefPtr<RenderTextureHost>>(
     340             :       "RenderThread::DeferredRenderTextureHostDestroy",
     341           0 :       this, &RenderThread::DeferredRenderTextureHostDestroy, Move(texture)
     342           0 :     ));
     343             :   } else {
     344           0 :     mRenderTextures.Remove(aExternalImageId);
     345             :   }
     346             : }
     347             : 
     348             : void
     349           0 : RenderThread::DeferredRenderTextureHostDestroy(RefPtr<RenderTextureHost>)
     350             : {
     351             :   // Do nothing. Just decrease the ref-count of RenderTextureHost.
     352           0 : }
     353             : 
     354             : RenderTextureHost*
     355           0 : RenderThread::GetRenderTexture(WrExternalImageId aExternalImageId)
     356             : {
     357           0 :   MOZ_ASSERT(IsInRenderThread());
     358             : 
     359           0 :   MutexAutoLock lock(mRenderTextureMapLock);
     360           0 :   MOZ_ASSERT(mRenderTextures.GetWeak(aExternalImageId.mHandle));
     361           0 :   return mRenderTextures.GetWeak(aExternalImageId.mHandle);
     362             : }
     363             : 
     364           0 : WebRenderThreadPool::WebRenderThreadPool()
     365             : {
     366           0 :   mThreadPool = wr_thread_pool_new();
     367           0 : }
     368             : 
     369           0 : WebRenderThreadPool::~WebRenderThreadPool()
     370             : {
     371           0 :   wr_thread_pool_delete(mThreadPool);
     372           0 : }
     373             : 
     374             : } // namespace wr
     375             : } // namespace mozilla
     376             : 
     377             : extern "C" {
     378             : 
     379           0 : void wr_notifier_new_frame_ready(WrWindowId aWindowId)
     380             : {
     381           0 :   mozilla::wr::RenderThread::Get()->IncPendingFrameCount(aWindowId);
     382           0 :   mozilla::wr::RenderThread::Get()->NewFrameReady(mozilla::wr::WindowId(aWindowId));
     383           0 : }
     384             : 
     385           0 : void wr_notifier_new_scroll_frame_ready(WrWindowId aWindowId, bool aCompositeNeeded)
     386             : {
     387             :   // It is not necessary to update rendering with new_scroll_frame_ready.
     388             :   // WebRenderBridgeParent::CompositeToTarget() is implemented to call
     389             :   // WebRenderAPI::GenerateFrame() if it is necessary to trigger UpdateAndRender().
     390             :   // See Bug 1377688.
     391           0 : }
     392             : 
     393           0 : void wr_notifier_external_event(WrWindowId aWindowId, size_t aRawEvent)
     394             : {
     395             :   mozilla::UniquePtr<mozilla::wr::RendererEvent> evt(
     396           0 :     reinterpret_cast<mozilla::wr::RendererEvent*>(aRawEvent));
     397           0 :   mozilla::wr::RenderThread::Get()->RunEvent(mozilla::wr::WindowId(aWindowId),
     398           0 :                                              mozilla::Move(evt));
     399           0 : }
     400             : 
     401             : } // extern C

Generated by: LCOV version 1.13